From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- build/.gdbinit | 208 ++ build/.gdbinit.loader | 29 + build/.gdbinit.py.in | 19 + build/.lldbinit.in | 21 + build/RunCbindgen.py | 102 + build/__init__.py | 0 build/android/libgcc.a | 1 + build/appini_header.py | 90 + build/application.ini.in | 56 + build/autoconf/acgeneral.m4 | 2607 ++++++++++++++ build/autoconf/acoldnames.m4 | 80 + build/autoconf/acspecific.m4 | 2758 +++++++++++++++ build/autoconf/alloc.m4 | 57 + build/autoconf/altoptions.m4 | 72 + build/autoconf/android.m4 | 20 + build/autoconf/arch.m4 | 15 + build/autoconf/autoconf.m4 | 28 + build/autoconf/autoconf.sh | 158 + build/autoconf/clang-plugin.m4 | 107 + build/autoconf/codeset.m4 | 25 + build/autoconf/compiler-opts.m4 | 198 ++ build/autoconf/config.guess | 1754 ++++++++++ build/autoconf/config.status.m4 | 154 + build/autoconf/config.sub | 1890 +++++++++++ build/autoconf/expandlibs.m4 | 53 + build/autoconf/hooks.m4 | 31 + build/autoconf/install-sh | 123 + build/autoconf/mozheader.m4 | 32 + build/autoconf/mozprog.m4 | 42 + build/autoconf/sanitize.m4 | 143 + build/autoconf/toolchain.m4 | 117 + build/binary-location.mk | 19 + build/build-clang/1stage.json | 4 + build/build-clang/2stages.json | 3 + build/build-clang/4stages-pgo.json | 7 + build/build-clang/D146664.patch | 99 + build/build-clang/README | 53 + ...-FlushViewOfFile-when-unmaping-gcda-files.patch | 31 + build/build-clang/allow-unversioned-android.patch | 36 + .../android-mangling-error_clang_12.patch | 24 + build/build-clang/build-clang.py | 843 +++++ build/build-clang/clang-14.json | 13 + build/build-clang/clang-17.json | 18 + build/build-clang/clang-18.json | 21 + build/build-clang/clang-8-missing-header.patch | 12 + build/build-clang/clang-8.0.json | 10 + build/build-clang/clang-tidy-ci.patch | 34 + build/build-clang/clang-tidy-external-linux64.json | 11 + build/build-clang/clang-tidy-linux64.json | 10 + build/build-clang/clang-tidy-macosx64.json | 7 + build/build-clang/clang-tidy-win64.json | 7 + build/build-clang/clang-trunk.json | 21 + .../compiler-rt-rss-limit-heap-profile.patch | 49 + .../downgrade-mangling-error_clang_12.patch | 23 + .../find_symbolizer_linux_clang_10.patch | 58 + .../find_symbolizer_linux_clang_15.patch | 53 + .../build-clang/fuzzing_ccov_build_clang_12.patch | 27 + build/build-clang/linux64.json | 5 + .../llvmorg-10-init-136-gb288d90b39f4.patch | 37 + .../llvmorg-15-init-16512-g4b1e3d193706.patch | 138 + build/build-clang/macosx64-aarch64.json | 3 + build/build-clang/macosx64.json | 9 + ...morg-16-init-17151-gaa0883b59ae1_clang_17.patch | 13 + ...evert-llvmorg-17-init-17713-gc8e055d485ea.patch | 33 + build/build-clang/profile.json | 6 + ...morg-15-init-11205-gcead4eceb01b_clang_16.patch | 1027 ++++++ ...morg-15-init-11205-gcead4eceb01b_clang_18.patch | 972 ++++++ ...evert-llvmorg-15-init-13446-g7524fe962e47.patch | 39 + ...morg-16-init-11301-g163bb6d64e5f_clang_17.patch | 172 + ...morg-16-init-11301-g163bb6d64e5f_clang_18.patch | 183 + ...revert-llvmorg-17-init-4120-g02e8eb1a438b.patch | 118 + ...vmorg-17-init-4120-g02e8eb1a438b_clang_18.patch | 115 + ...revert-llvmorg-18-init-6188-gc649f29c24c9.patch | 466 +++ ...revert-llvmorg-18-init-6193-gb88cffeafd39.patch | 63 + ...revert-llvmorg-18-init-6208-g2baf4a06ef06.patch | 28 + build/build-clang/skip-3-stages.json | 6 + build/build-clang/skip-stage-1-win64.json | 7 + build/build-clang/skip-stage-1.json | 6 + .../unpoison-thread-stacks_clang_10.patch | 64 + ...n64-ret-null-on-commitment-limit_clang_14.patch | 14 + build/build-clang/win64.json | 7 + build/build-rust/README | 3 + build/build-rust/cargo-vendor-std.patch | 413 +++ build/build-rust/example.patch | 12 + build/build-rust/rust-vendor-std.patch | 81 + build/buildconfig.py | 19 + build/cargo-host-linker | 3 + build/cargo-host-linker.bat | 3 + build/cargo-linker | 65 + build/cargo-linker.bat | 2 + build/cargo/cargo-audit.yaml | 6 + build/cargo/cargo-check.yaml | 5 + build/cargo/cargo-clippy.yaml | 5 + build/cargo/cargo-deny.yaml | 10 + build/cargo/cargo-machete.yaml | 4 + build/cargo/cargo-udeps.yaml | 4 + build/checksums.py | 154 + build/clang-plugin/.clang-format | 1 + build/clang-plugin/ArithmeticArgChecker.cpp | 60 + build/clang-plugin/ArithmeticArgChecker.h | 18 + build/clang-plugin/AssertAssignmentChecker.cpp | 20 + build/clang-plugin/AssertAssignmentChecker.h | 18 + build/clang-plugin/BaseCheck.h | 34 + build/clang-plugin/CanRunScriptChecker.cpp | 450 +++ build/clang-plugin/CanRunScriptChecker.h | 31 + build/clang-plugin/Checks.inc | 44 + build/clang-plugin/ChecksIncludes.inc | 45 + build/clang-plugin/CustomAttributes.cpp | 126 + build/clang-plugin/CustomAttributes.h | 41 + build/clang-plugin/CustomAttributes.inc | 31 + build/clang-plugin/CustomMatchers.h | 494 +++ build/clang-plugin/CustomTypeAnnotation.cpp | 182 + build/clang-plugin/CustomTypeAnnotation.h | 92 + build/clang-plugin/DanglingOnTemporaryChecker.cpp | 256 ++ build/clang-plugin/DanglingOnTemporaryChecker.h | 19 + build/clang-plugin/DiagnosticsMatcher.cpp | 17 + build/clang-plugin/DiagnosticsMatcher.h | 31 + build/clang-plugin/ExplicitImplicitChecker.cpp | 36 + build/clang-plugin/ExplicitImplicitChecker.h | 18 + build/clang-plugin/ExplicitOperatorBoolChecker.cpp | 31 + build/clang-plugin/ExplicitOperatorBoolChecker.h | 19 + build/clang-plugin/FopenUsageChecker.cpp | 73 + build/clang-plugin/FopenUsageChecker.h | 18 + .../clang-plugin/JSHandleRootedTypedefChecker.cpp | 38 + build/clang-plugin/JSHandleRootedTypedefChecker.h | 19 + build/clang-plugin/KnownLiveChecker.cpp | 35 + build/clang-plugin/KnownLiveChecker.h | 18 + build/clang-plugin/KungFuDeathGripChecker.cpp | 114 + build/clang-plugin/KungFuDeathGripChecker.h | 18 + build/clang-plugin/LoadLibraryUsageChecker.cpp | 34 + build/clang-plugin/LoadLibraryUsageChecker.h | 18 + build/clang-plugin/Makefile.in | 14 + build/clang-plugin/MemMoveAnnotation.h | 62 + build/clang-plugin/MozCheckAction.cpp | 27 + build/clang-plugin/MozillaTidyModule.cpp | 45 + build/clang-plugin/MustOverrideChecker.cpp | 60 + build/clang-plugin/MustOverrideChecker.h | 22 + build/clang-plugin/MustReturnFromCallerChecker.cpp | 136 + build/clang-plugin/MustReturnFromCallerChecker.h | 27 + build/clang-plugin/NaNExprChecker.cpp | 54 + build/clang-plugin/NaNExprChecker.h | 18 + build/clang-plugin/NeedsNoVTableTypeChecker.cpp | 39 + build/clang-plugin/NeedsNoVTableTypeChecker.h | 18 + .../NoAddRefReleaseOnReturnChecker.cpp | 32 + .../clang-plugin/NoAddRefReleaseOnReturnChecker.h | 19 + build/clang-plugin/NoAutoTypeChecker.cpp | 21 + build/clang-plugin/NoAutoTypeChecker.h | 18 + .../NoDuplicateRefCntMemberChecker.cpp | 65 + .../clang-plugin/NoDuplicateRefCntMemberChecker.h | 19 + .../NoExplicitMoveConstructorChecker.cpp | 25 + .../NoExplicitMoveConstructorChecker.h | 19 + build/clang-plugin/NoNewThreadsChecker.cpp | 36 + build/clang-plugin/NoNewThreadsChecker.h | 18 + build/clang-plugin/NoPrincipalGetURI.cpp | 27 + build/clang-plugin/NoPrincipalGetURI.h | 18 + .../NoUsingNamespaceMozillaJavaChecker.cpp | 24 + .../NoUsingNamespaceMozillaJavaChecker.h | 19 + build/clang-plugin/NonMemMovableMemberChecker.cpp | 34 + build/clang-plugin/NonMemMovableMemberChecker.h | 19 + .../NonMemMovableTemplateArgChecker.cpp | 51 + .../clang-plugin/NonMemMovableTemplateArgChecker.h | 19 + .../NonParamInsideFunctionDeclChecker.cpp | 217 ++ .../NonParamInsideFunctionDeclChecker.h | 19 + build/clang-plugin/NonTrivialTypeInFfiChecker.cpp | 56 + build/clang-plugin/NonTrivialTypeInFfiChecker.h | 19 + build/clang-plugin/OverrideBaseCallChecker.cpp | 109 + build/clang-plugin/OverrideBaseCallChecker.h | 27 + .../clang-plugin/OverrideBaseCallUsageChecker.cpp | 21 + build/clang-plugin/OverrideBaseCallUsageChecker.h | 23 + build/clang-plugin/ParamTraitsEnumChecker.cpp | 38 + build/clang-plugin/ParamTraitsEnumChecker.h | 18 + build/clang-plugin/RecurseGuard.h | 56 + .../RefCountedCopyConstructorChecker.cpp | 34 + .../RefCountedCopyConstructorChecker.h | 19 + .../clang-plugin/RefCountedInsideLambdaChecker.cpp | 164 + build/clang-plugin/RefCountedInsideLambdaChecker.h | 33 + .../RefCountedThisInsideConstructorChecker.cpp | 29 + .../RefCountedThisInsideConstructorChecker.h | 19 + build/clang-plugin/ScopeChecker.cpp | 180 + build/clang-plugin/ScopeChecker.h | 18 + build/clang-plugin/SprintfLiteralChecker.cpp | 84 + build/clang-plugin/SprintfLiteralChecker.h | 18 + build/clang-plugin/StmtToBlockMap.h | 90 + build/clang-plugin/ThirdPartyPaths.h | 17 + build/clang-plugin/ThirdPartyPaths.py | 40 + build/clang-plugin/ThreadAllows.py | 82 + build/clang-plugin/ThreadAllows.txt | 115 + build/clang-plugin/ThreadFileAllows.txt | 75 + build/clang-plugin/TrivialCtorDtorChecker.cpp | 29 + build/clang-plugin/TrivialCtorDtorChecker.h | 18 + build/clang-plugin/TrivialDtorChecker.cpp | 23 + build/clang-plugin/TrivialDtorChecker.h | 18 + build/clang-plugin/Utils.h | 499 +++ build/clang-plugin/VariableUsageHelpers.cpp | 275 ++ build/clang-plugin/VariableUsageHelpers.h | 63 + build/clang-plugin/alpha/AlphaChecks.inc | 10 + build/clang-plugin/alpha/AlphaIncludes.inc | 2 + build/clang-plugin/alpha/NonStdMoveChecker.cpp | 115 + build/clang-plugin/alpha/NonStdMoveChecker.h | 29 + build/clang-plugin/alpha/TempRefPtrChecker.cpp | 57 + build/clang-plugin/alpha/TempRefPtrChecker.h | 21 + build/clang-plugin/alpha/sources.mozbuild | 10 + build/clang-plugin/alpha/tests/TestNonStdMove.cpp | 125 + build/clang-plugin/alpha/tests/TestTempRefPtr.cpp | 52 + build/clang-plugin/alpha/tests/sources.mozbuild | 10 + build/clang-plugin/external/CustomAttributes.inc | 0 build/clang-plugin/external/ExternalChecks.inc | 8 + build/clang-plugin/external/ExternalIncludes.inc | 9 + build/clang-plugin/external/sources.mozbuild | 10 + build/clang-plugin/external/tests/sources.mozbuild | 10 + build/clang-plugin/import_mozilla_checks.py | 177 + build/clang-plugin/moz.build | 129 + .../mozsearch-plugin/BindingOperations.cpp | 792 +++++ .../mozsearch-plugin/BindingOperations.h | 17 + .../mozsearch-plugin/FileOperations.cpp | 140 + .../clang-plugin/mozsearch-plugin/FileOperations.h | 70 + .../mozsearch-plugin/MozsearchIndexer.cpp | 2436 +++++++++++++ build/clang-plugin/mozsearch-plugin/README | 12 + .../mozsearch-plugin/StringOperations.cpp | 42 + .../mozsearch-plugin/StringOperations.h | 25 + .../from-clangd/HeuristicResolver.cpp | 349 ++ .../from-clangd/HeuristicResolver.h | 122 + .../mozsearch-plugin/from-clangd/README.md | 10 + build/clang-plugin/plugin.h | 57 + build/clang-plugin/tests/Makefile.in | 19 + build/clang-plugin/tests/NonParameterTestCases.h | 61 + .../tests/TestAssertWithAssignment.cpp | 68 + .../tests/TestBadImplicitConversionCtor.cpp | 50 + build/clang-plugin/tests/TestCanRunScript.cpp | 881 +++++ build/clang-plugin/tests/TestCustomHeap.cpp | 29 + .../clang-plugin/tests/TestDanglingOnTemporary.cpp | 45 + .../tests/TestExplicitOperatorBool.cpp | 11 + build/clang-plugin/tests/TestFopenUsage.cpp | 50 + build/clang-plugin/tests/TestGlobalClass.cpp | 52 + build/clang-plugin/tests/TestHeapClass.cpp | 64 + .../TestInheritTypeAnnotationsFromTemplateArgs.cpp | 46 + .../tests/TestJSHandleRootedTypedef.cpp | 168 + build/clang-plugin/tests/TestKnownLive.cpp | 33 + build/clang-plugin/tests/TestKungFuDeathGrip.cpp | 142 + build/clang-plugin/tests/TestLoadLibraryUsage.cpp | 20 + .../clang-plugin/tests/TestMultipleAnnotations.cpp | 19 + build/clang-plugin/tests/TestMustOverride.cpp | 63 + .../tests/TestMustReturnFromCaller.cpp | 270 ++ build/clang-plugin/tests/TestNANTestingExpr.cpp | 24 + build/clang-plugin/tests/TestNANTestingExprC.c | 17 + build/clang-plugin/tests/TestNeedsNoVTableType.cpp | 94 + .../tests/TestNoAddRefReleaseOnReturn.cpp | 110 + .../tests/TestNoArithmeticExprInArgument.cpp | 32 + build/clang-plugin/tests/TestNoAutoType.cpp | 41 + .../tests/TestNoDuplicateRefCntMember.cpp | 49 + .../tests/TestNoExplicitMoveConstructor.cpp | 25 + .../clang-plugin/tests/TestNoNewThreadsChecker.cpp | 9 + build/clang-plugin/tests/TestNoPrincipalGetUri.cpp | 31 + .../tests/TestNoRefcountedInsideLambdas.cpp | 682 ++++ .../tests/TestNoUsingNamespaceMozillaJava.cpp | 29 + build/clang-plugin/tests/TestNonHeapClass.cpp | 62 + build/clang-plugin/tests/TestNonMemMovable.cpp | 830 +++++ build/clang-plugin/tests/TestNonMemMovableStd.cpp | 70 + .../tests/TestNonMemMovableStdAtomic.cpp | 30 + .../clang-plugin/tests/TestNonParameterChecker.cpp | 187 + build/clang-plugin/tests/TestNonTemporaryClass.cpp | 70 + .../clang-plugin/tests/TestNonTrivialTypeInFfi.cpp | 65 + build/clang-plugin/tests/TestOverrideBaseCall.cpp | 175 + .../tests/TestOverrideBaseCallAnnotation.cpp | 47 + build/clang-plugin/tests/TestParamTraitsEnum.cpp | 94 + .../tests/TestRefCountedCopyConstructor.cpp | 25 + .../tests/TestRefCountedThisInsideConstructor.cpp | 76 + build/clang-plugin/tests/TestSprintfLiteral.cpp | 41 + build/clang-plugin/tests/TestStackClass.cpp | 50 + build/clang-plugin/tests/TestStaticLocalClass.cpp | 54 + build/clang-plugin/tests/TestTemporaryClass.cpp | 72 + build/clang-plugin/tests/TestTrivialCtorDtor.cpp | 88 + build/clang-plugin/tests/TestTrivialDtor.cpp | 52 + build/clang-plugin/tests/moz.build | 101 + build/compare-mozconfig/compare-mozconfigs.py | 176 + build/compare-mozconfig/python.toml | 5 + build/debian-packages/pygobject.diff | 117 + build/debian-packages/ubuntu-glibc.diff | 13 + build/defines.sh | 3 + build/docs/build-overview.rst | 117 + build/docs/build-targets.rst | 62 + build/docs/chrome-registration.rst | 459 +++ build/docs/cppeclipse.rst | 53 + build/docs/cross-compile.rst | 15 + build/docs/defining-binaries.rst | 345 ++ build/docs/defining-xpcom-components.rst | 318 ++ build/docs/environment-variables.rst | 31 + build/docs/files-metadata.rst | 178 + build/docs/glossary.rst | 47 + build/docs/gn.rst | 17 + build/docs/index.rst | 66 + build/docs/jar-manifests.rst | 123 + build/docs/locales.rst | 368 ++ build/docs/mozbuild-files.rst | 176 + build/docs/mozbuild-symbols.rst | 7 + build/docs/mozbuild/index.rst | 40 + build/docs/mozconfigs.rst | 69 + build/docs/mozinfo.rst | 181 + build/docs/pgo.rst | 28 + build/docs/preprocessor.rst | 219 ++ build/docs/python.rst | 165 + build/docs/rust.rst | 181 + build/docs/sccache-dist.rst | 199 ++ build/docs/slow.rst | 153 + build/docs/snap.rst | 132 + build/docs/sparse.rst | 157 + build/docs/supported-configurations.rst | 166 + build/docs/telemetry.rst | 49 + build/docs/test_certificates.rst | 40 + build/docs/test_manifests.rst | 230 ++ build/docs/toolchains.rst | 272 ++ build/docs/unified-builds.rst | 55 + build/docs/visualstudio.rst | 82 + build/dumbmake-dependencies | 72 + build/gecko_templates.mozbuild | 125 + build/gen_symverscript.py | 24 + build/gen_test_packages_manifest.py | 125 + build/gyp.mozbuild | 109 + build/gyp_base.mozbuild | 39 + build/gyp_includes/common.gypi | 3589 ++++++++++++++++++++ build/gyp_includes/filename_rules.gypi | 96 + build/gyp_includes/internal/release_defaults.gypi | 18 + build/gyp_includes/internal/release_impl.gypi | 17 + .../internal/release_impl_official.gypi | 43 + build/gyp_includes/release.gypi | 17 + build/mach_initialize.py | 607 ++++ build/macosx/catalog.py | 123 + build/macosx/cross-mozconfig.common | 32 + build/macosx/mozconfig.common | 8 + build/macosx/permissions/chown_revert.c | 18 + build/macosx/permissions/chown_root.c | 12 + build/midl.py | 223 ++ build/moz-automation.mk | 110 + build/moz.build | 136 + build/moz.configure/android-ndk.configure | 305 ++ build/moz.configure/android-sdk.configure | 157 + build/moz.configure/arm.configure | 305 ++ build/moz.configure/bindgen.configure | 377 ++ build/moz.configure/bootstrap.configure | 341 ++ build/moz.configure/checks.configure | 206 ++ build/moz.configure/compile-checks.configure | 445 +++ build/moz.configure/compilers-util.configure | 204 ++ build/moz.configure/flags.configure | 198 ++ build/moz.configure/headers.configure | 119 + build/moz.configure/init.configure | 1278 +++++++ build/moz.configure/java.configure | 76 + build/moz.configure/keyfiles.configure | 68 + build/moz.configure/lto-pgo.configure | 437 +++ build/moz.configure/memory.configure | 120 + build/moz.configure/node.configure | 90 + build/moz.configure/nspr.configure | 116 + build/moz.configure/nss.configure | 29 + build/moz.configure/old.configure | 394 +++ build/moz.configure/pkg.configure | 210 ++ build/moz.configure/rust.configure | 786 +++++ build/moz.configure/toolchain.configure | 3290 ++++++++++++++++++ build/moz.configure/update-programs.configure | 198 ++ build/moz.configure/util.configure | 550 +++ build/moz.configure/warnings.configure | 324 ++ build/moz.configure/windows.configure | 481 +++ build/mozconfig.artifact | 7 + build/mozconfig.artifact.automation | 6 + build/mozconfig.automation | 22 + build/mozconfig.cache | 93 + build/mozconfig.clang-cl | 21 + build/mozconfig.common | 30 + build/mozconfig.common.override | 15 + build/mozconfig.lld-link | 6 + build/mozconfig.no-compile | 31 + build/mozconfig.rust | 1 + build/mozconfig.win-common | 3 + build/non-unified-compat | 126 + build/package/mac_osx/make-diskimage | 47 + build/package/mac_osx/mozilla-background.jpg | Bin 0 -> 16591 bytes build/package/mac_osx/mozilla.dsstore | Bin 0 -> 6148 bytes build/package/mac_osx/requirements.plist | 11 + build/package/mac_osx/unpack-diskimage | 54 + build/pgo/blueprint/LICENSE | 314 ++ build/pgo/blueprint/elements.html | 350 ++ build/pgo/blueprint/fancytype-screen.css | 75 + build/pgo/blueprint/forms.html | 144 + build/pgo/blueprint/grid.html | 317 ++ build/pgo/blueprint/grid.png | Bin 0 -> 206 bytes build/pgo/blueprint/print.css | 29 + build/pgo/blueprint/sample.html | 227 ++ build/pgo/blueprint/screen.css | 226 ++ build/pgo/blueprint/test-small.jpg | Bin 0 -> 1886 bytes build/pgo/blueprint/test.jpg | Bin 0 -> 35467 bytes build/pgo/certs/README | 5 + build/pgo/certs/alternateroot.ca | 18 + build/pgo/certs/alternateroot.ca.keyspec | 1 + build/pgo/certs/alternateroot.certspec | 7 + build/pgo/certs/badCertDomain.certspec | 3 + build/pgo/certs/bug1665057cert.certspec | 3 + build/pgo/certs/bug1706126cert.certspec | 3 + build/pgo/certs/bug413909cert.certspec | 3 + build/pgo/certs/cert9.db | Bin 0 -> 294912 bytes build/pgo/certs/dynamicPinningBad.certspec | 5 + build/pgo/certs/dynamicPinningBad.server.keyspec | 1 + build/pgo/certs/dynamicPinningGood.certspec | 3 + build/pgo/certs/escapeattack1.certspec | 3 + build/pgo/certs/evintermediate.ca | 26 + build/pgo/certs/evintermediate.ca.keyspec | 1 + build/pgo/certs/evintermediate.certspec | 7 + build/pgo/certs/expired.certspec | 4 + build/pgo/certs/http2-cert.ca | 19 + build/pgo/certs/http2-cert.ca.keyspec | 1 + build/pgo/certs/http2-cert.certspec | 5 + build/pgo/certs/imminently_distrusted.certspec | 4 + build/pgo/certs/key4.db | Bin 0 -> 360448 bytes build/pgo/certs/mochitest-cert.ca | 23 + build/pgo/certs/mochitest-cert.ca.keyspec | 1 + build/pgo/certs/mochitest-cert.certspec | 5 + build/pgo/certs/mochitest.certspec | 3 + build/pgo/certs/mochitest.client | Bin 0 -> 2448 bytes build/pgo/certs/mochitest.client.keyspec | 1 + build/pgo/certs/noSubjectAltName.certspec | 2 + build/pgo/certs/pgoca.ca | 21 + build/pgo/certs/pgoca.ca.keyspec | 1 + build/pgo/certs/pgoca.certspec | 5 + build/pgo/certs/pkcs11.txt | 5 + build/pgo/certs/selfsigned.certspec | 3 + build/pgo/certs/sha1_end_entity.certspec | 4 + build/pgo/certs/sha256_end_entity.certspec | 4 + build/pgo/certs/staticPinningBad.certspec | 5 + build/pgo/certs/staticPinningBad.server.keyspec | 1 + build/pgo/certs/unknown_ca.certspec | 5 + build/pgo/certs/untrusted.certspec | 3 + build/pgo/certs/untrustedandexpired.certspec | 4 + build/pgo/favicon.ico | Bin 0 -> 1406 bytes build/pgo/genpgocert.py | 251 ++ build/pgo/index.html | 111 + build/pgo/js-input/3d-thingy.html | 390 +++ build/pgo/js-input/crypto-otp.html | 1344 ++++++++ build/pgo/js-input/key.gif | Bin 0 -> 1119 bytes build/pgo/js-input/sunspider/3d-cube.html | 387 +++ build/pgo/js-input/sunspider/3d-morph.html | 104 + build/pgo/js-input/sunspider/3d-raytrace.html | 490 +++ .../js-input/sunspider/access-binary-trees.html | 100 + build/pgo/js-input/sunspider/access-fannkuch.html | 116 + build/pgo/js-input/sunspider/access-nbody.html | 219 ++ build/pgo/js-input/sunspider/access-nsieve.html | 88 + .../sunspider/bitops-3bit-bits-in-byte.html | 82 + .../js-input/sunspider/bitops-bits-in-byte.html | 72 + .../pgo/js-input/sunspider/bitops-bitwise-and.html | 78 + .../pgo/js-input/sunspider/bitops-nsieve-bits.html | 82 + .../js-input/sunspider/controlflow-recursive.html | 75 + build/pgo/js-input/sunspider/crypto-aes.html | 472 +++ build/pgo/js-input/sunspider/crypto-md5.html | 336 ++ build/pgo/js-input/sunspider/crypto-sha1.html | 274 ++ .../pgo/js-input/sunspider/date-format-tofte.html | 349 ++ .../pgo/js-input/sunspider/date-format-xparb.html | 467 +++ build/pgo/js-input/sunspider/math-cordic.html | 145 + .../pgo/js-input/sunspider/math-partial-sums.html | 83 + .../pgo/js-input/sunspider/math-spectral-norm.html | 101 + build/pgo/js-input/sunspider/regexp-dna.html | 1762 ++++++++++ build/pgo/js-input/sunspider/string-base64.html | 151 + build/pgo/js-input/sunspider/string-fasta.html | 135 + build/pgo/js-input/sunspider/string-tagcloud.html | 315 ++ .../pgo/js-input/sunspider/string-unpack-code.html | 117 + .../js-input/sunspider/string-validate-input.html | 139 + build/pgo/js-input/valid-xhtml10.png | Bin 0 -> 2414 bytes build/pgo/profileserver.py | 254 ++ build/pgo/server-locations.txt | 394 +++ build/psutil_requirements.in | 2 + build/psutil_requirements.txt | 22 + build/pure_virtual/moz.build | 23 + build/pure_virtual/pure_virtual.c | 27 + build/qemu-wrap | 24 + build/rust/backtrace/Cargo.toml | 8 + build/rust/backtrace/lib.rs | 0 build/rust/base64/Cargo.toml | 11 + build/rust/base64/lib.rs | 42 + build/rust/bindgen-0.63/Cargo.toml | 18 + build/rust/bindgen-0.63/lib.rs | 26 + build/rust/bitflags/Cargo.toml | 11 + build/rust/bitflags/lib.rs | 61 + build/rust/cfg-if/Cargo.toml | 11 + build/rust/cfg-if/lib.rs | 5 + build/rust/cmake/Cargo.toml | 8 + build/rust/cmake/lib.rs | 3 + build/rust/derive_more/Cargo.toml | 37 + build/rust/derive_more/lib.rs | 5 + build/rust/dummy-web/js-sys/Cargo.toml | 8 + build/rust/dummy-web/js-sys/lib.rs | 3 + build/rust/dummy-web/wasm-bindgen/Cargo.toml | 8 + build/rust/dummy-web/wasm-bindgen/lib.rs | 3 + build/rust/dummy-web/web-sys/Cargo.toml | 1423 ++++++++ build/rust/dummy-web/web-sys/lib.rs | 3 + build/rust/goblin/Cargo.toml | 11 + build/rust/goblin/lib.rs | 11 + build/rust/indexmap/Cargo.toml | 16 + build/rust/indexmap/lib.rs | 5 + build/rust/memmap2-0.5/Cargo.toml | 11 + build/rust/memmap2-0.5/lib.rs | 5 + build/rust/memmap2/Cargo.toml | 11 + build/rust/memmap2/lib.rs | 5 + build/rust/memoffset/Cargo.toml | 11 + build/rust/memoffset/lib.rs | 11 + build/rust/mozbuild/Cargo.toml | 8 + build/rust/mozbuild/build.rs | 20 + build/rust/mozbuild/generate_buildconfig.py | 95 + build/rust/mozbuild/lib.rs | 20 + build/rust/mozbuild/moz.build | 9 + build/rust/nix/Cargo.toml | 30 + build/rust/nix/lib.rs | 5 + build/rust/oslog/Cargo.toml | 15 + build/rust/oslog/LICENSE | 21 + build/rust/oslog/lib.rs | 25 + build/rust/redox_syscall/Cargo.toml | 8 + build/rust/redox_syscall/lib.rs | 3 + build/rust/redox_users/Cargo.toml | 8 + build/rust/redox_users/lib.rs | 3 + build/rust/terminal_size/Cargo.toml | 8 + build/rust/terminal_size/lib.rs | 26 + build/rust/tinyvec/Cargo.toml | 16 + build/rust/tinyvec/lib.rs | 6 + build/rust/vcpkg/Cargo.toml | 8 + build/rust/vcpkg/lib.rs | 23 + build/rust/wasi/Cargo.toml | 17 + build/rust/wasi/lib.rs | 5 + build/rust/windows-sys/Cargo.toml | 232 ++ build/rust/windows-sys/lib.rs | 5 + build/rust/windows-targets-0.48/Cargo.toml | 11 + build/rust/windows-targets-0.48/lib.rs | 5 + build/rust/windows-targets/Cargo.toml | 13 + build/rust/windows-targets/lib.rs | 86 + build/rust/windows/Cargo.toml | 736 ++++ build/rust/windows/src/lib.rs | 24 + build/sanitizers/asan_blacklist_win.txt | 28 + build/sanitizers/ubsan_enum_blacklist.txt | 17 + build/sanitizers/ubsan_function_blacklist.txt | 9 + build/sanitizers/ubsan_object_size_blacklist.txt | 7 + .../ubsan_pointer_overflow_blacklist.txt | 30 + .../sanitizers/ubsan_signed_overflow_blacklist.txt | 257 ++ .../ubsan_unsigned_overflow_blacklist.txt | 264 ++ build/sparse-profiles/docker-image | 26 + build/sparse-profiles/github-sync | 7 + build/sparse-profiles/mach | 19 + build/sparse-profiles/mozharness | 4 + build/sparse-profiles/perftest | 8 + build/sparse-profiles/profile-generate | 9 + build/sparse-profiles/push-to-try | 5 + build/sparse-profiles/sphinx-docs | 56 + build/sparse-profiles/startup-test | 6 + build/sparse-profiles/taskgraph | 94 + build/sparse-profiles/toolchain-build | 9 + build/sparse-profiles/tps | 5 + build/sparse-profiles/update-verify | 4 + build/sparse-profiles/upload-generated-sources | 4 + build/sparse-profiles/upload-symbols | 4 + build/sparse-profiles/webrender | 7 + build/templates.mozbuild | 237 ++ build/tests/cram/cram.toml | 1 + build/tests/cram/test_configure_help.t | 14 + build/unix/aix.exp | 5 + .../3A24BC1E8FB409FA9F14371813FCEF89DD9E3C4F.key | 51 + build/unix/build-binutils/build-binutils.sh | 106 + .../07F3DBBECC1A39605078094D980C197698C3739D.key | 53 + .../13975A70E63C361C73AE69EF6EEB81F8981C74C7.key | 82 + .../33C235A34C46AA3FFB293709A328C3A2C3C45C06.key | 33 + .../343C2FF0FBEE5EC2EDBEF399F3599FF828C67298.key | 35 + .../5ED46A6721D365587791E2AA783FCD8E58BCAFBA.key | 38 + .../7F74F97C103468EE5D750B583AB00996FC26A641.key | 54 + .../AD17A21EF8AED8F1CC02DBD9F7D5C9BF765C61E3.key | 57 + .../D3A93CAD751C2AF4F8C7AD516C35B99309B5FA62.key | 62 + .../DA23579A74D4AD9AF9D3F945CEFAC8EAAF17519D.key | 52 + .../EAF1C276A747E9ED86210CBAC3126D3B4AE55E93.key | 29 + build/unix/build-gcc/build-gcc.sh | 64 + build/unix/build-hfsplus/build-hfsplus.sh | 50 + build/unix/elfhack/Makefile.in | 46 + build/unix/elfhack/README | 28 + build/unix/elfhack/dummy.c | 7 + build/unix/elfhack/elf.cpp | 935 +++++ build/unix/elfhack/elfhack.cpp | 1458 ++++++++ build/unix/elfhack/elfxx.h | 700 ++++ build/unix/elfhack/inject.c | 225 ++ build/unix/elfhack/inject/copy_source.py | 10 + build/unix/elfhack/inject/moz.build | 56 + build/unix/elfhack/moz.build | 46 + build/unix/elfhack/relrhack.cpp | 567 ++++ build/unix/elfhack/relrhack.h | 25 + build/unix/elfhack/test-array.c | 8 + build/unix/elfhack/test-ctors.c | 16 + build/unix/elfhack/test.c | 221 ++ build/unix/moz.build | 12 + build/unix/mozconfig.asan | 14 + build/unix/mozconfig.linux | 15 + build/unix/mozconfig.linux32 | 8 + build/unix/mozconfig.stdcxx | 2 + build/unix/mozconfig.tsan | 17 + build/unix/mozconfig.unix | 22 + build/unix/print-non-newline.sh | 35 + build/unix/rewrite_sanitizer_dylib.py | 123 + build/unix/run-gprof.sh | 17 + build/unix/run-hiprof.sh | 25 + build/unix/run-mozilla.sh | 356 ++ build/unix/run-third.sh | 25 + build/unix/stdc++compat/hide_std.ld | 5 + build/unix/stdc++compat/moz.build | 24 + build/unix/stdc++compat/stdc++compat.cpp | 196 ++ build/update-settings.ini | 11 + build/upload.py | 106 + build/upload_generated_sources.py | 169 + build/valgrind/__init__.py | 0 build/valgrind/cross-architecture.sup | 204 ++ build/valgrind/i386-pc-linux-gnu.sup | 53 + build/valgrind/mach_commands.py | 262 ++ build/valgrind/output_handler.py | 117 + build/valgrind/x86_64-pc-linux-gnu.sup | 1068 ++++++ build/variables.py | 111 + build/vs/generate_yaml.py | 61 + build/vs/vs2019.yaml | 1853 ++++++++++ build/vs/vs2022.yaml | 1655 +++++++++ build/win32/__init__.py | 0 build/win32/autowinchecksec.py | 85 + build/win32/crashinject.cpp | 94 + build/win32/crashinjectdll/crashinjectdll.cpp | 29 + build/win32/crashinjectdll/crashinjectdll.def | 7 + build/win32/crashinjectdll/moz.build | 16 + build/win32/dummy_libs.py | 24 + build/win32/moz.build | 32 + build/win32/mozconfig.vs-latest | 3 + build/win32/mozconfig.vs2019 | 10 + build/win32/nsis-no-insert-timestamp.patch | 27 + build/win32/nsis-no-underscore.patch | 34 + build/win32/nsis-scons.patch | 23 + build/win64-aarch64/mozconfig.vs-latest | 3 + build/win64-aarch64/mozconfig.vs2019 | 8 + build/win64/mozconfig.asan | 23 + build/win64/mozconfig.vs-latest | 3 + build/win64/mozconfig.vs2019 | 8 + build/workspace-hack/Cargo.toml | 192 ++ build/workspace-hack/src/lib.rs | 11 + build/zstandard_requirements.in | 2 + build/zstandard_requirements.txt | 54 + 636 files changed, 83622 insertions(+) create mode 100644 build/.gdbinit create mode 100644 build/.gdbinit.loader create mode 100644 build/.gdbinit.py.in create mode 100644 build/.lldbinit.in create mode 100644 build/RunCbindgen.py create mode 100644 build/__init__.py create mode 100644 build/android/libgcc.a create mode 100644 build/appini_header.py create mode 100644 build/application.ini.in create mode 100644 build/autoconf/acgeneral.m4 create mode 100644 build/autoconf/acoldnames.m4 create mode 100644 build/autoconf/acspecific.m4 create mode 100644 build/autoconf/alloc.m4 create mode 100644 build/autoconf/altoptions.m4 create mode 100644 build/autoconf/android.m4 create mode 100644 build/autoconf/arch.m4 create mode 100644 build/autoconf/autoconf.m4 create mode 100644 build/autoconf/autoconf.sh create mode 100644 build/autoconf/clang-plugin.m4 create mode 100644 build/autoconf/codeset.m4 create mode 100644 build/autoconf/compiler-opts.m4 create mode 100755 build/autoconf/config.guess create mode 100644 build/autoconf/config.status.m4 create mode 100755 build/autoconf/config.sub create mode 100644 build/autoconf/expandlibs.m4 create mode 100644 build/autoconf/hooks.m4 create mode 100755 build/autoconf/install-sh create mode 100644 build/autoconf/mozheader.m4 create mode 100644 build/autoconf/mozprog.m4 create mode 100644 build/autoconf/sanitize.m4 create mode 100644 build/autoconf/toolchain.m4 create mode 100644 build/binary-location.mk create mode 100644 build/build-clang/1stage.json create mode 100644 build/build-clang/2stages.json create mode 100644 build/build-clang/4stages-pgo.json create mode 100644 build/build-clang/D146664.patch create mode 100644 build/build-clang/README create mode 100644 build/build-clang/Remove-FlushViewOfFile-when-unmaping-gcda-files.patch create mode 100644 build/build-clang/allow-unversioned-android.patch create mode 100644 build/build-clang/android-mangling-error_clang_12.patch create mode 100755 build/build-clang/build-clang.py create mode 100644 build/build-clang/clang-14.json create mode 100644 build/build-clang/clang-17.json create mode 100644 build/build-clang/clang-18.json create mode 100644 build/build-clang/clang-8-missing-header.patch create mode 100644 build/build-clang/clang-8.0.json create mode 100644 build/build-clang/clang-tidy-ci.patch create mode 100644 build/build-clang/clang-tidy-external-linux64.json create mode 100644 build/build-clang/clang-tidy-linux64.json create mode 100644 build/build-clang/clang-tidy-macosx64.json create mode 100644 build/build-clang/clang-tidy-win64.json create mode 100644 build/build-clang/clang-trunk.json create mode 100644 build/build-clang/compiler-rt-rss-limit-heap-profile.patch create mode 100644 build/build-clang/downgrade-mangling-error_clang_12.patch create mode 100644 build/build-clang/find_symbolizer_linux_clang_10.patch create mode 100644 build/build-clang/find_symbolizer_linux_clang_15.patch create mode 100644 build/build-clang/fuzzing_ccov_build_clang_12.patch create mode 100644 build/build-clang/linux64.json create mode 100644 build/build-clang/llvmorg-10-init-136-gb288d90b39f4.patch create mode 100644 build/build-clang/llvmorg-15-init-16512-g4b1e3d193706.patch create mode 100644 build/build-clang/macosx64-aarch64.json create mode 100644 build/build-clang/macosx64.json create mode 100644 build/build-clang/partial-revert-llvmorg-16-init-17151-gaa0883b59ae1_clang_17.patch create mode 100644 build/build-clang/partial-revert-llvmorg-17-init-17713-gc8e055d485ea.patch create mode 100644 build/build-clang/profile.json create mode 100644 build/build-clang/revert-llvmorg-15-init-11205-gcead4eceb01b_clang_16.patch create mode 100644 build/build-clang/revert-llvmorg-15-init-11205-gcead4eceb01b_clang_18.patch create mode 100644 build/build-clang/revert-llvmorg-15-init-13446-g7524fe962e47.patch create mode 100644 build/build-clang/revert-llvmorg-16-init-11301-g163bb6d64e5f_clang_17.patch create mode 100644 build/build-clang/revert-llvmorg-16-init-11301-g163bb6d64e5f_clang_18.patch create mode 100644 build/build-clang/revert-llvmorg-17-init-4120-g02e8eb1a438b.patch create mode 100644 build/build-clang/revert-llvmorg-17-init-4120-g02e8eb1a438b_clang_18.patch create mode 100644 build/build-clang/revert-llvmorg-18-init-6188-gc649f29c24c9.patch create mode 100644 build/build-clang/revert-llvmorg-18-init-6193-gb88cffeafd39.patch create mode 100644 build/build-clang/revert-llvmorg-18-init-6208-g2baf4a06ef06.patch create mode 100644 build/build-clang/skip-3-stages.json create mode 100644 build/build-clang/skip-stage-1-win64.json create mode 100644 build/build-clang/skip-stage-1.json create mode 100644 build/build-clang/unpoison-thread-stacks_clang_10.patch create mode 100644 build/build-clang/win64-ret-null-on-commitment-limit_clang_14.patch create mode 100644 build/build-clang/win64.json create mode 100644 build/build-rust/README create mode 100644 build/build-rust/cargo-vendor-std.patch create mode 100644 build/build-rust/example.patch create mode 100644 build/build-rust/rust-vendor-std.patch create mode 100644 build/buildconfig.py create mode 100755 build/cargo-host-linker create mode 100644 build/cargo-host-linker.bat create mode 100755 build/cargo-linker create mode 100644 build/cargo-linker.bat create mode 100644 build/cargo/cargo-audit.yaml create mode 100644 build/cargo/cargo-check.yaml create mode 100644 build/cargo/cargo-clippy.yaml create mode 100644 build/cargo/cargo-deny.yaml create mode 100644 build/cargo/cargo-machete.yaml create mode 100644 build/cargo/cargo-udeps.yaml create mode 100755 build/checksums.py create mode 100644 build/clang-plugin/.clang-format create mode 100644 build/clang-plugin/ArithmeticArgChecker.cpp create mode 100644 build/clang-plugin/ArithmeticArgChecker.h create mode 100644 build/clang-plugin/AssertAssignmentChecker.cpp create mode 100644 build/clang-plugin/AssertAssignmentChecker.h create mode 100644 build/clang-plugin/BaseCheck.h create mode 100644 build/clang-plugin/CanRunScriptChecker.cpp create mode 100644 build/clang-plugin/CanRunScriptChecker.h create mode 100644 build/clang-plugin/Checks.inc create mode 100644 build/clang-plugin/ChecksIncludes.inc create mode 100644 build/clang-plugin/CustomAttributes.cpp create mode 100644 build/clang-plugin/CustomAttributes.h create mode 100644 build/clang-plugin/CustomAttributes.inc create mode 100644 build/clang-plugin/CustomMatchers.h create mode 100644 build/clang-plugin/CustomTypeAnnotation.cpp create mode 100644 build/clang-plugin/CustomTypeAnnotation.h create mode 100644 build/clang-plugin/DanglingOnTemporaryChecker.cpp create mode 100644 build/clang-plugin/DanglingOnTemporaryChecker.h create mode 100644 build/clang-plugin/DiagnosticsMatcher.cpp create mode 100644 build/clang-plugin/DiagnosticsMatcher.h create mode 100644 build/clang-plugin/ExplicitImplicitChecker.cpp create mode 100644 build/clang-plugin/ExplicitImplicitChecker.h create mode 100644 build/clang-plugin/ExplicitOperatorBoolChecker.cpp create mode 100644 build/clang-plugin/ExplicitOperatorBoolChecker.h create mode 100644 build/clang-plugin/FopenUsageChecker.cpp create mode 100644 build/clang-plugin/FopenUsageChecker.h create mode 100644 build/clang-plugin/JSHandleRootedTypedefChecker.cpp create mode 100644 build/clang-plugin/JSHandleRootedTypedefChecker.h create mode 100644 build/clang-plugin/KnownLiveChecker.cpp create mode 100644 build/clang-plugin/KnownLiveChecker.h create mode 100644 build/clang-plugin/KungFuDeathGripChecker.cpp create mode 100644 build/clang-plugin/KungFuDeathGripChecker.h create mode 100644 build/clang-plugin/LoadLibraryUsageChecker.cpp create mode 100644 build/clang-plugin/LoadLibraryUsageChecker.h create mode 100644 build/clang-plugin/Makefile.in create mode 100644 build/clang-plugin/MemMoveAnnotation.h create mode 100644 build/clang-plugin/MozCheckAction.cpp create mode 100644 build/clang-plugin/MozillaTidyModule.cpp create mode 100644 build/clang-plugin/MustOverrideChecker.cpp create mode 100644 build/clang-plugin/MustOverrideChecker.h create mode 100644 build/clang-plugin/MustReturnFromCallerChecker.cpp create mode 100644 build/clang-plugin/MustReturnFromCallerChecker.h create mode 100644 build/clang-plugin/NaNExprChecker.cpp create mode 100644 build/clang-plugin/NaNExprChecker.h create mode 100644 build/clang-plugin/NeedsNoVTableTypeChecker.cpp create mode 100644 build/clang-plugin/NeedsNoVTableTypeChecker.h create mode 100644 build/clang-plugin/NoAddRefReleaseOnReturnChecker.cpp create mode 100644 build/clang-plugin/NoAddRefReleaseOnReturnChecker.h create mode 100644 build/clang-plugin/NoAutoTypeChecker.cpp create mode 100644 build/clang-plugin/NoAutoTypeChecker.h create mode 100644 build/clang-plugin/NoDuplicateRefCntMemberChecker.cpp create mode 100644 build/clang-plugin/NoDuplicateRefCntMemberChecker.h create mode 100644 build/clang-plugin/NoExplicitMoveConstructorChecker.cpp create mode 100644 build/clang-plugin/NoExplicitMoveConstructorChecker.h create mode 100644 build/clang-plugin/NoNewThreadsChecker.cpp create mode 100644 build/clang-plugin/NoNewThreadsChecker.h create mode 100644 build/clang-plugin/NoPrincipalGetURI.cpp create mode 100644 build/clang-plugin/NoPrincipalGetURI.h create mode 100644 build/clang-plugin/NoUsingNamespaceMozillaJavaChecker.cpp create mode 100644 build/clang-plugin/NoUsingNamespaceMozillaJavaChecker.h create mode 100644 build/clang-plugin/NonMemMovableMemberChecker.cpp create mode 100644 build/clang-plugin/NonMemMovableMemberChecker.h create mode 100644 build/clang-plugin/NonMemMovableTemplateArgChecker.cpp create mode 100644 build/clang-plugin/NonMemMovableTemplateArgChecker.h create mode 100644 build/clang-plugin/NonParamInsideFunctionDeclChecker.cpp create mode 100644 build/clang-plugin/NonParamInsideFunctionDeclChecker.h create mode 100644 build/clang-plugin/NonTrivialTypeInFfiChecker.cpp create mode 100644 build/clang-plugin/NonTrivialTypeInFfiChecker.h create mode 100644 build/clang-plugin/OverrideBaseCallChecker.cpp create mode 100644 build/clang-plugin/OverrideBaseCallChecker.h create mode 100644 build/clang-plugin/OverrideBaseCallUsageChecker.cpp create mode 100644 build/clang-plugin/OverrideBaseCallUsageChecker.h create mode 100644 build/clang-plugin/ParamTraitsEnumChecker.cpp create mode 100644 build/clang-plugin/ParamTraitsEnumChecker.h create mode 100644 build/clang-plugin/RecurseGuard.h create mode 100644 build/clang-plugin/RefCountedCopyConstructorChecker.cpp create mode 100644 build/clang-plugin/RefCountedCopyConstructorChecker.h create mode 100644 build/clang-plugin/RefCountedInsideLambdaChecker.cpp create mode 100644 build/clang-plugin/RefCountedInsideLambdaChecker.h create mode 100644 build/clang-plugin/RefCountedThisInsideConstructorChecker.cpp create mode 100644 build/clang-plugin/RefCountedThisInsideConstructorChecker.h create mode 100644 build/clang-plugin/ScopeChecker.cpp create mode 100644 build/clang-plugin/ScopeChecker.h create mode 100644 build/clang-plugin/SprintfLiteralChecker.cpp create mode 100644 build/clang-plugin/SprintfLiteralChecker.h create mode 100644 build/clang-plugin/StmtToBlockMap.h create mode 100644 build/clang-plugin/ThirdPartyPaths.h create mode 100644 build/clang-plugin/ThirdPartyPaths.py create mode 100644 build/clang-plugin/ThreadAllows.py create mode 100644 build/clang-plugin/ThreadAllows.txt create mode 100644 build/clang-plugin/ThreadFileAllows.txt create mode 100644 build/clang-plugin/TrivialCtorDtorChecker.cpp create mode 100644 build/clang-plugin/TrivialCtorDtorChecker.h create mode 100644 build/clang-plugin/TrivialDtorChecker.cpp create mode 100644 build/clang-plugin/TrivialDtorChecker.h create mode 100644 build/clang-plugin/Utils.h create mode 100644 build/clang-plugin/VariableUsageHelpers.cpp create mode 100644 build/clang-plugin/VariableUsageHelpers.h create mode 100644 build/clang-plugin/alpha/AlphaChecks.inc create mode 100644 build/clang-plugin/alpha/AlphaIncludes.inc create mode 100644 build/clang-plugin/alpha/NonStdMoveChecker.cpp create mode 100644 build/clang-plugin/alpha/NonStdMoveChecker.h create mode 100644 build/clang-plugin/alpha/TempRefPtrChecker.cpp create mode 100644 build/clang-plugin/alpha/TempRefPtrChecker.h create mode 100644 build/clang-plugin/alpha/sources.mozbuild create mode 100644 build/clang-plugin/alpha/tests/TestNonStdMove.cpp create mode 100644 build/clang-plugin/alpha/tests/TestTempRefPtr.cpp create mode 100644 build/clang-plugin/alpha/tests/sources.mozbuild create mode 100644 build/clang-plugin/external/CustomAttributes.inc create mode 100644 build/clang-plugin/external/ExternalChecks.inc create mode 100644 build/clang-plugin/external/ExternalIncludes.inc create mode 100644 build/clang-plugin/external/sources.mozbuild create mode 100644 build/clang-plugin/external/tests/sources.mozbuild create mode 100755 build/clang-plugin/import_mozilla_checks.py create mode 100644 build/clang-plugin/moz.build create mode 100644 build/clang-plugin/mozsearch-plugin/BindingOperations.cpp create mode 100644 build/clang-plugin/mozsearch-plugin/BindingOperations.h create mode 100644 build/clang-plugin/mozsearch-plugin/FileOperations.cpp create mode 100644 build/clang-plugin/mozsearch-plugin/FileOperations.h create mode 100644 build/clang-plugin/mozsearch-plugin/MozsearchIndexer.cpp create mode 100644 build/clang-plugin/mozsearch-plugin/README create mode 100644 build/clang-plugin/mozsearch-plugin/StringOperations.cpp create mode 100644 build/clang-plugin/mozsearch-plugin/StringOperations.h create mode 100644 build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.cpp create mode 100644 build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.h create mode 100644 build/clang-plugin/mozsearch-plugin/from-clangd/README.md create mode 100644 build/clang-plugin/plugin.h create mode 100644 build/clang-plugin/tests/Makefile.in create mode 100644 build/clang-plugin/tests/NonParameterTestCases.h create mode 100644 build/clang-plugin/tests/TestAssertWithAssignment.cpp create mode 100644 build/clang-plugin/tests/TestBadImplicitConversionCtor.cpp create mode 100644 build/clang-plugin/tests/TestCanRunScript.cpp create mode 100644 build/clang-plugin/tests/TestCustomHeap.cpp create mode 100644 build/clang-plugin/tests/TestDanglingOnTemporary.cpp create mode 100644 build/clang-plugin/tests/TestExplicitOperatorBool.cpp create mode 100644 build/clang-plugin/tests/TestFopenUsage.cpp create mode 100644 build/clang-plugin/tests/TestGlobalClass.cpp create mode 100644 build/clang-plugin/tests/TestHeapClass.cpp create mode 100644 build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp create mode 100644 build/clang-plugin/tests/TestJSHandleRootedTypedef.cpp create mode 100644 build/clang-plugin/tests/TestKnownLive.cpp create mode 100644 build/clang-plugin/tests/TestKungFuDeathGrip.cpp create mode 100644 build/clang-plugin/tests/TestLoadLibraryUsage.cpp create mode 100644 build/clang-plugin/tests/TestMultipleAnnotations.cpp create mode 100644 build/clang-plugin/tests/TestMustOverride.cpp create mode 100644 build/clang-plugin/tests/TestMustReturnFromCaller.cpp create mode 100644 build/clang-plugin/tests/TestNANTestingExpr.cpp create mode 100644 build/clang-plugin/tests/TestNANTestingExprC.c create mode 100644 build/clang-plugin/tests/TestNeedsNoVTableType.cpp create mode 100644 build/clang-plugin/tests/TestNoAddRefReleaseOnReturn.cpp create mode 100644 build/clang-plugin/tests/TestNoArithmeticExprInArgument.cpp create mode 100644 build/clang-plugin/tests/TestNoAutoType.cpp create mode 100644 build/clang-plugin/tests/TestNoDuplicateRefCntMember.cpp create mode 100644 build/clang-plugin/tests/TestNoExplicitMoveConstructor.cpp create mode 100644 build/clang-plugin/tests/TestNoNewThreadsChecker.cpp create mode 100644 build/clang-plugin/tests/TestNoPrincipalGetUri.cpp create mode 100644 build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp create mode 100644 build/clang-plugin/tests/TestNoUsingNamespaceMozillaJava.cpp create mode 100644 build/clang-plugin/tests/TestNonHeapClass.cpp create mode 100644 build/clang-plugin/tests/TestNonMemMovable.cpp create mode 100644 build/clang-plugin/tests/TestNonMemMovableStd.cpp create mode 100644 build/clang-plugin/tests/TestNonMemMovableStdAtomic.cpp create mode 100644 build/clang-plugin/tests/TestNonParameterChecker.cpp create mode 100644 build/clang-plugin/tests/TestNonTemporaryClass.cpp create mode 100644 build/clang-plugin/tests/TestNonTrivialTypeInFfi.cpp create mode 100644 build/clang-plugin/tests/TestOverrideBaseCall.cpp create mode 100644 build/clang-plugin/tests/TestOverrideBaseCallAnnotation.cpp create mode 100644 build/clang-plugin/tests/TestParamTraitsEnum.cpp create mode 100644 build/clang-plugin/tests/TestRefCountedCopyConstructor.cpp create mode 100644 build/clang-plugin/tests/TestRefCountedThisInsideConstructor.cpp create mode 100644 build/clang-plugin/tests/TestSprintfLiteral.cpp create mode 100644 build/clang-plugin/tests/TestStackClass.cpp create mode 100644 build/clang-plugin/tests/TestStaticLocalClass.cpp create mode 100644 build/clang-plugin/tests/TestTemporaryClass.cpp create mode 100644 build/clang-plugin/tests/TestTrivialCtorDtor.cpp create mode 100644 build/clang-plugin/tests/TestTrivialDtor.cpp create mode 100644 build/clang-plugin/tests/moz.build create mode 100644 build/compare-mozconfig/compare-mozconfigs.py create mode 100644 build/compare-mozconfig/python.toml create mode 100644 build/debian-packages/pygobject.diff create mode 100644 build/debian-packages/ubuntu-glibc.diff create mode 100644 build/defines.sh create mode 100644 build/docs/build-overview.rst create mode 100644 build/docs/build-targets.rst create mode 100644 build/docs/chrome-registration.rst create mode 100644 build/docs/cppeclipse.rst create mode 100644 build/docs/cross-compile.rst create mode 100644 build/docs/defining-binaries.rst create mode 100644 build/docs/defining-xpcom-components.rst create mode 100644 build/docs/environment-variables.rst create mode 100644 build/docs/files-metadata.rst create mode 100644 build/docs/glossary.rst create mode 100644 build/docs/gn.rst create mode 100644 build/docs/index.rst create mode 100644 build/docs/jar-manifests.rst create mode 100644 build/docs/locales.rst create mode 100644 build/docs/mozbuild-files.rst create mode 100644 build/docs/mozbuild-symbols.rst create mode 100644 build/docs/mozbuild/index.rst create mode 100644 build/docs/mozconfigs.rst create mode 100644 build/docs/mozinfo.rst create mode 100644 build/docs/pgo.rst create mode 100644 build/docs/preprocessor.rst create mode 100644 build/docs/python.rst create mode 100644 build/docs/rust.rst create mode 100644 build/docs/sccache-dist.rst create mode 100644 build/docs/slow.rst create mode 100644 build/docs/snap.rst create mode 100644 build/docs/sparse.rst create mode 100644 build/docs/supported-configurations.rst create mode 100644 build/docs/telemetry.rst create mode 100644 build/docs/test_certificates.rst create mode 100644 build/docs/test_manifests.rst create mode 100644 build/docs/toolchains.rst create mode 100644 build/docs/unified-builds.rst create mode 100644 build/docs/visualstudio.rst create mode 100644 build/dumbmake-dependencies create mode 100644 build/gecko_templates.mozbuild create mode 100644 build/gen_symverscript.py create mode 100644 build/gen_test_packages_manifest.py create mode 100644 build/gyp.mozbuild create mode 100644 build/gyp_base.mozbuild create mode 100644 build/gyp_includes/common.gypi create mode 100644 build/gyp_includes/filename_rules.gypi create mode 100644 build/gyp_includes/internal/release_defaults.gypi create mode 100644 build/gyp_includes/internal/release_impl.gypi create mode 100644 build/gyp_includes/internal/release_impl_official.gypi create mode 100644 build/gyp_includes/release.gypi create mode 100644 build/mach_initialize.py create mode 100644 build/macosx/catalog.py create mode 100644 build/macosx/cross-mozconfig.common create mode 100644 build/macosx/mozconfig.common create mode 100644 build/macosx/permissions/chown_revert.c create mode 100644 build/macosx/permissions/chown_root.c create mode 100644 build/midl.py create mode 100644 build/moz-automation.mk create mode 100644 build/moz.build create mode 100644 build/moz.configure/android-ndk.configure create mode 100644 build/moz.configure/android-sdk.configure create mode 100644 build/moz.configure/arm.configure create mode 100644 build/moz.configure/bindgen.configure create mode 100644 build/moz.configure/bootstrap.configure create mode 100644 build/moz.configure/checks.configure create mode 100644 build/moz.configure/compile-checks.configure create mode 100644 build/moz.configure/compilers-util.configure create mode 100644 build/moz.configure/flags.configure create mode 100644 build/moz.configure/headers.configure create mode 100644 build/moz.configure/init.configure create mode 100644 build/moz.configure/java.configure create mode 100644 build/moz.configure/keyfiles.configure create mode 100644 build/moz.configure/lto-pgo.configure create mode 100644 build/moz.configure/memory.configure create mode 100644 build/moz.configure/node.configure create mode 100644 build/moz.configure/nspr.configure create mode 100644 build/moz.configure/nss.configure create mode 100644 build/moz.configure/old.configure create mode 100644 build/moz.configure/pkg.configure create mode 100644 build/moz.configure/rust.configure create mode 100644 build/moz.configure/toolchain.configure create mode 100644 build/moz.configure/update-programs.configure create mode 100644 build/moz.configure/util.configure create mode 100644 build/moz.configure/warnings.configure create mode 100644 build/moz.configure/windows.configure create mode 100644 build/mozconfig.artifact create mode 100644 build/mozconfig.artifact.automation create mode 100644 build/mozconfig.automation create mode 100644 build/mozconfig.cache create mode 100644 build/mozconfig.clang-cl create mode 100644 build/mozconfig.common create mode 100644 build/mozconfig.common.override create mode 100644 build/mozconfig.lld-link create mode 100644 build/mozconfig.no-compile create mode 100644 build/mozconfig.rust create mode 100644 build/mozconfig.win-common create mode 100644 build/non-unified-compat create mode 100755 build/package/mac_osx/make-diskimage create mode 100644 build/package/mac_osx/mozilla-background.jpg create mode 100644 build/package/mac_osx/mozilla.dsstore create mode 100644 build/package/mac_osx/requirements.plist create mode 100755 build/package/mac_osx/unpack-diskimage create mode 100644 build/pgo/blueprint/LICENSE create mode 100644 build/pgo/blueprint/elements.html create mode 100644 build/pgo/blueprint/fancytype-screen.css create mode 100644 build/pgo/blueprint/forms.html create mode 100644 build/pgo/blueprint/grid.html create mode 100644 build/pgo/blueprint/grid.png create mode 100644 build/pgo/blueprint/print.css create mode 100644 build/pgo/blueprint/sample.html create mode 100644 build/pgo/blueprint/screen.css create mode 100644 build/pgo/blueprint/test-small.jpg create mode 100644 build/pgo/blueprint/test.jpg create mode 100644 build/pgo/certs/README create mode 100644 build/pgo/certs/alternateroot.ca create mode 100644 build/pgo/certs/alternateroot.ca.keyspec create mode 100644 build/pgo/certs/alternateroot.certspec create mode 100644 build/pgo/certs/badCertDomain.certspec create mode 100644 build/pgo/certs/bug1665057cert.certspec create mode 100644 build/pgo/certs/bug1706126cert.certspec create mode 100644 build/pgo/certs/bug413909cert.certspec create mode 100644 build/pgo/certs/cert9.db create mode 100644 build/pgo/certs/dynamicPinningBad.certspec create mode 100644 build/pgo/certs/dynamicPinningBad.server.keyspec create mode 100644 build/pgo/certs/dynamicPinningGood.certspec create mode 100644 build/pgo/certs/escapeattack1.certspec create mode 100644 build/pgo/certs/evintermediate.ca create mode 100644 build/pgo/certs/evintermediate.ca.keyspec create mode 100644 build/pgo/certs/evintermediate.certspec create mode 100644 build/pgo/certs/expired.certspec create mode 100644 build/pgo/certs/http2-cert.ca create mode 100644 build/pgo/certs/http2-cert.ca.keyspec create mode 100644 build/pgo/certs/http2-cert.certspec create mode 100644 build/pgo/certs/imminently_distrusted.certspec create mode 100644 build/pgo/certs/key4.db create mode 100644 build/pgo/certs/mochitest-cert.ca create mode 100644 build/pgo/certs/mochitest-cert.ca.keyspec create mode 100644 build/pgo/certs/mochitest-cert.certspec create mode 100644 build/pgo/certs/mochitest.certspec create mode 100644 build/pgo/certs/mochitest.client create mode 100644 build/pgo/certs/mochitest.client.keyspec create mode 100644 build/pgo/certs/noSubjectAltName.certspec create mode 100644 build/pgo/certs/pgoca.ca create mode 100644 build/pgo/certs/pgoca.ca.keyspec create mode 100644 build/pgo/certs/pgoca.certspec create mode 100644 build/pgo/certs/pkcs11.txt create mode 100644 build/pgo/certs/selfsigned.certspec create mode 100644 build/pgo/certs/sha1_end_entity.certspec create mode 100644 build/pgo/certs/sha256_end_entity.certspec create mode 100644 build/pgo/certs/staticPinningBad.certspec create mode 100644 build/pgo/certs/staticPinningBad.server.keyspec create mode 100644 build/pgo/certs/unknown_ca.certspec create mode 100644 build/pgo/certs/untrusted.certspec create mode 100644 build/pgo/certs/untrustedandexpired.certspec create mode 100644 build/pgo/favicon.ico create mode 100644 build/pgo/genpgocert.py create mode 100644 build/pgo/index.html create mode 100644 build/pgo/js-input/3d-thingy.html create mode 100644 build/pgo/js-input/crypto-otp.html create mode 100644 build/pgo/js-input/key.gif create mode 100644 build/pgo/js-input/sunspider/3d-cube.html create mode 100644 build/pgo/js-input/sunspider/3d-morph.html create mode 100644 build/pgo/js-input/sunspider/3d-raytrace.html create mode 100644 build/pgo/js-input/sunspider/access-binary-trees.html create mode 100644 build/pgo/js-input/sunspider/access-fannkuch.html create mode 100644 build/pgo/js-input/sunspider/access-nbody.html create mode 100644 build/pgo/js-input/sunspider/access-nsieve.html create mode 100644 build/pgo/js-input/sunspider/bitops-3bit-bits-in-byte.html create mode 100644 build/pgo/js-input/sunspider/bitops-bits-in-byte.html create mode 100644 build/pgo/js-input/sunspider/bitops-bitwise-and.html create mode 100644 build/pgo/js-input/sunspider/bitops-nsieve-bits.html create mode 100644 build/pgo/js-input/sunspider/controlflow-recursive.html create mode 100644 build/pgo/js-input/sunspider/crypto-aes.html create mode 100644 build/pgo/js-input/sunspider/crypto-md5.html create mode 100644 build/pgo/js-input/sunspider/crypto-sha1.html create mode 100644 build/pgo/js-input/sunspider/date-format-tofte.html create mode 100644 build/pgo/js-input/sunspider/date-format-xparb.html create mode 100644 build/pgo/js-input/sunspider/math-cordic.html create mode 100644 build/pgo/js-input/sunspider/math-partial-sums.html create mode 100644 build/pgo/js-input/sunspider/math-spectral-norm.html create mode 100644 build/pgo/js-input/sunspider/regexp-dna.html create mode 100644 build/pgo/js-input/sunspider/string-base64.html create mode 100644 build/pgo/js-input/sunspider/string-fasta.html create mode 100644 build/pgo/js-input/sunspider/string-tagcloud.html create mode 100644 build/pgo/js-input/sunspider/string-unpack-code.html create mode 100644 build/pgo/js-input/sunspider/string-validate-input.html create mode 100644 build/pgo/js-input/valid-xhtml10.png create mode 100755 build/pgo/profileserver.py create mode 100644 build/pgo/server-locations.txt create mode 100644 build/psutil_requirements.in create mode 100644 build/psutil_requirements.txt create mode 100644 build/pure_virtual/moz.build create mode 100644 build/pure_virtual/pure_virtual.c create mode 100755 build/qemu-wrap create mode 100644 build/rust/backtrace/Cargo.toml create mode 100644 build/rust/backtrace/lib.rs create mode 100644 build/rust/base64/Cargo.toml create mode 100644 build/rust/base64/lib.rs create mode 100644 build/rust/bindgen-0.63/Cargo.toml create mode 100644 build/rust/bindgen-0.63/lib.rs create mode 100644 build/rust/bitflags/Cargo.toml create mode 100644 build/rust/bitflags/lib.rs create mode 100644 build/rust/cfg-if/Cargo.toml create mode 100644 build/rust/cfg-if/lib.rs create mode 100644 build/rust/cmake/Cargo.toml create mode 100644 build/rust/cmake/lib.rs create mode 100644 build/rust/derive_more/Cargo.toml create mode 100644 build/rust/derive_more/lib.rs create mode 100644 build/rust/dummy-web/js-sys/Cargo.toml create mode 100644 build/rust/dummy-web/js-sys/lib.rs create mode 100644 build/rust/dummy-web/wasm-bindgen/Cargo.toml create mode 100644 build/rust/dummy-web/wasm-bindgen/lib.rs create mode 100644 build/rust/dummy-web/web-sys/Cargo.toml create mode 100644 build/rust/dummy-web/web-sys/lib.rs create mode 100644 build/rust/goblin/Cargo.toml create mode 100644 build/rust/goblin/lib.rs create mode 100644 build/rust/indexmap/Cargo.toml create mode 100644 build/rust/indexmap/lib.rs create mode 100644 build/rust/memmap2-0.5/Cargo.toml create mode 100644 build/rust/memmap2-0.5/lib.rs create mode 100644 build/rust/memmap2/Cargo.toml create mode 100644 build/rust/memmap2/lib.rs create mode 100644 build/rust/memoffset/Cargo.toml create mode 100644 build/rust/memoffset/lib.rs create mode 100644 build/rust/mozbuild/Cargo.toml create mode 100644 build/rust/mozbuild/build.rs create mode 100644 build/rust/mozbuild/generate_buildconfig.py create mode 100644 build/rust/mozbuild/lib.rs create mode 100644 build/rust/mozbuild/moz.build create mode 100644 build/rust/nix/Cargo.toml create mode 100644 build/rust/nix/lib.rs create mode 100644 build/rust/oslog/Cargo.toml create mode 100644 build/rust/oslog/LICENSE create mode 100644 build/rust/oslog/lib.rs create mode 100644 build/rust/redox_syscall/Cargo.toml create mode 100644 build/rust/redox_syscall/lib.rs create mode 100644 build/rust/redox_users/Cargo.toml create mode 100644 build/rust/redox_users/lib.rs create mode 100644 build/rust/terminal_size/Cargo.toml create mode 100644 build/rust/terminal_size/lib.rs create mode 100644 build/rust/tinyvec/Cargo.toml create mode 100644 build/rust/tinyvec/lib.rs create mode 100644 build/rust/vcpkg/Cargo.toml create mode 100644 build/rust/vcpkg/lib.rs create mode 100644 build/rust/wasi/Cargo.toml create mode 100644 build/rust/wasi/lib.rs create mode 100644 build/rust/windows-sys/Cargo.toml create mode 100644 build/rust/windows-sys/lib.rs create mode 100644 build/rust/windows-targets-0.48/Cargo.toml create mode 100644 build/rust/windows-targets-0.48/lib.rs create mode 100644 build/rust/windows-targets/Cargo.toml create mode 100644 build/rust/windows-targets/lib.rs create mode 100644 build/rust/windows/Cargo.toml create mode 100644 build/rust/windows/src/lib.rs create mode 100644 build/sanitizers/asan_blacklist_win.txt create mode 100644 build/sanitizers/ubsan_enum_blacklist.txt create mode 100644 build/sanitizers/ubsan_function_blacklist.txt create mode 100644 build/sanitizers/ubsan_object_size_blacklist.txt create mode 100644 build/sanitizers/ubsan_pointer_overflow_blacklist.txt create mode 100644 build/sanitizers/ubsan_signed_overflow_blacklist.txt create mode 100644 build/sanitizers/ubsan_unsigned_overflow_blacklist.txt create mode 100644 build/sparse-profiles/docker-image create mode 100644 build/sparse-profiles/github-sync create mode 100644 build/sparse-profiles/mach create mode 100644 build/sparse-profiles/mozharness create mode 100644 build/sparse-profiles/perftest create mode 100644 build/sparse-profiles/profile-generate create mode 100644 build/sparse-profiles/push-to-try create mode 100644 build/sparse-profiles/sphinx-docs create mode 100644 build/sparse-profiles/startup-test create mode 100644 build/sparse-profiles/taskgraph create mode 100644 build/sparse-profiles/toolchain-build create mode 100644 build/sparse-profiles/tps create mode 100644 build/sparse-profiles/update-verify create mode 100644 build/sparse-profiles/upload-generated-sources create mode 100644 build/sparse-profiles/upload-symbols create mode 100644 build/sparse-profiles/webrender create mode 100644 build/templates.mozbuild create mode 100644 build/tests/cram/cram.toml create mode 100644 build/tests/cram/test_configure_help.t create mode 100644 build/unix/aix.exp create mode 100644 build/unix/build-binutils/3A24BC1E8FB409FA9F14371813FCEF89DD9E3C4F.key create mode 100755 build/unix/build-binutils/build-binutils.sh create mode 100644 build/unix/build-gcc/07F3DBBECC1A39605078094D980C197698C3739D.key create mode 100644 build/unix/build-gcc/13975A70E63C361C73AE69EF6EEB81F8981C74C7.key create mode 100644 build/unix/build-gcc/33C235A34C46AA3FFB293709A328C3A2C3C45C06.key create mode 100644 build/unix/build-gcc/343C2FF0FBEE5EC2EDBEF399F3599FF828C67298.key create mode 100644 build/unix/build-gcc/5ED46A6721D365587791E2AA783FCD8E58BCAFBA.key create mode 100644 build/unix/build-gcc/7F74F97C103468EE5D750B583AB00996FC26A641.key create mode 100644 build/unix/build-gcc/AD17A21EF8AED8F1CC02DBD9F7D5C9BF765C61E3.key create mode 100644 build/unix/build-gcc/D3A93CAD751C2AF4F8C7AD516C35B99309B5FA62.key create mode 100644 build/unix/build-gcc/DA23579A74D4AD9AF9D3F945CEFAC8EAAF17519D.key create mode 100644 build/unix/build-gcc/EAF1C276A747E9ED86210CBAC3126D3B4AE55E93.key create mode 100755 build/unix/build-gcc/build-gcc.sh create mode 100755 build/unix/build-hfsplus/build-hfsplus.sh create mode 100644 build/unix/elfhack/Makefile.in create mode 100644 build/unix/elfhack/README create mode 100644 build/unix/elfhack/dummy.c create mode 100644 build/unix/elfhack/elf.cpp create mode 100644 build/unix/elfhack/elfhack.cpp create mode 100644 build/unix/elfhack/elfxx.h create mode 100644 build/unix/elfhack/inject.c create mode 100644 build/unix/elfhack/inject/copy_source.py create mode 100644 build/unix/elfhack/inject/moz.build create mode 100644 build/unix/elfhack/moz.build create mode 100644 build/unix/elfhack/relrhack.cpp create mode 100644 build/unix/elfhack/relrhack.h create mode 100644 build/unix/elfhack/test-array.c create mode 100644 build/unix/elfhack/test-ctors.c create mode 100644 build/unix/elfhack/test.c create mode 100644 build/unix/moz.build create mode 100644 build/unix/mozconfig.asan create mode 100644 build/unix/mozconfig.linux create mode 100644 build/unix/mozconfig.linux32 create mode 100644 build/unix/mozconfig.stdcxx create mode 100644 build/unix/mozconfig.tsan create mode 100644 build/unix/mozconfig.unix create mode 100755 build/unix/print-non-newline.sh create mode 100644 build/unix/rewrite_sanitizer_dylib.py create mode 100644 build/unix/run-gprof.sh create mode 100644 build/unix/run-hiprof.sh create mode 100755 build/unix/run-mozilla.sh create mode 100644 build/unix/run-third.sh create mode 100644 build/unix/stdc++compat/hide_std.ld create mode 100644 build/unix/stdc++compat/moz.build create mode 100644 build/unix/stdc++compat/stdc++compat.cpp create mode 100644 build/update-settings.ini create mode 100644 build/upload.py create mode 100644 build/upload_generated_sources.py create mode 100644 build/valgrind/__init__.py create mode 100644 build/valgrind/cross-architecture.sup create mode 100644 build/valgrind/i386-pc-linux-gnu.sup create mode 100644 build/valgrind/mach_commands.py create mode 100644 build/valgrind/output_handler.py create mode 100644 build/valgrind/x86_64-pc-linux-gnu.sup create mode 100644 build/variables.py create mode 100755 build/vs/generate_yaml.py create mode 100644 build/vs/vs2019.yaml create mode 100644 build/vs/vs2022.yaml create mode 100644 build/win32/__init__.py create mode 100644 build/win32/autowinchecksec.py create mode 100644 build/win32/crashinject.cpp create mode 100644 build/win32/crashinjectdll/crashinjectdll.cpp create mode 100644 build/win32/crashinjectdll/crashinjectdll.def create mode 100644 build/win32/crashinjectdll/moz.build create mode 100644 build/win32/dummy_libs.py create mode 100644 build/win32/moz.build create mode 100644 build/win32/mozconfig.vs-latest create mode 100644 build/win32/mozconfig.vs2019 create mode 100644 build/win32/nsis-no-insert-timestamp.patch create mode 100644 build/win32/nsis-no-underscore.patch create mode 100644 build/win32/nsis-scons.patch create mode 100644 build/win64-aarch64/mozconfig.vs-latest create mode 100644 build/win64-aarch64/mozconfig.vs2019 create mode 100644 build/win64/mozconfig.asan create mode 100644 build/win64/mozconfig.vs-latest create mode 100644 build/win64/mozconfig.vs2019 create mode 100644 build/workspace-hack/Cargo.toml create mode 100644 build/workspace-hack/src/lib.rs create mode 100644 build/zstandard_requirements.in create mode 100644 build/zstandard_requirements.txt (limited to 'build') diff --git a/build/.gdbinit b/build/.gdbinit new file mode 100644 index 0000000000..870c0a81da --- /dev/null +++ b/build/.gdbinit @@ -0,0 +1,208 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# .gdbinit file for debugging Mozilla + +# You may need to put an 'add-auto-load-safe-path' command in your +# $HOME/.gdbinit file to get GDB to trust this file. If your builds are +# generally in $HOME/moz, then you can say: +# +# add-auto-load-safe-path ~/moz + +# Don't stop for the SIG32/33/etc signals that Flash produces +handle SIG32 noprint nostop pass +handle SIG33 noprint nostop pass +handle SIGPIPE noprint nostop pass + +# Don't stop for certain other signals where it's not useful, +# such as the SIG64 signals triggered by the Linux +# sandboxing code on older kernels. +handle SIG38 noprint nostop pass +handle SIG64 noprint nostop pass +handle SIGSYS noprint nostop pass + +# Show the concrete types behind nsIFoo +set print object on + +# run when using the auto-solib-add trick +define prun + tbreak main + run + set auto-solib-add 0 + cont +end + +# run -mail, when using the auto-solib-add trick +define pmail + tbreak main + run -mail + set auto-solib-add 0 + cont +end + +# Define a "pu" command to display PRUnichar * strings (100 chars max) +# Also allows an optional argument for how many chars to print as long as +# it's less than 100. +define pu + set $uni = $arg0 + if $argc == 2 + set $limit = $arg1 + if $limit > 100 + set $limit = 100 + end + else + set $limit = 100 + end + # scratch array with space for 100 chars plus null terminator. Make + # sure to not use ' ' as the char so this copy/pastes well. + set $scratch = "____________________________________________________________________________________________________" + set $i = 0 + set $scratch_idx = 0 + while (*$uni && $i++ < $limit) + if (*$uni < 0x80) + set $scratch[$scratch_idx++] = *(char*)$uni++ + else + if ($scratch_idx > 0) + set $scratch[$scratch_idx] = '\0' + print $scratch + set $scratch_idx = 0 + end + print /x *(short*)$uni++ + end + end + if ($scratch_idx > 0) + set $scratch[$scratch_idx] = '\0' + print $scratch + end +end + +# Define a "ps" command to display subclasses of nsAC?String. Note that +# this assumes strings as of Gecko 1.9 (well, and probably a few +# releases before that as well); going back far enough will get you +# to string classes that this function doesn't work for. +define ps + set $str = $arg0 + if (sizeof(*$str.mData) == 1 && ($str.mFlags & 1) != 0) + print $str.mData + else + pu $str.mData $str.mLength + end +end + +# Define a "pa" command to display the string value for an nsAtom +define pa + set $atom = $arg0 + if (sizeof(*((&*$atom)->mString)) == 2) + pu (&*$atom)->mString + end +end + +# define a "pxul" command to display the type of a XUL element from +# an nsXULElement* pointer. +define pxul + set $p = $arg0 + print $p->mNodeInfo.mRawPtr->mInner.mName->mStaticAtom->mString +end + +# define a "prefcnt" command to display the refcount of an XPCOM obj +define prefcnt + set $p = $arg0 + print ((nsPurpleBufferEntry*)$p->mRefCnt.mTagged)->mRefCnt +end + +# define a "ptag" command to display the tag name of a content node +define ptag + set $p = $arg0 + pa $p->mNodeInfo.mRawPtr->mInner.mName +end + +## +## nsTArray +## +define ptarray + if $argc == 0 + help ptarray + else + set $size = $arg0.mHdr->mLength + set $capacity = $arg0.mHdr->mCapacity + set $size_max = $size - 1 + set $elts = $arg0.Elements() + end + if $argc == 1 + set $i = 0 + while $i < $size + printf "elem[%u]: ", $i + p *($elts + $i) + set $i++ + end + end + if $argc == 2 + set $idx = $arg1 + if $idx < 0 || $idx > $size_max + printf "idx1, idx2 are not in acceptable range: [0..%u].\n", $size_max + else + printf "elem[%u]: ", $idx + p *($elts + $idx) + end + end + if $argc == 3 + set $start_idx = $arg1 + set $stop_idx = $arg2 + if $start_idx > $stop_idx + set $tmp_idx = $start_idx + set $start_idx = $stop_idx + set $stop_idx = $tmp_idx + end + if $start_idx < 0 || $stop_idx < 0 || $start_idx > $size_max || $stop_idx > $size_max + printf "idx1, idx2 are not in acceptable range: [0..%u].\n", $size_max + else + set $i = $start_idx + while $i <= $stop_idx + printf "elem[%u]: ", $i + p *($elts + $i) + set $i++ + end + end + end + if $argc > 0 + printf "nsTArray length = %u\n", $size + printf "nsTArray capacity = %u\n", $capacity + printf "Element " + whatis *$elts + end +end + +document ptarray + Prints nsTArray information. + Syntax: ptarray + Note: idx, idx1 and idx2 must be in acceptable range [0...size()-1]. + Examples: + ptarray a - Prints tarray content, size, capacity and T typedef + ptarray a 0 - Prints element[idx] from tarray + ptarray a 1 2 - Prints elements in range [idx1..idx2] from tarray +end + +define js + call DumpJSStack() +end + +define ct + call $arg0->Dump() +end + +define ft + call $arg0->DumpFrameTree() +end + +define ftp + call $arg0->DumpFrameTreeInCSSPixels() +end + +define ftl + call $arg0->DumpFrameTreeLimited() +end + +define ftlp + call $arg0->DumpFrameTreeLimitedInCSSPixels() +end diff --git a/build/.gdbinit.loader b/build/.gdbinit.loader new file mode 100644 index 0000000000..e8a13432f7 --- /dev/null +++ b/build/.gdbinit.loader @@ -0,0 +1,29 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# loader for .gdbinit file + +# This file provides a guard against multiple inclusion. GDB command syntax is +# rather limited in that you cannot have a `documentation` command inside of an +# `if`. So we use a separate loader file that sources `.gdbinit` within the +# `if`. + +# You may need to put an 'add-auto-load-safe-path' command in your +# $HOME/.gdbinit file to get GDB to trust this file. If your builds are +# generally in $HOME/moz, then you can say: +# +# add-auto-load-safe-path ~/moz + +# Multiple include guard +if $_moz_gdbinit_loaded + # already loaded +else + set $_moz_gdbinit_loaded=1 + + source -s build/.gdbinit + + # This requires $objdir to have been added to gdb's source directory search + # path. Normally this will be done by libxul.so-gdb.py or js-gdb.py. + source -s build/.gdbinit.py +end diff --git a/build/.gdbinit.py.in b/build/.gdbinit.py.in new file mode 100644 index 0000000000..ec8c11b51b --- /dev/null +++ b/build/.gdbinit.py.in @@ -0,0 +1,19 @@ +#filter substitution + +import os +import sys + +sys.path.append(os.path.join('@topsrcdir@', 'js', 'src', 'gdb')) +sys.path.append(os.path.join('@topsrcdir@', 'python', 'gdbpp')) + +# JS prettyprinters + +import mozilla.autoload +mozilla.autoload.register(gdb.current_objfile()) + +import mozilla.asmjs +mozilla.asmjs.install() + +# Gecko prettyprinters + +import gdbpp diff --git a/build/.lldbinit.in b/build/.lldbinit.in new file mode 100644 index 0000000000..bf43fe9cff --- /dev/null +++ b/build/.lldbinit.in @@ -0,0 +1,21 @@ +# This must be the first Python variable set in this file +script ignore__see_bug_1605268 = True + +#filter substitution +script topsrcdir = "@topsrcdir@"; lldb.debugger.HandleCommand("command source -s true '%s'" % os.path.join(topsrcdir, ".lldbinit")) + +#ifdef MOZ_WIDGET_ANDROID +settings set symbols.enable-external-lookup true + +# This is where libxul.so and libmozglue.so are produced in full builds. +settings append target.exec-search-paths @topobjdir@/toolkit/library/build +settings append target.exec-search-paths @topobjdir@/mozglue/build +settings append target.exec-search-paths @topobjdir@/security + +# This is where artifact builds unpacks "crashreporter-symbols-full" uncompressed ELF debug symbols. +settings append target.debug-file-search-paths @topobjdir@/dist/crashreporter-symbols + +# These are specific paths encoded into Mozilla's automation outputs. +settings append target.source-map /builds/worker/workspace/build/src/obj-firefox @topobjdir@ +settings append target.source-map /builds/worker/workspace/build/src @topsrcdir@ +#endif diff --git a/build/RunCbindgen.py b/build/RunCbindgen.py new file mode 100644 index 0000000000..e166556f68 --- /dev/null +++ b/build/RunCbindgen.py @@ -0,0 +1,102 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import subprocess + +import buildconfig +import mozpack.path as mozpath +import six +import toml + + +# Try to read the package name or otherwise assume same name as the crate path. +def _get_crate_name(crate_path): + try: + with open(mozpath.join(crate_path, "Cargo.toml"), encoding="utf-8") as f: + return toml.load(f)["package"]["name"] + except Exception: + return mozpath.basename(crate_path) + + +CARGO_LOCK = mozpath.join(buildconfig.topsrcdir, "Cargo.lock") +CARGO_TOML = mozpath.join(buildconfig.topsrcdir, "Cargo.toml") + + +def _run_process(args): + env = os.environ.copy() + env["CARGO"] = str(buildconfig.substs["CARGO"]) + env["RUSTC"] = str(buildconfig.substs["RUSTC"]) + + p = subprocess.Popen(args, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + stdout, stderr = p.communicate() + stdout = six.ensure_text(stdout) + stderr = six.ensure_text(stderr) + if p.returncode != 0: + print(stdout) + print(stderr) + return (stdout, p.returncode) + + +def generate_metadata(output, cargo_config): + args = [ + buildconfig.substs["CARGO"], + "metadata", + "--all-features", + "--format-version", + "1", + "--manifest-path", + CARGO_TOML, + ] + + # The Spidermonkey library can be built from a package tarball outside the + # tree, so we want to let Cargo create lock files in this case. When built + # within a tree, the Rust dependencies have been vendored in so Cargo won't + # touch the lock file. + if not buildconfig.substs.get("JS_STANDALONE"): + args.append("--frozen") + + stdout, returncode = _run_process(args) + + if returncode != 0: + return returncode + + output.write(stdout) + + # This is not quite accurate, but cbindgen only cares about a subset of the + # data which, when changed, causes these files to change. + return set([CARGO_LOCK, CARGO_TOML]) + + +def generate(output, metadata_path, cbindgen_crate_path, *in_tree_dependencies): + stdout, returncode = _run_process( + [ + buildconfig.substs["CBINDGEN"], + buildconfig.topsrcdir, + "--lockfile", + CARGO_LOCK, + "--crate", + _get_crate_name(cbindgen_crate_path), + "--metadata", + metadata_path, + "--cpp-compat", + ] + ) + + if returncode != 0: + return returncode + + output.write(stdout) + + deps = set() + deps.add(CARGO_LOCK) + deps.add(mozpath.join(cbindgen_crate_path, "cbindgen.toml")) + for directory in in_tree_dependencies + (cbindgen_crate_path,): + for path, dirs, files in os.walk(directory): + for file in files: + if os.path.splitext(file)[1] == ".rs": + deps.add(mozpath.join(path, file)) + + return deps diff --git a/build/__init__.py b/build/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/build/android/libgcc.a b/build/android/libgcc.a new file mode 100644 index 0000000000..d8349075d7 --- /dev/null +++ b/build/android/libgcc.a @@ -0,0 +1 @@ +INPUT(-lunwind) diff --git a/build/appini_header.py b/build/appini_header.py new file mode 100644 index 0000000000..4cf9481ea0 --- /dev/null +++ b/build/appini_header.py @@ -0,0 +1,90 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +"""Parses a given application.ini file and outputs the corresponding + StaticXREAppData structure as a C++ header file""" + +import configparser +import sys + + +def main(output, file): + config = configparser.RawConfigParser() + config.read(file) + flags = set() + try: + if config.getint("XRE", "EnableProfileMigrator") == 1: + flags.add("NS_XRE_ENABLE_PROFILE_MIGRATOR") + except Exception: + pass + try: + if config.getint("Crash Reporter", "Enabled") == 1: + flags.add("NS_XRE_ENABLE_CRASH_REPORTER") + except Exception: + pass + appdata = dict( + ("%s:%s" % (s, o), config.get(s, o)) + for s in config.sections() + for o in config.options(s) + ) + appdata["flags"] = " | ".join(sorted(flags)) if flags else "0" + for key in ("App:vendor", "App:profile"): + # Set to NULL when not present or falsy such as an empty string + appdata[key] = '"%s"' % appdata[key] if appdata.get(key, None) else "NULL" + expected = ( + "App:vendor", + "App:name", + "App:remotingname", + "App:version", + "App:buildid", + "App:id", + "Gecko:minversion", + "Gecko:maxversion", + ) + missing = [var for var in expected if var not in appdata] + if missing: + print("Missing values in %s: %s" % (file, ", ".join(missing)), file=sys.stderr) + sys.exit(1) + + if "Crash Reporter:serverurl" not in appdata: + appdata["Crash Reporter:serverurl"] = "" + + if "App:sourcerepository" in appdata and "App:sourcestamp" in appdata: + appdata["App:sourceurl"] = ( + '"%(App:sourcerepository)s/rev/%(App:sourcestamp)s"' % appdata + ) + else: + appdata["App:sourceurl"] = "NULL" + + if "AppUpdate:url" not in appdata: + appdata["AppUpdate:url"] = "" + + output.write( + """#include "mozilla/XREAppData.h" + static const mozilla::StaticXREAppData sAppData = { + %(App:vendor)s, + "%(App:name)s", + "%(App:remotingname)s", + "%(App:version)s", + "%(App:buildid)s", + "%(App:id)s", + NULL, // copyright + %(flags)s, + "%(Gecko:minversion)s", + "%(Gecko:maxversion)s", + "%(Crash Reporter:serverurl)s", + %(App:profile)s, + NULL, // UAName + %(App:sourceurl)s, + "%(AppUpdate:url)s" + };""" + % appdata + ) + + +if __name__ == "__main__": + if len(sys.argv) != 1: + main(sys.stdout, sys.argv[1]) + else: + print("Usage: %s /path/to/application.ini" % sys.argv[0], file=sys.stderr) diff --git a/build/application.ini.in b/build/application.ini.in new file mode 100644 index 0000000000..6df13230a4 --- /dev/null +++ b/build/application.ini.in @@ -0,0 +1,56 @@ +#ifdef MOZ_BUILD_APP_IS_BROWSER +; This file is not used. If you modify it and want the application to use +; your modifications, move it under the browser/ subdirectory and start with +; the "-app /path/to/browser/application.ini" argument. +#else +; This file is not used. If you modify it and want the application to use +; your modifications, start with the "-app /path/to/application.ini" +; argument. +#endif +#if 0 +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. +#endif +#filter substitution +#include @TOPOBJDIR@/buildid.h +#include @TOPOBJDIR@/source-repo.h +[App] +Vendor=@MOZ_APP_VENDOR@ +Name=@MOZ_APP_BASENAME@ +RemotingName=@MOZ_APP_REMOTINGNAME@ +#ifdef MOZ_APP_DISPLAYNAME +CodeName=@MOZ_APP_DISPLAYNAME@ +#endif +Version=@MOZ_APP_VERSION@ +#ifdef MOZ_APP_PROFILE +Profile=@MOZ_APP_PROFILE@ +#endif +BuildID=@MOZ_BUILDID@ +#ifdef MOZ_SOURCE_REPO +SourceRepository=@MOZ_SOURCE_REPO@ +#endif +#ifdef MOZ_SOURCE_STAMP +SourceStamp=@MOZ_SOURCE_STAMP@ +#endif +ID=@MOZ_APP_ID@ + +[Gecko] +MinVersion=@GRE_MILESTONE@ +MaxVersion=@GRE_MILESTONE@ + +[XRE] +#ifdef MOZ_PROFILE_MIGRATOR +EnableProfileMigrator=1 +#endif + +#if MOZ_CRASHREPORTER +[Crash Reporter] +Enabled=1 +ServerURL=@MOZ_CRASHREPORTER_URL@/submit?id=@MOZ_APP_ID@&version=@MOZ_APP_VERSION@&buildid=@MOZ_BUILDID@ +#endif + +#if MOZ_UPDATER +[AppUpdate] +URL=https://@MOZ_APPUPDATE_HOST@/update/6/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%SYSTEM_CAPABILITIES%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml +#endif diff --git a/build/autoconf/acgeneral.m4 b/build/autoconf/acgeneral.m4 new file mode 100644 index 0000000000..772622849b --- /dev/null +++ b/build/autoconf/acgeneral.m4 @@ -0,0 +1,2607 @@ +dnl Parameterized macros. +dnl Requires GNU m4. +dnl This file is part of Autoconf. +dnl Copyright (C) 1992, 93, 94, 95, 96, 1998 Free Software Foundation, Inc. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception, the Free Software Foundation gives unlimited +dnl permission to copy, distribute and modify the configure scripts that +dnl are the output of Autoconf. You need not follow the terms of the GNU +dnl General Public License when using or distributing such scripts, even +dnl though portions of the text of Autoconf appear in them. The GNU +dnl General Public License (GPL) does govern all other use of the material +dnl that constitutes the Autoconf program. +dnl +dnl Certain portions of the Autoconf source text are designed to be copied +dnl (in certain cases, depending on the input) into the output of +dnl Autoconf. We call these the "data" portions. The rest of the Autoconf +dnl source text consists of comments plus executable code that decides which +dnl of the data portions to output in any given case. We call these +dnl comments and executable code the "non-data" portions. Autoconf never +dnl copies any of the non-data portions into its output. +dnl +dnl This special exception to the GPL applies to versions of Autoconf +dnl released by the Free Software Foundation. When you make and +dnl distribute a modified version of Autoconf, you may extend this special +dnl exception to the GPL to apply to your modified version as well, *unless* +dnl your modified version has the potential to copy into its output some +dnl of the text that was the non-data portion of the version that you started +dnl with. (In other words, unless your change moves or copies text from +dnl the non-data portions to the data portions.) If your modification has +dnl such potential, you must delete any notice of this special exception +dnl to the GPL from your modified version. +dnl +dnl Written by David MacKenzie, with help from +dnl Franc,ois Pinard, Karl Berry, Richard Pixley, Ian Lance Taylor, +dnl Roland McGrath, Noah Friedman, david d zuhn, and many others. +dnl +divert(-1)dnl Throw away output until AC_INIT is called. +changequote([, ]) + +define(AC_ACVERSION, 2.13) + +dnl Some old m4's don't support m4exit. But they provide +dnl equivalent functionality by core dumping because of the +dnl long macros we define. +ifdef([__gnu__], , [errprint(Autoconf requires GNU m4. +Install it before installing Autoconf or set the +M4 environment variable to its path name. +)m4exit(2)]) + +undefine([eval]) +undefine([include]) +undefine([shift]) +undefine([format]) + + +dnl ### Defining macros + + +dnl m4 output diversions. We let m4 output them all in order at the end, +dnl except that we explicitly undivert AC_DIVERSION_SED, AC_DIVERSION_CMDS, +dnl and AC_DIVERSION_ICMDS. + +dnl AC_DIVERSION_NOTICE - 1 (= 0) AC_REQUIRE'd #! /bin/sh line +define(AC_DIVERSION_NOTICE, 1)dnl copyright notice & option help strings +define(AC_DIVERSION_INIT, 2)dnl initialization code +define(AC_DIVERSION_NORMAL_4, 3)dnl AC_REQUIRE'd code, 4 level deep +define(AC_DIVERSION_NORMAL_3, 4)dnl AC_REQUIRE'd code, 3 level deep +define(AC_DIVERSION_NORMAL_2, 5)dnl AC_REQUIRE'd code, 2 level deep +define(AC_DIVERSION_NORMAL_1, 6)dnl AC_REQUIRE'd code, 1 level deep +define(AC_DIVERSION_NORMAL, 7)dnl the tests and output code +define(AC_DIVERSION_SED, 8)dnl variable substitutions in config.status +define(AC_DIVERSION_CMDS, 9)dnl extra shell commands in config.status +define(AC_DIVERSION_ICMDS, 10)dnl extra initialization in config.status + +dnl Change the diversion stream to STREAM, while stacking old values. +dnl AC_DIVERT_PUSH(STREAM) +define(AC_DIVERT_PUSH, +[pushdef([AC_DIVERSION_CURRENT], $1)dnl +divert(AC_DIVERSION_CURRENT)dnl +]) + +dnl Change the diversion stream to its previous value, unstacking it. +dnl AC_DIVERT_POP() +define(AC_DIVERT_POP, +[popdef([AC_DIVERSION_CURRENT])dnl +divert(AC_DIVERSION_CURRENT)dnl +]) + +dnl Initialize the diversion setup. +define([AC_DIVERSION_CURRENT], AC_DIVERSION_NORMAL) +dnl This will be popped by AC_REQUIRE in AC_INIT. +pushdef([AC_DIVERSION_CURRENT], AC_DIVERSION_NOTICE) + +dnl The prologue for Autoconf macros. +dnl AC_PRO(MACRO-NAME) +define(AC_PRO, +[define([AC_PROVIDE_$1], )dnl +ifelse(AC_DIVERSION_CURRENT, AC_DIVERSION_NORMAL, +[AC_DIVERT_PUSH(builtin(eval, AC_DIVERSION_CURRENT - 1))], +[pushdef([AC_DIVERSION_CURRENT], AC_DIVERSION_CURRENT)])dnl +]) + +dnl The Epilogue for Autoconf macros. +dnl AC_EPI() +define(AC_EPI, +[AC_DIVERT_POP()dnl +ifelse(AC_DIVERSION_CURRENT, AC_DIVERSION_NORMAL, +[undivert(AC_DIVERSION_NORMAL_4)dnl +undivert(AC_DIVERSION_NORMAL_3)dnl +undivert(AC_DIVERSION_NORMAL_2)dnl +undivert(AC_DIVERSION_NORMAL_1)dnl +])dnl +]) + +dnl Define a macro which automatically provides itself. Add machinery +dnl so the macro automatically switches expansion to the diversion +dnl stack if it is not already using it. In this case, once finished, +dnl it will bring back all the code accumulated in the diversion stack. +dnl This, combined with AC_REQUIRE, achieves the topological ordering of +dnl macros. We don't use this macro to define some frequently called +dnl macros that are not involved in ordering constraints, to save m4 +dnl processing. +dnl AC_DEFUN(NAME, EXPANSION) +define([AC_DEFUN], +[define($1, [AC_PRO([$1])$2[]AC_EPI()])]) + + +dnl ### Initialization + + +dnl AC_INIT_NOTICE() +AC_DEFUN(AC_INIT_NOTICE, +[# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version] AC_ACVERSION [ +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +[#] Any additions from configure.in:]) + +dnl AC_PREFIX_DEFAULT(PREFIX) +AC_DEFUN(AC_PREFIX_DEFAULT, +[AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)dnl +ac_default_prefix=$1 +AC_DIVERT_POP()]) + +dnl AC_INIT_PARSE_ARGS() +AC_DEFUN(AC_INIT_PARSE_ARGS, +[ +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +dnl Installation directory options. +dnl These are left unexpanded so users can "make install exec_prefix=/foo" +dnl and all the variables that are supposed to be based on exec_prefix +dnl by default will actually change. +dnl Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in +changequote(, )dnl + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; +changequote([, ])dnl + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. +changequote(, )dnl + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then +changequote([, ])dnl + AC_MSG_ERROR($ac_feature: invalid feature name) + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. +changequote(, )dnl + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then +changequote([, ])dnl + AC_MSG_ERROR($ac_feature: invalid feature name) + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +changequote(, )dnl +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +changequote([, ])dnl +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version AC_ACVERSION" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. +changequote(, )dnl + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then +changequote([, ])dnl + AC_MSG_ERROR($ac_package: invalid package name) + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. +changequote(, )dnl + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then +changequote([, ])dnl + AC_MSG_ERROR($ac_package: invalid package name) + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) AC_MSG_ERROR([$ac_option: invalid option; use --help to show usage]) + ;; + + *) +changequote(, )dnl + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then +changequote([, ])dnl + AC_MSG_WARN($ac_option: invalid host type) + fi + if test "x$nonopt" != xNONE; then + AC_MSG_ERROR(can only configure for one host and one target at a time) + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + AC_MSG_ERROR(missing argument to --`echo $ac_prev | sed 's/_/-/g'`) +fi +]) + +dnl Try to have only one #! line, so the script doesn't look funny +dnl for users of AC_REVISION. +dnl AC_INIT_BINSH() +AC_DEFUN(AC_INIT_BINSH, +[#! /bin/sh +]) + +dnl AC_INIT(UNIQUE-FILE-IN-SOURCE-DIR) +AC_DEFUN(AC_INIT, +[sinclude(acsite.m4)dnl +sinclude(./aclocal.m4)dnl +AC_REQUIRE([AC_INIT_BINSH])dnl +AC_INIT_NOTICE +AC_DIVERT_POP()dnl to NORMAL +AC_DIVERT_PUSH(AC_DIVERSION_INIT)dnl +AC_INIT_PARSE_ARGS +AC_INIT_PREPARE($1)dnl +AC_DIVERT_POP()dnl to NORMAL +]) + +dnl AC_INIT_PREPARE(UNIQUE-FILE-IN-SOURCE-DIR) +AC_DEFUN(AC_INIT_PREPARE, +[trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +define(AC_FD_MSG, 6)dnl +[#] AC_FD_MSG checking for... messages and results +define(AC_FD_CC, 5)dnl +[#] AC_FD_CC compiler messages saved in config.log +if test "$silent" = yes; then + exec AC_FD_MSG>/dev/null +else + exec AC_FD_MSG>&1 +fi +exec AC_FD_CC>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&AC_FD_CC + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; +changequote(<<, >>)dnl +dnl If you change this globbing pattern, test it on an old shell -- +dnl it's sensitive. Putting any kind of quote in it causes syntax errors. + *" "*|*" "*|*[\[\]\~\<<#>>\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; +changequote([, ])dnl + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=$1 + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=[$]0 +changequote(, )dnl + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` +changequote([, ])dnl + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + AC_MSG_ERROR(can not find sources in $ac_confdir or ..) + else + AC_MSG_ERROR(can not find sources in $srcdir) + fi +fi +dnl Double slashes in pathnames in object file debugging info +dnl mess up M-x gdb in Emacs. +changequote(, )dnl +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` +changequote([, ])dnl + +dnl Let the site file select an alternate cache file if it wants to. +AC_SITE_LOAD +AC_CACHE_LOAD +AC_LANG_C +dnl By default always use an empty string as the executable +dnl extension. Only change it if the script calls AC_EXEEXT. +ac_exeext= +dnl By default assume that objects files use an extension of .o. Only +dnl change it if the script calls AC_OBJEXT. +ac_objext=o +AC_PROG_ECHO_N +dnl Substitute for predefined variables. +AC_SUBST(SHELL)dnl +AC_SUBST(CFLAGS)dnl +AC_SUBST(CPPFLAGS)dnl +AC_SUBST(CXXFLAGS)dnl +AC_SUBST(FFLAGS)dnl +AC_SUBST(DEFS)dnl +AC_SUBST(LDFLAGS)dnl +AC_SUBST(LIBS)dnl +AC_SUBST(exec_prefix)dnl +AC_SUBST(prefix)dnl +AC_SUBST(program_transform_name)dnl +dnl Installation directory options. +AC_SUBST(bindir)dnl +AC_SUBST(sbindir)dnl +AC_SUBST(libexecdir)dnl +AC_SUBST(datadir)dnl +AC_SUBST(sysconfdir)dnl +AC_SUBST(sharedstatedir)dnl +AC_SUBST(localstatedir)dnl +AC_SUBST(libdir)dnl +AC_SUBST(includedir)dnl +AC_SUBST(oldincludedir)dnl +AC_SUBST(infodir)dnl +AC_SUBST(mandir)dnl +]) + + +dnl ### Selecting optional features + + +dnl AC_ARG_ENABLE(FEATURE, HELP-STRING, ACTION-IF-TRUE [, ACTION-IF-FALSE]) +AC_DEFUN(AC_ARG_ENABLE, +[AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)dnl +ac_help="$ac_help +[$2]" +AC_DIVERT_POP()dnl +[#] Check whether --enable-[$1] or --disable-[$1] was given. +if test "[${enable_]patsubst([$1], -, _)+set}" = set; then + enableval="[$enable_]patsubst([$1], -, _)" + ifelse([$3], , :, [$3]) +ifelse([$4], , , [else + $4 +])dnl +fi +]) + +AC_DEFUN(AC_ENABLE, +[AC_OBSOLETE([$0], [; instead use AC_ARG_ENABLE])dnl +AC_ARG_ENABLE([$1], [ --enable-$1], [$2], [$3])dnl +]) + + +dnl ### Working with optional software + + +dnl AC_ARG_WITH(PACKAGE, HELP-STRING, ACTION-IF-TRUE [, ACTION-IF-FALSE]) +AC_DEFUN(AC_ARG_WITH, +[AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)dnl +ac_help="$ac_help +[$2]" +AC_DIVERT_POP()dnl +[#] Check whether --with-[$1] or --without-[$1] was given. +if test "[${with_]patsubst([$1], -, _)+set}" = set; then + withval="[$with_]patsubst([$1], -, _)" + ifelse([$3], , :, [$3]) +ifelse([$4], , , [else + $4 +])dnl +fi +]) + +AC_DEFUN(AC_WITH, +[AC_OBSOLETE([$0], [; instead use AC_ARG_WITH])dnl +AC_ARG_WITH([$1], [ --with-$1], [$2], [$3])dnl +]) + + +dnl ### Transforming program names. + + +dnl AC_ARG_PROGRAM() +AC_DEFUN(AC_ARG_PROGRAM, +[if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," +]) + + +dnl ### Version numbers + + +dnl AC_REVISION(REVISION-INFO) +AC_DEFUN(AC_REVISION, +[AC_REQUIRE([AC_INIT_BINSH])dnl +[# From configure.in] translit([$1], $")]) + +dnl Subroutines of AC_PREREQ. + +dnl Change the dots in NUMBER into commas. +dnl AC_PREREQ_SPLIT(NUMBER) +define(AC_PREREQ_SPLIT, +[translit($1, ., [, ])]) + +dnl Default the ternary version number to 0 (e.g., 1, 7 -> 1, 7, 0). +dnl AC_PREREQ_CANON(MAJOR, MINOR [,TERNARY]) +define(AC_PREREQ_CANON, +[$1, $2, ifelse([$3], , 0, [$3])]) + +dnl Complain and exit if version number 1 is less than version number 2. +dnl PRINTABLE2 is the printable version of version number 2. +dnl AC_PREREQ_COMPARE(MAJOR1, MINOR1, TERNARY1, MAJOR2, MINOR2, TERNARY2, +dnl PRINTABLE2) +define(AC_PREREQ_COMPARE, +[ifelse(builtin([eval], +[$3 + $2 * 1000 + $1 * 1000000 < $6 + $5 * 1000 + $4 * 1000000]), 1, +[errprint(dnl +FATAL ERROR: Autoconf version $7 or higher is required for this script +)m4exit(3)])]) + +dnl Complain and exit if the Autoconf version is less than VERSION. +dnl AC_PREREQ(VERSION) +define(AC_PREREQ, +[AC_PREREQ_COMPARE(AC_PREREQ_CANON(AC_PREREQ_SPLIT(AC_ACVERSION)), +AC_PREREQ_CANON(AC_PREREQ_SPLIT([$1])), [$1])]) + + +dnl ### Getting the canonical system type + + +dnl Find install-sh, config.sub, config.guess, and Cygnus configure +dnl in directory DIR. These are auxiliary files used in configuration. +dnl DIR can be either absolute or relative to $srcdir. +dnl AC_CONFIG_AUX_DIR(DIR) +AC_DEFUN(AC_CONFIG_AUX_DIR, +[AC_CONFIG_AUX_DIRS($1 $srcdir/$1)]) + +dnl The default is `$srcdir' or `$srcdir/..' or `$srcdir/../..'. +dnl There's no need to call this macro explicitly; just AC_REQUIRE it. +AC_DEFUN(AC_CONFIG_AUX_DIR_DEFAULT, +[AC_CONFIG_AUX_DIRS($srcdir $srcdir/.. $srcdir/../..)]) + +dnl Internal subroutine. +dnl Search for the configuration auxiliary files in directory list $1. +dnl We look only for install-sh, so users of AC_PROG_INSTALL +dnl do not automatically need to distribute the other auxiliary files. +dnl AC_CONFIG_AUX_DIRS(DIR ...) +AC_DEFUN(AC_CONFIG_AUX_DIRS, +[ac_aux_dir= +for ac_dir in $1; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + AC_MSG_ERROR([can not find install-sh or install.sh in $1]) +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. +AC_PROVIDE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +]) + +dnl Canonicalize the host, target, and build system types. +AC_DEFUN(AC_CANONICAL_SYSTEM, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [AC_ARG_PROGRAM]) +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) AC_MSG_ERROR(can only configure for one host and one target at a time) ;; +esac + +AC_CANONICAL_HOST +AC_CANONICAL_TARGET +AC_CANONICAL_BUILD +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- +]) + +dnl Subroutines of AC_CANONICAL_SYSTEM. + +AC_DEFUN(AC_CANONICAL_HOST, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else AC_MSG_ERROR(can not run $ac_config_sub) +fi + +AC_MSG_CHECKING(host system type) + +dnl Set host_alias. +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else AC_MSG_ERROR(can not guess host type; you must specify one) + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +dnl Set the other host vars. +changequote(<<, >>)dnl +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +changequote([, ])dnl +AC_MSG_RESULT($host) +AC_SUBST(host)dnl +AC_SUBST(host_alias)dnl +AC_SUBST(host_cpu)dnl +AC_SUBST(host_vendor)dnl +AC_SUBST(host_os)dnl +]) + +dnl Internal use only. +AC_DEFUN(AC_CANONICAL_TARGET, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_MSG_CHECKING(target system type) + +dnl Set target_alias. +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +dnl Set the other target vars. +changequote(<<, >>)dnl +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +changequote([, ])dnl +AC_MSG_RESULT($target) +AC_SUBST(target)dnl +AC_SUBST(target_alias)dnl +AC_SUBST(target_cpu)dnl +AC_SUBST(target_vendor)dnl +AC_SUBST(target_os)dnl +]) + +dnl Internal use only. +AC_DEFUN(AC_CANONICAL_BUILD, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_MSG_CHECKING(build system type) + +dnl Set build_alias. +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +dnl Set the other build vars. +changequote(<<, >>)dnl +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +changequote([, ])dnl +AC_MSG_RESULT($build) +AC_SUBST(build)dnl +AC_SUBST(build_alias)dnl +AC_SUBST(build_cpu)dnl +AC_SUBST(build_vendor)dnl +AC_SUBST(build_os)dnl +]) + + +dnl AC_VALIDATE_CACHED_SYSTEM_TUPLE[(cmd)] +dnl if the cache file is inconsistent with the current host, +dnl target and build system types, execute CMD or print a default +dnl error message. +AC_DEFUN(AC_VALIDATE_CACHED_SYSTEM_TUPLE, [ + AC_REQUIRE([AC_CANONICAL_SYSTEM]) + AC_MSG_CHECKING([cached system tuple]) + if { test x"${ac_cv_host_system_type+set}" = x"set" && + test x"$ac_cv_host_system_type" != x"$host"; } || + { test x"${ac_cv_build_system_type+set}" = x"set" && + test x"$ac_cv_build_system_type" != x"$build"; } || + { test x"${ac_cv_target_system_type+set}" = x"set" && + test x"$ac_cv_target_system_type" != x"$target"; }; then + AC_MSG_RESULT([different]) + ifelse($#, 1, [$1], + [AC_MSG_ERROR([remove config.cache and re-run configure])]) + else + AC_MSG_RESULT(ok) + fi + ac_cv_host_system_type="$host" + ac_cv_build_system_type="$build" + ac_cv_target_system_type="$target" +]) + + +dnl ### Caching test results + + +dnl Look for site or system specific initialization scripts. +dnl AC_SITE_LOAD() +define(AC_SITE_LOAD, +[# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done +]) + +dnl AC_CACHE_LOAD() +define(AC_CACHE_LOAD, +[if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi +]) + +dnl AC_CACHE_SAVE() +define(AC_CACHE_SAVE, +[cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +dnl Allow a site initialization script to override cache values. +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +changequote(, )dnl +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +changequote([, ])dnl +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache +]) + +dnl The name of shell var CACHE-ID must contain `_cv_' in order to get saved. +dnl AC_CACHE_VAL(CACHE-ID, COMMANDS-TO-SET-IT) +define(AC_CACHE_VAL, +[dnl We used to use the below line, but it fails if the 1st arg is a +dnl shell variable, so we need the eval. +dnl if test "${$1+set}" = set; then +dnl the '' avoids an AIX 4.1 sh bug ("invalid expansion"). +if eval "test \"`echo '$''{'$1'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&AC_FD_MSG +else + $2 +fi +]) + +dnl AC_CACHE_CHECK(MESSAGE, CACHE-ID, COMMANDS) +define(AC_CACHE_CHECK, +[AC_MSG_CHECKING([$1]) +AC_CACHE_VAL([$2], [$3]) +AC_MSG_RESULT([$]$2)]) + + +dnl ### Defining symbols + + +dnl Set VARIABLE to VALUE, verbatim, or 1. +dnl AC_DEFINE(VARIABLE [, VALUE]) +define(AC_DEFINE, +[cat >> confdefs.h <<\EOF +[#define] $1 ifelse($#, 2, [$2], $#, 3, [$2], 1) +EOF +]) + +dnl Similar, but perform shell substitutions $ ` \ once on VALUE. +define(AC_DEFINE_UNQUOTED, +[cat >> confdefs.h <&AC_FD_MSG +echo "configure:__oline__: checking $1" >&AC_FD_CC]) + +dnl AC_CHECKING(FEATURE-DESCRIPTION) +define(AC_CHECKING, +[echo "checking $1" 1>&AC_FD_MSG +echo "configure:__oline__: checking $1" >&AC_FD_CC]) + +dnl AC_MSG_RESULT(RESULT-DESCRIPTION) +define(AC_MSG_RESULT, +[echo "$ac_t""$1" 1>&AC_FD_MSG]) + +dnl AC_VERBOSE(RESULT-DESCRIPTION) +define(AC_VERBOSE, +[AC_OBSOLETE([$0], [; instead use AC_MSG_RESULT])dnl +echo " $1" 1>&AC_FD_MSG]) + +dnl AC_MSG_WARN(PROBLEM-DESCRIPTION) +define(AC_MSG_WARN, +[echo "configure: warning: $1" 1>&2]) + +dnl AC_MSG_ERROR(ERROR-DESCRIPTION) +define(AC_MSG_ERROR, +[{ echo "configure: error: $1" 1>&2; exit 1; }]) + + +dnl ### Selecting which language to use for testing + + +dnl AC_LANG_C() +AC_DEFUN(AC_LANG_C, +[define([AC_LANG], [C])dnl +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&AC_FD_CC' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC' +cross_compiling=$ac_cv_prog_cc_cross +]) + +dnl AC_LANG_CPLUSPLUS() +AC_DEFUN(AC_LANG_CPLUSPLUS, +[define([AC_LANG], [CPLUSPLUS])dnl +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&AC_FD_CC' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC' +cross_compiling=$ac_cv_prog_cxx_cross +]) + +dnl AC_LANG_FORTRAN77() +AC_DEFUN(AC_LANG_FORTRAN77, +[define([AC_LANG], [FORTRAN77])dnl +ac_ext=f +ac_compile='${F77-f77} -c $FFLAGS conftest.$ac_ext 1>&AC_FD_CC' +ac_link='${F77-f77} -o conftest${ac_exeext} $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC' +cross_compiling=$ac_cv_prog_f77_cross +]) + +dnl Push the current language on a stack. +dnl AC_LANG_SAVE() +define(AC_LANG_SAVE, +[pushdef([AC_LANG_STACK], AC_LANG)]) + +dnl Restore the current language from the stack. +dnl AC_LANG_RESTORE() +pushdef([AC_LANG_RESTORE], +[ifelse(AC_LANG_STACK, [C], [AC_LANG_C],dnl +AC_LANG_STACK, [CPLUSPLUS], [AC_LANG_CPLUSPLUS],dnl +AC_LANG_STACK, [FORTRAN77], [AC_LANG_FORTRAN77])[]popdef([AC_LANG_STACK])]) + + +dnl ### Compiler-running mechanics + + +dnl The purpose of this macro is to "configure:123: command line" +dnl written into config.log for every test run. +dnl AC_TRY_EVAL(VARIABLE) +AC_DEFUN(AC_TRY_EVAL, +[{ (eval echo configure:__oline__: \"[$]$1\") 1>&AC_FD_CC; dnl +(eval [$]$1) 2>&AC_FD_CC; }]) + +dnl AC_TRY_COMMAND(COMMAND) +AC_DEFUN(AC_TRY_COMMAND, +[{ ac_try='$1'; AC_TRY_EVAL(ac_try); }]) + + +dnl ### Dependencies between macros + + +dnl AC_BEFORE(THIS-MACRO-NAME, CALLED-MACRO-NAME) +define(AC_BEFORE, +[ifdef([AC_PROVIDE_$2], [errprint(__file__:__line__: [$2 was called before $1 +])])]) + +dnl AC_REQUIRE(MACRO-NAME) +define(AC_REQUIRE, +[ifdef([AC_PROVIDE_$1], , +[AC_DIVERT_PUSH(builtin(eval, AC_DIVERSION_CURRENT - 1))dnl +indir([$1]) +AC_DIVERT_POP()dnl +])]) + +dnl AC_PROVIDE(MACRO-NAME) +define(AC_PROVIDE, +[define([AC_PROVIDE_$1], )]) + +dnl AC_OBSOLETE(THIS-MACRO-NAME [, SUGGESTION]) +define(AC_OBSOLETE, +[errprint(__file__:__line__: warning: [$1] is obsolete[$2] +)]) + + +dnl ### Checking for programs + + +dnl AC_CHECK_PROG(VARIABLE, PROG-TO-CHECK-FOR, VALUE-IF-FOUND +dnl [, [VALUE-IF-NOT-FOUND] [, [PATH] [, [REJECT]]]]) +AC_DEFUN(AC_CHECK_PROG, +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_prog_$1, +[if test -n "[$]$1"; then + ac_cv_prog_$1="[$]$1" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" +ifelse([$6], , , [ ac_prog_rejected=no +])dnl +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$5], , $PATH, [$5])" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then +ifelse([$6], , , dnl +[ if test "[$ac_dir/$ac_word]" = "$6"; then + ac_prog_rejected=yes + continue + fi +])dnl + ac_cv_prog_$1="$3" + break + fi + done + IFS="$ac_save_ifs" +ifelse([$6], , , [if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy [$]ac_cv_prog_$1 + shift + if test [$]# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set $1 to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "[$]@" + shift + ac_cv_prog_$1="[$]@" +ifelse([$2], [$4], dnl +[ else + # Default is a loser. + AC_MSG_ERROR([$1=$6 unacceptable, but no other $4 found in dnl +ifelse([$5], , [\$]PATH, [$5])]) +])dnl + fi +fi +])dnl +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_CHECK_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_prog_$1" && ac_cv_prog_$1="$4" +])dnl +fi])dnl +$1="$ac_cv_prog_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + +dnl AC_PATH_PROG(VARIABLE, PROG-TO-CHECK-FOR [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN(AC_PATH_PROG, +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$4], , $PATH, [$4])" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" +dnl If no 3rd arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$3], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$3" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + +dnl AC_CHECK_PROGS(VARIABLE, PROGS-TO-CHECK-FOR [, VALUE-IF-NOT-FOUND +dnl [, PATH]]) +AC_DEFUN(AC_CHECK_PROGS, +[for ac_prog in $2 +do +AC_CHECK_PROG($1, [$]ac_prog, [$]ac_prog, , $4) +test -n "[$]$1" && break +done +ifelse([$3], , , [test -n "[$]$1" || $1="$3" +])]) + +dnl AC_PATH_PROGS(VARIABLE, PROGS-TO-CHECK-FOR [, VALUE-IF-NOT-FOUND +dnl [, PATH]]) +AC_DEFUN(AC_PATH_PROGS, +[for ac_prog in $2 +do +AC_PATH_PROG($1, [$]ac_prog, , $4) +test -n "[$]$1" && break +done +ifelse([$3], , , [test -n "[$]$1" || $1="$3" +])]) + +dnl Internal subroutine. +AC_DEFUN(AC_CHECK_TOOL_PREFIX, +[AC_REQUIRE([AC_CANONICAL_HOST])AC_REQUIRE([AC_CANONICAL_BUILD])dnl +if test $host != $build; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi +]) + +dnl AC_CHECK_TOOL(VARIABLE, PROG-TO-CHECK-FOR[, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN(AC_CHECK_TOOL, +[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])dnl +AC_CHECK_PROG($1, ${ac_tool_prefix}$2, ${ac_tool_prefix}$2, + ifelse([$3], , [$2], ), $4) +ifelse([$3], , , [ +if test -z "$ac_cv_prog_$1"; then +if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG($1, $2, $2, $3) +else + $1="$3" +fi +fi]) +]) + +dnl Guess the value for the `prefix' variable by looking for +dnl the argument program along PATH and taking its parent. +dnl Example: if the argument is `gcc' and we find /usr/local/gnu/bin/gcc, +dnl set `prefix' to /usr/local/gnu. +dnl This comes too late to find a site file based on the prefix, +dnl and it might use a cached value for the path. +dnl No big loss, I think, since most configures don't use this macro anyway. +dnl AC_PREFIX_PROGRAM(PROGRAM) +AC_DEFUN(AC_PREFIX_PROGRAM, +[if test "x$prefix" = xNONE; then +changequote(<<, >>)dnl +define(<>, translit($1, [a-z], [A-Z]))dnl +changequote([, ])dnl +dnl We reimplement AC_MSG_CHECKING (mostly) to avoid the ... in the middle. +echo $ac_n "checking for prefix by $ac_c" 1>&AC_FD_MSG +AC_PATH_PROG(AC_VAR_NAME, $1) +changequote(<<, >>)dnl + if test -n "$ac_cv_path_<<>>AC_VAR_NAME"; then + prefix=`echo $ac_cv_path_<<>>AC_VAR_NAME|sed 's%/[^/][^/]*//*[^/][^/]*$%%'` +changequote([, ])dnl + fi +fi +undefine([AC_VAR_NAME])dnl +]) + +dnl Try to compile, link and execute TEST-PROGRAM. Set WORKING-VAR to +dnl `yes' if the current compiler works, otherwise set it ti `no'. Set +dnl CROSS-VAR to `yes' if the compiler and linker produce non-native +dnl executables, otherwise set it to `no'. Before calling +dnl `AC_TRY_COMPILER()', call `AC_LANG_*' to set-up for the right +dnl language. +dnl +dnl AC_TRY_COMPILER(TEST-PROGRAM, WORKING-VAR, CROSS-VAR) +AC_DEFUN(AC_TRY_COMPILER, +[cat > conftest.$ac_ext << EOF +ifelse(AC_LANG, [FORTRAN77], , +[ +[#]line __oline__ "configure" +#include "confdefs.h" +]) +[$1] +EOF +if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + [$2]=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + [$3]=no + else + [$3]=yes + fi +else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC + [$2]=no +fi +rm -fr conftest*]) + + +dnl ### Checking for libraries + + +dnl AC_TRY_LINK_FUNC(func, action-if-found, action-if-not-found) +dnl Try to link a program that calls FUNC, handling GCC builtins. If +dnl the link succeeds, execute ACTION-IF-FOUND; otherwise, execute +dnl ACTION-IF-NOT-FOUND. + +AC_DEFUN(AC_TRY_LINK_FUNC, +AC_TRY_LINK(dnl +ifelse([$1], [main], , dnl Avoid conflicting decl of main. +[/* Override any gcc2 internal prototype to avoid an error. */ +]ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus +extern "C" +#endif +])dnl +[/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $1(); +]), +[$1()], +[$2], +[$3])) + + +dnl AC_SEARCH_LIBS(FUNCTION, SEARCH-LIBS [, ACTION-IF-FOUND +dnl [, ACTION-IF-NOT-FOUND [, OTHER-LIBRARIES]]]) +dnl Search for a library defining FUNC, if it's not already available. + +AC_DEFUN(AC_SEARCH_LIBS, +[AC_PREREQ([2.13]) +AC_CACHE_CHECK([for library containing $1], [ac_cv_search_$1], +[ac_func_search_save_LIBS="$LIBS" +ac_cv_search_$1="no" +AC_TRY_LINK_FUNC([$1], [ac_cv_search_$1="none required"]) +test "$ac_cv_search_$1" = "no" && for i in $2; do +LIBS="-l$i $5 $ac_func_search_save_LIBS" +AC_TRY_LINK_FUNC([$1], +[ac_cv_search_$1="-l$i" +break]) +done +LIBS="$ac_func_search_save_LIBS"]) +if test "$ac_cv_search_$1" != "no"; then + test "$ac_cv_search_$1" = "none required" || LIBS="$ac_cv_search_$1 $LIBS" + $3 +else : + $4 +fi]) + + + +dnl AC_CHECK_LIB(LIBRARY, FUNCTION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND +dnl [, OTHER-LIBRARIES]]]) +AC_DEFUN(AC_CHECK_LIB, +[AC_MSG_CHECKING([for $2 in -l$1]) +dnl Use a cache variable name containing both the library and function name, +dnl because the test really is for library $1 defining function $2, not +dnl just for library $1. Separate tests with the same $1 and different $2s +dnl may have different results. +ac_lib_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'` +AC_CACHE_VAL(ac_cv_lib_$ac_lib_var, +[ac_save_LIBS="$LIBS" +LIBS="-l$1 $5 $LIBS" +AC_TRY_LINK(dnl +ifelse(AC_LANG, [FORTRAN77], , +ifelse([$2], [main], , dnl Avoid conflicting decl of main. +[/* Override any gcc2 internal prototype to avoid an error. */ +]ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus +extern "C" +#endif +])dnl +[/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $2(); +])), + [$2()], + eval "ac_cv_lib_$ac_lib_var=yes", + eval "ac_cv_lib_$ac_lib_var=no") +LIBS="$ac_save_LIBS" +])dnl +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$3], , +[changequote(, )dnl + ac_tr_lib=HAVE_LIB`echo $1 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` +changequote([, ])dnl + AC_DEFINE_UNQUOTED($ac_tr_lib) + LIBS="-l$1 $LIBS" +], [$3]) +else + AC_MSG_RESULT(no) +ifelse([$4], , , [$4 +])dnl +fi +]) + +dnl AC_HAVE_LIBRARY(LIBRARY, [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND +dnl [, OTHER-LIBRARIES]]]) +AC_DEFUN(AC_HAVE_LIBRARY, +[AC_OBSOLETE([$0], [; instead use AC_CHECK_LIB])dnl +changequote(<<, >>)dnl +define(<>, dnl +patsubst(patsubst($1, <>, <<\1>>), <<-l>>, <<>>))dnl +define(<>, ac_cv_lib_<<>>AC_LIB_NAME)dnl +changequote([, ])dnl +AC_MSG_CHECKING([for -l[]AC_LIB_NAME]) +AC_CACHE_VAL(AC_CV_NAME, +[ac_save_LIBS="$LIBS" +LIBS="-l[]AC_LIB_NAME[] $4 $LIBS" +AC_TRY_LINK( , [main()], AC_CV_NAME=yes, AC_CV_NAME=no) +LIBS="$ac_save_LIBS" +])dnl +AC_MSG_RESULT($AC_CV_NAME) +if test "$AC_CV_NAME" = yes; then + ifelse([$2], , +[AC_DEFINE([HAVE_LIB]translit(AC_LIB_NAME, [a-z], [A-Z])) + LIBS="-l[]AC_LIB_NAME[] $LIBS" +], [$2]) +ifelse([$3], , , [else + $3 +])dnl +fi +undefine([AC_LIB_NAME])dnl +undefine([AC_CV_NAME])dnl +]) + + +dnl ### Examining declarations + + +dnl AC_TRY_CPP(INCLUDES, [ACTION-IF-TRUE [, ACTION-IF-FALSE]]) +AC_DEFUN(AC_TRY_CPP, +[AC_REQUIRE_CPP()dnl +cat > conftest.$ac_ext <&AC_FD_CC + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +ifelse([$3], , , [ rm -rf conftest* + $3 +])dnl +fi +rm -f conftest*]) + +dnl AC_EGREP_HEADER(PATTERN, HEADER-FILE, ACTION-IF-FOUND [, +dnl ACTION-IF-NOT-FOUND]) +AC_DEFUN(AC_EGREP_HEADER, +[AC_EGREP_CPP([$1], [#include <$2>], [$3], [$4])]) + +dnl Because this macro is used by AC_PROG_GCC_TRADITIONAL, which must +dnl come early, it is not included in AC_BEFORE checks. +dnl AC_EGREP_CPP(PATTERN, PROGRAM, [ACTION-IF-FOUND [, +dnl ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_EGREP_CPP, +[AC_REQUIRE_CPP()dnl +cat > conftest.$ac_ext <&AC_FD_CC | +dnl Prevent m4 from eating character classes: +changequote(, )dnl + grep -E "$1" >/dev/null 2>&1; then +changequote([, ])dnl + ifelse([$3], , :, [rm -rf conftest* + $3]) +ifelse([$4], , , [else + rm -rf conftest* + $4 +])dnl +fi +rm -f conftest* +]) + + +dnl ### Examining syntax + + +dnl AC_TRY_COMPILE(INCLUDES, FUNCTION-BODY, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_TRY_COMPILE, +[cat > conftest.$ac_ext <&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +ifelse([$4], , , [ rm -rf conftest* + $4 +])dnl +fi +rm -f conftest*]) + + +dnl ### Examining libraries + + +dnl AC_COMPILE_CHECK(ECHO-TEXT, INCLUDES, FUNCTION-BODY, +dnl ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +AC_DEFUN(AC_COMPILE_CHECK, +[AC_OBSOLETE([$0], [; instead use AC_TRY_COMPILE or AC_TRY_LINK, and AC_MSG_CHECKING and AC_MSG_RESULT])dnl +ifelse([$1], , , [AC_CHECKING([for $1]) +])dnl +AC_TRY_LINK([$2], [$3], [$4], [$5]) +]) + +dnl AC_TRY_LINK(INCLUDES, FUNCTION-BODY, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_TRY_LINK, +[cat > conftest.$ac_ext <&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +ifelse([$4], , , [ rm -rf conftest* + $4 +])dnl +fi +rm -f conftest*]) + + +dnl ### Checking for run-time features + + +dnl AC_TRY_RUN(PROGRAM, [ACTION-IF-TRUE [, ACTION-IF-FALSE +dnl [, ACTION-IF-CROSS-COMPILING]]]) +AC_DEFUN(AC_TRY_RUN, +[if test "$cross_compiling" = yes; then + ifelse([$4], , + [errprint(__file__:__line__: warning: [AC_TRY_RUN] called without default to allow cross compiling +)dnl + AC_MSG_ERROR(can not run test program while cross compiling)], + [$4]) +else + AC_TRY_RUN_NATIVE([$1], [$2], [$3]) +fi +]) + +dnl Like AC_TRY_RUN but assumes a native-environment (non-cross) compiler. +dnl AC_TRY_RUN_NATIVE(PROGRAM, [ACTION-IF-TRUE [, ACTION-IF-FALSE]]) +AC_DEFUN(AC_TRY_RUN_NATIVE, +[cat > conftest.$ac_ext </dev/null +then +dnl Don't remove the temporary files here, so they can be examined. + ifelse([$2], , :, [$2]) +else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +ifelse([$3], , , [ rm -fr conftest* + $3 +])dnl +fi +rm -fr conftest*]) + + +dnl ### Checking for header files + + +dnl AC_CHECK_HEADER(HEADER-FILE, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_CHECK_HEADER, +[dnl Do the transliteration at runtime so arg 1 can be a shell variable. +ac_safe=`echo "$1" | sed 'y%./+-%__p_%'` +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(ac_cv_header_$ac_safe, +[AC_TRY_CPP([#include <$1>], eval "ac_cv_header_$ac_safe=yes", + eval "ac_cv_header_$ac_safe=no")])dnl +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) +else + AC_MSG_RESULT(no) +ifelse([$3], , , [$3 +])dnl +fi +]) + +dnl AC_CHECK_HEADERS(HEADER-FILE... [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_CHECK_HEADERS, +[for ac_hdr in $1 +do +AC_CHECK_HEADER($ac_hdr, +[changequote(, )dnl + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` +changequote([, ])dnl + AC_DEFINE_UNQUOTED($ac_tr_hdr) $2], $3)dnl +done +]) + + +dnl ### Checking for the existence of files + +dnl AC_CHECK_FILE(FILE, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_CHECK_FILE, +[AC_REQUIRE([AC_PROG_CC]) +dnl Do the transliteration at runtime so arg 1 can be a shell variable. +ac_safe=`echo "$1" | sed 'y%./+-%__p_%'` +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(ac_cv_file_$ac_safe, +[if test "$cross_compiling" = yes; then + errprint(__file__:__line__: warning: Cannot check for file existence when cross compiling +)dnl + AC_MSG_ERROR(Cannot check for file existence when cross compiling) +else + if test -r $1; then + eval "ac_cv_file_$ac_safe=yes" + else + eval "ac_cv_file_$ac_safe=no" + fi +fi])dnl +if eval "test \"`echo '$ac_cv_file_'$ac_safe`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) +else + AC_MSG_RESULT(no) +ifelse([$3], , , [$3]) +fi +]) + +dnl AC_CHECK_FILES(FILE... [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_CHECK_FILES, +[for ac_file in $1 +do +AC_CHECK_FILE($ac_file, +[changequote(, )dnl + ac_tr_file=HAVE_`echo $ac_file | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` +changequote([, ])dnl + AC_DEFINE_UNQUOTED($ac_tr_file) $2], $3)dnl +done +]) + + +dnl ### Checking for library functions + + +dnl AC_CHECK_FUNC(FUNCTION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_CHECK_FUNC, +[AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(ac_cv_func_$1, +[AC_TRY_LINK( +dnl Don't include because on OSF/1 3.0 it includes +dnl which includes which contains a prototype for +dnl select. Similarly for bzero. +[/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $1(); below. */ +#include +/* Override any gcc2 internal prototype to avoid an error. */ +]ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus +extern "C" +#endif +])dnl +[/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $1(); +], [ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$1) || defined (__stub___$1) +choke me +#else +$1(); +#endif +], eval "ac_cv_func_$1=yes", eval "ac_cv_func_$1=no")]) +if eval "test \"`echo '$ac_cv_func_'$1`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) +else + AC_MSG_RESULT(no) +ifelse([$3], , , [$3 +])dnl +fi +]) + +dnl AC_CHECK_FUNCS(FUNCTION... [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AC_CHECK_FUNCS, +[for ac_func in $1 +do +AC_CHECK_FUNC($ac_func, +[changequote(, )dnl + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` +changequote([, ])dnl + AC_DEFINE_UNQUOTED($ac_tr_func) $2], $3)dnl +done +]) + +dnl AC_REPLACE_FUNCS(FUNCTION...) +AC_DEFUN(AC_REPLACE_FUNCS, +[AC_CHECK_FUNCS([$1], , [LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"]) +AC_SUBST(LIBOBJS)dnl +]) + + +dnl ### Checking compiler characteristics + + +dnl AC_CHECK_SIZEOF(TYPE [, CROSS-SIZE]) +AC_DEFUN(AC_CHECK_SIZEOF, +[changequote(<<, >>)dnl +dnl The name to #define. +define(<>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl +dnl The cache variable name. +define(<>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl +changequote([, ])dnl +AC_MSG_CHECKING(size of $1) +AC_CACHE_VAL(AC_CV_NAME, +[AC_TRY_RUN([#include +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof($1)); + exit(0); +}], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, ifelse([$2], , , AC_CV_NAME=$2))])dnl +AC_MSG_RESULT($AC_CV_NAME) +AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME) +undefine([AC_TYPE_NAME])dnl +undefine([AC_CV_NAME])dnl +]) + + +dnl ### Checking for typedefs + + +dnl AC_CHECK_TYPE(TYPE, DEFAULT) +AC_DEFUN(AC_CHECK_TYPE, +[AC_REQUIRE([AC_HEADER_STDC])dnl +AC_MSG_CHECKING(for $1) +AC_CACHE_VAL(ac_cv_type_$1, +[AC_EGREP_CPP(dnl +changequote(<<,>>)dnl +<<(^|[^a-zA-Z_0-9])$1[^a-zA-Z_0-9]>>dnl +changequote([,]), [#include +#if STDC_HEADERS +#include +#include +#endif], ac_cv_type_$1=yes, ac_cv_type_$1=no)])dnl +AC_MSG_RESULT($ac_cv_type_$1) +if test $ac_cv_type_$1 = no; then + AC_DEFINE($1, $2) +fi +]) + + +dnl ### Creating output files + + +dnl AC_CONFIG_HEADER(HEADER-TO-CREATE ...) +AC_DEFUN(AC_CONFIG_HEADER, +[define(AC_LIST_HEADER, $1)]) + +dnl Link each of the existing files SOURCE... to the corresponding +dnl link name in DEST... +dnl AC_LINK_FILES(SOURCE..., DEST...) +AC_DEFUN(AC_LINK_FILES, +[dnl +define([AC_LIST_FILES], ifdef([AC_LIST_FILES], [AC_LIST_FILES ],)[$1])dnl +define([AC_LIST_LINKS], ifdef([AC_LIST_LINKS], [AC_LIST_LINKS ],)[$2])]) + +dnl Add additional commands for AC_OUTPUT to put into config.status. +dnl Use diversions instead of macros so we can be robust in the +dnl presence of commas in $1 and/or $2. +dnl AC_OUTPUT_COMMANDS(EXTRA-CMDS, INIT-CMDS) +AC_DEFUN(AC_OUTPUT_COMMANDS, +[AC_DIVERT_PUSH(AC_DIVERSION_CMDS)dnl +[$1] +AC_DIVERT_POP()dnl +AC_DIVERT_PUSH(AC_DIVERSION_ICMDS)dnl +[$2] +AC_DIVERT_POP()]) + +dnl AC_CONFIG_SUBDIRS(DIR ...) +AC_DEFUN(AC_CONFIG_SUBDIRS, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +define([AC_LIST_SUBDIRS], ifdef([AC_LIST_SUBDIRS], [AC_LIST_SUBDIRS ],)[$1])dnl +subdirs="AC_LIST_SUBDIRS" +AC_SUBST(subdirs)dnl +]) + +dnl The big finish. +dnl Produce config.status, config.h, and links; and configure subdirs. +dnl AC_OUTPUT([FILE...] [, EXTRA-CMDS] [, INIT-CMDS]) +define(AC_OUTPUT, +[trap '' 1 2 15 +AC_CACHE_SAVE +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then +changequote(, )dnl + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +changequote([, ])dnl +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +ifdef([AC_LIST_HEADER], [DEFS=-DHAVE_CONFIG_H], [AC_OUTPUT_MAKE_DEFS()]) + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +[#] [$]0 [$]ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +changequote(, )dnl +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +changequote([, ])dnl +for ac_option +do + case "[\$]ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running [\$]{CONFIG_SHELL-/bin/sh} [$]0 [$]ac_configure_args --no-create --no-recursion" + exec [\$]{CONFIG_SHELL-/bin/sh} [$]0 [$]ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version AC_ACVERSION" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "[\$]ac_cs_usage"; exit 0 ;; + *) echo "[\$]ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ifdef([AC_PROVIDE_AC_PROG_INSTALL], [ac_given_INSTALL="$INSTALL" +])dnl + +changequote(<<, >>)dnl +ifdef(<>, +<>, +<>) +changequote([, ])dnl +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +undivert(AC_DIVERSION_CMDS)dnl +$2 +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 +dnl config.status should not do recursion. +ifdef([AC_LIST_SUBDIRS], [AC_OUTPUT_SUBDIRS(AC_LIST_SUBDIRS)])dnl +])dnl + +dnl Set the DEFS variable to the -D options determined earlier. +dnl This is a subroutine of AC_OUTPUT. +dnl It is called inside configure, outside of config.status. +dnl AC_OUTPUT_MAKE_DEFS() +define(AC_OUTPUT_MAKE_DEFS, +[# Transform confdefs.h into DEFS. +dnl Using a here document instead of a string reduces the quoting nightmare. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +cat > conftest.defs <<\EOF +changequote(<<, >>)dnl +s%<<#define>> \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g +s%[ `~<<#>>$^&*(){}\\|;'"<>?]%\\&%g +s%\[%\\&%g +s%\]%\\&%g +s%\$%$$%g +changequote([, ])dnl +EOF +DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` +rm -f conftest.defs +]) + +dnl Do the variable substitutions to create the Makefiles or whatever. +dnl This is a subroutine of AC_OUTPUT. It is called inside an unquoted +dnl here document whose contents are going into config.status, but +dnl upon returning, the here document is being quoted. +dnl AC_OUTPUT_FILES(FILE...) +define(AC_OUTPUT_FILES, +[# Protect against being on the right side of a sed subst in config.status. +changequote(, )dnl +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +changequote([, ])dnl +dnl These here document variables are unquoted when configure runs +dnl but quoted when config.status runs, so variables are expanded once. +$ac_vpsub +dnl Shell code in configure.in might set extrasub. +$extrasub +dnl Insert the sed substitutions of variables. +undivert(AC_DIVERSION_SED) +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then +changequote(, )dnl + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` +changequote([, ])dnl + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. +changequote(, )dnl + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` +changequote([, ])dnl + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + +ifdef([AC_PROVIDE_AC_PROG_INSTALL], +[ case "$ac_given_INSTALL" in +changequote(, )dnl + [/$]*) INSTALL="$ac_given_INSTALL" ;; +changequote([, ])dnl + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac +])dnl + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +ifdef([AC_PROVIDE_AC_PROG_INSTALL], [s%@INSTALL@%$INSTALL%g +])dnl +dnl The parens around the eval prevent an "illegal io" in Ultrix sh. +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +dnl This would break Makefile dependencies. +dnl if cmp -s $ac_file conftest.out 2>/dev/null; then +dnl echo "$ac_file is unchanged" +dnl rm -f conftest.out +dnl else +dnl rm -f $ac_file +dnl mv conftest.out $ac_file +dnl fi +fi; done +rm -f conftest.s* +]) + +dnl Create the config.h files from the config.h.in files. +dnl This is a subroutine of AC_OUTPUT. It is called inside a quoted +dnl here document whose contents are going into config.status. +dnl AC_OUTPUT_HEADER(HEADER-FILE...) +define(AC_OUTPUT_HEADER, +[changequote(<<, >>)dnl +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='<<$>>%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' +changequote([, ])dnl + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +dnl Support passing AC_CONFIG_HEADER a value containing shell variables. +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then +changequote(, )dnl + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac +changequote([, ])dnl + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +dnl Using a here document instead of a string reduces the quoting nightmare. +dnl Putting comments in sed scripts is not portable. +cat > conftest.hdr <<\EOF +changequote(<<, >>)dnl +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%<<#define>> \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +changequote([, ])dnl +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +changequote(, )dnl +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +changequote([, ])dnl +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +dnl Now back to your regularly scheduled config.status. +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + changequote(, )dnl + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + changequote([, ])dnl + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +]) + +dnl This is a subroutine of AC_OUTPUT. It is called inside a quoted +dnl here document whose contents are going into config.status. +dnl AC_OUTPUT_LINKS(SOURCE..., DEST...) +define(AC_OUTPUT_LINKS, +[EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +srcdir=$ac_given_srcdir +while test -n "$ac_sources"; do + set $ac_dests; ac_dest=[$]1; shift; ac_dests=[$]* + set $ac_sources; ac_source=[$]1; shift; ac_sources=[$]* + + echo "linking $srcdir/$ac_source to $ac_dest" + + if test ! -r $srcdir/$ac_source; then + AC_MSG_ERROR($srcdir/$ac_source: File not found) + fi + rm -f $ac_dest + + # Make relative symlinks. + # Remove last slash and all that follows it. Not all systems have dirname. +changequote(, )dnl + ac_dest_dir=`echo $ac_dest|sed 's%/[^/][^/]*$%%'` +changequote([, ])dnl + if test "$ac_dest_dir" != "$ac_dest" && test "$ac_dest_dir" != .; then + # The dest file is in a subdirectory. + test ! -d "$ac_dest_dir" && mkdir "$ac_dest_dir" + ac_dest_dir_suffix="/`echo $ac_dest_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dest_dir_suffix. +changequote(, )dnl + ac_dots=`echo $ac_dest_dir_suffix|sed 's%/[^/]*%../%g'` +changequote([, ])dnl + else + ac_dest_dir_suffix= ac_dots= + fi + + case "$srcdir" in +changequote(, )dnl + [/$]*) ac_rel_source="$srcdir/$ac_source" ;; +changequote([, ])dnl + *) ac_rel_source="$ac_dots$srcdir/$ac_source" ;; + esac + + # Make a symlink if possible; otherwise try a hard link. + if ln -s $ac_rel_source $ac_dest 2>/dev/null || + ln $srcdir/$ac_source $ac_dest; then : + else + AC_MSG_ERROR(can not link $ac_dest to $srcdir/$ac_source) + fi +done +]) + +dnl This is a subroutine of AC_OUTPUT. +dnl It is called after running config.status. +dnl AC_OUTPUT_SUBDIRS(DIRECTORY...) +define(AC_OUTPUT_SUBDIRS, +[ +if test "$no_recursion" != yes; then + + # Remove --cache-file and --srcdir arguments so they do not pile up. + ac_sub_configure_args= + ac_prev= + for ac_arg in $ac_configure_args; do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case "$ac_arg" in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + *) ac_sub_configure_args="$ac_sub_configure_args $ac_arg" ;; + esac + done + + for ac_config_dir in $1; do + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + if test ! -d $srcdir/$ac_config_dir; then + continue + fi + + echo configuring in $ac_config_dir + + case "$srcdir" in + .) ;; + *) + if test -d ./$ac_config_dir || mkdir ./$ac_config_dir; then :; + else + AC_MSG_ERROR(can not create `pwd`/$ac_config_dir) + fi + ;; + esac + + ac_popdir=`pwd` + cd $ac_config_dir + +changequote(, )dnl + # A "../" for each directory in /$ac_config_dir. + ac_dots=`echo $ac_config_dir|sed -e 's%^\./%%' -e 's%[^/]$%&/%' -e 's%[^/]*/%../%g'` +changequote([, ])dnl + + case "$srcdir" in + .) # No --srcdir option. We are building in place. + ac_sub_srcdir=$srcdir ;; + /*) # Absolute path. + ac_sub_srcdir=$srcdir/$ac_config_dir ;; + *) # Relative path. + ac_sub_srcdir=$ac_dots$srcdir/$ac_config_dir ;; + esac + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_sub_srcdir/configure; then + ac_sub_configure=$ac_sub_srcdir/configure + elif test -f $ac_sub_srcdir/configure.in; then + ac_sub_configure=$ac_configure + else + AC_MSG_WARN(no configuration information is in $ac_config_dir) + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + + # Make the cache file name correct relative to the subdirectory. + case "$cache_file" in + /*) ac_sub_cache_file=$cache_file ;; + *) # Relative path. + ac_sub_cache_file="$ac_dots$cache_file" ;; + esac +ifdef([AC_PROVIDE_AC_PROG_INSTALL], + [ case "$ac_given_INSTALL" in +changequote(, )dnl + [/$]*) INSTALL="$ac_given_INSTALL" ;; +changequote([, ])dnl + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac +])dnl + + echo "[running ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file] --srcdir=$ac_sub_srcdir" + # The eval makes quoting arguments work. + if eval ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir + then : + else + AC_MSG_ERROR($ac_sub_configure failed for $ac_config_dir) + fi + fi + + cd $ac_popdir + done +fi +]) diff --git a/build/autoconf/acoldnames.m4 b/build/autoconf/acoldnames.m4 new file mode 100644 index 0000000000..d31cdd754f --- /dev/null +++ b/build/autoconf/acoldnames.m4 @@ -0,0 +1,80 @@ +dnl Map old names of Autoconf macros to new regularized names. +dnl This file is part of Autoconf. +dnl Copyright (C) 1994 Free Software Foundation, Inc. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl General macros. +dnl +define(AC_WARN, [indir([AC_MSG_WARN], $@)])dnl +define(AC_ERROR, [indir([AC_MSG_ERROR], $@)])dnl +AC_DEFUN(AC_PROGRAM_CHECK, [indir([AC_CHECK_PROG], $@)])dnl +AC_DEFUN(AC_PROGRAM_PATH, [indir([AC_PATH_PROG], $@)])dnl +AC_DEFUN(AC_PROGRAMS_CHECK, [indir([AC_CHECK_PROGS], $@)])dnl +AC_DEFUN(AC_PROGRAMS_PATH, [indir([AC_PATH_PROGS], $@)])dnl +AC_DEFUN(AC_PREFIX, [indir([AC_PREFIX_PROGRAM], $@)])dnl +AC_DEFUN(AC_HEADER_EGREP, [indir([AC_EGREP_HEADER], $@)])dnl +AC_DEFUN(AC_PROGRAM_EGREP, [indir([AC_EGREP_CPP], $@)])dnl +AC_DEFUN(AC_TEST_PROGRAM, [indir([AC_TRY_RUN], $@)])dnl +AC_DEFUN(AC_TEST_CPP, [indir([AC_TRY_CPP], $@)])dnl +AC_DEFUN(AC_HEADER_CHECK, [indir([AC_CHECK_HEADER], $@)])dnl +AC_DEFUN(AC_FUNC_CHECK, [indir([AC_CHECK_FUNC], $@)])dnl +AC_DEFUN(AC_HAVE_FUNCS, [indir([AC_CHECK_FUNCS], $@)])dnl +AC_DEFUN(AC_HAVE_HEADERS, [indir([AC_CHECK_HEADERS], $@)])dnl +AC_DEFUN(AC_SIZEOF_TYPE, [indir([AC_CHECK_SIZEOF], $@)])dnl +dnl +dnl Specific macros. +dnl +AC_DEFUN(AC_GCC_TRADITIONAL, [indir([AC_PROG_GCC_TRADITIONAL])])dnl +AC_DEFUN(AC_MINUS_C_MINUS_O, [indir([AC_PROG_CC_C_O])])dnl +AC_DEFUN(AC_SET_MAKE, [indir([AC_PROG_MAKE_SET])])dnl +AC_DEFUN(AC_YYTEXT_POINTER, [indir([AC_DECL_YYTEXT])])dnl +AC_DEFUN(AC_LN_S, [indir([AC_PROG_LN_S])])dnl +AC_DEFUN(AC_STDC_HEADERS, [indir([AC_HEADER_STDC])])dnl +AC_DEFUN(AC_MAJOR_HEADER, [indir([AC_HEADER_MAJOR])])dnl +AC_DEFUN(AC_STAT_MACROS_BROKEN, [indir([AC_HEADER_STAT])])dnl +AC_DEFUN(AC_SYS_SIGLIST_DECLARED, [indir([AC_DECL_SYS_SIGLIST])])dnl +AC_DEFUN(AC_GETGROUPS_T, [indir([AC_TYPE_GETGROUPS])])dnl +AC_DEFUN(AC_UID_T, [indir([AC_TYPE_UID_T])])dnl +AC_DEFUN(AC_SIZE_T, [indir([AC_TYPE_SIZE_T])])dnl +AC_DEFUN(AC_PID_T, [indir([AC_TYPE_PID_T])])dnl +AC_DEFUN(AC_OFF_T, [indir([AC_TYPE_OFF_T])])dnl +AC_DEFUN(AC_MODE_T, [indir([AC_TYPE_MODE_T])])dnl +AC_DEFUN(AC_RETSIGTYPE, [indir([AC_TYPE_SIGNAL])])dnl +AC_DEFUN(AC_MMAP, [indir([AC_FUNC_MMAP])])dnl +AC_DEFUN(AC_VPRINTF, [indir([AC_FUNC_VPRINTF])])dnl +AC_DEFUN(AC_VFORK, [indir([AC_FUNC_VFORK])])dnl +AC_DEFUN(AC_WAIT3, [indir([AC_FUNC_WAIT3])])dnl +AC_DEFUN(AC_ALLOCA, [indir([AC_FUNC_ALLOCA])])dnl +AC_DEFUN(AC_GETLOADAVG, [indir([AC_FUNC_GETLOADAVG])])dnl +AC_DEFUN(AC_UTIME_NULL, [indir([AC_FUNC_UTIME_NULL])])dnl +AC_DEFUN(AC_STRCOLL, [indir([AC_FUNC_STRCOLL])])dnl +AC_DEFUN(AC_SETVBUF_REVERSED, [indir([AC_FUNC_SETVBUF_REVERSED])])dnl +AC_DEFUN(AC_TIME_WITH_SYS_TIME, [indir([AC_HEADER_TIME])])dnl +AC_DEFUN(AC_TIMEZONE, [indir([AC_STRUCT_TIMEZONE])])dnl +AC_DEFUN(AC_ST_BLOCKS, [indir([AC_STRUCT_ST_BLOCKS])])dnl +AC_DEFUN(AC_ST_BLKSIZE, [indir([AC_STRUCT_ST_BLKSIZE])])dnl +AC_DEFUN(AC_ST_RDEV, [indir([AC_STRUCT_ST_RDEV])])dnl +AC_DEFUN(AC_CROSS_CHECK, [indir([AC_C_CROSS])])dnl +AC_DEFUN(AC_CHAR_UNSIGNED, [indir([AC_C_CHAR_UNSIGNED])])dnl +AC_DEFUN(AC_LONG_DOUBLE, [indir([AC_C_LONG_DOUBLE])])dnl +AC_DEFUN(AC_WORDS_BIGENDIAN, [indir([AC_C_BIGENDIAN])])dnl +AC_DEFUN(AC_INLINE, [indir([AC_C_INLINE])])dnl +AC_DEFUN(AC_CONST, [indir([AC_C_CONST])])dnl +AC_DEFUN(AC_LONG_FILE_NAMES, [indir([AC_SYS_LONG_FILE_NAMES])])dnl +AC_DEFUN(AC_RESTARTABLE_SYSCALLS, [indir([AC_SYS_RESTARTABLE_SYSCALLS])])dnl +AC_DEFUN(AC_FIND_X, [indir([AC_PATH_X])])dnl +AC_DEFUN(AC_FIND_XTRA, [indir([AC_PATH_XTRA])])dnl diff --git a/build/autoconf/acspecific.m4 b/build/autoconf/acspecific.m4 new file mode 100644 index 0000000000..28af522876 --- /dev/null +++ b/build/autoconf/acspecific.m4 @@ -0,0 +1,2758 @@ +dnl Macros that test for specific features. +dnl This file is part of Autoconf. +dnl Copyright (C) 1992, 93, 94, 95, 96, 1998 Free Software Foundation, Inc. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception, the Free Software Foundation gives unlimited +dnl permission to copy, distribute and modify the configure scripts that +dnl are the output of Autoconf. You need not follow the terms of the GNU +dnl General Public License when using or distributing such scripts, even +dnl though portions of the text of Autoconf appear in them. The GNU +dnl General Public License (GPL) does govern all other use of the material +dnl that constitutes the Autoconf program. +dnl +dnl Certain portions of the Autoconf source text are designed to be copied +dnl (in certain cases, depending on the input) into the output of +dnl Autoconf. We call these the "data" portions. The rest of the Autoconf +dnl source text consists of comments plus executable code that decides which +dnl of the data portions to output in any given case. We call these +dnl comments and executable code the "non-data" portions. Autoconf never +dnl copies any of the non-data portions into its output. +dnl +dnl This special exception to the GPL applies to versions of Autoconf +dnl released by the Free Software Foundation. When you make and +dnl distribute a modified version of Autoconf, you may extend this special +dnl exception to the GPL to apply to your modified version as well, *unless* +dnl your modified version has the potential to copy into its output some +dnl of the text that was the non-data portion of the version that you started +dnl with. (In other words, unless your change moves or copies text from +dnl the non-data portions to the data portions.) If your modification has +dnl such potential, you must delete any notice of this special exception +dnl to the GPL from your modified version. +dnl +dnl Written by David MacKenzie, with help from +dnl Franc,ois Pinard, Karl Berry, Richard Pixley, Ian Lance Taylor, +dnl Roland McGrath, Noah Friedman, david d zuhn, and many others. + + +dnl ### Checks for programs + + +dnl Check whether to use -n, \c, or newline-tab to separate +dnl checking messages from result messages. +dnl Idea borrowed from dist 3.0. +dnl Internal use only. +AC_DEFUN(AC_PROG_ECHO_N, +[if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi +]) + +AC_DEFUN(AC_PROG_CC, +[AC_BEFORE([$0], [AC_PROG_CPP])dnl +AC_CHECK_PROG(CC, gcc, gcc) +if test -z "$CC"; then + AC_CHECK_PROG(CC, cc, cc, , , /usr/ucb/cc) + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + AC_CHECK_PROG(CC, cl, cl) ;; + esac + fi + test -z "$CC" && AC_MSG_ERROR([no acceptable cc found in \$PATH]) +fi + +AC_PROG_CC_WORKS +AC_PROG_CC_GNU + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +dnl Check whether -g works, even if CFLAGS is set, in case the package +dnl plays around with CFLAGS (such as to build both debugging and +dnl normal versions of a library), tasteless as that idea is. +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +AC_PROG_CC_G +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +]) + +AC_DEFUN(AC_PROG_CXX, +[AC_BEFORE([$0], [AC_PROG_CXXCPP])dnl +AC_CHECK_PROGS(CXX, $CCC c++ g++ gcc CC cxx cc++ cl, gcc) + +AC_PROG_CXX_WORKS +AC_PROG_CXX_GNU + +if test $ac_cv_prog_gxx = yes; then + GXX=yes +else + GXX= +fi + +dnl Check whether -g works, even if CXXFLAGS is set, in case the package +dnl plays around with CXXFLAGS (such as to build both debugging and +dnl normal versions of a library), tasteless as that idea is. +ac_test_CXXFLAGS="${CXXFLAGS+set}" +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS= +AC_PROG_CXX_G +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +]) + +dnl Determine a Fortran 77 compiler to use. If `F77' is not already set +dnl in the environment, check for `g77', `f77' and `f2c', in that order. +dnl Set the output variable `F77' to the name of the compiler found. +dnl +dnl If using `g77' (the GNU Fortran 77 compiler), then `AC_PROG_F77' +dnl will set the shell variable `G77' to `yes', and empty otherwise. If +dnl the output variable `FFLAGS' was not already set in the environment, +dnl then set it to `-g -02' for `g77' (or `-O2' where `g77' does not +dnl accept `-g'). Otherwise, set `FFLAGS' to `-g' for all other Fortran +dnl 77 compilers. +dnl +dnl AC_PROG_F77() +AC_DEFUN(AC_PROG_F77, +[AC_BEFORE([$0], [AC_PROG_CPP])dnl +if test -z "$F77"; then + AC_CHECK_PROGS(F77, g77 f77 f2c) + test -z "$F77" && AC_MSG_ERROR([no acceptable Fortran 77 compiler found in \$PATH]) +fi + +AC_PROG_F77_WORKS +AC_PROG_F77_GNU + +if test $ac_cv_prog_g77 = yes; then + G77=yes +dnl Check whether -g works, even if FFLAGS is set, in case the package +dnl plays around with FFLAGS (such as to build both debugging and +dnl normal versions of a library), tasteless as that idea is. + ac_test_FFLAGS="${FFLAGS+set}" + ac_save_FFLAGS="$FFLAGS" + FFLAGS= + AC_PROG_F77_G + if test "$ac_test_FFLAGS" = set; then + FFLAGS="$ac_save_FFLAGS" + elif test $ac_cv_prog_f77_g = yes; then + FFLAGS="-g -O2" + else + FFLAGS="-O2" + fi +else + G77= + test "${FFLAGS+set}" = set || FFLAGS="-g" +fi +]) + +AC_DEFUN(AC_PROG_CC_WORKS, +[AC_MSG_CHECKING([whether the C compiler ($CC $CFLAGS $LDFLAGS) works]) +AC_LANG_SAVE +AC_LANG_C +AC_TRY_COMPILER([main(){return(0);}], ac_cv_prog_cc_works, ac_cv_prog_cc_cross) +AC_LANG_RESTORE +AC_MSG_RESULT($ac_cv_prog_cc_works) +if test $ac_cv_prog_cc_works = no; then + AC_MSG_ERROR([installation or configuration problem: C compiler cannot create executables.]) +fi +AC_MSG_CHECKING([whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler]) +AC_MSG_RESULT($ac_cv_prog_cc_cross) +cross_compiling=$ac_cv_prog_cc_cross +]) + +AC_DEFUN(AC_PROG_CXX_WORKS, +[AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works]) +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_TRY_COMPILER([int main(){return(0);}], ac_cv_prog_cxx_works, ac_cv_prog_cxx_cross) +AC_LANG_RESTORE +AC_MSG_RESULT($ac_cv_prog_cxx_works) +if test $ac_cv_prog_cxx_works = no; then + AC_MSG_ERROR([installation or configuration problem: C++ compiler cannot create executables.]) +fi +AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler]) +AC_MSG_RESULT($ac_cv_prog_cxx_cross) +cross_compiling=$ac_cv_prog_cxx_cross +]) + +dnl Test whether the Fortran 77 compiler can compile and link a trivial +dnl Fortran program. Also, test whether the Fortran 77 compiler is a +dnl cross-compiler (which may realistically be the case if the Fortran +dnl compiler is `g77'). +dnl +dnl AC_PROG_F77_WORKS() +AC_DEFUN(AC_PROG_F77_WORKS, +[AC_MSG_CHECKING([whether the Fortran 77 compiler ($F77 $FFLAGS $LDFLAGS) works]) +AC_LANG_SAVE +AC_LANG_FORTRAN77 +AC_TRY_COMPILER(dnl +[ program conftest + end +], ac_cv_prog_f77_works, ac_cv_prog_f77_cross) +AC_LANG_RESTORE +AC_MSG_RESULT($ac_cv_prog_f77_works) +if test $ac_cv_prog_f77_works = no; then + AC_MSG_ERROR([installation or configuration problem: Fortran 77 compiler cannot create executables.]) +fi +AC_MSG_CHECKING([whether the Fortran 77 compiler ($F77 $FFLAGS $LDFLAGS) is a cross-compiler]) +AC_MSG_RESULT($ac_cv_prog_f77_cross) +cross_compiling=$ac_cv_prog_f77_cross +]) + +AC_DEFUN(AC_PROG_CC_GNU, +[AC_CACHE_CHECK(whether we are using GNU C, ac_cv_prog_gcc, +[dnl The semicolon is to pacify NeXT's syntax-checking cpp. +cat > conftest.c </dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi])]) + +AC_DEFUN(AC_PROG_CXX_GNU, +[AC_CACHE_CHECK(whether we are using GNU C++, ac_cv_prog_gxx, +[dnl The semicolon is to pacify NeXT's syntax-checking cpp. +cat > conftest.C </dev/null 2>&1; then + ac_cv_prog_gxx=yes +else + ac_cv_prog_gxx=no +fi])]) + +dnl Test whether for Fortran 77 compiler is `g77' (the GNU Fortran 77 +dnl Compiler). This test depends on whether the Fortran 77 compiler can +dnl do CPP pre-processing. +dnl +dnl AC_PROG_F77_GNU() +AC_DEFUN(AC_PROG_F77_GNU, +[AC_CACHE_CHECK(whether we are using GNU Fortran 77, ac_cv_prog_g77, +[cat > conftest.fpp </dev/null 2>&1; then + ac_cv_prog_g77=yes +else + ac_cv_prog_g77=no +fi])]) + +AC_DEFUN(AC_PROG_CC_G, +[AC_CACHE_CHECK(whether ${CC-cc} accepts -g, ac_cv_prog_cc_g, +[echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* +])]) + +AC_DEFUN(AC_PROG_CXX_G, +[AC_CACHE_CHECK(whether ${CXX-g++} accepts -g, ac_cv_prog_cxx_g, +[echo 'void f(){}' > conftest.cc +if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then + ac_cv_prog_cxx_g=yes +else + ac_cv_prog_cxx_g=no +fi +rm -f conftest* +])]) + +dnl Test whether the Fortran 77 compiler can accept the `-g' option to +dnl enable debugging. +dnl +dnl AC_PROG_F77_G() +AC_DEFUN(AC_PROG_F77_G, +[AC_CACHE_CHECK(whether $F77 accepts -g, ac_cv_prog_f77_g, +[cat > conftest.f << EOF + program conftest + end +EOF +if test -z "`$F77 -g -c conftest.f 2>&1`"; then + ac_cv_prog_f77_g=yes +else + ac_cv_prog_f77_g=no +fi +rm -f conftest* +])]) + +AC_DEFUN(AC_PROG_GCC_TRADITIONAL, +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_CPP])dnl +if test $ac_cv_prog_gcc = yes; then + AC_CACHE_CHECK(whether ${CC-cc} needs -traditional, + ac_cv_prog_gcc_traditional, +[ ac_pattern="Autoconf.*'x'" + AC_EGREP_CPP($ac_pattern, [#include +Autoconf TIOCGETP], + ac_cv_prog_gcc_traditional=yes, ac_cv_prog_gcc_traditional=no) + + if test $ac_cv_prog_gcc_traditional = no; then + AC_EGREP_CPP($ac_pattern, [#include +Autoconf TCGETA], + ac_cv_prog_gcc_traditional=yes) + fi]) + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi +]) + +AC_DEFUN(AC_PROG_CC_C_O, +[if test "x$CC" != xcc; then + AC_MSG_CHECKING(whether $CC and cc understand -c and -o together) +else + AC_MSG_CHECKING(whether cc understands -c and -o together) +fi +set dummy $CC; ac_cc="`echo [$]2 | +changequote(, )dnl + sed -e 's/[^a-zA-Z0-9_]/_/g' -e 's/^[0-9]/_/'`" +changequote([, ])dnl +AC_CACHE_VAL(ac_cv_prog_cc_${ac_cc}_c_o, +[echo 'foo(){}' > conftest.c +# Make sure it works both with $CC and with simple cc. +# We do the test twice because some compilers refuse to overwrite an +# existing .o file with -o, though they will create one. +ac_try='${CC-cc} -c conftest.c -o conftest.o 1>&AC_FD_CC' +if AC_TRY_EVAL(ac_try) && + test -f conftest.o && AC_TRY_EVAL(ac_try); +then + eval ac_cv_prog_cc_${ac_cc}_c_o=yes + if test "x$CC" != xcc; then + # Test first that cc exists at all. + if AC_TRY_COMMAND(cc -c conftest.c 1>&AC_FD_CC); then + ac_try='cc -c conftest.c -o conftest.o 1>&AC_FD_CC' + if AC_TRY_EVAL(ac_try) && + test -f conftest.o && AC_TRY_EVAL(ac_try); + then + # cc works too. + : + else + # cc exists but doesn't like -o. + eval ac_cv_prog_cc_${ac_cc}_c_o=no + fi + fi + fi +else + eval ac_cv_prog_cc_${ac_cc}_c_o=no +fi +rm -f conftest* +])dnl +if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" = yes"; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) + AC_DEFINE(NO_MINUS_C_MINUS_O) +fi +]) + +dnl Test if the Fortran 77 compiler accepts the options `-c' and `-o' +dnl simultaneously, and define `F77_NO_MINUS_C_MINUS_O' if it does not. +dnl +dnl The usefulness of this macro is questionable, as I can't really see +dnl why anyone would use it. The only reason I include it is for +dnl completeness, since a similar test exists for the C compiler. +dnl +dnl AC_PROG_F77_C_O +AC_DEFUN(AC_PROG_F77_C_O, +[AC_BEFORE([$0], [AC_PROG_F77])dnl +AC_MSG_CHECKING(whether $F77 understand -c and -o together) +set dummy $F77; ac_f77="`echo [$]2 | +changequote(, )dnl +sed -e 's/[^a-zA-Z0-9_]/_/g' -e 's/^[0-9]/_/'`" +changequote([, ])dnl +AC_CACHE_VAL(ac_cv_prog_f77_${ac_f77}_c_o, +[cat > conftest.f << EOF + program conftest + end +EOF +# We do the `AC_TRY_EVAL' test twice because some compilers refuse to +# overwrite an existing `.o' file with `-o', although they will create +# one. +ac_try='$F77 $FFLAGS -c conftest.f -o conftest.o 1>&AC_FD_CC' +if AC_TRY_EVAL(ac_try) && test -f conftest.o && AC_TRY_EVAL(ac_try); then + eval ac_cv_prog_f77_${ac_f77}_c_o=yes +else + eval ac_cv_prog_f77_${ac_f77}_c_o=no +fi +rm -f conftest* +])dnl +if eval "test \"`echo '$ac_cv_prog_f77_'${ac_f77}_c_o`\" = yes"; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) + AC_DEFINE(F77_NO_MINUS_C_MINUS_O) +fi +]) + +dnl Define SET_MAKE to set ${MAKE} if make doesn't. +AC_DEFUN(AC_PROG_MAKE_SET, +[AC_MSG_CHECKING(whether ${MAKE-make} sets \${MAKE}) +set dummy ${MAKE-make}; ac_make=`echo "[$]2" | sed 'y%./+-%__p_%'` +AC_CACHE_VAL(ac_cv_prog_make_${ac_make}_set, +[cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +changequote(, )dnl +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +changequote([, ])dnl +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake])dnl +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + AC_MSG_RESULT(yes) + SET_MAKE= +else + AC_MSG_RESULT(no) + SET_MAKE="MAKE=${MAKE-make}" +fi +AC_SUBST([SET_MAKE])dnl +]) + +AC_DEFUN(AC_PROG_RANLIB, +[AC_CHECK_PROG(RANLIB, ranlib, ranlib, :)]) + +dnl Check for mawk first since it's generally faster. +AC_DEFUN(AC_PROG_AWK, +[AC_CHECK_PROGS(AWK, mawk gawk nawk awk, )]) + +AC_DEFUN(AC_PROG_YACC, +[AC_CHECK_PROGS(YACC, 'bison -y' byacc, yacc)]) + +AC_DEFUN(AC_PROG_CPP, +[AC_MSG_CHECKING(how to run the C preprocessor) +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +AC_CACHE_VAL(ac_cv_prog_CPP, +[ # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. +dnl Use a header file that comes with gcc, so configuring glibc +dnl with a fresh cross-compiler works. + AC_TRY_CPP([#include +Syntax Error], , + CPP="${CC-cc} -E -traditional-cpp" + AC_TRY_CPP([#include +Syntax Error], , + CPP="${CC-cc} -nologo -E" + AC_TRY_CPP([#include +Syntax Error], , CPP=/lib/cpp))) + ac_cv_prog_CPP="$CPP"])dnl + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +AC_MSG_RESULT($CPP) +AC_SUBST(CPP)dnl +]) + +AC_DEFUN(AC_PROG_CXXCPP, +[AC_MSG_CHECKING(how to run the C++ preprocessor) +if test -z "$CXXCPP"; then +AC_CACHE_VAL(ac_cv_prog_CXXCPP, +[AC_LANG_SAVE[]dnl +AC_LANG_CPLUSPLUS[]dnl + CXXCPP="${CXX-g++} -E" + AC_TRY_CPP([#include ], , CXXCPP=/lib/cpp) + ac_cv_prog_CXXCPP="$CXXCPP" +AC_LANG_RESTORE[]dnl +fi])dnl +CXXCPP="$ac_cv_prog_CXXCPP" +AC_MSG_RESULT($CXXCPP) +AC_SUBST(CXXCPP)dnl +]) + +dnl Require finding the C or C++ preprocessor, whichever is the +dnl current language. +AC_DEFUN(AC_REQUIRE_CPP, +[ifelse(AC_LANG, C, [AC_REQUIRE([AC_PROG_CPP])], [AC_REQUIRE([AC_PROG_CXXCPP])])]) + +AC_DEFUN(AC_PROG_LEX, +[AC_CHECK_PROG(LEX, flex, flex, lex) +if test -z "$LEXLIB" +then + case "$LEX" in + flex*) ac_lib=fl ;; + *) ac_lib=l ;; + esac + AC_CHECK_LIB($ac_lib, yywrap, LEXLIB="-l$ac_lib") +fi +AC_SUBST(LEXLIB)]) + +dnl Check if lex declares yytext as a char * by default, not a char[]. +undefine([AC_DECL_YYTEXT]) +AC_DEFUN(AC_DECL_YYTEXT, +[AC_REQUIRE_CPP()dnl +AC_REQUIRE([AC_PROG_LEX])dnl +AC_CACHE_CHECK(lex output file root, ac_cv_prog_lex_root, +[# The minimal lex program is just a single line: %%. But some broken lexes +# (Solaris, I think it was) want two %% lines, so accommodate them. +echo '%% +%%' | $LEX +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + AC_MSG_ERROR(cannot find output from $LEX; giving up) +fi]) +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root +AC_SUBST(LEX_OUTPUT_ROOT)dnl + +AC_CACHE_CHECK(whether yytext is a pointer, ac_cv_prog_lex_yytext_pointer, +[# POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c +ac_save_LIBS="$LIBS" +LIBS="$LIBS $LEXLIB" +AC_TRY_LINK(`cat $LEX_OUTPUT_ROOT.c`, , ac_cv_prog_lex_yytext_pointer=yes) +LIBS="$ac_save_LIBS" +rm -f "${LEX_OUTPUT_ROOT}.c" +]) +dnl +if test $ac_cv_prog_lex_yytext_pointer = yes; then + AC_DEFINE(YYTEXT_POINTER) +fi +]) + +AC_DEFUN(AC_PROG_INSTALL, +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +AC_MSG_CHECKING(for a BSD compatible install) +if test -z "$INSTALL"; then +AC_CACHE_VAL(ac_cv_path_install, +[ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" +])dnl + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +dnl We do special magic for INSTALL instead of AC_SUBST, to get +dnl relative paths right. +AC_MSG_RESULT($INSTALL) + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' +AC_SUBST(INSTALL_PROGRAM)dnl + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' +AC_SUBST(INSTALL_SCRIPT)dnl + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' +AC_SUBST(INSTALL_DATA)dnl +]) + +AC_DEFUN(AC_PROG_LN_S, +[AC_MSG_CHECKING(whether ln -s works) +AC_CACHE_VAL(ac_cv_prog_LN_S, +[rm -f conftestdata +if ln -s X conftestdata 2>/dev/null +then + rm -f conftestdata + ac_cv_prog_LN_S="ln -s" +else + ac_cv_prog_LN_S=ln +fi])dnl +LN_S="$ac_cv_prog_LN_S" +if test "$ac_cv_prog_LN_S" = "ln -s"; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AC_SUBST(LN_S)dnl +]) + +define(AC_RSH, +[errprint(__file__:__line__: [$0] has been removed; replace it with equivalent code +)m4exit(4)]) + + +dnl ### Checks for header files + + +AC_DEFUN(AC_HEADER_STDC, +[AC_REQUIRE_CPP()dnl +AC_CACHE_CHECK(for ANSI C header files, ac_cv_header_stdc, +[AC_TRY_CPP([#include +#include +#include +#include ], ac_cv_header_stdc=yes, ac_cv_header_stdc=no) + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +AC_EGREP_HEADER(memchr, string.h, , ac_cv_header_stdc=no) +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +AC_EGREP_HEADER(free, stdlib.h, , ac_cv_header_stdc=no) +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +AC_TRY_RUN([#include +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } +], , ac_cv_header_stdc=no, :) +fi]) +if test $ac_cv_header_stdc = yes; then + AC_DEFINE(STDC_HEADERS) +fi +]) + +AC_DEFUN(AC_UNISTD_H, +[AC_OBSOLETE([$0], [; instead use AC_CHECK_HEADERS(unistd.h)])dnl +AC_CHECK_HEADER(unistd.h, AC_DEFINE(HAVE_UNISTD_H))]) + +AC_DEFUN(AC_USG, +[AC_OBSOLETE([$0], + [; instead use AC_CHECK_HEADERS(string.h) and HAVE_STRING_H])dnl +AC_MSG_CHECKING([for BSD string and memory functions]) +AC_TRY_LINK([#include ], [rindex(0, 0); bzero(0, 0);], + [AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no); AC_DEFINE(USG)])]) + + +dnl If memchr and the like aren't declared in , include . +dnl To avoid problems, don't check for gcc2 built-ins. +AC_DEFUN(AC_MEMORY_H, +[AC_OBSOLETE([$0], [; instead use AC_CHECK_HEADERS(memory.h) and HAVE_MEMORY_H])dnl +AC_MSG_CHECKING(whether string.h declares mem functions) +AC_EGREP_HEADER(memchr, string.h, ac_found=yes, ac_found=no) +AC_MSG_RESULT($ac_found) +if test $ac_found = no; then + AC_CHECK_HEADER(memory.h, [AC_DEFINE(NEED_MEMORY_H)]) +fi +]) + +AC_DEFUN(AC_HEADER_MAJOR, +[AC_CACHE_CHECK(whether sys/types.h defines makedev, + ac_cv_header_sys_types_h_makedev, +[AC_TRY_LINK([#include ], [return makedev(0, 0);], + ac_cv_header_sys_types_h_makedev=yes, ac_cv_header_sys_types_h_makedev=no) +]) + +if test $ac_cv_header_sys_types_h_makedev = no; then +AC_CHECK_HEADER(sys/mkdev.h, [AC_DEFINE(MAJOR_IN_MKDEV)]) + + if test $ac_cv_header_sys_mkdev_h = no; then +AC_CHECK_HEADER(sys/sysmacros.h, [AC_DEFINE(MAJOR_IN_SYSMACROS)]) + fi +fi +]) + +AC_DEFUN(AC_HEADER_DIRENT, +[ac_header_dirent=no +AC_CHECK_HEADERS_DIRENT(dirent.h sys/ndir.h sys/dir.h ndir.h, + [ac_header_dirent=$ac_hdr; break]) +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +AC_CHECK_LIB(dir, opendir, LIBS="$LIBS -ldir") +else +AC_CHECK_LIB(x, opendir, LIBS="$LIBS -lx") +fi +]) + +dnl Like AC_CHECK_HEADER, except also make sure that HEADER-FILE +dnl defines the type `DIR'. dirent.h on NextStep 3.2 doesn't. +dnl AC_CHECK_HEADER_DIRENT(HEADER-FILE, ACTION-IF-FOUND) +AC_DEFUN(AC_CHECK_HEADER_DIRENT, +[ac_safe=`echo "$1" | sed 'y%./+-%__p_%'` +AC_MSG_CHECKING([for $1 that defines DIR]) +AC_CACHE_VAL(ac_cv_header_dirent_$ac_safe, +[AC_TRY_COMPILE([#include +#include <$1>], [DIR *dirp = 0;], + eval "ac_cv_header_dirent_$ac_safe=yes", + eval "ac_cv_header_dirent_$ac_safe=no")])dnl +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + AC_MSG_RESULT(yes) + $2 +else + AC_MSG_RESULT(no) +fi +]) + +dnl Like AC_CHECK_HEADERS, except succeed only for a HEADER-FILE that +dnl defines `DIR'. +dnl AC_CHECK_HEADERS_DIRENT(HEADER-FILE... [, ACTION]) +define(AC_CHECK_HEADERS_DIRENT, +[for ac_hdr in $1 +do +AC_CHECK_HEADER_DIRENT($ac_hdr, +[changequote(, )dnl + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` +changequote([, ])dnl + AC_DEFINE_UNQUOTED($ac_tr_hdr) $2])dnl +done]) + +AC_DEFUN(AC_DIR_HEADER, +[AC_OBSOLETE([$0], [; instead use AC_HEADER_DIRENT])dnl +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do + AC_CHECK_HEADER_DIRENT($ac_hdr, [ac_header_dirent=$ac_hdr; break]) +done + +case "$ac_header_dirent" in +dirent.h) AC_DEFINE(DIRENT) ;; +sys/ndir.h) AC_DEFINE(SYSNDIR) ;; +sys/dir.h) AC_DEFINE(SYSDIR) ;; +ndir.h) AC_DEFINE(NDIR) ;; +esac + +AC_CACHE_CHECK(whether closedir returns void, ac_cv_func_closedir_void, +[AC_TRY_RUN([#include +#include <$ac_header_dirent> +int closedir(); main() { exit(closedir(opendir(".")) != 0); }], + ac_cv_func_closedir_void=no, ac_cv_func_closedir_void=yes, ac_cv_func_closedir_void=yes)]) +if test $ac_cv_func_closedir_void = yes; then + AC_DEFINE(VOID_CLOSEDIR) +fi +]) + +AC_DEFUN(AC_HEADER_STAT, +[AC_CACHE_CHECK(whether stat file-mode macros are broken, + ac_cv_header_stat_broken, +[AC_EGREP_CPP([You lose], [#include +#include + +#if defined(S_ISBLK) && defined(S_IFDIR) +# if S_ISBLK (S_IFDIR) +You lose. +# endif +#endif + +#if defined(S_ISBLK) && defined(S_IFCHR) +# if S_ISBLK (S_IFCHR) +You lose. +# endif +#endif + +#if defined(S_ISLNK) && defined(S_IFREG) +# if S_ISLNK (S_IFREG) +You lose. +# endif +#endif + +#if defined(S_ISSOCK) && defined(S_IFREG) +# if S_ISSOCK (S_IFREG) +You lose. +# endif +#endif +], ac_cv_header_stat_broken=yes, ac_cv_header_stat_broken=no)]) +if test $ac_cv_header_stat_broken = yes; then + AC_DEFINE(STAT_MACROS_BROKEN) +fi +]) + +AC_DEFUN(AC_DECL_SYS_SIGLIST, +[AC_CACHE_CHECK([for sys_siglist declaration in signal.h or unistd.h], + ac_cv_decl_sys_siglist, +[AC_TRY_COMPILE([#include +#include +/* NetBSD declares sys_siglist in unistd.h. */ +#ifdef HAVE_UNISTD_H +#include +#endif], [char *msg = *(sys_siglist + 1);], + ac_cv_decl_sys_siglist=yes, ac_cv_decl_sys_siglist=no)]) +if test $ac_cv_decl_sys_siglist = yes; then + AC_DEFINE(SYS_SIGLIST_DECLARED) +fi +]) + +AC_DEFUN(AC_HEADER_SYS_WAIT, +[AC_CACHE_CHECK([for sys/wait.h that is POSIX.1 compatible], + ac_cv_header_sys_wait_h, +[AC_TRY_COMPILE([#include +#include +#ifndef WEXITSTATUS +#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif], [int s; +wait (&s); +s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;], +ac_cv_header_sys_wait_h=yes, ac_cv_header_sys_wait_h=no)]) +if test $ac_cv_header_sys_wait_h = yes; then + AC_DEFINE(HAVE_SYS_WAIT_H) +fi +]) + + +dnl ### Checks for typedefs + + +AC_DEFUN(AC_TYPE_GETGROUPS, +[AC_REQUIRE([AC_TYPE_UID_T])dnl +AC_CACHE_CHECK(type of array argument to getgroups, ac_cv_type_getgroups, +[AC_TRY_RUN( +changequote(<<, >>)dnl +<< +/* Thanks to Mike Rendell for this test. */ +#include +#define NGID 256 +#undef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +main() +{ + gid_t gidset[NGID]; + int i, n; + union { gid_t gval; long lval; } val; + + val.lval = -1; + for (i = 0; i < NGID; i++) + gidset[i] = val.gval; + n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1, + gidset); + /* Exit non-zero if getgroups seems to require an array of ints. This + happens when gid_t is short but getgroups modifies an array of ints. */ + exit ((n > 0 && gidset[n] != val.gval) ? 1 : 0); +} +>>, +changequote([, ])dnl + ac_cv_type_getgroups=gid_t, ac_cv_type_getgroups=int, + ac_cv_type_getgroups=cross) +if test $ac_cv_type_getgroups = cross; then + dnl When we can't run the test program (we are cross compiling), presume + dnl that has either an accurate prototype for getgroups or none. + dnl Old systems without prototypes probably use int. + AC_EGREP_HEADER([getgroups.*int.*gid_t], unistd.h, + ac_cv_type_getgroups=gid_t, ac_cv_type_getgroups=int) +fi]) +AC_DEFINE_UNQUOTED(GETGROUPS_T, $ac_cv_type_getgroups) +]) + +AC_DEFUN(AC_TYPE_UID_T, +[AC_CACHE_CHECK(for uid_t in sys/types.h, ac_cv_type_uid_t, +[AC_EGREP_HEADER(uid_t, sys/types.h, + ac_cv_type_uid_t=yes, ac_cv_type_uid_t=no)]) +if test $ac_cv_type_uid_t = no; then + AC_DEFINE(uid_t, int) + AC_DEFINE(gid_t, int) +fi +]) + +AC_DEFUN(AC_TYPE_SIZE_T, +[AC_CHECK_TYPE(size_t, unsigned)]) + +AC_DEFUN(AC_TYPE_PID_T, +[AC_CHECK_TYPE(pid_t, int)]) + +AC_DEFUN(AC_TYPE_OFF_T, +[AC_CHECK_TYPE(off_t, long)]) + +AC_DEFUN(AC_TYPE_MODE_T, +[AC_CHECK_TYPE(mode_t, int)]) + +dnl Note that identifiers starting with SIG are reserved by ANSI C. +AC_DEFUN(AC_TYPE_SIGNAL, +[AC_CACHE_CHECK([return type of signal handlers], ac_cv_type_signal, +[AC_TRY_COMPILE([#include +#include +#ifdef signal +#undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif +], +[int i;], ac_cv_type_signal=void, ac_cv_type_signal=int)]) +AC_DEFINE_UNQUOTED(RETSIGTYPE, $ac_cv_type_signal) +]) + + +dnl ### Checks for functions + + +AC_DEFUN(AC_FUNC_CLOSEDIR_VOID, +[AC_REQUIRE([AC_HEADER_DIRENT])dnl +AC_CACHE_CHECK(whether closedir returns void, ac_cv_func_closedir_void, +[AC_TRY_RUN([#include +#include <$ac_header_dirent> +int closedir(); main() { exit(closedir(opendir(".")) != 0); }], + ac_cv_func_closedir_void=no, ac_cv_func_closedir_void=yes, ac_cv_func_closedir_void=yes)]) +if test $ac_cv_func_closedir_void = yes; then + AC_DEFINE(CLOSEDIR_VOID) +fi +]) + +AC_DEFUN(AC_FUNC_FNMATCH, +[AC_CACHE_CHECK(for working fnmatch, ac_cv_func_fnmatch_works, +# Some versions of Solaris or SCO have a broken fnmatch function. +# So we run a test program. If we are cross-compiling, take no chance. +# Thanks to John Oleynick and Franc,ois Pinard for this test. +[AC_TRY_RUN([main() { exit (fnmatch ("a*", "abc", 0) != 0); }], +ac_cv_func_fnmatch_works=yes, ac_cv_func_fnmatch_works=no, +ac_cv_func_fnmatch_works=no)]) +if test $ac_cv_func_fnmatch_works = yes; then + AC_DEFINE(HAVE_FNMATCH) +fi +]) + +AC_DEFUN(AC_FUNC_MMAP, +[AC_CHECK_HEADERS(unistd.h) +AC_CHECK_FUNCS(getpagesize) +AC_CACHE_CHECK(for working mmap, ac_cv_func_mmap_fixed_mapped, +[AC_TRY_RUN([ +/* Thanks to Mike Haertel and Jim Avera for this test. + Here is a matrix of mmap possibilities: + mmap private not fixed + mmap private fixed at somewhere currently unmapped + mmap private fixed at somewhere already mapped + mmap shared not fixed + mmap shared fixed at somewhere currently unmapped + mmap shared fixed at somewhere already mapped + For private mappings, we should verify that changes cannot be read() + back from the file, nor mmap's back from the file at a different + address. (There have been systems where private was not correctly + implemented like the infamous i386 svr4.0, and systems where the + VM page cache was not coherent with the filesystem buffer cache + like early versions of FreeBSD and possibly contemporary NetBSD.) + For shared mappings, we should conversely verify that changes get + propogated back to all the places they're supposed to be. + + Grep wants private fixed already mapped. + The main things grep needs to know about mmap are: + * does it exist and is it safe to write into the mmap'd area + * how to use it (BSD variants) */ +#include +#include +#include + +/* This mess was copied from the GNU getpagesize.h. */ +#ifndef HAVE_GETPAGESIZE +# ifdef HAVE_UNISTD_H +# include +# endif + +/* Assume that all systems that can run configure have sys/param.h. */ +# ifndef HAVE_SYS_PARAM_H +# define HAVE_SYS_PARAM_H 1 +# endif + +# ifdef _SC_PAGESIZE +# define getpagesize() sysconf(_SC_PAGESIZE) +# else /* no _SC_PAGESIZE */ +# ifdef HAVE_SYS_PARAM_H +# include +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* no CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define getpagesize() NBPC +# else /* no NBPC */ +# ifdef PAGESIZE +# define getpagesize() PAGESIZE +# endif /* PAGESIZE */ +# endif /* no NBPC */ +# endif /* no NBPG */ +# endif /* no EXEC_PAGESIZE */ +# else /* no HAVE_SYS_PARAM_H */ +# define getpagesize() 8192 /* punt totally */ +# endif /* no HAVE_SYS_PARAM_H */ +# endif /* no _SC_PAGESIZE */ + +#endif /* no HAVE_GETPAGESIZE */ + +#ifdef __cplusplus +extern "C" { void *malloc(unsigned); } +#else +char *malloc(); +#endif + +int +main() +{ + char *data, *data2, *data3; + int i, pagesize; + int fd; + + pagesize = getpagesize(); + + /* + * First, make a file with some known garbage in it. + */ + data = malloc(pagesize); + if (!data) + exit(1); + for (i = 0; i < pagesize; ++i) + *(data + i) = rand(); + umask(0); + fd = creat("conftestmmap", 0600); + if (fd < 0) + exit(1); + if (write(fd, data, pagesize) != pagesize) + exit(1); + close(fd); + + /* + * Next, try to mmap the file at a fixed address which + * already has something else allocated at it. If we can, + * also make sure that we see the same garbage. + */ + fd = open("conftestmmap", O_RDWR); + if (fd < 0) + exit(1); + data2 = malloc(2 * pagesize); + if (!data2) + exit(1); + data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1); + if (data2 != mmap(data2, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0L)) + exit(1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data2 + i)) + exit(1); + + /* + * Finally, make sure that changes to the mapped area + * do not percolate back to the file as seen by read(). + * (This is a bug on some variants of i386 svr4.0.) + */ + for (i = 0; i < pagesize; ++i) + *(data2 + i) = *(data2 + i) + 1; + data3 = malloc(pagesize); + if (!data3) + exit(1); + if (read(fd, data3, pagesize) != pagesize) + exit(1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data3 + i)) + exit(1); + close(fd); + unlink("conftestmmap"); + exit(0); +} +], ac_cv_func_mmap_fixed_mapped=yes, ac_cv_func_mmap_fixed_mapped=no, +ac_cv_func_mmap_fixed_mapped=no)]) +if test $ac_cv_func_mmap_fixed_mapped = yes; then + AC_DEFINE(HAVE_MMAP) +fi +]) + +AC_DEFUN(AC_FUNC_GETPGRP, +[AC_CACHE_CHECK(whether getpgrp takes no argument, ac_cv_func_getpgrp_void, +[AC_TRY_RUN([ +/* + * If this system has a BSD-style getpgrp(), + * which takes a pid argument, exit unsuccessfully. + * + * Snarfed from Chet Ramey's bash pgrp.c test program + */ +#include +#include + +int pid; +int pg1, pg2, pg3, pg4; +int ng, np, s, child; + +main() +{ + pid = getpid(); + pg1 = getpgrp(0); + pg2 = getpgrp(); + pg3 = getpgrp(pid); + pg4 = getpgrp(1); + + /* + * If all of these values are the same, it's pretty sure that + * we're on a system that ignores getpgrp's first argument. + */ + if (pg2 == pg4 && pg1 == pg3 && pg2 == pg3) + exit(0); + + child = fork(); + if (child < 0) + exit(1); + else if (child == 0) { + np = getpid(); + /* + * If this is Sys V, this will not work; pgrp will be + * set to np because setpgrp just changes a pgrp to be + * the same as the pid. + */ + setpgrp(np, pg1); + ng = getpgrp(0); /* Same result for Sys V and BSD */ + if (ng == pg1) { + exit(1); + } else { + exit(0); + } + } else { + wait(&s); + exit(s>>8); + } +} +], ac_cv_func_getpgrp_void=yes, ac_cv_func_getpgrp_void=no, + AC_MSG_ERROR(cannot check getpgrp if cross compiling)) +]) +if test $ac_cv_func_getpgrp_void = yes; then + AC_DEFINE(GETPGRP_VOID) +fi +]) + +AC_DEFUN(AC_FUNC_SETPGRP, +[AC_CACHE_CHECK(whether setpgrp takes no argument, ac_cv_func_setpgrp_void, +AC_TRY_RUN([ +#ifdef HAVE_UNISTD_H +#include +#endif + +/* + * If this system has a BSD-style setpgrp, which takes arguments, exit + * successfully. + */ +main() +{ + if (setpgrp(1,1) == -1) + exit(0); + else + exit(1); +} +], ac_cv_func_setpgrp_void=no, ac_cv_func_setpgrp_void=yes, + AC_MSG_ERROR(cannot check setpgrp if cross compiling)) +) +if test $ac_cv_func_setpgrp_void = yes; then + AC_DEFINE(SETPGRP_VOID) +fi +]) + +AC_DEFUN(AC_FUNC_VPRINTF, +[AC_CHECK_FUNC(vprintf, AC_DEFINE(HAVE_VPRINTF)) +if test "$ac_cv_func_vprintf" != yes; then +AC_CHECK_FUNC(_doprnt, AC_DEFINE(HAVE_DOPRNT)) +fi +]) + +AC_DEFUN(AC_FUNC_VFORK, +[AC_REQUIRE([AC_TYPE_PID_T])dnl +AC_CHECK_HEADER(vfork.h, AC_DEFINE(HAVE_VFORK_H)) +AC_CACHE_CHECK(for working vfork, ac_cv_func_vfork_works, +[AC_TRY_RUN([/* Thanks to Paul Eggert for this test. */ +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_VFORK_H +#include +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. + The compiler is told about this with #include , + but some compilers (e.g. gcc -O) don't grok . + Test for this by using a static variable whose address + is put into a register that is clobbered by the vfork. */ +static +#ifdef __cplusplus +sparc_address_test (int arg) +#else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} +main() { + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. + This test uses lots of local variables, at least + as many local variables as main has allocated so far + including compiler temporaries. 4 locals are enough for + gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. + A buggy compiler should reuse the register of parent + for one of the local variables, since it will think that + parent can't possibly be used any more in this routine. + Assigning to the local variable will thus munge parent + in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), + vfork doesn't separate parent from child file descriptors. + If the child closes a descriptor before it execs or exits, + this munges the parent's descriptor as well. + Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + exit( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +}], +ac_cv_func_vfork_works=yes, ac_cv_func_vfork_works=no, AC_CHECK_FUNC(vfork) +ac_cv_func_vfork_works=$ac_cv_func_vfork)]) +if test $ac_cv_func_vfork_works = no; then + AC_DEFINE(vfork, fork) +fi +]) + +AC_DEFUN(AC_FUNC_WAIT3, +[AC_CACHE_CHECK(for wait3 that fills in rusage, ac_cv_func_wait3_rusage, +[AC_TRY_RUN([#include +#include +#include +#include +/* HP-UX has wait3 but does not fill in rusage at all. */ +main() { + struct rusage r; + int i; + /* Use a field that we can force nonzero -- + voluntary context switches. + For systems like NeXT and OSF/1 that don't set it, + also use the system CPU time. And page faults (I/O) for Linux. */ + r.ru_nvcsw = 0; + r.ru_stime.tv_sec = 0; + r.ru_stime.tv_usec = 0; + r.ru_majflt = r.ru_minflt = 0; + switch (fork()) { + case 0: /* Child. */ + sleep(1); /* Give up the CPU. */ + _exit(0); + case -1: _exit(0); /* What can we do? */ + default: /* Parent. */ + wait3(&i, 0, &r); + sleep(2); /* Avoid "text file busy" from rm on fast HP-UX machines. */ + exit(r.ru_nvcsw == 0 && r.ru_majflt == 0 && r.ru_minflt == 0 + && r.ru_stime.tv_sec == 0 && r.ru_stime.tv_usec == 0); + } +}], ac_cv_func_wait3_rusage=yes, ac_cv_func_wait3_rusage=no, +ac_cv_func_wait3_rusage=no)]) +if test $ac_cv_func_wait3_rusage = yes; then + AC_DEFINE(HAVE_WAIT3) +fi +]) + +AC_DEFUN(AC_FUNC_ALLOCA, +[AC_REQUIRE_CPP()dnl Set CPP; we run AC_EGREP_CPP conditionally. +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +AC_CACHE_CHECK([for working alloca.h], ac_cv_header_alloca_h, +[AC_TRY_LINK([#include ], [char *p = alloca(2 * sizeof(int));], + ac_cv_header_alloca_h=yes, ac_cv_header_alloca_h=no)]) +if test $ac_cv_header_alloca_h = yes; then + AC_DEFINE(HAVE_ALLOCA_H) +fi + +AC_CACHE_CHECK([for alloca], ac_cv_func_alloca_works, +[AC_TRY_LINK([ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef _MSC_VER +# include +# define alloca _alloca +# else +# if HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +# endif +#endif +], [char *p = (char *) alloca(1);], + ac_cv_func_alloca_works=yes, ac_cv_func_alloca_works=no)]) +if test $ac_cv_func_alloca_works = yes; then + AC_DEFINE(HAVE_ALLOCA) +fi + +if test $ac_cv_func_alloca_works = no; then + # The SVR3 libPW and SVR4 libucb both contain incompatible functions + # that cause trouble. Some versions do not even contain alloca or + # contain a buggy version. If you still want to use their alloca, + # use ar to extract alloca.o from them instead of compiling alloca.c. + ALLOCA=alloca.${ac_objext} + AC_DEFINE(C_ALLOCA) + +AC_CACHE_CHECK(whether alloca needs Cray hooks, ac_cv_os_cray, +[AC_EGREP_CPP(webecray, +[#if defined(CRAY) && ! defined(CRAY2) +webecray +#else +wenotbecray +#endif +], ac_cv_os_cray=yes, ac_cv_os_cray=no)]) +if test $ac_cv_os_cray = yes; then +for ac_func in _getb67 GETB67 getb67; do + AC_CHECK_FUNC($ac_func, [AC_DEFINE_UNQUOTED(CRAY_STACKSEG_END, $ac_func) + break]) +done +fi + +AC_CACHE_CHECK(stack direction for C alloca, ac_cv_c_stack_direction, +[AC_TRY_RUN([find_stack_direction () +{ + static char *addr = 0; + auto char dummy; + if (addr == 0) + { + addr = &dummy; + return find_stack_direction (); + } + else + return (&dummy > addr) ? 1 : -1; +} +main () +{ + exit (find_stack_direction() < 0); +}], ac_cv_c_stack_direction=1, ac_cv_c_stack_direction=-1, + ac_cv_c_stack_direction=0)]) +AC_DEFINE_UNQUOTED(STACK_DIRECTION, $ac_cv_c_stack_direction) +fi +AC_SUBST(ALLOCA)dnl +]) + +AC_DEFUN(AC_FUNC_GETLOADAVG, +[ac_have_func=no # yes means we've found a way to get the load average. + +# Some systems with -lutil have (and need) -lkvm as well, some do not. +# On Solaris, -lkvm requires nlist from -lelf, so check that first +# to get the right answer into the cache. +AC_CHECK_LIB(elf, elf_begin, LIBS="-lelf $LIBS") +AC_CHECK_LIB(kvm, kvm_open, LIBS="-lkvm $LIBS") +# Check for the 4.4BSD definition of getloadavg. +AC_CHECK_LIB(util, getloadavg, + [LIBS="-lutil $LIBS" ac_have_func=yes ac_cv_func_getloadavg_setgid=yes]) + +if test $ac_have_func = no; then + # There is a commonly available library for RS/6000 AIX. + # Since it is not a standard part of AIX, it might be installed locally. + ac_getloadavg_LIBS="$LIBS"; LIBS="-L/usr/local/lib $LIBS" + AC_CHECK_LIB(getloadavg, getloadavg, + LIBS="-lgetloadavg $LIBS", LIBS="$ac_getloadavg_LIBS") +fi + +# Make sure it is really in the library, if we think we found it. +AC_REPLACE_FUNCS(getloadavg) + +if test $ac_cv_func_getloadavg = yes; then + AC_DEFINE(HAVE_GETLOADAVG) + ac_have_func=yes +else + # Figure out what our getloadavg.c needs. + ac_have_func=no + AC_CHECK_HEADER(sys/dg_sys_info.h, + [ac_have_func=yes; AC_DEFINE(DGUX) + AC_CHECK_LIB(dgc, dg_sys_info)]) + + # We cannot check for , because Solaris 2 does not use dwarf (it + # uses stabs), but it is still SVR4. We cannot check for because + # Irix 4.0.5F has the header but not the library. + if test $ac_have_func = no && test $ac_cv_lib_elf_elf_begin = yes; then + ac_have_func=yes; AC_DEFINE(SVR4) + fi + + if test $ac_have_func = no; then + AC_CHECK_HEADER(inq_stats/cpustats.h, + [ac_have_func=yes; AC_DEFINE(UMAX) + AC_DEFINE(UMAX4_3)]) + fi + + if test $ac_have_func = no; then + AC_CHECK_HEADER(sys/cpustats.h, + [ac_have_func=yes; AC_DEFINE(UMAX)]) + fi + + if test $ac_have_func = no; then + AC_CHECK_HEADERS(mach/mach.h) + fi + + AC_CHECK_HEADER(nlist.h, + [AC_DEFINE(NLIST_STRUCT) + AC_CACHE_CHECK([for n_un in struct nlist], ac_cv_struct_nlist_n_un, + [AC_TRY_COMPILE([#include ], + [struct nlist n; n.n_un.n_name = 0;], + ac_cv_struct_nlist_n_un=yes, ac_cv_struct_nlist_n_un=no)]) + if test $ac_cv_struct_nlist_n_un = yes; then + AC_DEFINE(NLIST_NAME_UNION) + fi + ])dnl +fi # Do not have getloadavg in system libraries. + +# Some definitions of getloadavg require that the program be installed setgid. +dnl FIXME Don't hardwire the path of getloadavg.c in the top-level directory. +AC_CACHE_CHECK(whether getloadavg requires setgid, + ac_cv_func_getloadavg_setgid, +[AC_EGREP_CPP([Yowza Am I SETGID yet], +[#include "$srcdir/getloadavg.c" +#ifdef LDAV_PRIVILEGED +Yowza Am I SETGID yet +#endif], + ac_cv_func_getloadavg_setgid=yes, ac_cv_func_getloadavg_setgid=no)]) +if test $ac_cv_func_getloadavg_setgid = yes; then + NEED_SETGID=true; AC_DEFINE(GETLOADAVG_PRIVILEGED) +else + NEED_SETGID=false +fi +AC_SUBST(NEED_SETGID)dnl + +if test $ac_cv_func_getloadavg_setgid = yes; then + AC_CACHE_CHECK(group of /dev/kmem, ac_cv_group_kmem, +[changequote(, )dnl + # On Solaris, /dev/kmem is a symlink. Get info on the real file. + ac_ls_output=`ls -lgL /dev/kmem 2>/dev/null` + # If we got an error (system does not support symlinks), try without -L. + test -z "$ac_ls_output" && ac_ls_output=`ls -lg /dev/kmem` + ac_cv_group_kmem=`echo $ac_ls_output \ + | sed -ne 's/[ ][ ]*/ /g; + s/^.[sSrwx-]* *[0-9]* *\([^0-9]*\) *.*/\1/; + / /s/.* //;p;'` +changequote([, ])dnl +]) + KMEM_GROUP=$ac_cv_group_kmem +fi +AC_SUBST(KMEM_GROUP)dnl +]) + +AC_DEFUN(AC_FUNC_UTIME_NULL, +[AC_CACHE_CHECK(whether utime accepts a null argument, ac_cv_func_utime_null, +[rm -f conftestdata; > conftestdata +# Sequent interprets utime(file, 0) to mean use start of epoch. Wrong. +AC_TRY_RUN([#include +#include +main() { +struct stat s, t; +exit(!(stat ("conftestdata", &s) == 0 && utime("conftestdata", (long *)0) == 0 +&& stat("conftestdata", &t) == 0 && t.st_mtime >= s.st_mtime +&& t.st_mtime - s.st_mtime < 120)); +}], ac_cv_func_utime_null=yes, ac_cv_func_utime_null=no, + ac_cv_func_utime_null=no) +rm -f core core.* *.core]) +if test $ac_cv_func_utime_null = yes; then + AC_DEFINE(HAVE_UTIME_NULL) +fi +]) + +AC_DEFUN(AC_FUNC_STRCOLL, +[AC_CACHE_CHECK(for working strcoll, ac_cv_func_strcoll_works, +[AC_TRY_RUN([#include +main () +{ + exit (strcoll ("abc", "def") >= 0 || + strcoll ("ABC", "DEF") >= 0 || + strcoll ("123", "456") >= 0); +}], ac_cv_func_strcoll_works=yes, ac_cv_func_strcoll_works=no, +ac_cv_func_strcoll_works=no)]) +if test $ac_cv_func_strcoll_works = yes; then + AC_DEFINE(HAVE_STRCOLL) +fi +]) + +AC_DEFUN(AC_FUNC_SETVBUF_REVERSED, +[AC_CACHE_CHECK(whether setvbuf arguments are reversed, + ac_cv_func_setvbuf_reversed, +[AC_TRY_RUN([#include +/* If setvbuf has the reversed format, exit 0. */ +main () { + /* This call has the arguments reversed. + A reversed system may check and see that the address of main + is not _IOLBF, _IONBF, or _IOFBF, and return nonzero. */ + if (setvbuf(stdout, _IOLBF, (char *) main, BUFSIZ) != 0) + exit(1); + putc('\r', stdout); + exit(0); /* Non-reversed systems segv here. */ +}], ac_cv_func_setvbuf_reversed=yes, ac_cv_func_setvbuf_reversed=no) +rm -f core core.* *.core]) +if test $ac_cv_func_setvbuf_reversed = yes; then + AC_DEFINE(SETVBUF_REVERSED) +fi +]) + +AC_DEFUN(AC_FUNC_GETMNTENT, +[# getmntent is in -lsun on Irix 4, -lseq on Dynix/PTX, -lgen on Unixware. +AC_CHECK_LIB(sun, getmntent, LIBS="-lsun $LIBS", + [AC_CHECK_LIB(seq, getmntent, LIBS="-lseq $LIBS", + [AC_CHECK_LIB(gen, getmntent, LIBS="-lgen $LIBS")])]) +AC_CHECK_FUNC(getmntent, [AC_DEFINE(HAVE_GETMNTENT)])]) + +AC_DEFUN(AC_FUNC_STRFTIME, +[AC_CHECK_FUNC(strftime, [AC_DEFINE(HAVE_STRFTIME)], +[# strftime is in -lintl on SCO UNIX. +AC_CHECK_LIB(intl, strftime, +[AC_DEFINE(HAVE_STRFTIME) +LIBS="-lintl $LIBS"])])]) + +AC_DEFUN(AC_FUNC_MEMCMP, +[AC_CACHE_CHECK(for 8-bit clean memcmp, ac_cv_func_memcmp_clean, +[AC_TRY_RUN([ +main() +{ + char c0 = 0x40, c1 = 0x80, c2 = 0x81; + exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1); +} +], ac_cv_func_memcmp_clean=yes, ac_cv_func_memcmp_clean=no, +ac_cv_func_memcmp_clean=no)]) +test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" +AC_SUBST(LIBOBJS)dnl +]) + +AC_DEFUN(AC_FUNC_SELECT_ARGTYPES, +[AC_MSG_CHECKING([types of arguments for select()]) + AC_CACHE_VAL(ac_cv_func_select_arg234,dnl + [AC_CACHE_VAL(ac_cv_func_select_arg1,dnl + [AC_CACHE_VAL(ac_cv_func_select_arg5,dnl + [for ac_cv_func_select_arg234 in 'fd_set *' 'int *' 'void *'; do + for ac_cv_func_select_arg1 in 'int' 'size_t' 'unsigned long' 'unsigned'; do + for ac_cv_func_select_arg5 in 'struct timeval *' 'const struct timeval *'; do + AC_TRY_COMPILE(dnl +[#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +extern select ($ac_cv_func_select_arg1,$ac_cv_func_select_arg234,$ac_cv_func_select_arg234,$ac_cv_func_select_arg234,$ac_cv_func_select_arg5);],,dnl + [ac_not_found=no ; break 3],ac_not_found=yes) + done + done + done + ])dnl AC_CACHE_VAL + ])dnl AC_CACHE_VAL + ])dnl AC_CACHE_VAL + if test "$ac_not_found" = yes; then + ac_cv_func_select_arg1=int + ac_cv_func_select_arg234='int *' + ac_cv_func_select_arg5='struct timeval *' + fi + AC_MSG_RESULT([$ac_cv_func_select_arg1,$ac_cv_func_select_arg234,$ac_cv_func_select_arg5]) + AC_DEFINE_UNQUOTED(SELECT_TYPE_ARG1,$ac_cv_func_select_arg1) + AC_DEFINE_UNQUOTED(SELECT_TYPE_ARG234,($ac_cv_func_select_arg234)) + AC_DEFINE_UNQUOTED(SELECT_TYPE_ARG5,($ac_cv_func_select_arg5)) +]) + + +dnl ### Checks for structure members + + +AC_DEFUN(AC_HEADER_TIME, +[AC_CACHE_CHECK([whether time.h and sys/time.h may both be included], + ac_cv_header_time, +[AC_TRY_COMPILE([#include +#include +#include ], +[struct tm *tp;], ac_cv_header_time=yes, ac_cv_header_time=no)]) +if test $ac_cv_header_time = yes; then + AC_DEFINE(TIME_WITH_SYS_TIME) +fi +]) + +AC_DEFUN(AC_STRUCT_TM, +[AC_CACHE_CHECK([whether struct tm is in sys/time.h or time.h], + ac_cv_struct_tm, +[AC_TRY_COMPILE([#include +#include ], +[struct tm *tp; tp->tm_sec;], + ac_cv_struct_tm=time.h, ac_cv_struct_tm=sys/time.h)]) +if test $ac_cv_struct_tm = sys/time.h; then + AC_DEFINE(TM_IN_SYS_TIME) +fi +]) + +AC_DEFUN(AC_STRUCT_TIMEZONE, +[AC_REQUIRE([AC_STRUCT_TM])dnl +AC_CACHE_CHECK([for tm_zone in struct tm], ac_cv_struct_tm_zone, +[AC_TRY_COMPILE([#include +#include <$ac_cv_struct_tm>], [struct tm tm; tm.tm_zone;], + ac_cv_struct_tm_zone=yes, ac_cv_struct_tm_zone=no)]) +if test "$ac_cv_struct_tm_zone" = yes; then + AC_DEFINE(HAVE_TM_ZONE) +else + AC_CACHE_CHECK(for tzname, ac_cv_var_tzname, +[AC_TRY_LINK( +changequote(<<, >>)dnl +<<#include +#ifndef tzname /* For SGI. */ +extern char *tzname[]; /* RS6000 and others reject char **tzname. */ +#endif>>, +changequote([, ])dnl +[atoi(*tzname);], ac_cv_var_tzname=yes, ac_cv_var_tzname=no)]) + if test $ac_cv_var_tzname = yes; then + AC_DEFINE(HAVE_TZNAME) + fi +fi +]) + +AC_DEFUN(AC_STRUCT_ST_BLOCKS, +[AC_CACHE_CHECK([for st_blocks in struct stat], ac_cv_struct_st_blocks, +[AC_TRY_COMPILE([#include +#include ], [struct stat s; s.st_blocks;], +ac_cv_struct_st_blocks=yes, ac_cv_struct_st_blocks=no)]) +if test $ac_cv_struct_st_blocks = yes; then + AC_DEFINE(HAVE_ST_BLOCKS) +else + LIBOBJS="$LIBOBJS fileblocks.${ac_objext}" +fi +AC_SUBST(LIBOBJS)dnl +]) + +AC_DEFUN(AC_STRUCT_ST_BLKSIZE, +[AC_CACHE_CHECK([for st_blksize in struct stat], ac_cv_struct_st_blksize, +[AC_TRY_COMPILE([#include +#include ], [struct stat s; s.st_blksize;], +ac_cv_struct_st_blksize=yes, ac_cv_struct_st_blksize=no)]) +if test $ac_cv_struct_st_blksize = yes; then + AC_DEFINE(HAVE_ST_BLKSIZE) +fi +]) + +AC_DEFUN(AC_STRUCT_ST_RDEV, +[AC_CACHE_CHECK([for st_rdev in struct stat], ac_cv_struct_st_rdev, +[AC_TRY_COMPILE([#include +#include ], [struct stat s; s.st_rdev;], +ac_cv_struct_st_rdev=yes, ac_cv_struct_st_rdev=no)]) +if test $ac_cv_struct_st_rdev = yes; then + AC_DEFINE(HAVE_ST_RDEV) +fi +]) + + +dnl ### Checks for compiler characteristics + + +AC_DEFUN(AC_C_CROSS, +[AC_OBSOLETE([$0], [; it has been merged into AC_PROG_CC])]) + +AC_DEFUN(AC_C_CHAR_UNSIGNED, +[AC_CACHE_CHECK(whether char is unsigned, ac_cv_c_char_unsigned, +[if test "$GCC" = yes; then + # GCC predefines this symbol on systems where it applies. +AC_EGREP_CPP(yes, +[#ifdef __CHAR_UNSIGNED__ + yes +#endif +], ac_cv_c_char_unsigned=yes, ac_cv_c_char_unsigned=no) +else +AC_TRY_RUN( +[/* volatile prevents gcc2 from optimizing the test away on sparcs. */ +#if !defined(__STDC__) || __STDC__ != 1 +#define volatile +#endif +main() { + volatile char c = 255; exit(c < 0); +}], ac_cv_c_char_unsigned=yes, ac_cv_c_char_unsigned=no) +fi]) +if test $ac_cv_c_char_unsigned = yes && test "$GCC" != yes; then + AC_DEFINE(__CHAR_UNSIGNED__) +fi +]) + +AC_DEFUN(AC_C_LONG_DOUBLE, +[AC_CACHE_CHECK(for long double, ac_cv_c_long_double, +[if test "$GCC" = yes; then + ac_cv_c_long_double=yes +else +AC_TRY_RUN([int main() { +/* The Stardent Vistra knows sizeof(long double), but does not support it. */ +long double foo = 0.0; +/* On Ultrix 4.3 cc, long double is 4 and double is 8. */ +exit(sizeof(long double) < sizeof(double)); }], +ac_cv_c_long_double=yes, ac_cv_c_long_double=no) +fi]) +if test $ac_cv_c_long_double = yes; then + AC_DEFINE(HAVE_LONG_DOUBLE) +fi +]) + +AC_DEFUN(AC_INT_16_BITS, +[AC_OBSOLETE([$0], [; instead use AC_CHECK_SIZEOF(int)])dnl +AC_MSG_CHECKING(whether int is 16 bits) +AC_TRY_RUN([main() { exit(sizeof(int) != 2); }], + [AC_MSG_RESULT(yes) + AC_DEFINE(INT_16_BITS)], AC_MSG_RESULT(no)) +]) + +AC_DEFUN(AC_LONG_64_BITS, +[AC_OBSOLETE([$0], [; instead use AC_CHECK_SIZEOF(long)])dnl +AC_MSG_CHECKING(whether long int is 64 bits) +AC_TRY_RUN([main() { exit(sizeof(long int) != 8); }], + [AC_MSG_RESULT(yes) + AC_DEFINE(LONG_64_BITS)], AC_MSG_RESULT(no)) +]) + +AC_DEFUN(AC_C_BIGENDIAN, +[AC_CACHE_CHECK(whether byte ordering is bigendian, ac_cv_c_bigendian, +[ac_cv_c_bigendian=unknown +# See if sys/param.h defines the BYTE_ORDER macro. +AC_TRY_COMPILE([#include +#include ], [ +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif], [# It does; now see whether it defined to BIG_ENDIAN or not. +AC_TRY_COMPILE([#include +#include ], [ +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif], ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no)]) +if test $ac_cv_c_bigendian = unknown; then +AC_TRY_RUN([main () { + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long l; + char c[sizeof (long)]; + } u; + u.l = 1; + exit (u.c[sizeof (long) - 1] == 1); +}], ac_cv_c_bigendian=no, ac_cv_c_bigendian=yes) +fi]) +if test $ac_cv_c_bigendian = yes; then + AC_DEFINE(WORDS_BIGENDIAN) +fi +]) + +dnl Do nothing if the compiler accepts the inline keyword. +dnl Otherwise define inline to __inline__ or __inline if one of those work, +dnl otherwise define inline to be empty. +AC_DEFUN(AC_C_INLINE, +[AC_CACHE_CHECK([for inline], ac_cv_c_inline, +[ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + AC_TRY_COMPILE(, [} $ac_kw foo() {], [ac_cv_c_inline=$ac_kw; break]) +done +]) +case "$ac_cv_c_inline" in + inline | yes) ;; + no) AC_DEFINE(inline, ) ;; + *) AC_DEFINE_UNQUOTED(inline, $ac_cv_c_inline) ;; +esac +]) + +AC_DEFUN(AC_C_CONST, +[dnl This message is consistent in form with the other checking messages, +dnl and with the result message. +AC_CACHE_CHECK([for working const], ac_cv_c_const, +[AC_TRY_COMPILE(, +changequote(<<, >>)dnl +<< +/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* NEC SVR4.0.2 mips cc rejects this. */ +struct point {int x, y;}; +static struct point const zero = {0,0}; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} +>>, +changequote([, ])dnl +ac_cv_c_const=yes, ac_cv_c_const=no)]) +if test $ac_cv_c_const = no; then + AC_DEFINE(const, ) +fi +]) + +AC_DEFUN(AC_C_STRINGIZE, [ +AC_REQUIRE([AC_PROG_CPP]) +AC_MSG_CHECKING([for preprocessor stringizing operator]) +AC_CACHE_VAL(ac_cv_c_stringize, +AC_EGREP_CPP([#teststring],[ +#define x(y) #y + +char *s = x(teststring); +], ac_cv_c_stringize=no, ac_cv_c_stringize=yes)) +if test "${ac_cv_c_stringize}" = yes +then + AC_DEFINE(HAVE_STRINGIZE) +fi +AC_MSG_RESULT([${ac_cv_c_stringize}]) +])dnl + +define(AC_ARG_ARRAY, +[errprint(__file__:__line__: [$0] has been removed; don't do unportable things with arguments +)m4exit(4)]) + +dnl Check the object extension used by the compiler: typically .o or +dnl .obj. If this is called, some other behaviour will change, +dnl determined by ac_objext. +AC_DEFUN(AC_OBJEXT, +[AC_MSG_CHECKING([for object suffix]) +AC_CACHE_VAL(ac_cv_objext, +[rm -f conftest* +echo 'int i = 1;' > conftest.$ac_ext +if AC_TRY_EVAL(ac_compile); then + for ac_file in conftest.*; do + case $ac_file in + *.c) ;; + *) ac_cv_objext=`echo $ac_file | sed -e s/conftest.//` ;; + esac + done +else + AC_MSG_ERROR([installation or configuration problem; compiler does not work]) +fi +rm -f conftest*]) +AC_MSG_RESULT($ac_cv_objext) +OBJEXT=$ac_cv_objext +ac_objext=$ac_cv_objext +AC_SUBST(OBJEXT)]) + +dnl Determine the linker flags (e.g. `-L' and `-l') for the Fortran 77 +dnl intrinsic and run-time libraries that are required to successfully +dnl link a Fortran 77 program or shared library. The output variable +dnl FLIBS is set to these flags. +dnl +dnl This macro is intended to be used in those situations when it is +dnl necessary to mix, e.g. C++ and Fortran 77, source code into a single +dnl program or shared library. +dnl +dnl For example, if object files from a C++ and Fortran 77 compiler must +dnl be linked together, then the C++ compiler/linker must be used for +dnl linking (since special C++-ish things need to happen at link time +dnl like calling global constructors, instantiating templates, enabling +dnl exception support, etc.). +dnl +dnl However, the Fortran 77 intrinsic and run-time libraries must be +dnl linked in as well, but the C++ compiler/linker doesn't know how to +dnl add these Fortran 77 libraries. Hence, the macro +dnl `AC_F77_LIBRARY_LDFLAGS' was created to determine these Fortran 77 +dnl libraries. +dnl +dnl This macro was packaged in its current form by Matthew D. Langston +dnl . However, nearly all of this macro +dnl came from the `OCTAVE_FLIBS' macro in `octave-2.0.13/aclocal.m4', +dnl and full credit should go to John W. Eaton for writing this +dnl extremely useful macro. Thank you John. +dnl +dnl AC_F77_LIBRARY_LDFLAGS() +AC_DEFUN(AC_F77_LIBRARY_LDFLAGS, +[AC_MSG_CHECKING([for Fortran 77 libraries]) +AC_REQUIRE([AC_PROG_F77]) +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_CACHE_VAL(ac_cv_flibs, +[changequote(, )dnl +dnl Write a minimal program and compile it with -v. I don't know what +dnl to do if your compiler doesn't have -v... +echo " END" > conftest.f +foutput=`${F77} -v -o conftest conftest.f 2>&1` +dnl +dnl The easiest thing to do for xlf output is to replace all the commas +dnl with spaces. Try to only do that if the output is really from xlf, +dnl since doing that causes problems on other systems. +dnl +xlf_p=`echo $foutput | grep xlfentry` +if test -n "$xlf_p"; then + foutput=`echo $foutput | sed 's/,/ /g'` +fi +dnl +ld_run_path=`echo $foutput | \ + sed -n -e 's/^.*LD_RUN_PATH *= *\([^ ]*\).*/\1/p'` +dnl +dnl We are only supposed to find this on Solaris systems... +dnl Uh, the run path should be absolute, shouldn't it? +dnl +case "$ld_run_path" in + /*) + if test "$ac_cv_prog_gcc" = yes; then + ld_run_path="-Xlinker -R -Xlinker $ld_run_path" + else + ld_run_path="-R $ld_run_path" + fi + ;; + *) + ld_run_path= + ;; +esac +dnl +flibs= +lflags= +dnl +dnl If want_arg is set, we know we want the arg to be added to the list, +dnl so we don't have to examine it. +dnl +want_arg= +dnl +for arg in $foutput; do + old_want_arg=$want_arg + want_arg= +dnl +dnl None of the options that take arguments expect the argument to +dnl start with a -, so pretend we didn't see anything special. +dnl + if test -n "$old_want_arg"; then + case "$arg" in + -*) + old_want_arg= + ;; + esac + fi + case "$old_want_arg" in + '') + case $arg in + /*.a) + exists=false + for f in $lflags; do + if test x$arg = x$f; then + exists=true + fi + done + if $exists; then + arg= + else + lflags="$lflags $arg" + fi + ;; + -bI:*) + exists=false + for f in $lflags; do + if test x$arg = x$f; then + exists=true + fi + done + if $exists; then + arg= + else + if test "$ac_cv_prog_gcc" = yes; then + lflags="$lflags -Xlinker $arg" + else + lflags="$lflags $arg" + fi + fi + ;; + -lang* | -lcrt0.o | -lc | -lgcc) + arg= + ;; + -[lLR]) + want_arg=$arg + arg= + ;; + -[lLR]*) + exists=false + for f in $lflags; do + if test x$arg = x$f; then + exists=true + fi + done + if $exists; then + arg= + else + case "$arg" in + -lkernel32) + case "$canonical_host_type" in + *-*-cygwin*) + arg= + ;; + *) + lflags="$lflags $arg" + ;; + esac + ;; + -lm) + ;; + *) + lflags="$lflags $arg" + ;; + esac + fi + ;; + -u) + want_arg=$arg + arg= + ;; + -Y) + want_arg=$arg + arg= + ;; + *) + arg= + ;; + esac + ;; + -[lLR]) + arg="$old_want_arg $arg" + ;; + -u) + arg="-u $arg" + ;; + -Y) +dnl +dnl Should probably try to ensure unique directory options here too. +dnl This probably only applies to Solaris systems, and then will only +dnl work with gcc... +dnl + arg=`echo $arg | sed -e 's%^P,%%'` + SAVE_IFS=$IFS + IFS=: + list= + for elt in $arg; do + list="$list -L$elt" + done + IFS=$SAVE_IFS + arg="$list" + ;; + esac +dnl + if test -n "$arg"; then + flibs="$flibs $arg" + fi +done +if test -n "$ld_run_path"; then + flibs_result="$ld_run_path $flibs" +else + flibs_result="$flibs" +fi +changequote([, ])dnl +ac_cv_flibs="$flibs_result"]) +FLIBS="$ac_cv_flibs" +AC_SUBST(FLIBS)dnl +AC_MSG_RESULT($FLIBS) +]) + + +dnl ### Checks for operating system services + + +AC_DEFUN(AC_SYS_INTERPRETER, +[# Pull the hash mark out of the macro call to avoid m4 problems. +ac_msg="whether #! works in shell scripts" +AC_CACHE_CHECK($ac_msg, ac_cv_sys_interpreter, +[echo '#! /bin/cat +exit 69 +' > conftest +chmod u+x conftest +(SHELL=/bin/sh; export SHELL; ./conftest >/dev/null) +if test $? -ne 69; then + ac_cv_sys_interpreter=yes +else + ac_cv_sys_interpreter=no +fi +rm -f conftest]) +interpval="$ac_cv_sys_interpreter" +]) + +define(AC_HAVE_POUNDBANG, +[errprint(__file__:__line__: [$0 has been replaced by AC_SYS_INTERPRETER, taking no arguments +])m4exit(4)]) + +AC_DEFUN(AC_SYS_LONG_FILE_NAMES, +[AC_CACHE_CHECK(for long file names, ac_cv_sys_long_file_names, +[ac_cv_sys_long_file_names=yes +# Test for long file names in all the places we know might matter: +# . the current directory, where building will happen +# $prefix/lib where we will be installing things +# $exec_prefix/lib likewise +# eval it to expand exec_prefix. +# $TMPDIR if set, where it might want to write temporary files +# if $TMPDIR is not set: +# /tmp where it might want to write temporary files +# /var/tmp likewise +# /usr/tmp likewise +if test -n "$TMPDIR" && test -d "$TMPDIR" && test -w "$TMPDIR"; then + ac_tmpdirs="$TMPDIR" +else + ac_tmpdirs='/tmp /var/tmp /usr/tmp' +fi +for ac_dir in . $ac_tmpdirs `eval echo $prefix/lib $exec_prefix/lib` ; do + test -d $ac_dir || continue + test -w $ac_dir || continue # It is less confusing to not echo anything here. + (echo 1 > $ac_dir/conftest9012345) 2>/dev/null + (echo 2 > $ac_dir/conftest9012346) 2>/dev/null + val=`cat $ac_dir/conftest9012345 2>/dev/null` + if test ! -f $ac_dir/conftest9012345 || test "$val" != 1; then + ac_cv_sys_long_file_names=no + rm -f $ac_dir/conftest9012345 $ac_dir/conftest9012346 2>/dev/null + break + fi + rm -f $ac_dir/conftest9012345 $ac_dir/conftest9012346 2>/dev/null +done]) +if test $ac_cv_sys_long_file_names = yes; then + AC_DEFINE(HAVE_LONG_FILE_NAMES) +fi +]) + +AC_DEFUN(AC_SYS_RESTARTABLE_SYSCALLS, +[AC_CACHE_CHECK(for restartable system calls, ac_cv_sys_restartable_syscalls, +[AC_TRY_RUN( +[/* Exit 0 (true) if wait returns something other than -1, + i.e. the pid of the child, which means that wait was restarted + after getting the signal. */ +#include +#include +ucatch (isig) { } +main () { + int i = fork (), status; + if (i == 0) { sleep (3); kill (getppid (), SIGINT); sleep (3); exit (0); } + signal (SIGINT, ucatch); + status = wait(&i); + if (status == -1) wait(&i); + exit (status == -1); +} +], ac_cv_sys_restartable_syscalls=yes, ac_cv_sys_restartable_syscalls=no)]) +if test $ac_cv_sys_restartable_syscalls = yes; then + AC_DEFINE(HAVE_RESTARTABLE_SYSCALLS) +fi +]) + +AC_DEFUN(AC_PATH_X, +[AC_REQUIRE_CPP()dnl Set CPP; we run AC_PATH_X_DIRECT conditionally. +# If we find X, set shell vars x_includes and x_libraries to the +# paths, otherwise set no_x=yes. +# Uses ac_ vars as temps to allow command line to override cache and checks. +# --without-x overrides everything else, but does not touch the cache. +AC_MSG_CHECKING(for X) + +AC_ARG_WITH(x, [ --with-x use the X Window System]) +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then + # Both variables are already set. + have_x=yes + else +AC_CACHE_VAL(ac_cv_have_x, +[# One or both of the vars are not set, and there is no cached value. +ac_x_includes=NO ac_x_libraries=NO +AC_PATH_X_XMKMF +AC_PATH_X_DIRECT +if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then + # Didn't find X anywhere. Cache the known absence of X. + ac_cv_have_x="have_x=no" +else + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries" +fi])dnl + fi + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + AC_MSG_RESULT($have_x) + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$x_includes ac_x_libraries=$x_libraries" + AC_MSG_RESULT([libraries $x_libraries, headers $x_includes]) +fi +]) + +dnl Internal subroutine of AC_PATH_X. +dnl Set ac_x_includes and/or ac_x_libraries. +AC_DEFUN(AC_PATH_X_XMKMF, +[rm -fr conftestdir +if mkdir conftestdir; then + cd conftestdir + # Make sure to not put "make" in the Imakefile rules, since we grep it out. + cat > Imakefile <<'EOF' +acfindx: + @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"' +EOF + if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering...", which would confuse us. + eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl; do + if test ! -f $ac_im_usrlibdir/libX11.$ac_extension && + test -f $ac_im_libdir/libX11.$ac_extension; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case "$ac_im_incroot" in + /usr/include) ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;; + esac + case "$ac_im_usrlibdir" in + /usr/lib | /lib) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;; + esac + fi + cd .. + rm -fr conftestdir +fi +]) + +dnl Internal subroutine of AC_PATH_X. +dnl Set ac_x_includes and/or ac_x_libraries. +AC_DEFUN(AC_PATH_X_DIRECT, +[if test "$ac_x_includes" = NO; then + # Guess where to find include files, by looking for this one X11 .h file. + test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h + + # First, try using that file with no special directory specified. +AC_TRY_CPP([#include <$x_direct_test_include>], +[# We can compile using X headers with no special include directory. +ac_x_includes=], +[# Look for the header file in a standard set of common directories. +# Check X11 before X11Rn because it is often a symlink to the current release. + for ac_dir in \ + /usr/X11/include \ + /usr/X11R6/include \ + /usr/X11R5/include \ + /usr/X11R4/include \ + \ + /usr/include/X11 \ + /usr/include/X11R6 \ + /usr/include/X11R5 \ + /usr/include/X11R4 \ + \ + /usr/local/X11/include \ + /usr/local/X11R6/include \ + /usr/local/X11R5/include \ + /usr/local/X11R4/include \ + \ + /usr/local/include/X11 \ + /usr/local/include/X11R6 \ + /usr/local/include/X11R5 \ + /usr/local/include/X11R4 \ + \ + /usr/X386/include \ + /usr/x386/include \ + /usr/XFree86/include/X11 \ + \ + /usr/include \ + /usr/local/include \ + /usr/unsupported/include \ + /usr/athena/include \ + /usr/local/x11r5/include \ + /usr/lpp/Xamples/include \ + \ + /usr/openwin/include \ + /usr/openwin/share/include \ + ; \ + do + if test -r "$ac_dir/$x_direct_test_include"; then + ac_x_includes=$ac_dir + break + fi + done]) +fi # $ac_x_includes = NO + +if test "$ac_x_libraries" = NO; then + # Check for the libraries. + + test -z "$x_direct_test_library" && x_direct_test_library=Xt + test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc + + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS="$LIBS" + LIBS="-l$x_direct_test_library $LIBS" +AC_TRY_LINK(, [${x_direct_test_function}()], +[LIBS="$ac_save_LIBS" +# We can link X programs with no special library path. +ac_x_libraries=], +[LIBS="$ac_save_LIBS" +# First see if replacing the include by lib works. +# Check X11 before X11Rn because it is often a symlink to the current release. +for ac_dir in `echo "$ac_x_includes" | sed s/include/lib/` \ + /usr/X11/lib \ + /usr/X11R6/lib \ + /usr/X11R5/lib \ + /usr/X11R4/lib \ + \ + /usr/lib/X11 \ + /usr/lib/X11R6 \ + /usr/lib/X11R5 \ + /usr/lib/X11R4 \ + \ + /usr/local/X11/lib \ + /usr/local/X11R6/lib \ + /usr/local/X11R5/lib \ + /usr/local/X11R4/lib \ + \ + /usr/local/lib/X11 \ + /usr/local/lib/X11R6 \ + /usr/local/lib/X11R5 \ + /usr/local/lib/X11R4 \ + \ + /usr/X386/lib \ + /usr/x386/lib \ + /usr/XFree86/lib/X11 \ + \ + /usr/lib \ + /usr/local/lib \ + /usr/unsupported/lib \ + /usr/athena/lib \ + /usr/local/x11r5/lib \ + /usr/lpp/Xamples/lib \ + /lib/usr/lib/X11 \ + \ + /usr/openwin/lib \ + /usr/openwin/share/lib \ + ; \ +do +dnl Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl; do + if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done]) +fi # $ac_x_libraries = NO +]) + +dnl Find additional X libraries, magic flags, etc. +AC_DEFUN(AC_PATH_XTRA, +[AC_REQUIRE([AC_PATH_X])dnl +if test "$no_x" = yes; then + # Not all programs may use this symbol, but it does not hurt to define it. + AC_DEFINE(X_DISPLAY_MISSING) + X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= +else + if test -n "$x_includes"; then + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + # It would also be nice to do this for all -L options, not just this one. + if test -n "$x_libraries"; then + X_LIBS="$X_LIBS -L$x_libraries" +dnl FIXME banish uname from this macro! + # For Solaris; some versions of Sun CC require a space after -R and + # others require no space. Words are not sufficient . . . . + case "`(uname -sr) 2>/dev/null`" in + "SunOS 5"*) + AC_MSG_CHECKING(whether -R must be followed by a space) + ac_xsave_LIBS="$LIBS"; LIBS="$LIBS -R$x_libraries" + AC_TRY_LINK(, , ac_R_nospace=yes, ac_R_nospace=no) + if test $ac_R_nospace = yes; then + AC_MSG_RESULT(no) + X_LIBS="$X_LIBS -R$x_libraries" + else + LIBS="$ac_xsave_LIBS -R $x_libraries" + AC_TRY_LINK(, , ac_R_space=yes, ac_R_space=no) + if test $ac_R_space = yes; then + AC_MSG_RESULT(yes) + X_LIBS="$X_LIBS -R $x_libraries" + else + AC_MSG_RESULT(neither works) + fi + fi + LIBS="$ac_xsave_LIBS" + esac + fi + + # Check for system-dependent libraries X programs must link with. + # Do this before checking for the system-independent R6 libraries + # (-lICE), since we may need -lsocket or whatever for X linking. + + if test "$ISC" = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" + else + # Martyn.Johnson@cl.cam.ac.uk says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And karl@cs.umb.edu says + # the Alpha needs dnet_stub (dnet does not exist). + AC_CHECK_LIB(dnet, dnet_ntoa, [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"]) + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + AC_CHECK_LIB(dnet_stub, dnet_ntoa, + [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"]) + fi + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # chad@anasazi.com says the Pyramis MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to dickey@clark.net. + AC_CHECK_FUNC(gethostbyname) + if test $ac_cv_func_gethostbyname = no; then + AC_CHECK_LIB(nsl, gethostbyname, X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl") + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says simon@lia.di.epfl.ch: it contains + # gethostby* variants that don't use the nameserver (or something). + # -lsocket must be given before -lnsl if both are needed. + # We assume that if connect needs -lnsl, so does gethostbyname. + AC_CHECK_FUNC(connect) + if test $ac_cv_func_connect = no; then + AC_CHECK_LIB(socket, connect, X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS", , + $X_EXTRA_LIBS) + fi + + # gomez@mi.uni-erlangen.de says -lposix is necessary on A/UX. + AC_CHECK_FUNC(remove) + if test $ac_cv_func_remove = no; then + AC_CHECK_LIB(posix, remove, X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix") + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + AC_CHECK_FUNC(shmat) + if test $ac_cv_func_shmat = no; then + AC_CHECK_LIB(ipc, shmat, X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc") + fi + fi + + # Check for libraries that X11R6 Xt/Xaw programs need. + ac_save_LDFLAGS="$LDFLAGS" + test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" + # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to + # check for ICE first), but we must link in the order -lSM -lICE or + # we get undefined symbols. So assume we have SM if we have ICE. + # These have to be linked with before -lX11, unlike the other + # libraries we check for below, so use a different variable. + # --interran@uluru.Stanford.EDU, kb@cs.umb.edu. + AC_CHECK_LIB(ICE, IceConnectionNumber, + [X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE"], , $X_EXTRA_LIBS) + LDFLAGS="$ac_save_LDFLAGS" + +fi +AC_SUBST(X_CFLAGS)dnl +AC_SUBST(X_PRE_LIBS)dnl +AC_SUBST(X_LIBS)dnl +AC_SUBST(X_EXTRA_LIBS)dnl +]) + +dnl The old Cygwin32 macro is deprecated. +AC_DEFUN(AC_CYGWIN32, +[AC_OBSOLETE([$0], [; instead use AC_CYGWIN])dnl +AC_CYGWIN]) + +dnl Check for Cygwin. This is a way to set the right value for +dnl EXEEXT. +AC_DEFUN(AC_CYGWIN, +[AC_CACHE_CHECK(for Cygwin environment, ac_cv_cygwin, +[AC_TRY_COMPILE(,[ +#ifndef __CYGWIN__ +#define __CYGWIN__ __CYGWIN32__ +#endif +return __CYGWIN__;], +ac_cv_cygwin=yes, ac_cv_cygwin=no) +rm -f conftest*]) +CYGWIN= +test "$ac_cv_cygwin" = yes && CYGWIN=yes]) + +dnl Check for mingw32. This is another way to set the right value for +dnl EXEEXT. +AC_DEFUN(AC_MINGW32, +[AC_CACHE_CHECK(for mingw32 environment, ac_cv_mingw32, +[AC_TRY_COMPILE(,[return __MINGW32__;], +ac_cv_mingw32=yes, ac_cv_mingw32=no) +rm -f conftest*]) +MINGW32= +test "$ac_cv_mingw32" = yes && MINGW32=yes]) + +dnl Check for the extension used for executables. This knows that we +dnl add .exe for Cygwin or mingw32. Otherwise, it compiles a test +dnl executable. If this is called, the executable extensions will be +dnl automatically used by link commands run by the configure script. +AC_DEFUN(AC_EXEEXT, +[AC_REQUIRE([AC_CYGWIN]) +AC_REQUIRE([AC_MINGW32]) +AC_MSG_CHECKING([for executable suffix]) +AC_CACHE_VAL(ac_cv_exeext, +[if test "$CYGWIN" = yes || test "$MINGW32" = yes; then + ac_cv_exeext=.exe +else + rm -f conftest* + echo 'int main () { return 0; }' > conftest.$ac_ext + ac_cv_exeext= + if AC_TRY_EVAL(ac_link); then + for file in conftest.*; do + case $file in + *.c | *.o | *.obj) ;; + *) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;; + esac + done + else + AC_MSG_ERROR([installation or configuration problem: compiler cannot create executables.]) + fi + rm -f conftest* + test x"${ac_cv_exeext}" = x && ac_cv_exeext=no +fi]) +EXEEXT="" +test x"${ac_cv_exeext}" != xno && EXEEXT=${ac_cv_exeext} +AC_MSG_RESULT(${ac_cv_exeext}) +dnl Setting ac_exeext will implicitly change the ac_link command. +ac_exeext=$EXEEXT +AC_SUBST(EXEEXT)]) + + +dnl ### Checks for UNIX variants +dnl These are kludges which should be replaced by a single POSIX check. +dnl They aren't cached, to discourage their use. + + +AC_DEFUN(AC_AIX, +[AC_BEFORE([$0], [AC_TRY_COMPILE])dnl +AC_BEFORE([$0], [AC_TRY_RUN])dnl +AC_MSG_CHECKING(for AIX) +AC_EGREP_CPP(yes, +[#ifdef _AIX + yes +#endif +], [AC_MSG_RESULT(yes); AC_DEFINE(_ALL_SOURCE)], AC_MSG_RESULT(no)) +]) + +AC_DEFUN(AC_MINIX, +[AC_BEFORE([$0], [AC_TRY_COMPILE])dnl +AC_BEFORE([$0], [AC_TRY_RUN])dnl +AC_CHECK_HEADER(minix/config.h, MINIX=yes, MINIX=) +if test "$MINIX" = yes; then + AC_DEFINE(_POSIX_SOURCE) + AC_DEFINE(_POSIX_1_SOURCE, 2) + AC_DEFINE(_MINIX) +fi +]) + +AC_DEFUN(AC_ISC_POSIX, +[AC_REQUIRE([AC_PROG_CC])dnl +AC_BEFORE([$0], [AC_TRY_COMPILE])dnl +AC_BEFORE([$0], [AC_TRY_RUN])dnl +AC_MSG_CHECKING(for POSIXized ISC) +if test -d /etc/conf/kconfig.d && + grep _POSIX_VERSION [/usr/include/sys/unistd.h] >/dev/null 2>&1 +then + AC_MSG_RESULT(yes) + ISC=yes # If later tests want to check for ISC. + AC_DEFINE(_POSIX_SOURCE) + if test "$GCC" = yes; then + CC="$CC -posix" + else + CC="$CC -Xp" + fi +else + AC_MSG_RESULT(no) + ISC= +fi +]) + +AC_DEFUN(AC_XENIX_DIR, +[AC_OBSOLETE([$0], [; instead use AC_HEADER_DIRENT])dnl +AC_REQUIRE([AC_DIR_HEADER])dnl +AC_MSG_CHECKING(for Xenix) +AC_EGREP_CPP(yes, +[#if defined(M_XENIX) && !defined(M_UNIX) + yes +#endif +], [AC_MSG_RESULT(yes); XENIX=yes], [AC_MSG_RESULT(no); XENIX=]) +if test "$XENIX" = yes; then + # Make sure -ldir precedes -lx. + test $ac_header_dirent = dirent.h && LIBS="-ldir $LIBS" + LIBS="$LIBS -lx" +fi +]) + +AC_DEFUN(AC_DYNIX_SEQ, +[AC_OBSOLETE([$0], [; instead use AC_FUNC_GETMNTENT])dnl +AC_CHECK_LIB(seq, getmntent, LIBS="-lseq $LIBS") +]) + +AC_DEFUN(AC_IRIX_SUN, +[AC_OBSOLETE([$0], [; instead use AC_FUNC_GETMNTENT or AC_CHECK_LIB(sun, getpwnam)])dnl +AC_CHECK_LIB(sun, getmntent, LIBS="-lsun $LIBS") +]) + +AC_DEFUN(AC_SCO_INTL, +[AC_OBSOLETE([$0], [; instead use AC_FUNC_STRFTIME])dnl +AC_CHECK_LIB(intl, strftime, LIBS="-lintl $LIBS") +]) diff --git a/build/autoconf/alloc.m4 b/build/autoconf/alloc.m4 new file mode 100644 index 0000000000..5a739a420c --- /dev/null +++ b/build/autoconf/alloc.m4 @@ -0,0 +1,57 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +dnl Check for the existence of various allocation headers/functions +AC_DEFUN([MOZ_CHECK_ALLOCATOR],[ + +MALLOC_HEADERS="malloc.h malloc_np.h malloc/malloc.h sys/malloc.h" +MALLOC_H= + +for file in $MALLOC_HEADERS; do + MOZ_CHECK_HEADER($file, [MALLOC_H=$file]) + if test "$MALLOC_H" != ""; then + AC_DEFINE_UNQUOTED(MALLOC_H, <$MALLOC_H>) + break + fi +done + +MALLOC_USABLE_SIZE_CONST_PTR=const +if test -n "$HAVE_MALLOC_H"; then + AC_CACHE_CHECK([whether malloc_usable_size definition can use const argument], + moz_cv_malloc_usable_size_constness, + [AC_TRY_COMPILE([#include + #include + size_t malloc_usable_size(const void *ptr);], + [return malloc_usable_size(0);], + [moz_cv_malloc_usable_size_constness=yes], + [moz_cv_malloc_usable_size_constness=no])]) + if test "$moz_cv_malloc_usable_size_constness" = no ; then + MALLOC_USABLE_SIZE_CONST_PTR= + fi +fi +AC_DEFINE_UNQUOTED([MALLOC_USABLE_SIZE_CONST_PTR],[$MALLOC_USABLE_SIZE_CONST_PTR]) + + +dnl In newer bionic headers, valloc is built but not defined, +dnl so we check more carefully here. +AC_MSG_CHECKING([for valloc in malloc.h]) +AC_EGREP_HEADER(valloc, malloc.h, + AC_DEFINE(HAVE_VALLOC) + AC_MSG_RESULT([yes]), + AC_MSG_RESULT([no])) + +AC_MSG_CHECKING([for valloc in unistd.h]) +AC_EGREP_HEADER(valloc, unistd.h, + AC_DEFINE(HAVE_VALLOC) + AC_MSG_RESULT([yes]), + AC_MSG_RESULT([no])) + +AC_MSG_CHECKING([for _aligned_malloc in malloc.h]) +AC_EGREP_HEADER(_aligned_malloc, malloc.h, + AC_DEFINE(HAVE_ALIGNED_MALLOC) + AC_MSG_RESULT([yes]), + AC_MSG_RESULT([no])) + + +]) diff --git a/build/autoconf/altoptions.m4 b/build/autoconf/altoptions.m4 new file mode 100644 index 0000000000..3105de0065 --- /dev/null +++ b/build/autoconf/altoptions.m4 @@ -0,0 +1,72 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +dnl altoptions.m4 - An alternative way of specifying command-line options. +dnl These macros are needed to support a menu-based configurator. +dnl This file also includes the macro, AM_READ_MYCONFIG, for reading +dnl the 'myconfig.m4' file. + +dnl Send comments, improvements, bugs to Steve Lamm (slamm@netscape.com). + + +dnl MOZ_ARG_ENABLE_BOOL( NAME, HELP, IF-YES [, IF-NO [, ELSE]]) +dnl MOZ_ARG_DISABLE_BOOL( NAME, HELP, IF-NO [, IF-YES [, ELSE]]) +dnl MOZ_ARG_ENABLE_STRING( NAME, HELP, IF-SET [, ELSE]) +dnl MOZ_ARG_WITH_BOOL( NAME, HELP, IF-YES [, IF-NO [, ELSE]) +dnl MOZ_ARG_WITH_STRING( NAME, HELP, IF-SET [, ELSE]) +dnl MOZ_READ_MYCONFIG() - Read in 'myconfig.sh' file + +define([MOZ_DIVERSION_ARGS], 12) + +AC_DEFUN([MOZ_ARG],[dnl +AC_DIVERT_PUSH(MOZ_DIVERSION_ARGS)dnl + '$1', +AC_DIVERT_POP()dnl +]) +AC_DEFUN([MOZ_AC_ARG_ENABLE],[MOZ_ARG([--enable-]translit([$1],[_],[-]))AC_ARG_ENABLE([$1], [$2], [$3], [$4])]) +AC_DEFUN([MOZ_AC_ARG_WITH],[MOZ_ARG([--with-]translit([$1],[_],[-]))AC_ARG_WITH([$1], [$2], [$3], [$4])]) + +dnl MOZ_TWO_STRING_TEST(NAME, VAL, STR1, IF-STR1, STR2, IF-STR2 [, ELSE]) +AC_DEFUN([MOZ_TWO_STRING_TEST], +[if test "[$2]" = "[$3]"; then + ifelse([$4], , :, [$4]) + elif test "[$2]" = "[$5]"; then + ifelse([$6], , :, [$6]) + else + ifelse([$7], , + [AC_MSG_ERROR([Option, [$1], does not take an argument ([$2]).])], + [$7]) + fi]) + +dnl MOZ_ARG_ENABLE_BOOL(NAME, HELP, IF-YES [, IF-NO [, ELSE]]) +AC_DEFUN([MOZ_ARG_ENABLE_BOOL], +[MOZ_AC_ARG_ENABLE([$1], [$2], + [MOZ_TWO_STRING_TEST([$1], [$enableval], yes, [$3], no, [$4])], + [$5])]) + +dnl MOZ_ARG_DISABLE_BOOL(NAME, HELP, IF-NO [, IF-YES [, ELSE]]) +AC_DEFUN([MOZ_ARG_DISABLE_BOOL], +[MOZ_AC_ARG_ENABLE([$1], [$2], + [MOZ_TWO_STRING_TEST([$1], [$enableval], no, [$3], yes, [$4])], + [$5])]) + +dnl MOZ_ARG_ENABLE_STRING(NAME, HELP, IF-SET [, ELSE]) +AC_DEFUN([MOZ_ARG_ENABLE_STRING], +[MOZ_AC_ARG_ENABLE([$1], [$2], [$3], [$4])]) + +dnl MOZ_ARG_WITH_BOOL(NAME, HELP, IF-YES [, IF-NO [, ELSE]) +AC_DEFUN([MOZ_ARG_WITH_BOOL], +[MOZ_AC_ARG_WITH([$1], [$2], + [MOZ_TWO_STRING_TEST([$1], [$withval], yes, [$3], no, [$4])], + [$5])]) + +dnl MOZ_ARG_WITH_STRING(NAME, HELP, IF-SET [, ELSE]) +AC_DEFUN([MOZ_ARG_WITH_STRING], +[MOZ_AC_ARG_WITH([$1], [$2], [$3], [$4])]) + +dnl MOZ_READ_MYCONFIG() - Read in 'myconfig.sh' file +AC_DEFUN([MOZ_READ_MOZCONFIG], +[AC_REQUIRE([AC_INIT_BINSH])dnl +. $OLD_CONFIGURE_VARS +]) diff --git a/build/autoconf/android.m4 b/build/autoconf/android.m4 new file mode 100644 index 0000000000..95027ded9d --- /dev/null +++ b/build/autoconf/android.m4 @@ -0,0 +1,20 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +AC_DEFUN([MOZ_ANDROID_NDK], +[ + +case "$target" in +*-android*|*-linuxandroid*) + dnl $extra_android_flags will be set for us by Python configure. + dnl $_topsrcdir/build/android is a hack for versions of rustc < 1.68 + LDFLAGS="$extra_android_flags -L$_topsrcdir/build/android $LDFLAGS" + CPPFLAGS="$extra_android_flags $CPPFLAGS" + CFLAGS="-fno-short-enums $CFLAGS" + CXXFLAGS="-fno-short-enums $CXXFLAGS" + ASFLAGS="$extra_android_flags -DANDROID $ASFLAGS" + ;; +esac + +]) diff --git a/build/autoconf/arch.m4 b/build/autoconf/arch.m4 new file mode 100644 index 0000000000..45c671082d --- /dev/null +++ b/build/autoconf/arch.m4 @@ -0,0 +1,15 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +AC_DEFUN([MOZ_ARCH_OPTS], +[ +if test -n "$_ARM_FLAGS"; then + CFLAGS="$CFLAGS $_ARM_FLAGS" + CXXFLAGS="$CXXFLAGS $_ARM_FLAGS" + ASFLAGS="$ASFLAGS $_ARM_FLAGS" + if test -n "$_THUMB_FLAGS"; then + LDFLAGS="$LDFLAGS $_THUMB_FLAGS" + fi +fi +]) diff --git a/build/autoconf/autoconf.m4 b/build/autoconf/autoconf.m4 new file mode 100644 index 0000000000..dde59ab380 --- /dev/null +++ b/build/autoconf/autoconf.m4 @@ -0,0 +1,28 @@ +dnl Driver that loads the Autoconf macro files. +dnl Requires GNU m4. +dnl This file is part of Autoconf. +dnl Copyright (C) 1994 Free Software Foundation, Inc. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl Written by David MacKenzie. +dnl +include(acgeneral.m4)dnl +builtin(include, acspecific.m4)dnl +builtin(include, acoldnames.m4)dnl +dnl Do not sinclude acsite.m4 here, because it may not be installed +dnl yet when Autoconf is frozen. +dnl Do not sinclude ./aclocal.m4 here, to prevent it from being frozen. diff --git a/build/autoconf/autoconf.sh b/build/autoconf/autoconf.sh new file mode 100644 index 0000000000..ceb8a25b00 --- /dev/null +++ b/build/autoconf/autoconf.sh @@ -0,0 +1,158 @@ +#! @SHELL@ +# autoconf -- create `configure' using m4 macros +# Copyright (C) 1992, 1993, 1994, 1996 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# If given no args, create `configure' from template file `configure.in'. +# With one arg, create a configure script on standard output from +# the given template file. + +usage="\ +Usage: autoconf [-h] [--help] [-m dir] [--macrodir=dir] + [-l dir] [--localdir=dir] [--version] [template-file]" + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +: ${AC_MACRODIR=@datadir@} +: ${M4=@M4@} +: ${AWK=@AWK@} +case "${M4}" in +/*) # Handle the case that m4 has moved since we were configured. + # It may have been found originally in a build directory. + test -f "${M4}" || M4=m4 ;; +esac + +: ${TMPDIR=/tmp} +tmpout=${TMPDIR}/acout.$$ +localdir= +show_version=no + +while test $# -gt 0 ; do + case "${1}" in + -h | --help | --h* ) + echo "${usage}" 1>&2; exit 0 ;; + --localdir=* | --l*=* ) + localdir="`echo \"${1}\" | sed -e 's/^[^=]*=//'`" + shift ;; + -l | --localdir | --l*) + shift + test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; } + localdir="${1}" + shift ;; + --macrodir=* | --m*=* ) + AC_MACRODIR="`echo \"${1}\" | sed -e 's/^[^=]*=//'`" + shift ;; + -m | --macrodir | --m* ) + shift + test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; } + AC_MACRODIR="${1}" + shift ;; + --version | --v* ) + show_version=yes; shift ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "${usage}" 1>&2; exit 1 ;; + * ) + break ;; + esac +done + +if test $show_version = yes; then + version=`sed -n 's/define.AC_ACVERSION.[ ]*\([0-9.]*\).*/\1/p' \ + $AC_MACRODIR/acgeneral.m4` + echo "Autoconf version $version" + exit 0 +fi + +case $# in + 0) infile=configure.in ;; + 1) infile="$1" ;; + *) echo "$usage" >&2; exit 1 ;; +esac + +trap 'rm -f $tmpin $tmpout; exit 1' 1 2 15 + +tmpin=${TMPDIR}/acin.$$ # Always set this, to avoid bogus errors from some rm's. +if test z$infile = z-; then + infile=$tmpin + cat > $infile +elif test ! -r "$infile"; then + echo "autoconf: ${infile}: No such file or directory" >&2 + exit 1 +fi + +if test -n "$localdir"; then + use_localdir="-I$localdir -DAC_LOCALDIR=$localdir" +else + use_localdir= +fi + +# Use the frozen version of Autoconf if available. +r= f= +# Some non-GNU m4's don't reject the --help option, so give them /dev/null. +case `$M4 --help < /dev/null 2>&1` in +*reload-state*) test -r $AC_MACRODIR/autoconf.m4f && { r=--reload f=f; } ;; +*traditional*) ;; +*) echo Autoconf requires GNU m4 1.1 or later >&2; rm -f $tmpin; exit 1 ;; +esac + +$M4 -I$AC_MACRODIR $use_localdir $r autoconf.m4$f $infile > $tmpout || + { rm -f $tmpin $tmpout; exit 2; } + +# You could add your own prefixes to pattern if you wanted to check for +# them too, e.g. pattern='\(AC_\|ILT_\)', except that UNIX sed doesn't do +# alternation. +pattern="AC_" + +status=0 +if grep "^[^#]*${pattern}" $tmpout > /dev/null 2>&1; then + echo "autoconf: Undefined macros:" >&2 + sed -n "s/^[^#]*\\(${pattern}[_A-Za-z0-9]*\\).*/\\1/p" $tmpout | + while read macro; do + grep -n "^[^#]*$macro" $infile /dev/null + test $? -eq 1 && echo >&2 "***BUG in Autoconf--please report*** $macro" + done | sort -u >&2 + status=1 +fi + +if test $# -eq 0; then + echo "This case should not be reached." + exit 1 +fi + +# Put the real line numbers into the output to make config.log more helpful. +$AWK ' +/__oline__/ { printf "%d:", NR + 1 } + { print } +' $tmpout | sed ' +/__oline__/s/^\([0-9][0-9]*\):\(.*\)__oline__/\2\1/ +' + +rm -f $tmpout + +exit $status diff --git a/build/autoconf/clang-plugin.m4 b/build/autoconf/clang-plugin.m4 new file mode 100644 index 0000000000..2bbb471e5b --- /dev/null +++ b/build/autoconf/clang-plugin.m4 @@ -0,0 +1,107 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +AC_DEFUN([MOZ_CONFIG_CLANG_PLUGIN], [ + +if test -n "$ENABLE_CLANG_PLUGIN"; then + dnl For some reason the llvm-config downloaded from clang.llvm.org for clang3_8 + dnl produces a -isysroot flag for a sysroot which might not ship when passed + dnl --cxxflags. We use sed to remove this argument so that builds work on OSX + dnl + dnl For a similar reason, we remove any -gcc-toolchain arguments, since the + dnl directories specified by such arguments might not exist on the current + dnl machine. + LLVM_CXXFLAGS=`$LLVM_CONFIG --cxxflags | sed -e 's/-isysroot [[^ ]]*//' -e 's/-gcc-toolchain [[^ ]]*//'` + + LLVM_LDFLAGS=`$LLVM_CONFIG --ldflags | tr '\n' ' '` + + if test "${HOST_OS_ARCH}" = "Darwin"; then + dnl We need to make sure that we use the symbols coming from the clang + dnl binary. In order to do this, we need to pass -flat_namespace and + dnl -undefined suppress to the linker. This makes sure that we link the + dnl symbols into the flat namespace provided by clang, and thus get + dnl access to all of the symbols which are undefined in our dylib as we + dnl are building it right now, and also that we don't fail the build + dnl due to undefined symbols (which will be provided by clang). + CLANG_LDFLAGS="-Wl,-flat_namespace -Wl,-undefined,suppress" + dnl We are loaded into clang, so we don't need to link to very many things, + dnl we just need to link to clangASTMatchers because it is not used by clang + CLANG_LDFLAGS="$CLANG_LDFLAGS `$LLVM_CONFIG --prefix`/lib/libclangASTMatchers.a" + dnl We need to remove -L/path/to/clang/lib from LDFLAGS to ensure that we + dnl don't accidentally link against the libc++ there which is a newer + dnl version that what our build machines have installed. + LLVM_LDFLAGS=`echo "$LLVM_LDFLAGS" | sed -E 's/-L[[^ ]]+\/clang\/lib//'` + elif test "${HOST_OS_ARCH}" = "WINNT"; then + CLANG_LDFLAGS="clangASTMatchers.lib clang.lib" + else + CLANG_LDFLAGS="-lclangASTMatchers" + fi + + if test -n "$CLANG_CL"; then + dnl The llvm-config coming with clang-cl may give us arguments in the + dnl /ARG form, which in msys will be interpreted as a path name. So we + dnl need to split the args and convert the leading slashes that we find + dnl into a dash. + LLVM_REPLACE_CXXFLAGS='' + for arg in $LLVM_CXXFLAGS; do + dnl The following expression replaces a leading slash with a dash. + dnl Also replace any backslashes with forward slash. + arg=`echo "$arg"|sed -e 's/^\//-/' -e 's/\\\\/\//g'` + LLVM_REPLACE_CXXFLAGS="$LLVM_REPLACE_CXXFLAGS $arg" + done + LLVM_CXXFLAGS="$LLVM_REPLACE_CXXFLAGS" + dnl We'll also want to replace `-std:` with `-Xclang -std=` so that + dnl LLVM_CXXFLAGS can correctly override the `-Xclang -std=` set by + dnl toolchain.configure. + LLVM_CXXFLAGS=`echo "$LLVM_CXXFLAGS"|sed -e 's/ \(-Xclang \|\)-std[[:=]]/ -Xclang -std=/'` + + LLVM_REPLACE_LDFLAGS='' + for arg in $LLVM_LDFLAGS; do + dnl The following expression replaces a leading slash with a dash. + dnl Also replace any backslashes with forward slash. + arg=`echo "$arg"|sed -e 's/^\//-/' -e 's/\\\\/\//g'` + LLVM_REPLACE_LDFLAGS="$LLVM_REPLACE_LDFLAGS $arg" + done + LLVM_LDFLAGS="$LLVM_REPLACE_LDFLAGS" + + CLANG_REPLACE_LDFLAGS='' + for arg in $CLANG_LDFLAGS; do + dnl The following expression replaces a leading slash with a dash. + dnl Also replace any backslashes with forward slash. + arg=`echo "$arg"|sed -e 's/^\//-/' -e 's/\\\\/\//g'` + CLANG_REPLACE_LDFLAGS="$CLANG_REPLACE_LDFLAGS $arg" + done + CLANG_LDFLAGS="$CLANG_REPLACE_LDFLAGS" + fi + + CLANG_PLUGIN_FLAGS="-Xclang -load -Xclang $CLANG_PLUGIN -Xclang -add-plugin -Xclang moz-check" + + AC_DEFINE(MOZ_CLANG_PLUGIN) +fi + +if test -n "$ENABLE_MOZSEARCH_PLUGIN"; then + if test -z "${ENABLE_CLANG_PLUGIN}"; then + AC_MSG_ERROR([Can't use mozsearch plugin without --enable-clang-plugin.]) + fi + + CLANG_PLUGIN_FLAGS="$CLANG_PLUGIN_FLAGS -Xclang -add-plugin -Xclang mozsearch-index" + + dnl Parameters are: srcdir, outdir (path where output JSON is stored), objdir. + CLANG_PLUGIN_FLAGS="$CLANG_PLUGIN_FLAGS -Xclang -plugin-arg-mozsearch-index -Xclang $_topsrcdir" + CLANG_PLUGIN_FLAGS="$CLANG_PLUGIN_FLAGS -Xclang -plugin-arg-mozsearch-index -Xclang $_objdir/mozsearch_index" + CLANG_PLUGIN_FLAGS="$CLANG_PLUGIN_FLAGS -Xclang -plugin-arg-mozsearch-index -Xclang $_objdir" + + AC_DEFINE(MOZ_MOZSEARCH_PLUGIN) +fi + +AC_SUBST_LIST(CLANG_PLUGIN_FLAGS) +AC_SUBST_LIST(LLVM_CXXFLAGS) +AC_SUBST_LIST(LLVM_LDFLAGS) +AC_SUBST_LIST(CLANG_LDFLAGS) + +AC_SUBST(ENABLE_CLANG_PLUGIN) +AC_SUBST(ENABLE_CLANG_PLUGIN_ALPHA) +AC_SUBST(ENABLE_MOZSEARCH_PLUGIN) + +]) diff --git a/build/autoconf/codeset.m4 b/build/autoconf/codeset.m4 new file mode 100644 index 0000000000..3a25c42961 --- /dev/null +++ b/build/autoconf/codeset.m4 @@ -0,0 +1,25 @@ +# codeset.m4 serial AM1 (gettext-0.10.40) +dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +AC_DEFUN([AM_LANGINFO_CODESET], +[ + AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, + [AC_TRY_LINK([#include ], + [char* cs = nl_langinfo(CODESET);], + am_cv_langinfo_codeset=yes, + am_cv_langinfo_codeset=no) + ]) + if test $am_cv_langinfo_codeset = yes; then + AC_DEFINE(HAVE_LANGINFO_CODESET, 1, + [Define if you have and nl_langinfo(CODESET).]) + HAVE_LANGINFO_CODESET=1 + fi + AC_SUBST(HAVE_LANGINFO_CODESET) +]) diff --git a/build/autoconf/compiler-opts.m4 b/build/autoconf/compiler-opts.m4 new file mode 100644 index 0000000000..68960acbc1 --- /dev/null +++ b/build/autoconf/compiler-opts.m4 @@ -0,0 +1,198 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +dnl Add compiler specific options + +dnl ============================================================================ +dnl C++ rtti +dnl We don't use it in the code, but it can be usefull for debugging, so give +dnl the user the option of enabling it. +dnl ============================================================================ +AC_DEFUN([MOZ_RTTI], +[ +if test -z "$_MOZ_USE_RTTI"; then + if test "$GNU_CC"; then + CXXFLAGS="$CXXFLAGS -fno-rtti" + else + case "$target" in + *-mingw*) + CXXFLAGS="$CXXFLAGS -GR-" + esac + fi +fi +]) + +dnl ======================================================== +dnl = +dnl = Debugging Options +dnl = +dnl ======================================================== +AC_DEFUN([MOZ_DEBUGGING_OPTS], +[ + +if test -z "$MOZ_DEBUG" -o -n "$MOZ_ASAN"; then + MOZ_NO_DEBUG_RTL=1 +fi + +AC_SUBST(MOZ_NO_DEBUG_RTL) + +if test -n "$MOZ_DEBUG"; then + if test -n "$COMPILE_ENVIRONMENT"; then + AC_MSG_CHECKING([for valid debug flags]) + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $MOZ_DEBUG_FLAGS" + AC_TRY_COMPILE([#include ], + [printf("Hello World\n");], + _results=yes, + _results=no) + AC_MSG_RESULT([$_results]) + if test "$_results" = "no"; then + AC_MSG_ERROR([These compiler flags are invalid: $MOZ_DEBUG_FLAGS]) + fi + CFLAGS=$_SAVE_CFLAGS + fi +fi +]) + +dnl A high level macro for selecting compiler options. +AC_DEFUN([MOZ_COMPILER_OPTS], +[ + MOZ_DEBUGGING_OPTS + MOZ_RTTI + +if test "$GNU_CC"; then + if test -z "$DEVELOPER_OPTIONS"; then + CFLAGS="$CFLAGS -ffunction-sections -fdata-sections" + CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections" + fi + + CFLAGS="$CFLAGS -fno-math-errno" + CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-math-errno" +fi + +dnl ======================================================== +dnl = Identical Code Folding +dnl ======================================================== + +if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$MOZ_DISABLE_ICF" -a -z "$DEVELOPER_OPTIONS"; then + AC_CACHE_CHECK([whether the linker supports Identical Code Folding], + moz_cv_opt_ld_supports_icf, + [echo 'int foo() {return 42;}' \ + 'int bar() {return 42;}' \ + 'int main() {return foo() - bar();}' > conftest.${ac_ext} + # If the linker supports ICF, foo and bar symbols will have + # the same address + if AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS -Wl,--icf=safe -ffunction-sections conftest.${ac_ext} $LIBS 1>&2]) && + test -s conftest${ac_exeext} && + $LLVM_OBJDUMP -t conftest${ac_exeext} | awk changequote(<<, >>)'{a[<<$>>6] = <<$>>1} END {if (a["foo"] && (a["foo"] != a["bar"])) { exit 1 }}'changequote([, ]); then + moz_cv_opt_ld_supports_icf=yes + else + moz_cv_opt_ld_supports_icf=no + fi + rm -rf conftest*]) + if test "$moz_cv_opt_ld_supports_icf" = yes; then + _SAVE_LDFLAGS="$LDFLAGS -Wl,--icf=safe" + LDFLAGS="$LDFLAGS -Wl,--icf=safe -Wl,--print-icf-sections" + AC_TRY_LINK([], [], + [LD_PRINT_ICF_SECTIONS=-Wl,--print-icf-sections], + [LD_PRINT_ICF_SECTIONS=]) + AC_SUBST([LD_PRINT_ICF_SECTIONS]) + LDFLAGS="$_SAVE_LDFLAGS" + fi +fi + +dnl ======================================================== +dnl = Detect static linkage of libstdc++ +dnl ======================================================== + +if test "$OS_TARGET" = Linux; then + +AC_CACHE_CHECK([whether we're trying to statically link with libstdc++], + moz_cv_opt_static_libstdcxx, + [moz_cv_opt_static_libstdcxx=no + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + cat > conftest.$ac_ext < +int main() { std::cout << 1; } +EOF + dnl This test is quite conservative: it assumes dynamic linkage if the compilation step fails or if + dnl the binary format is not supported. But it still detects basic issues. + if AC_TRY_EVAL([ac_link]) && test -s conftest${ac_exeext} && $LLVM_OBJDUMP --private-headers conftest${ac_exeext} 2> conftest.err 1> conftest.out + then + if test -s conftest.err + then : + elif grep -q -E 'NEEDED.*lib(std)?c\+\+' conftest.out + then : + else moz_cv_opt_static_libstdcxx=yes + fi + fi + AC_LANG_RESTORE + rm -f conftest* +]) +if test "$moz_cv_opt_static_libstdcxx" = "yes"; then + AC_MSG_ERROR([Firefox does not support linking statically with libstdc++]) +fi + +fi + +dnl ======================================================== +dnl = Automatically remove dead symbols +dnl ======================================================== + +SANCOV= +if test -n "$LIBFUZZER"; then + case "$LIBFUZZER_FLAGS" in + *-fsanitize-coverage*|*-fsanitize=fuzzer*) + SANCOV=1 + ;; + esac +fi + +if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$DEVELOPER_OPTIONS" -a -z "$MOZ_PROFILE_GENERATE" -a -z "$SANCOV"; then + if test -n "$MOZ_DEBUG_FLAGS"; then + dnl See bug 670659 + AC_CACHE_CHECK([whether removing dead symbols breaks debugging], + moz_cv_opt_gc_sections_breaks_debug_ranges, + [echo 'int foo() {return 42;}' \ + 'int bar() {return 1;}' \ + 'int main() {return foo();}' > conftest.${ac_ext} + if AC_TRY_COMMAND([${CC-cc} -o conftest.${ac_objext} $CFLAGS $MOZ_DEBUG_FLAGS -c conftest.${ac_ext} 1>&2]) && + AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS $MOZ_DEBUG_FLAGS -Wl,--gc-sections conftest.${ac_objext} $LIBS 1>&2]) && + test -s conftest${ac_exeext} -a -s conftest.${ac_objext}; then + if test "`$PYTHON3 -m mozbuild.configure.check_debug_ranges conftest.${ac_objext} conftest.${ac_ext}`" = \ + "`$PYTHON3 -m mozbuild.configure.check_debug_ranges conftest${ac_exeext} conftest.${ac_ext}`"; then + moz_cv_opt_gc_sections_breaks_debug_ranges=no + else + moz_cv_opt_gc_sections_breaks_debug_ranges=yes + fi + else + dnl We really don't expect to get here, but just in case + moz_cv_opt_gc_sections_breaks_debug_ranges="no, but it's broken in some other way" + fi + rm -rf conftest*]) + if test "$moz_cv_opt_gc_sections_breaks_debug_ranges" = no; then + DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections" + fi + else + DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections" + fi +fi + +if test "$GNU_CC$CLANG_CC"; then + case "${OS_TARGET}" in + Darwin|WASI) + # It's the default on those targets, and clang complains about -pie + # being unused if passed. + ;; + *) + MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie" + ;; + esac +fi + +AC_SUBST(MOZ_PROGRAM_LDFLAGS) + + +]) diff --git a/build/autoconf/config.guess b/build/autoconf/config.guess new file mode 100755 index 0000000000..7f76b6228f --- /dev/null +++ b/build/autoconf/config.guess @@ -0,0 +1,1754 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2022 Free Software Foundation, Inc. + +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2022-01-09' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess +# +# Please send patches to . + + +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2022 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +# Just in case it came from the environment. +GUESS= + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +tmp= +# shellcheck disable=SC2172 +trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 + +set_cc_for_build() { + # prevent multiple calls if $tmp is already set + test "$tmp" && return 0 + : "${TMPDIR=/tmp}" + # shellcheck disable=SC2039,SC3028 + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } + dummy=$tmp/dummy + case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" + for driver in cc gcc c89 c99 ; do + if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD=$driver + break + fi + done + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; + esac +} + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if test -f /.attbin/uname ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case $UNAME_SYSTEM in +Linux|GNU|GNU/*) + LIBC=unknown + + set_cc_for_build + cat <<-EOF > "$dummy.c" + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #elif defined(__GLIBC__) + LIBC=gnu + #else + #include + /* First heuristic to detect musl libc. */ + #ifdef __DEFINED_va_list + LIBC=musl + #endif + #endif + EOF + cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "$cc_set_libc" + + # Second heuristic to detect musl libc. + if [ "$LIBC" = unknown ] && + command -v ldd >/dev/null && + ldd --version 2>&1 | grep -q ^musl; then + LIBC=musl + fi + + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + if [ "$LIBC" = unknown ]; then + LIBC=gnu + fi + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + echo unknown)` + case $UNAME_MACHINE_ARCH in + aarch64eb) machine=aarch64_be-unknown ;; + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=$UNAME_MACHINE_ARCH-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case $UNAME_MACHINE_ARCH in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case $UNAME_MACHINE_ARCH in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case $UNAME_VERSION in + Debian*) + release='-gnu' + ;; + *) + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + GUESS=$machine-${os}${release}${abi-} + ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE + ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE + ;; + *:SecBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE + ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE + ;; + *:MidnightBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE + ;; + *:ekkoBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE + ;; + *:SolidBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE + ;; + *:OS108:*:*) + GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE + ;; + macppc:MirBSD:*:*) + GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE + ;; + *:MirBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE + ;; + *:Sortix:*:*) + GUESS=$UNAME_MACHINE-unknown-sortix + ;; + *:Twizzler:*:*) + GUESS=$UNAME_MACHINE-unknown-twizzler + ;; + *:Redox:*:*) + GUESS=$UNAME_MACHINE-unknown-redox + ;; + mips:OSF1:*.*) + GUESS=mips-dec-osf1 + ;; + alpha:OSF1:*:*) + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + trap '' 0 + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case $ALPHA_CPU_TYPE in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + GUESS=$UNAME_MACHINE-dec-osf$OSF_REL + ;; + Amiga*:UNIX_System_V:4.0:*) + GUESS=m68k-unknown-sysv4 + ;; + *:[Aa]miga[Oo][Ss]:*:*) + GUESS=$UNAME_MACHINE-unknown-amigaos + ;; + *:[Mm]orph[Oo][Ss]:*:*) + GUESS=$UNAME_MACHINE-unknown-morphos + ;; + *:OS/390:*:*) + GUESS=i370-ibm-openedition + ;; + *:z/VM:*:*) + GUESS=s390-ibm-zvmoe + ;; + *:OS400:*:*) + GUESS=powerpc-ibm-os400 + ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + GUESS=arm-acorn-riscix$UNAME_RELEASE + ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + GUESS=arm-unknown-riscos + ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + GUESS=hppa1.1-hitachi-hiuxmpp + ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + case `(/bin/universe) 2>/dev/null` in + att) GUESS=pyramid-pyramid-sysv3 ;; + *) GUESS=pyramid-pyramid-bsd ;; + esac + ;; + NILE*:*:*:dcosx) + GUESS=pyramid-pyramid-svr4 + ;; + DRS?6000:unix:4.0:6*) + GUESS=sparc-icl-nx6 + ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) GUESS=sparc-icl-nx7 ;; + esac + ;; + s390x:SunOS:*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL + ;; + sun4H:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-hal-solaris2$SUN_REL + ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris2$SUN_REL + ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + GUESS=i386-pc-auroraux$UNAME_RELEASE + ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$SUN_ARCH-pc-solaris2$SUN_REL + ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris3$SUN_REL + ;; + sun4*:SunOS:*:*) + case `/usr/bin/arch -k` in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` + GUESS=sparc-sun-sunos$SUN_REL + ;; + sun3*:SunOS:*:*) + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 + case `/bin/arch` in + sun3) + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; + sun4) + GUESS=sparc-sun-sunos$UNAME_RELEASE + ;; + esac + ;; + aushp:SunOS:*:*) + GUESS=sparc-auspex-sunos$UNAME_RELEASE + ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + GUESS=m68k-milan-mint$UNAME_RELEASE + ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + GUESS=m68k-hades-mint$UNAME_RELEASE + ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + GUESS=m68k-unknown-mint$UNAME_RELEASE + ;; + m68k:machten:*:*) + GUESS=m68k-apple-machten$UNAME_RELEASE + ;; + powerpc:machten:*:*) + GUESS=powerpc-apple-machten$UNAME_RELEASE + ;; + RISC*:Mach:*:*) + GUESS=mips-dec-mach_bsd4.3 + ;; + RISC*:ULTRIX:*:*) + GUESS=mips-dec-ultrix$UNAME_RELEASE + ;; + VAX*:ULTRIX*:*:*) + GUESS=vax-dec-ultrix$UNAME_RELEASE + ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + GUESS=clipper-intergraph-clix$UNAME_RELEASE + ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && + { echo "$SYSTEM_NAME"; exit; } + GUESS=mips-mips-riscos$UNAME_RELEASE + ;; + Motorola:PowerMAX_OS:*:*) + GUESS=powerpc-motorola-powermax + ;; + Motorola:*:4.3:PL8-*) + GUESS=powerpc-harris-powermax + ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + GUESS=powerpc-harris-powermax + ;; + Night_Hawk:Power_UNIX:*:*) + GUESS=powerpc-harris-powerunix + ;; + m88k:CX/UX:7*:*) + GUESS=m88k-harris-cxux7 + ;; + m88k:*:4*:R4*) + GUESS=m88k-motorola-sysv4 + ;; + m88k:*:3*:R3*) + GUESS=m88k-motorola-sysv3 + ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 + then + if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ + test "$TARGET_BINARY_INTERFACE"x = x + then + GUESS=m88k-dg-dgux$UNAME_RELEASE + else + GUESS=m88k-dg-dguxbcs$UNAME_RELEASE + fi + else + GUESS=i586-dg-dgux$UNAME_RELEASE + fi + ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + GUESS=m88k-dolphin-sysv3 + ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + GUESS=m88k-motorola-sysv3 + ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + GUESS=m88k-tektronix-sysv3 + ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + GUESS=m68k-tektronix-bsd + ;; + *:IRIX*:*:*) + IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` + GUESS=mips-sgi-irix$IRIX_REL + ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id + ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + GUESS=i386-ibm-aix + ;; + ia64:AIX:*:*) + if test -x /usr/bin/oslevel ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE + fi + GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV + ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` + then + GUESS=$SYSTEM_NAME + else + GUESS=rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + GUESS=rs6000-ibm-aix3.2.4 + else + GUESS=rs6000-ibm-aix3.2 + fi + ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if test -x /usr/bin/lslpp ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE + fi + GUESS=$IBM_ARCH-ibm-aix$IBM_REV + ;; + *:AIX:*:*) + GUESS=rs6000-ibm-aix + ;; + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) + GUESS=romp-ibm-bsd4.4 + ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to + ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + GUESS=rs6000-bull-bosx + ;; + DPX/2?00:B.O.S.:*:*) + GUESS=m68k-bull-sysv3 + ;; + 9000/[34]??:4.3bsd:1.*:*) + GUESS=m68k-hp-bsd + ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + GUESS=m68k-hp-bsd4.4 + ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + case $UNAME_MACHINE in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if test -x /usr/bin/getconf; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case $sc_cpu_version in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case $sc_kernel_bits in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if test "$HP_ARCH" = ""; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if test "$HP_ARCH" = hppa2.0w + then + set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + GUESS=$HP_ARCH-hp-hpux$HPUX_REV + ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + GUESS=ia64-hp-hpux$HPUX_REV + ;; + 3050*:HI-UX:*:*) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + GUESS=unknown-hitachi-hiuxwe2 + ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) + GUESS=hppa1.1-hp-bsd + ;; + 9000/8??:4.3bsd:*:*) + GUESS=hppa1.0-hp-bsd + ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + GUESS=hppa1.0-hp-mpeix + ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) + GUESS=hppa1.1-hp-osf + ;; + hp8??:OSF1:*:*) + GUESS=hppa1.0-hp-osf + ;; + i*86:OSF1:*:*) + if test -x /usr/sbin/sysversion ; then + GUESS=$UNAME_MACHINE-unknown-osf1mk + else + GUESS=$UNAME_MACHINE-unknown-osf1 + fi + ;; + parisc*:Lites*:*:*) + GUESS=hppa1.1-hp-lites + ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + GUESS=c1-convex-bsd + ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + GUESS=c34-convex-bsd + ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + GUESS=c38-convex-bsd + ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + GUESS=c4-convex-bsd + ;; + CRAY*Y-MP:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=ymp-cray-unicos$CRAY_REL + ;; + CRAY*[A-Z]90:*:*:*) + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=t90-cray-unicos$CRAY_REL + ;; + CRAY*T3E:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=alphaev5-cray-unicosmk$CRAY_REL + ;; + CRAY*SV1:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=sv1-cray-unicos$CRAY_REL + ;; + *:UNICOS/mp:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=craynv-cray-unicosmp$CRAY_REL + ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` + GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE + ;; + sparc*:BSD/OS:*:*) + GUESS=sparc-unknown-bsdi$UNAME_RELEASE + ;; + *:BSD/OS:*:*) + GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE + ;; + arm:FreeBSD:*:*) + UNAME_PROCESSOR=`uname -p` + set_cc_for_build + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi + else + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf + fi + ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case $UNAME_PROCESSOR in + amd64) + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; + esac + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL + ;; + i*:CYGWIN*:*) + GUESS=$UNAME_MACHINE-pc-cygwin + ;; + *:MINGW64*:*) + GUESS=$UNAME_MACHINE-pc-mingw64 + ;; + *:MINGW*:*) + GUESS=$UNAME_MACHINE-pc-mingw32 + ;; + *:MSYS*:*) + GUESS=$UNAME_MACHINE-pc-msys + ;; + i*:PW*:*) + GUESS=$UNAME_MACHINE-pc-pw32 + ;; + *:SerenityOS:*:*) + GUESS=$UNAME_MACHINE-pc-serenity + ;; + *:Interix*:*) + case $UNAME_MACHINE in + x86) + GUESS=i586-pc-interix$UNAME_RELEASE + ;; + authenticamd | genuineintel | EM64T) + GUESS=x86_64-unknown-interix$UNAME_RELEASE + ;; + IA64) + GUESS=ia64-unknown-interix$UNAME_RELEASE + ;; + esac ;; + i*:UWIN*:*) + GUESS=$UNAME_MACHINE-pc-uwin + ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + GUESS=x86_64-pc-cygwin + ;; + prep*:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=powerpcle-unknown-solaris2$SUN_REL + ;; + *:GNU:*:*) + # the GNU system + GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` + GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL + ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC + ;; + *:Minix:*:*) + GUESS=$UNAME_MACHINE-unknown-minix + ;; + aarch64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arm*:Linux:*:*) + set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi + else + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf + fi + fi + ;; + avr32*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + cris:Linux:*:*) + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; + crisv32:Linux:*:*) + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; + e2k:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + frv:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + hexagon:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + i*86:Linux:*:*) + GUESS=$UNAME_MACHINE-pc-linux-$LIBC + ;; + ia64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + k1om:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + m32r*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + m68*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + mips:Linux:*:* | mips64:Linux:*:*) + set_cc_for_build + IS_GLIBC=0 + test x"${LIBC}" = xgnu && IS_GLIBC=1 + sed 's/^ //' << EOF > "$dummy.c" + #undef CPU + #undef mips + #undef mipsel + #undef mips64 + #undef mips64el + #if ${IS_GLIBC} && defined(_ABI64) + LIBCABI=gnuabi64 + #else + #if ${IS_GLIBC} && defined(_ABIN32) + LIBCABI=gnuabin32 + #else + LIBCABI=${LIBC} + #endif + #endif + + #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa64r6 + #else + #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa32r6 + #else + #if defined(__mips64) + CPU=mips64 + #else + CPU=mips + #endif + #endif + #endif + + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + MIPS_ENDIAN=el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + MIPS_ENDIAN= + #else + MIPS_ENDIAN= + #endif + #endif +EOF + cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` + eval "$cc_set_vars" + test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } + ;; + mips64el:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + openrisc*:Linux:*:*) + GUESS=or1k-unknown-linux-$LIBC + ;; + or32:Linux:*:* | or1k*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + padre:Linux:*:*) + GUESS=sparc-unknown-linux-$LIBC + ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + GUESS=hppa64-unknown-linux-$LIBC + ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; + PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; + *) GUESS=hppa-unknown-linux-$LIBC ;; + esac + ;; + ppc64:Linux:*:*) + GUESS=powerpc64-unknown-linux-$LIBC + ;; + ppc:Linux:*:*) + GUESS=powerpc-unknown-linux-$LIBC + ;; + ppc64le:Linux:*:*) + GUESS=powerpc64le-unknown-linux-$LIBC + ;; + ppcle:Linux:*:*) + GUESS=powerpcle-unknown-linux-$LIBC + ;; + riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + s390:Linux:*:* | s390x:Linux:*:*) + GUESS=$UNAME_MACHINE-ibm-linux-$LIBC + ;; + sh64*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + sh*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + tile*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + vax:Linux:*:*) + GUESS=$UNAME_MACHINE-dec-linux-$LIBC + ;; + x86_64:Linux:*:*) + set_cc_for_build + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_X32 >/dev/null + then + LIBCABI=${LIBC}x32 + fi + fi + GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI + ;; + xtensa*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + GUESS=i386-sequent-sysv4 + ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION + ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + GUESS=$UNAME_MACHINE-pc-os2-emx + ;; + i*86:XTS-300:*:STOP) + GUESS=$UNAME_MACHINE-unknown-stop + ;; + i*86:atheos:*:*) + GUESS=$UNAME_MACHINE-unknown-atheos + ;; + i*86:syllable:*:*) + GUESS=$UNAME_MACHINE-pc-syllable + ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + GUESS=i386-unknown-lynxos$UNAME_RELEASE + ;; + i*86:*DOS:*:*) + GUESS=$UNAME_MACHINE-pc-msdosdjgpp + ;; + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL + else + GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL + fi + ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL + else + GUESS=$UNAME_MACHINE-pc-sysv32 + fi + ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + GUESS=i586-pc-msdosdjgpp + ;; + Intel:Mach:3*:*) + GUESS=i386-pc-mach3 + ;; + paragon:*:*:*) + GUESS=i860-intel-osf1 + ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 + fi + ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + GUESS=m68010-convergent-sysv + ;; + mc68k:UNIX:SYSTEM5:3.51m) + GUESS=m68k-convergent-sysv + ;; + M680?0:D-NIX:5.3:*) + GUESS=m68k-diab-dnix + ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + GUESS=m68k-unknown-lynxos$UNAME_RELEASE + ;; + mc68030:UNIX_System_V:4.*:*) + GUESS=m68k-atari-sysv4 + ;; + TSUNAMI:LynxOS:2.*:*) + GUESS=sparc-unknown-lynxos$UNAME_RELEASE + ;; + rs6000:LynxOS:2.*:*) + GUESS=rs6000-unknown-lynxos$UNAME_RELEASE + ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + GUESS=powerpc-unknown-lynxos$UNAME_RELEASE + ;; + SM[BE]S:UNIX_SV:*:*) + GUESS=mips-dde-sysv$UNAME_RELEASE + ;; + RM*:ReliantUNIX-*:*:*) + GUESS=mips-sni-sysv4 + ;; + RM*:SINIX-*:*:*) + GUESS=mips-sni-sysv4 + ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + GUESS=$UNAME_MACHINE-sni-sysv4 + else + GUESS=ns32k-sni-sysv + fi + ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + GUESS=i586-unisys-sysv4 + ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + GUESS=hppa1.1-stratus-sysv4 + ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + GUESS=i860-stratus-sysv4 + ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + GUESS=$UNAME_MACHINE-stratus-vos + ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + GUESS=hppa1.1-stratus-vos + ;; + mc68*:A/UX:*:*) + GUESS=m68k-apple-aux$UNAME_RELEASE + ;; + news*:NEWS-OS:6*:*) + GUESS=mips-sony-newsos6 + ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if test -d /usr/nec; then + GUESS=mips-nec-sysv$UNAME_RELEASE + else + GUESS=mips-unknown-sysv$UNAME_RELEASE + fi + ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + GUESS=powerpc-be-beos + ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + GUESS=powerpc-apple-beos + ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + GUESS=i586-pc-beos + ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + GUESS=i586-pc-haiku + ;; + x86_64:Haiku:*:*) + GUESS=x86_64-unknown-haiku + ;; + SX-4:SUPER-UX:*:*) + GUESS=sx4-nec-superux$UNAME_RELEASE + ;; + SX-5:SUPER-UX:*:*) + GUESS=sx5-nec-superux$UNAME_RELEASE + ;; + SX-6:SUPER-UX:*:*) + GUESS=sx6-nec-superux$UNAME_RELEASE + ;; + SX-7:SUPER-UX:*:*) + GUESS=sx7-nec-superux$UNAME_RELEASE + ;; + SX-8:SUPER-UX:*:*) + GUESS=sx8-nec-superux$UNAME_RELEASE + ;; + SX-8R:SUPER-UX:*:*) + GUESS=sx8r-nec-superux$UNAME_RELEASE + ;; + SX-ACE:SUPER-UX:*:*) + GUESS=sxace-nec-superux$UNAME_RELEASE + ;; + Power*:Rhapsody:*:*) + GUESS=powerpc-apple-rhapsody$UNAME_RELEASE + ;; + *:Rhapsody:*:*) + GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE + ;; + arm64:Darwin:*:*) + GUESS=aarch64-apple-darwin$UNAME_RELEASE + ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + if command -v xcode-select > /dev/null 2> /dev/null && \ + ! xcode-select --print-path > /dev/null 2> /dev/null ; then + # Avoid executing cc if there is no toolchain installed as + # cc will be a stub that puts up a graphical alert + # prompting the user to install developer tools. + CC_FOR_BUILD=no_compiler_found + else + set_cc_for_build + fi + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # uname -m returns i386 or x86_64 + UNAME_PROCESSOR=$UNAME_MACHINE + fi + GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE + ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE + ;; + *:QNX:*:4*) + GUESS=i386-pc-qnx + ;; + NEO-*:NONSTOP_KERNEL:*:*) + GUESS=neo-tandem-nsk$UNAME_RELEASE + ;; + NSE-*:NONSTOP_KERNEL:*:*) + GUESS=nse-tandem-nsk$UNAME_RELEASE + ;; + NSR-*:NONSTOP_KERNEL:*:*) + GUESS=nsr-tandem-nsk$UNAME_RELEASE + ;; + NSV-*:NONSTOP_KERNEL:*:*) + GUESS=nsv-tandem-nsk$UNAME_RELEASE + ;; + NSX-*:NONSTOP_KERNEL:*:*) + GUESS=nsx-tandem-nsk$UNAME_RELEASE + ;; + *:NonStop-UX:*:*) + GUESS=mips-compaq-nonstopux + ;; + BS2000:POSIX*:*:*) + GUESS=bs2000-siemens-sysv + ;; + DS/*:UNIX_System_V:*:*) + GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE + ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "${cputype-}" = 386; then + UNAME_MACHINE=i386 + elif test "x${cputype-}" != x; then + UNAME_MACHINE=$cputype + fi + GUESS=$UNAME_MACHINE-unknown-plan9 + ;; + *:TOPS-10:*:*) + GUESS=pdp10-unknown-tops10 + ;; + *:TENEX:*:*) + GUESS=pdp10-unknown-tenex + ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + GUESS=pdp10-dec-tops20 + ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + GUESS=pdp10-xkl-tops20 + ;; + *:TOPS-20:*:*) + GUESS=pdp10-unknown-tops20 + ;; + *:ITS:*:*) + GUESS=pdp10-unknown-its + ;; + SEI:*:*:SEIUX) + GUESS=mips-sei-seiux$UNAME_RELEASE + ;; + *:DragonFly:*:*) + DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL + ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case $UNAME_MACHINE in + A*) GUESS=alpha-dec-vms ;; + I*) GUESS=ia64-dec-vms ;; + V*) GUESS=vax-dec-vms ;; + esac ;; + *:XENIX:*:SysV) + GUESS=i386-pc-xenix + ;; + i*86:skyos:*:*) + SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` + GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL + ;; + i*86:rdos:*:*) + GUESS=$UNAME_MACHINE-pc-rdos + ;; + i*86:Fiwix:*:*) + GUESS=$UNAME_MACHINE-pc-fiwix + ;; + *:AROS:*:*) + GUESS=$UNAME_MACHINE-unknown-aros + ;; + x86_64:VMkernel:*:*) + GUESS=$UNAME_MACHINE-unknown-esx + ;; + amd64:Isilon\ OneFS:*:*) + GUESS=x86_64-unknown-onefs + ;; + *:Unleashed:*:*) + GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE + ;; +esac + +# Do we have a guess based on uname results? +if test "x$GUESS" != x; then + echo "$GUESS" + exit +fi + +# No uname command or uname output not recognized. +set_cc_for_build +cat > "$dummy.c" < +#include +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#include +#if defined(_SIZE_T_) || defined(SIGLOST) +#include +#endif +#endif +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); +#endif + +#if defined (vax) +#if !defined (ultrix) +#include +#if defined (BSD) +#if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +#else +#if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#endif +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#else +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname un; + uname (&un); + printf ("vax-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname *un; + uname (&un); + printf ("mips-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("mips-dec-ultrix\n"); exit (0); +#endif +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. +test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } + +echo "$0: unable to guess system type" >&2 + +case $UNAME_MACHINE:$UNAME_SYSTEM in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 <&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" +EOF +fi + +exit 1 + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/build/autoconf/config.status.m4 b/build/autoconf/config.status.m4 new file mode 100644 index 0000000000..41571a414b --- /dev/null +++ b/build/autoconf/config.status.m4 @@ -0,0 +1,154 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +dnl For use in AC_SUBST replacement +define([MOZ_DIVERSION_SUBST], 11) + +dnl Replace AC_SUBST to store values in a format suitable for python. +dnl The necessary comma after the tuple can't be put here because it +dnl can mess around with things like: +dnl AC_SOMETHING(foo,AC_SUBST(),bar) +define([AC_SUBST], +[ifdef([AC_SUBST_SET_$1], [m4_fatal([Cannot use AC_SUBST and AC_SUBST_SET on the same variable ($1)])], +[ifdef([AC_SUBST_LIST_$1], [m4_fatal([Cannot use AC_SUBST and AC_SUBST_LIST on the same variable ($1)])], +[ifdef([AC_SUBST_$1], , +[define([AC_SUBST_$1], )dnl +AC_DIVERT_PUSH(MOZ_DIVERSION_SUBST)dnl + (''' $1 ''', r''' [$]$1 ''') +AC_DIVERT_POP()dnl +])])])])]) + +dnl Like AC_SUBST, but makes the value available as a set in python, +dnl with values got from the value of the environment variable, split on +dnl whitespaces. +define([AC_SUBST_SET], +[ifdef([AC_SUBST_$1], [m4_fatal([Cannot use AC_SUBST and AC_SUBST_SET on the same variable ($1)])], +[ifdef([AC_SUBST_LIST_$1], [m4_fatal([Cannot use AC_SUBST_LIST and AC_SUBST_SET on the same variable ($1)])], +[ifdef([AC_SUBST_SET_$1], , +[define([AC_SUBST_SET_$1], )dnl +AC_DIVERT_PUSH(MOZ_DIVERSION_SUBST)dnl + (''' $1 ''', unique_list(split(r''' [$]$1 '''))) +AC_DIVERT_POP()dnl +])])])])]) + +dnl Like AC_SUBST, but makes the value available as a list in python, +dnl with values got from the value of the environment variable, split on +dnl whitespaces. +define([AC_SUBST_LIST], +[ifdef([AC_SUBST_$1], [m4_fatal([Cannot use AC_SUBST and AC_SUBST_LIST on the same variable ($1)])], +[ifdef([AC_SUBST_SET_$1], [m4_fatal([Cannot use AC_SUBST_SET and AC_SUBST_LIST on the same variable ($1)])], +[ifdef([AC_SUBST_LIST_$1], , +[define([AC_SUBST_LIST_$1], )dnl +AC_DIVERT_PUSH(MOZ_DIVERSION_SUBST)dnl + (''' $1 ''', list(split(r''' [$]$1 '''))) +AC_DIVERT_POP()dnl +])])])])]) + +dnl Ignore AC_SUBSTs for variables we don't have use for but that autoconf +dnl itself exports. +define([AC_SUBST_CFLAGS], ) +define([AC_SUBST_CPPFLAGS], ) +define([AC_SUBST_CXXFLAGS], ) +define([AC_SUBST_FFLAGS], ) +define([AC_SUBST_DEFS], ) +define([AC_SUBST_LDFLAGS], ) +define([AC_SUBST_LIBS], ) + +dnl Wrap AC_DEFINE to store values in a format suitable for python. +dnl autoconf's AC_DEFINE still needs to be used to fill confdefs.h, +dnl which is #included during some compile checks. +dnl The necessary comma after the tuple can't be put here because it +dnl can mess around with things like: +dnl AC_SOMETHING(foo,AC_DEFINE(),bar) +define([_MOZ_AC_DEFINE], defn([AC_DEFINE])) +define([AC_DEFINE], +[cat >> confdefs.pytmp <<\EOF + (''' $1 ''', ifelse($#, 2, [r''' $2 '''], $#, 3, [r''' $2 '''], ' 1 ')) +EOF +ifelse($#, 2, _MOZ_AC_DEFINE([$1], [$2]), $#, 3, _MOZ_AC_DEFINE([$1], [$2], [$3]),_MOZ_AC_DEFINE([$1]))dnl +]) + +dnl Wrap AC_DEFINE_UNQUOTED to store values in a format suitable for +dnl python. +define([_MOZ_AC_DEFINE_UNQUOTED], defn([AC_DEFINE_UNQUOTED])) +define([AC_DEFINE_UNQUOTED], +[cat >> confdefs.pytmp <>>)dnl +echo creating $CONFIG_STATUS + +cat > $CONFIG_STATUS <> $CONFIG_STATUS +rm confdefs.pytmp confdefs.h + +cat >> $CONFIG_STATUS <<\EOF +] + +substs = [ +EOF + +dnl The MOZ_DIVERSION_SUBST output diversion contains AC_SUBSTs, in the +dnl expected format, but lacks the final comma (see above). +sed 's/$/,/' >> $CONFIG_STATUS <> $CONFIG_STATUS +done + +cat >> $CONFIG_STATUS <<\EOF +] + +flags = [ +undivert(MOZ_DIVERSION_ARGS)dnl +] +EOF + +changequote([, ]) +]) + +define([m4_fatal],[ +errprint([$1 +]) +m4exit(1) +]) + +define([AC_OUTPUT], [ifelse($#_$1, 1_, [MOZ_CREATE_CONFIG_STATUS() +MOZ_RUN_CONFIG_STATUS()], +[m4_fatal([Use CONFIGURE_SUBST_FILES in moz.build files to create substituted files.])] +)]) + +define([AC_CONFIG_HEADER], +[m4_fatal([Use CONFIGURE_DEFINE_FILES in moz.build files to produce header files.]) +]) diff --git a/build/autoconf/config.sub b/build/autoconf/config.sub new file mode 100755 index 0000000000..dba16e84c7 --- /dev/null +++ b/build/autoconf/config.sub @@ -0,0 +1,1890 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2022 Free Software Foundation, Inc. + +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2022-01-03' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2022 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo "$1" + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Split fields of configuration type +# shellcheck disable=SC2162 +saved_IFS=$IFS +IFS="-" read field1 field2 field3 field4 <&2 + exit 1 + ;; + *-*-*-*) + basic_machine=$field1-$field2 + basic_os=$field3-$field4 + ;; + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + basic_os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + basic_os=linux-android + ;; + *) + basic_machine=$field1-$field2 + basic_os=$field3 + ;; + esac + ;; + *-*) + # A lone config we happen to match not fitting any pattern + case $field1-$field2 in + decstation-3100) + basic_machine=mips-dec + basic_os= + ;; + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + basic_os=$field2 + ;; + zephyr*) + basic_machine=$field1-unknown + basic_os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* \ + | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ + | ultra | tti* | harris | dolphin | highlevel | gould \ + | cbm | ns | masscomp | apple | axis | knuth | cray \ + | microblaze* | sim | cisco \ + | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + basic_os= + ;; + *) + basic_machine=$field1 + basic_os=$field2 + ;; + esac + ;; + esac + ;; + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + basic_os=bsd + ;; + a29khif) + basic_machine=a29k-amd + basic_os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + basic_os=scout + ;; + alliant) + basic_machine=fx80-alliant + basic_os= + ;; + altos | altos3068) + basic_machine=m68k-altos + basic_os= + ;; + am29k) + basic_machine=a29k-none + basic_os=bsd + ;; + amdahl) + basic_machine=580-amdahl + basic_os=sysv + ;; + amiga) + basic_machine=m68k-unknown + basic_os= + ;; + amigaos | amigados) + basic_machine=m68k-unknown + basic_os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + basic_os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + basic_os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + basic_os=bsd + ;; + aros) + basic_machine=i386-pc + basic_os=aros + ;; + aux) + basic_machine=m68k-apple + basic_os=aux + ;; + balance) + basic_machine=ns32k-sequent + basic_os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + basic_os=linux + ;; + cegcc) + basic_machine=arm-unknown + basic_os=cegcc + ;; + convex-c1) + basic_machine=c1-convex + basic_os=bsd + ;; + convex-c2) + basic_machine=c2-convex + basic_os=bsd + ;; + convex-c32) + basic_machine=c32-convex + basic_os=bsd + ;; + convex-c34) + basic_machine=c34-convex + basic_os=bsd + ;; + convex-c38) + basic_machine=c38-convex + basic_os=bsd + ;; + cray) + basic_machine=j90-cray + basic_os=unicos + ;; + crds | unos) + basic_machine=m68k-crds + basic_os= + ;; + da30) + basic_machine=m68k-da30 + basic_os= + ;; + decstation | pmax | pmin | dec3100 | decstatn) + basic_machine=mips-dec + basic_os= + ;; + delta88) + basic_machine=m88k-motorola + basic_os=sysv3 + ;; + dicos) + basic_machine=i686-pc + basic_os=dicos + ;; + djgpp) + basic_machine=i586-pc + basic_os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + basic_os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + basic_os=ose + ;; + gmicro) + basic_machine=tron-gmicro + basic_os=sysv + ;; + go32) + basic_machine=i386-pc + basic_os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + basic_os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + basic_os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + basic_os=hms + ;; + harris) + basic_machine=m88k-harris + basic_os=sysv3 + ;; + hp300 | hp300hpux) + basic_machine=m68k-hp + basic_os=hpux + ;; + hp300bsd) + basic_machine=m68k-hp + basic_os=bsd + ;; + hppaosf) + basic_machine=hppa1.1-hp + basic_os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + basic_os=proelf + ;; + i386mach) + basic_machine=i386-mach + basic_os=mach + ;; + isi68 | isi) + basic_machine=m68k-isi + basic_os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + basic_os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + basic_os=sysv + ;; + merlin) + basic_machine=ns32k-utek + basic_os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + basic_os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + basic_os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + basic_os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + basic_os=coff + ;; + morphos) + basic_machine=powerpc-unknown + basic_os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + basic_os=moxiebox + ;; + msdos) + basic_machine=i386-pc + basic_os=msdos + ;; + msys) + basic_machine=i686-pc + basic_os=msys + ;; + mvs) + basic_machine=i370-ibm + basic_os=mvs + ;; + nacl) + basic_machine=le32-unknown + basic_os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + basic_os=sysv4 + ;; + netbsd386) + basic_machine=i386-pc + basic_os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + basic_os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + basic_os=newsos + ;; + news1000) + basic_machine=m68030-sony + basic_os=newsos + ;; + necv70) + basic_machine=v70-nec + basic_os=sysv + ;; + nh3000) + basic_machine=m68k-harris + basic_os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + basic_os=cxux + ;; + nindy960) + basic_machine=i960-intel + basic_os=nindy + ;; + mon960) + basic_machine=i960-intel + basic_os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + basic_os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + basic_os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + basic_os=ose + ;; + os68k) + basic_machine=m68k-none + basic_os=os68k + ;; + paragon) + basic_machine=i860-intel + basic_os=osf + ;; + parisc) + basic_machine=hppa-unknown + basic_os=linux + ;; + psp) + basic_machine=mipsallegrexel-sony + basic_os=psp + ;; + pw32) + basic_machine=i586-unknown + basic_os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + basic_os=rdos + ;; + rdos32) + basic_machine=i386-pc + basic_os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + basic_os=coff + ;; + sa29200) + basic_machine=a29k-amd + basic_os=udi + ;; + sei) + basic_machine=mips-sei + basic_os=seiux + ;; + sequent) + basic_machine=i386-sequent + basic_os= + ;; + sps7) + basic_machine=m68k-bull + basic_os=sysv2 + ;; + st2000) + basic_machine=m68k-tandem + basic_os= + ;; + stratus) + basic_machine=i860-stratus + basic_os=sysv4 + ;; + sun2) + basic_machine=m68000-sun + basic_os= + ;; + sun2os3) + basic_machine=m68000-sun + basic_os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + basic_os=sunos4 + ;; + sun3) + basic_machine=m68k-sun + basic_os= + ;; + sun3os3) + basic_machine=m68k-sun + basic_os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + basic_os=sunos4 + ;; + sun4) + basic_machine=sparc-sun + basic_os= + ;; + sun4os3) + basic_machine=sparc-sun + basic_os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + basic_os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + basic_os=solaris2 + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + basic_os= + ;; + sv1) + basic_machine=sv1-cray + basic_os=unicos + ;; + symmetry) + basic_machine=i386-sequent + basic_os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + basic_os=unicos + ;; + t90) + basic_machine=t90-cray + basic_os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + basic_os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + basic_os=tpf + ;; + udi29k) + basic_machine=a29k-amd + basic_os=udi + ;; + ultra3) + basic_machine=a29k-nyu + basic_os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + basic_os=none + ;; + vaxv) + basic_machine=vax-dec + basic_os=sysv + ;; + vms) + basic_machine=vax-dec + basic_os=vms + ;; + vsta) + basic_machine=i386-pc + basic_os=vsta + ;; + vxworks960) + basic_machine=i960-wrs + basic_os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + basic_os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + basic_os=vxworks + ;; + xbox) + basic_machine=i686-pc + basic_os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + basic_os=unicos + ;; + *) + basic_machine=$1 + basic_os= + ;; + esac + ;; +esac + +# Decode 1-component or ad-hoc basic machines +case $basic_machine in + # Here we handle the default manufacturer of certain CPU types. It is in + # some cases the only manufacturer, in others, it is the most popular. + w89k) + cpu=hppa1.1 + vendor=winbond + ;; + op50n) + cpu=hppa1.1 + vendor=oki + ;; + op60c) + cpu=hppa1.1 + vendor=oki + ;; + ibm*) + cpu=i370 + vendor=ibm + ;; + orion105) + cpu=clipper + vendor=highlevel + ;; + mac | mpw | mac-mpw) + cpu=m68k + vendor=apple + ;; + pmac | pmac-mpw) + cpu=powerpc + vendor=apple + ;; + + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + cpu=m68000 + vendor=att + ;; + 3b*) + cpu=we32k + vendor=att + ;; + bluegene*) + cpu=powerpc + vendor=ibm + basic_os=cnk + ;; + decsystem10* | dec10*) + cpu=pdp10 + vendor=dec + basic_os=tops10 + ;; + decsystem20* | dec20*) + cpu=pdp10 + vendor=dec + basic_os=tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + cpu=m68k + vendor=motorola + ;; + dpx2*) + cpu=m68k + vendor=bull + basic_os=sysv3 + ;; + encore | umax | mmax) + cpu=ns32k + vendor=encore + ;; + elxsi) + cpu=elxsi + vendor=elxsi + basic_os=${basic_os:-bsd} + ;; + fx2800) + cpu=i860 + vendor=alliant + ;; + genix) + cpu=ns32k + vendor=ns + ;; + h3050r* | hiux*) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + cpu=m68000 + vendor=hp + ;; + hp9k3[2-9][0-9]) + cpu=m68k + vendor=hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + i*86v32) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv32 + ;; + i*86v4*) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv4 + ;; + i*86v) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv + ;; + i*86sol2) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=solaris2 + ;; + j90 | j90-cray) + cpu=j90 + vendor=cray + basic_os=${basic_os:-unicos} + ;; + iris | iris4d) + cpu=mips + vendor=sgi + case $basic_os in + irix*) + ;; + *) + basic_os=irix4 + ;; + esac + ;; + miniframe) + cpu=m68000 + vendor=convergent + ;; + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) + cpu=m68k + vendor=atari + basic_os=mint + ;; + news-3600 | risc-news) + cpu=mips + vendor=sony + basic_os=newsos + ;; + next | m*-next) + cpu=m68k + vendor=next + case $basic_os in + openstep*) + ;; + nextstep*) + ;; + ns2*) + basic_os=nextstep2 + ;; + *) + basic_os=nextstep3 + ;; + esac + ;; + np1) + cpu=np1 + vendor=gould + ;; + op50n-* | op60c-*) + cpu=hppa1.1 + vendor=oki + basic_os=proelf + ;; + pa-hitachi) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + pbd) + cpu=sparc + vendor=tti + ;; + pbb) + cpu=m68k + vendor=tti + ;; + pc532) + cpu=ns32k + vendor=pc532 + ;; + pn) + cpu=pn + vendor=gould + ;; + power) + cpu=power + vendor=ibm + ;; + ps2) + cpu=i386 + vendor=ibm + ;; + rm[46]00) + cpu=mips + vendor=siemens + ;; + rtpc | rtpc-*) + cpu=romp + vendor=ibm + ;; + sde) + cpu=mipsisa32 + vendor=sde + basic_os=${basic_os:-elf} + ;; + simso-wrs) + cpu=sparclite + vendor=wrs + basic_os=vxworks + ;; + tower | tower-32) + cpu=m68k + vendor=ncr + ;; + vpp*|vx|vx-*) + cpu=f301 + vendor=fujitsu + ;; + w65) + cpu=w65 + vendor=wdc + ;; + w89k-*) + cpu=hppa1.1 + vendor=winbond + basic_os=proelf + ;; + none) + cpu=none + vendor=none + ;; + leon|leon[3-9]) + cpu=sparc + vendor=$basic_machine + ;; + leon-*|leon[3-9]-*) + cpu=sparc + vendor=`echo "$basic_machine" | sed 's/-.*//'` + ;; + + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read cpu vendor <&2 + exit 1 + ;; + esac + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $vendor in + digital*) + vendor=dec + ;; + commodore*) + vendor=cbm + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if test x$basic_os != x +then + +# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just +# set os. +case $basic_os in + gnu/linux*) + kernel=linux + os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` + ;; + os2-emx) + kernel=os2 + os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` + ;; + nto-qnx*) + kernel=nto + os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` + ;; + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read kernel os <&2 + exit 1 + ;; +esac + +# As a final step for OS-related things, validate the OS-kernel combination +# (given a valid OS), if there is a kernel. +case $kernel-$os in + linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ + | linux-musl* | linux-relibc* | linux-uclibc* ) + ;; + uclinux-uclibc* ) + ;; + -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) + # These are just libc implementations, not actual OSes, and thus + # require a kernel. + echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + exit 1 + ;; + kfreebsd*-gnu* | kopensolaris*-gnu*) + ;; + vxworks-simlinux | vxworks-simwindows | vxworks-spe) + ;; + nto-qnx*) + ;; + os2-emx) + ;; + *-eabi* | *-gnueabi*) + ;; + -*) + # Blank kernel with real OS is always fine. + ;; + *-*) + echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + exit 1 + ;; +esac + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +case $vendor in + unknown) + case $cpu-$os in + *-riscix*) + vendor=acorn + ;; + *-sunos*) + vendor=sun + ;; + *-cnk* | *-aix*) + vendor=ibm + ;; + *-beos*) + vendor=be + ;; + *-hpux*) + vendor=hp + ;; + *-mpeix*) + vendor=hp + ;; + *-hiux*) + vendor=hitachi + ;; + *-unos*) + vendor=crds + ;; + *-dgux*) + vendor=dg + ;; + *-luna*) + vendor=omron + ;; + *-genix*) + vendor=ns + ;; + *-clix*) + vendor=intergraph + ;; + *-mvs* | *-opened*) + vendor=ibm + ;; + *-os400*) + vendor=ibm + ;; + s390-* | s390x-*) + vendor=ibm + ;; + *-ptx*) + vendor=sequent + ;; + *-tpf*) + vendor=ibm + ;; + *-vxsim* | *-vxworks* | *-windiss*) + vendor=wrs + ;; + *-aux*) + vendor=apple + ;; + *-hms*) + vendor=hitachi + ;; + *-mpw* | *-macos*) + vendor=apple + ;; + *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) + vendor=atari + ;; + *-vos*) + vendor=stratus + ;; + esac + ;; +esac + +echo "$cpu-$vendor-${kernel:+$kernel-}$os" +exit + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/build/autoconf/expandlibs.m4 b/build/autoconf/expandlibs.m4 new file mode 100644 index 0000000000..70bc153e66 --- /dev/null +++ b/build/autoconf/expandlibs.m4 @@ -0,0 +1,53 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +AC_DEFUN([MOZ_EXPAND_LIBS], +[ +dnl ======================================================== +dnl = +dnl = Check what kind of list files are supported by the +dnl = linker +dnl = +dnl ======================================================== + +AC_CACHE_CHECK(what kind of list files are supported by the linker, + moz_cv_expand_libs_list_style, + [echo "int main() {return 0;}" > conftest.${ac_ext} + dnl Because BFD ld doesn't work with LTO + linker scripts, we + dnl must pass the LTO CFLAGS to the compile command, and the LTO + dnl LDFLAGS to all subsequent link commands. + dnl https://sourceware.org/bugzilla/show_bug.cgi?id=23600 + if AC_TRY_COMMAND(${CC-cc} -o conftest.${OBJ_SUFFIX} -c $MOZ_LTO_CFLAGS $CFLAGS $CPPFLAGS conftest.${ac_ext} 1>&5) && test -s conftest.${OBJ_SUFFIX}; then + echo "INPUT(conftest.${OBJ_SUFFIX})" > conftest.list + if test "$CC_TYPE" = "clang-cl"; then + link="$LINKER -OUT:conftest${ac_exeext}" + else + link="${CC-cc} -o conftest${ac_exeext}" + fi + if AC_TRY_COMMAND($link $MOZ_LTO_LDFLAGS $LDFLAGS conftest.list $LIBS 1>&5) && test -s conftest${ac_exeext}; then + moz_cv_expand_libs_list_style=linkerscript + else + echo "conftest.${OBJ_SUFFIX}" > conftest.list + dnl -filelist is for the OS X linker. We need to try -filelist + dnl first because clang understands @file, but may pass an + dnl oversized argument list to the linker depending on the + dnl contents of @file. + if AC_TRY_COMMAND($link $MOZ_LTO_LDFLAGS $LDFLAGS [-Wl,-filelist,conftest.list] $LIBS 1>&5) && test -s conftest${ac_exeext}; then + moz_cv_expand_libs_list_style=filelist + elif AC_TRY_COMMAND($link $MOZ_LTO_LDFLAGS $LDFLAGS @conftest.list $LIBS 1>&5) && test -s conftest${ac_exeext}; then + moz_cv_expand_libs_list_style=list + else + AC_ERROR([Couldn't find one that works]) + fi + fi + else + dnl We really don't expect to get here, but just in case + AC_ERROR([couldn't compile a simple C file]) + fi + rm -rf conftest*]) + +EXPAND_LIBS_LIST_STYLE=$moz_cv_expand_libs_list_style +AC_SUBST(EXPAND_LIBS_LIST_STYLE) + +]) diff --git a/build/autoconf/hooks.m4 b/build/autoconf/hooks.m4 new file mode 100644 index 0000000000..84d58205c1 --- /dev/null +++ b/build/autoconf/hooks.m4 @@ -0,0 +1,31 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +dnl Wrap AC_INIT_PREPARE to add the above trap. +define([_MOZ_AC_INIT_PREPARE], defn([AC_INIT_PREPARE])) +define([AC_INIT_PREPARE], +[_MOZ_AC_INIT_PREPARE($1) + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' +]) + +dnl Print error messages in config.log as well as stderr +define([AC_MSG_ERROR], +[{ echo "configure: error: $1" 1>&2; echo "configure: error: $1" 1>&5; exit 1; }]) + +dnl Divert AC_TRY_COMPILER to make ac_cv_prog_*_works actually cached. +dnl This will allow to just skip the test when python configure has set +dnl the value for us. But since ac_cv_prog_*_cross is calculated at the same +dnl time, and has a different meaning as in python configure, we only want to +dnl use its value to display whether a cross-compile is happening. We forbid +dnl configure tests that would rely on ac_cv_prog_*_cross autoconf meaning +dnl (being able to execute the product of compilation), which are already bad +dnl for cross compiles anyways, so it's a win to get rid of them. +define([_MOZ_AC_TRY_COMPILER], defn([AC_TRY_COMPILER])) +define([AC_TRY_COMPILER], [AC_CACHE_VAL($2, _MOZ_AC_TRY_COMPILER($1, $2, $3))]) + +define([AC_TRY_RUN], [m4_fatal([AC_TRY_RUN is forbidden])]) +define([AC_CHECK_FILE], [m4_fatal([AC_CHECK_FILE is forbidden])]) diff --git a/build/autoconf/install-sh b/build/autoconf/install-sh new file mode 100755 index 0000000000..a4be13e59f --- /dev/null +++ b/build/autoconf/install-sh @@ -0,0 +1,123 @@ +#!/bin/sh +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +# +# install - install a program, script, or datafile +# This comes from X11R5; it is not part of GNU. +# +# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" + +instcmd="$mvprog" +chmodcmd="" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +fi + +if [ x"$dst" = x ] +then + echo "install: no destination specified" + exit 1 +fi + + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + +if [ -d $dst ] +then + dst="$dst"/`basename $src` +fi + +# Make a temp file name in the proper directory. + +dstdir=`dirname $dst` +dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + +$doit $instcmd $src $dsttmp + +# and set any options; do chmod last to preserve setuid bits + +if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi +if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi +if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi +if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi + +# Now rename the file to the real destination. + +$doit $rmcmd $dst +$doit $mvcmd $dsttmp $dst + + +exit 0 diff --git a/build/autoconf/mozheader.m4 b/build/autoconf/mozheader.m4 new file mode 100644 index 0000000000..e99e35a403 --- /dev/null +++ b/build/autoconf/mozheader.m4 @@ -0,0 +1,32 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +dnl MOZ_CHECK_HEADER(HEADER-FILE, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, INCLUDES]]]) +AC_DEFUN([MOZ_CHECK_HEADER], +[ dnl Do the transliteration at runtime so arg 1 can be a shell variable. + ac_safe=`echo "$1" | sed 'y%./+-%__p_%'` + AC_MSG_CHECKING([for $1]) + AC_CACHE_VAL(ac_cv_header_$ac_safe, + [ AC_TRY_COMPILE([$4 +#include <$1>], , + eval "ac_cv_header_$ac_safe=yes", + eval "ac_cv_header_$ac_safe=no") ]) + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + ifelse([$3], , , [$3]) + fi +]) + +dnl MOZ_CHECK_HEADERS(HEADER-FILE... [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, INCLUDES]]]) +AC_DEFUN([MOZ_CHECK_HEADERS], +[ for ac_hdr in $1 + do + MOZ_CHECK_HEADER($ac_hdr, + [ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + AC_DEFINE_UNQUOTED($ac_tr_hdr) $2], $3, [$4]) + done +]) diff --git a/build/autoconf/mozprog.m4 b/build/autoconf/mozprog.m4 new file mode 100644 index 0000000000..00e357a807 --- /dev/null +++ b/build/autoconf/mozprog.m4 @@ -0,0 +1,42 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +AC_DEFUN([MOZ_PROG_CHECKMSYS], +[AC_REQUIRE([AC_INIT_BINSH])dnl +if test `uname -s | grep -c "MINGW\|MSYS" 2>/dev/null` != "0"; then + msyshost=1 +fi +]) + +AC_DEFUN([MOZ_PATH_PROG], +[ AC_PATH_PROG($1,$2,$3,$4) + if test "$msyshost"; then + case "[$]$1" in + /*) + tmp_DIRNAME=`dirname "[$]$1"` + tmp_BASENAME=`basename "[$]$1"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + $1="$tmp_PWD/$tmp_BASENAME" + if test -e "[$]$1.exe"; then + $1="[$]$1.exe" + fi + esac + fi +]) + +AC_DEFUN([MOZ_PATH_PROGS], +[ AC_PATH_PROGS($1,$2,$3,$4) + if test "$msyshost"; then + case "[$]$1" in + /*) + tmp_DIRNAME=`dirname "[$]$1"` + tmp_BASENAME=`basename "[$]$1"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + $1="$tmp_PWD/$tmp_BASENAME" + if test -e "[$]$1.exe"; then + $1="[$]$1.exe" + fi + esac + fi +]) diff --git a/build/autoconf/sanitize.m4 b/build/autoconf/sanitize.m4 new file mode 100644 index 0000000000..becdf0295d --- /dev/null +++ b/build/autoconf/sanitize.m4 @@ -0,0 +1,143 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +AC_DEFUN([MOZ_CONFIG_SANITIZE], [ + +dnl ======================================================== +dnl = Use Address Sanitizer +dnl ======================================================== +if test -n "$MOZ_ASAN"; then + if test -n "$CLANG_CL"; then + # Look for the ASan runtime binary + if test "$TARGET_CPU" = "x86_64"; then + MOZ_CLANG_RT_ASAN_LIB=clang_rt.asan_dynamic-x86_64.dll + else + MOZ_CLANG_RT_ASAN_LIB=clang_rt.asan_dynamic-i386.dll + fi + # We use MOZ_PATH_PROG in order to get a Windows style path. + MOZ_PATH_PROG(MOZ_CLANG_RT_ASAN_LIB_PATH, $MOZ_CLANG_RT_ASAN_LIB) + if test -z "$MOZ_CLANG_RT_ASAN_LIB_PATH"; then + AC_MSG_ERROR([Couldn't find $MOZ_CLANG_RT_ASAN_LIB. It should be available in the same location as clang-cl.]) + fi + AC_SUBST(MOZ_CLANG_RT_ASAN_LIB_PATH) + # Suppressing errors in recompiled code. + if test "$OS_ARCH" = "WINNT"; then + CFLAGS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/asan_blacklist_win.txt $CFLAGS" + CXXFLAGS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/asan_blacklist_win.txt $CXXFLAGS" + fi + fi + ASAN_FLAGS="-fsanitize=address" + if test "$OS_TARGET" = Linux; then + # -fno-sanitize-address-globals-dead-stripping is used to work around + # https://github.com/rust-lang/rust/issues/113404 + # It forces clang not to use __asan_register_elf_globals/__asan_globals_registered, + # avoiding the conflict with rust. + ASAN_FLAGS="$ASAN_FLAGS -fno-sanitize-address-globals-dead-stripping" + fi + CFLAGS="$ASAN_FLAGS $CFLAGS" + CXXFLAGS="$ASAN_FLAGS $CXXFLAGS" + if test -z "$CLANG_CL"; then + LDFLAGS="-fsanitize=address -rdynamic $LDFLAGS" + fi + AC_DEFINE(MOZ_ASAN) + MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer) +fi +AC_SUBST(MOZ_ASAN) + +dnl ======================================================== +dnl = Use Memory Sanitizer +dnl ======================================================== +if test -n "$MOZ_MSAN"; then + CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins $CFLAGS" + CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins $CXXFLAGS" + if test -z "$CLANG_CL"; then + LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -rdynamic $LDFLAGS" + fi + AC_DEFINE(MOZ_MSAN) + MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer) +fi +AC_SUBST(MOZ_MSAN) + +dnl ======================================================== +dnl = Use Thread Sanitizer +dnl ======================================================== +if test -n "$MOZ_TSAN"; then + CFLAGS="-fsanitize=thread $CFLAGS" + CXXFLAGS="-fsanitize=thread $CXXFLAGS" + if test -z "$CLANG_CL"; then + LDFLAGS="-fsanitize=thread -rdynamic $LDFLAGS" + fi + AC_DEFINE(MOZ_TSAN) + MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer) +fi +AC_SUBST(MOZ_TSAN) + +dnl ======================================================== +dnl = Use UndefinedBehavior Sanitizer (with custom checks) +dnl ======================================================== +if test -n "$MOZ_UBSAN_CHECKS"; then + MOZ_UBSAN=1 + UBSAN_TXT="$_objdir/ubsan_blacklist.txt" + cat $_topsrcdir/build/sanitizers/ubsan_*_blacklist.txt > $UBSAN_TXT + UBSAN_FLAGS="-fsanitize=$MOZ_UBSAN_CHECKS -fno-sanitize-recover=$MOZ_UBSAN_CHECKS -fsanitize-blacklist=$UBSAN_TXT" + CFLAGS="$UBSAN_FLAGS $CFLAGS" + CXXFLAGS="$UBSAN_FLAGS $CXXFLAGS" + if test -z "$CLANG_CL"; then + LDFLAGS="-fsanitize=undefined -rdynamic $LDFLAGS" + fi + AC_DEFINE(MOZ_UBSAN) + MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer) +fi +AC_SUBST(MOZ_UBSAN) + +dnl ======================================================== +dnl = Use UndefinedBehavior Sanitizer to find integer overflows +dnl ======================================================== +if test -n "$MOZ_SIGNED_OVERFLOW_SANITIZE$MOZ_UNSIGNED_OVERFLOW_SANITIZE"; then + MOZ_UBSAN=1 + SANITIZER_BLACKLISTS="" + if test -n "$MOZ_SIGNED_OVERFLOW_SANITIZE"; then + SANITIZER_BLACKLISTS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/ubsan_signed_overflow_blacklist.txt $SANITIZER_BLACKLISTS" + CFLAGS="-fsanitize=signed-integer-overflow $CFLAGS" + CXXFLAGS="-fsanitize=signed-integer-overflow $CXXFLAGS" + if test -z "$CLANG_CL"; then + LDFLAGS="-fsanitize=signed-integer-overflow -rdynamic $LDFLAGS" + fi + AC_DEFINE(MOZ_SIGNED_OVERFLOW_SANITIZE) + fi + if test -n "$MOZ_UNSIGNED_OVERFLOW_SANITIZE"; then + SANITIZER_BLACKLISTS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/ubsan_unsigned_overflow_blacklist.txt $SANITIZER_BLACKLISTS" + CFLAGS="-fsanitize=unsigned-integer-overflow $CFLAGS" + CXXFLAGS="-fsanitize=unsigned-integer-overflow $CXXFLAGS" + if test -z "$CLANG_CL"; then + LDFLAGS="-fsanitize=unsigned-integer-overflow -rdynamic $LDFLAGS" + fi + AC_DEFINE(MOZ_UNSIGNED_OVERFLOW_SANITIZE) + fi + CFLAGS="$SANITIZER_BLACKLISTS $CFLAGS" + CXXFLAGS="$SANITIZER_BLACKLISTS $CXXFLAGS" + AC_DEFINE(MOZ_UBSAN) + MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer) +fi +AC_SUBST(MOZ_SIGNED_OVERFLOW_SANITIZE) +AC_SUBST(MOZ_UNSIGNED_OVERFLOW_SANITIZE) +AC_SUBST(MOZ_UBSAN) + +dnl ======================================================= +dnl = Required for stand-alone (sanitizer-less) libFuzzer. +dnl ======================================================= +if test -n "$LIBFUZZER"; then + LDFLAGS="$LIBFUZZER_FLAGS -rdynamic $LDFLAGS" +fi + +# The LLVM symbolizer is used by all sanitizers +AC_SUBST(LLVM_SYMBOLIZER) + +dnl ======================================================== +dnl = Test for whether the compiler is compatible with the +dnl = given sanitize options. +dnl ======================================================== +AC_TRY_LINK(,,,AC_MSG_ERROR([compiler is incompatible with sanitize options])) + +]) diff --git a/build/autoconf/toolchain.m4 b/build/autoconf/toolchain.m4 new file mode 100644 index 0000000000..270738f4d5 --- /dev/null +++ b/build/autoconf/toolchain.m4 @@ -0,0 +1,117 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +dnl Several autoconf functions AC_REQUIRE AC_PROG_CPP/AC_PROG_CXXCPP +dnl or AC_HEADER_STDC, meaning they are called even when we don't call +dnl them explicitly. +dnl However, theses checks are not necessary and python configure sets +dnl the corresponding variables already, so just skip those tests +dnl entirely. +define([AC_PROG_CPP],[]) +define([AC_PROG_CXXCPP],[]) +define([AC_HEADER_STDC], []) + +dnl AC_LANG_* set ac_link to the C/C++ compiler, which works fine with +dnl gcc and clang, but not great with clang-cl, where the build system +dnl currently expects to run the linker independently. So LDFLAGS are not +dnl really adapted to be used with clang-cl, which then proceeds to +dnl execute link.exe rather than lld-link.exe. +dnl So when the compiler is clang-cl, we modify ac_link to use a separate +dnl linker call. +define([_MOZ_AC_LANG_C], defn([AC_LANG_C])) +define([AC_LANG_C], +[_MOZ_AC_LANG_C +if test "$CC_TYPE" = "clang-cl"; then + ac_link="$ac_compile"' && ${LINKER} -OUT:conftest${ac_exeext} $LDFLAGS conftest.obj $LIBS 1>&AC_FD_CC' +fi +]) + +define([_MOZ_AC_LANG_CPLUSPLUS], defn([AC_LANG_CPLUSPLUS])) +define([AC_LANG_CPLUSPLUS], +[_MOZ_AC_LANG_CPLUSPLUS +if test "$CC_TYPE" = "clang-cl"; then + ac_link="$ac_compile"' && ${LINKER} -OUT:conftest${ac_exeext} $LDFLAGS conftest.obj $LIBS 1>&AC_FD_CC' +fi +]) + +AC_DEFUN([MOZ_TOOL_VARIABLES], +[ +GNU_CC= +GNU_CXX= +if test "$CC_TYPE" = "gcc"; then + GNU_CC=1 + GNU_CXX=1 +fi + +CLANG_CC= +CLANG_CXX= +CLANG_CL= +if test "$CC_TYPE" = "clang"; then + GNU_CC=1 + GNU_CXX=1 + CLANG_CC=1 + CLANG_CXX=1 +fi +if test "$CC_TYPE" = "clang-cl"; then + CLANG_CL=1 +fi + +AC_SUBST(CLANG_CXX) +AC_SUBST(CLANG_CL) +]) + +AC_DEFUN([MOZ_CROSS_COMPILER], +[ +echo "cross compiling from $host to $target" + +dnl AC_CHECK_PROGS manually goes through $PATH, and as such fails to handle +dnl absolute or relative paths. Relative paths wouldn't work anyways, but +dnl absolute paths would. Trick AC_CHECK_PROGS into working in that case by +dnl adding / to PATH. This is temporary until this moves to moz.configure +dnl (soon). +_SAVE_PATH=$PATH +case "${TOOLCHAIN_PREFIX}" in +/*) + PATH="/:$PATH" + ;; +esac +AC_PROG_CC +AC_PROG_CXX + +PATH=$_SAVE_PATH +]) + +AC_DEFUN([MOZ_CXX11], +[ +dnl Updates to the test below should be duplicated further below for the +dnl cross-compiling case. +AC_LANG_CPLUSPLUS +if test "$GNU_CXX"; then + AC_CACHE_CHECK([whether 64-bits std::atomic requires -latomic], + ac_cv_needs_atomic, + AC_TRY_LINK( + [#include + #include ], + [ std::atomic foo; foo = 1; ], + ac_cv_needs_atomic=no, + _SAVE_LIBS="$LIBS" + LIBS="$LIBS -latomic" + AC_TRY_LINK( + [#include + #include ], + [ std::atomic foo; foo = 1; ], + ac_cv_needs_atomic=yes, + ac_cv_needs_atomic="do not know; assuming no") + LIBS="$_SAVE_LIBS" + ) + ) + if test "$ac_cv_needs_atomic" = yes; then + MOZ_NEEDS_LIBATOMIC=1 + else + MOZ_NEEDS_LIBATOMIC= + fi + AC_SUBST(MOZ_NEEDS_LIBATOMIC) +fi +AC_LANG_C +]) diff --git a/build/binary-location.mk b/build/binary-location.mk new file mode 100644 index 0000000000..19ae4b55f3 --- /dev/null +++ b/build/binary-location.mk @@ -0,0 +1,19 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# finds the location of the browser and puts it in the variable $(browser_path) + +ifneq (,$(filter WINNT,$(OS_ARCH))) +program = $(MOZ_APP_NAME)$(BIN_SUFFIX) +else +program = $(MOZ_APP_NAME)-bin$(BIN_SUFFIX) +endif + +TARGET_DIST = $(TARGET_DEPTH)/dist + +ifeq ($(OS_ARCH),Darwin) +browser_path = $(TARGET_DIST)/$(MOZ_MACBUNDLE_NAME)/Contents/MacOS/$(program) +else +browser_path = $(TARGET_DIST)/bin/$(program) +endif diff --git a/build/build-clang/1stage.json b/build/build-clang/1stage.json new file mode 100644 index 0000000000..4633a3e93e --- /dev/null +++ b/build/build-clang/1stage.json @@ -0,0 +1,4 @@ +{ + "stages": "1", + "targets": "X86;ARM;AArch64;WebAssembly" +} diff --git a/build/build-clang/2stages.json b/build/build-clang/2stages.json new file mode 100644 index 0000000000..e34226758d --- /dev/null +++ b/build/build-clang/2stages.json @@ -0,0 +1,3 @@ +{ + "stages": "2" +} diff --git a/build/build-clang/4stages-pgo.json b/build/build-clang/4stages-pgo.json new file mode 100644 index 0000000000..8f0c5aa97d --- /dev/null +++ b/build/build-clang/4stages-pgo.json @@ -0,0 +1,7 @@ +{ + "stages": "4", + "targets": "X86;ARM;AArch64;WebAssembly", + "pgo": true, + "ranlib": "{MOZ_FETCHES_DIR}/clang/bin/llvm-ranlib", + "ar": "{MOZ_FETCHES_DIR}/clang/bin/llvm-ar" +} diff --git a/build/build-clang/D146664.patch b/build/build-clang/D146664.patch new file mode 100644 index 0000000000..9813c6c86e --- /dev/null +++ b/build/build-clang/D146664.patch @@ -0,0 +1,99 @@ +From b57ff6da9c8b281ae9312e245fd3372e7ffaff28 Mon Sep 17 00:00:00 2001 +From: Mike Hommey +Date: Thu, 23 Mar 2023 06:52:28 +0900 +Subject: [PATCH] Apply the same fallbacks as runtimes search for stdlib search + +When building clang with e.g. LLVM_ENABLE_RUNTIMES=libcxx;libunwind, +those runtimes end up in the stdlib search directory, and when +LLVM_ENABLE_PER_TARGET_RUNTIME_DIR is set, that ends up in a +target-specific subdirectory. The stdlib search does handle the +situation, but when the target in question is Android, the same issues +as those that required fallbacks for runtimes search apply. + +Traditionally, those libraries are shipped as part of the Android NDK, +but when one builds their own clang for Android, they may want to use +the runtimes from the same version rather than the ones from the NDK. + +Differential Revision: https://reviews.llvm.org/D146664 +--- + clang/lib/Driver/ToolChain.cpp | 42 +++++++++++++++++++--------------- + 1 file changed, 24 insertions(+), 18 deletions(-) + +diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp +index 2dba975a5a8f..9052099cad5e 100644 +--- a/clang/lib/Driver/ToolChain.cpp ++++ b/clang/lib/Driver/ToolChain.cpp +@@ -569,15 +569,9 @@ const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args, + return Args.MakeArgString(getCompilerRT(Args, Component, Type)); + } + +-ToolChain::path_list ToolChain::getRuntimePaths() const { +- path_list Paths; +- auto addPathForTriple = [this, &Paths](const llvm::Triple &Triple) { +- SmallString<128> P(D.ResourceDir); +- llvm::sys::path::append(P, "lib", Triple.str()); +- Paths.push_back(std::string(P.str())); +- }; +- +- addPathForTriple(getTriple()); ++template ++static void fillPaths(const ToolChain &TC, F addPathForTriple) { ++ addPathForTriple(TC.getTriple()); + + // When building with per target runtime directories, various ways of naming + // the Arm architecture may have been normalised to simply "arm". +@@ -594,30 +588,42 @@ ToolChain::path_list ToolChain::getRuntimePaths() const { + // + // M profile Arm is bare metal and we know they will not be using the per + // target runtime directory layout. +- if (getTriple().getArch() == Triple::arm && !getTriple().isArmMClass()) { +- llvm::Triple ArmTriple = getTriple(); ++ if (TC.getTriple().getArch() == Triple::arm && ++ !TC.getTriple().isArmMClass()) { ++ llvm::Triple ArmTriple = TC.getTriple(); + ArmTriple.setArch(Triple::arm); + addPathForTriple(ArmTriple); + } + + // Android targets may include an API level at the end. We still want to fall + // back on a path without the API level. +- if (getTriple().isAndroid() && +- getTriple().getEnvironmentName() != "android") { +- llvm::Triple TripleWithoutLevel = getTriple(); ++ if (TC.getTriple().isAndroid() && ++ TC.getTriple().getEnvironmentName() != "android") { ++ llvm::Triple TripleWithoutLevel = TC.getTriple(); + TripleWithoutLevel.setEnvironmentName("android"); + addPathForTriple(TripleWithoutLevel); + } ++} + ++ToolChain::path_list ToolChain::getRuntimePaths() const { ++ path_list Paths; ++ auto addPathForTriple = [this, &Paths](const llvm::Triple &Triple) { ++ SmallString<128> P(D.ResourceDir); ++ llvm::sys::path::append(P, "lib", Triple.str()); ++ Paths.push_back(std::string(P.str())); ++ }; ++ fillPaths(*this, addPathForTriple); + return Paths; + } + + ToolChain::path_list ToolChain::getStdlibPaths() const { + path_list Paths; +- SmallString<128> P(D.Dir); +- llvm::sys::path::append(P, "..", "lib", getTripleString()); +- Paths.push_back(std::string(P.str())); +- ++ auto addPathForTriple = [this, &Paths](const llvm::Triple &Triple) { ++ SmallString<128> P(D.Dir); ++ llvm::sys::path::append(P, "..", "lib", Triple.str()); ++ Paths.push_back(std::string(P.str())); ++ }; ++ fillPaths(*this, addPathForTriple); + return Paths; + } + +-- +2.39.0.1.g6739ec1790 + diff --git a/build/build-clang/README b/build/build-clang/README new file mode 100644 index 0000000000..5b13edeeb9 --- /dev/null +++ b/build/build-clang/README @@ -0,0 +1,53 @@ +build-clang.py +============== + +A script to build clang from source. + +``` +usage: build-clang.py [-h] -c CONFIG [--clean] + +optional arguments: + -h, --help show this help message and exit + -c CONFIG, --config CONFIG + Clang configuration file + --clean Clean the build directory +``` + +Pre-requisites +-------------- +* Working build toolchain. +* git +* CMake +* Ninja +* Python 2.7 and 3 + +Please use the latest available CMake for your platform to avoid surprises. + +Config file format +------------------ + +build-clang.py accepts a JSON config format with the following fields: + +* stages: Use 1, 2, 3 or 4 to select different compiler stages. The default is 2. +* cc: Path to the bootsraping C Compiler. +* cxx: Path to the bootsraping C++ Compiler. +* as: Path to the assembler tool. +* ar: Path to the library archiver tool. +* ranlib: Path to the ranlib tool (optional). +* ld: Path to the linker. +* patches: Optional list of patches to apply. +* build_type: The type of build to make. Supported types: Release, Debug, RelWithDebInfo or MinSizeRel. +* targets: The targets supported by the final stage LLVM/clang. +* build_clang_tidy: Whether to build clang-tidy with the Mozilla checks imported. The default is false. +* osx_cross_compile: Whether to invoke CMake for OS X cross compile builds. +* assertions: Whether to enable LLVM assertions. The default is false. +* pgo: Whether to build with PGO (requires stages == 4). The default is false. + +The revisions are defined in taskcluster/ci/fetch/toolchains.yml. They are usually commit sha1s corresponding to upstream tags. + +Environment Variables +--------------------- + +The following environment variables are used for cross-compile builds targeting OS X on Linux. + +* CROSS_SYSROOT: Path to the OS X SDK directory for cross compile builds. diff --git a/build/build-clang/Remove-FlushViewOfFile-when-unmaping-gcda-files.patch b/build/build-clang/Remove-FlushViewOfFile-when-unmaping-gcda-files.patch new file mode 100644 index 0000000000..a3ea2d75f9 --- /dev/null +++ b/build/build-clang/Remove-FlushViewOfFile-when-unmaping-gcda-files.patch @@ -0,0 +1,31 @@ +From 78a6bcfed4b73f13b9973afd69b76067dd4a5dde Mon Sep 17 00:00:00 2001 +From: Calixte Denizet +Date: Mon, 4 Oct 2021 11:07:56 +0200 +Subject: [PATCH] Remove FlushViewOfFile when unmaping gcda files - it can + causes bad performances with slow disks; - MS docs say that it's mainly + useful in case of hard failures (OS crash, electrical failure, ...): so it's + useless to call this function when ccov builds run on CI. + +--- + compiler-rt/lib/profile/GCDAProfiling.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c +index 4293e8f7b5bf..83650d33c95d 100644 +--- a/compiler-rt/lib/profile/GCDAProfiling.c ++++ b/compiler-rt/lib/profile/GCDAProfiling.c +@@ -286,11 +286,6 @@ static int map_file() { + + static void unmap_file() { + #if defined(_WIN32) +- if (!FlushViewOfFile(write_buffer, file_size)) { +- fprintf(stderr, "profiling: %s: cannot flush mapped view: %lu\n", filename, +- GetLastError()); +- } +- + if (!UnmapViewOfFile(write_buffer)) { + fprintf(stderr, "profiling: %s: cannot unmap mapped view: %lu\n", filename, + GetLastError()); +-- +2.33.0 + diff --git a/build/build-clang/allow-unversioned-android.patch b/build/build-clang/allow-unversioned-android.patch new file mode 100644 index 0000000000..afd82bfc25 --- /dev/null +++ b/build/build-clang/allow-unversioned-android.patch @@ -0,0 +1,36 @@ +diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp +index 31245964c4ba..dbdccd95bb4f 100644 +--- a/clang/lib/Driver/ToolChain.cpp ++++ b/clang/lib/Driver/ToolChain.cpp +@@ -689,7 +689,6 @@ ToolChain::getFallbackAndroidTargetPath(StringRef BaseDir) const { + unsigned BestVersion = 0; + + SmallString<32> TripleDir; +- bool UsingUnversionedDir = false; + std::error_code EC; + for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(BaseDir, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { +@@ -698,14 +697,12 @@ ToolChain::getFallbackAndroidTargetPath(StringRef BaseDir) const { + if (DirNameSuffix.consume_front(TripleWithoutLevelStr)) { + if (DirNameSuffix.empty() && TripleDir.empty()) { + TripleDir = DirName; +- UsingUnversionedDir = true; + } else { + unsigned Version; + if (!DirNameSuffix.getAsInteger(10, Version) && Version > BestVersion && + Version < TripleVersion) { + BestVersion = Version; + TripleDir = DirName; +- UsingUnversionedDir = false; + } + } + } +@@ -716,8 +713,6 @@ ToolChain::getFallbackAndroidTargetPath(StringRef BaseDir) const { + + SmallString<128> P(BaseDir); + llvm::sys::path::append(P, TripleDir); +- if (UsingUnversionedDir) +- D.Diag(diag::warn_android_unversioned_fallback) << P << getTripleString(); + return std::string(P); + } + diff --git a/build/build-clang/android-mangling-error_clang_12.patch b/build/build-clang/android-mangling-error_clang_12.patch new file mode 100644 index 0000000000..315756d30b --- /dev/null +++ b/build/build-clang/android-mangling-error_clang_12.patch @@ -0,0 +1,24 @@ +Workaround segfault in clang's mangling code that is tickled when +attempting to mangle the declaration: + std:__ndk1::__find_detail::__find_exactly_one_checked::__matches +in the header in the Android NDK. +This codepath is exercised by MozsearchIndexer.cpp (the searchfox +indexer) when indexing on Android. See also +https://bugs.llvm.org/show_bug.cgi?id=40747 + +diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp +index 4420f6a2c1c3..39792e6b7350 100644 +--- a/clang/lib/AST/ItaniumMangle.cpp ++++ b/clang/lib/AST/ItaniumMangle.cpp +@@ -3954,6 +3954,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, + // produces no output, where ImplicitlyConvertedToType and AsTemplateArg need + // to be preserved. + recurse: ++ if (!E) { ++ Out << "MOZ_WE_HACKED_AROUND_BUG_1500941"; ++ return; ++ } ++ + switch (E->getStmtClass()) { + case Expr::NoStmtClass: + #define ABSTRACT_STMT(Type) diff --git a/build/build-clang/build-clang.py b/build/build-clang/build-clang.py new file mode 100755 index 0000000000..08e05483f5 --- /dev/null +++ b/build/build-clang/build-clang.py @@ -0,0 +1,843 @@ +#!/usr/bin/python3 +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Only necessary for flake8 to be happy... +import argparse +import errno +import fnmatch +import glob +import json +import os +import os.path +import platform +import re +import shutil +import subprocess +import sys +import tarfile +from contextlib import contextmanager +from shutil import which + +import zstandard + +SUPPORTED_TARGETS = { + "x86_64-unknown-linux-gnu": ("Linux", "x86_64"), + "x86_64-pc-windows-msvc": ("Windows", "AMD64"), + "x86_64-apple-darwin": ("Darwin", "x86_64"), + "aarch64-apple-darwin": ("Darwin", "arm64"), +} + + +def is_llvm_toolchain(cc, cxx): + return "clang" in cc and "clang" in cxx + + +def check_run(args): + print(" ".join(args), file=sys.stderr, flush=True) + if args[0] == "cmake": + # CMake `message(STATUS)` messages, as appearing in failed source code + # compiles, appear on stdout, so we only capture that. + p = subprocess.Popen(args, stdout=subprocess.PIPE) + lines = [] + for line in p.stdout: + lines.append(line) + sys.stdout.write(line.decode()) + sys.stdout.flush() + r = p.wait() + if r != 0 and os.environ.get("UPLOAD_DIR"): + cmake_output_re = re.compile(b'See also "(.*/CMakeOutput.log)"') + cmake_error_re = re.compile(b'See also "(.*/CMakeError.log)"') + + def find_first_match(re): + for l in lines: + match = re.search(l) + if match: + return match + + output_match = find_first_match(cmake_output_re) + error_match = find_first_match(cmake_error_re) + + upload_dir = os.environ["UPLOAD_DIR"].encode("utf-8") + if output_match or error_match: + mkdir_p(upload_dir) + if output_match: + shutil.copy2(output_match.group(1), upload_dir) + if error_match: + shutil.copy2(error_match.group(1), upload_dir) + else: + r = subprocess.call(args) + assert r == 0 + + +def run_in(path, args): + with chdir(path): + check_run(args) + + +@contextmanager +def chdir(path): + d = os.getcwd() + print('cd "%s"' % path, file=sys.stderr) + os.chdir(path) + try: + yield + finally: + print('cd "%s"' % d, file=sys.stderr) + os.chdir(d) + + +def patch(patch, srcdir): + patch = os.path.realpath(patch) + check_run(["patch", "-d", srcdir, "-p1", "-i", patch, "--fuzz=0", "-s"]) + + +def import_clang_tidy(source_dir, build_clang_tidy_alpha, build_clang_tidy_external): + clang_plugin_path = os.path.join(os.path.dirname(sys.argv[0]), "..", "clang-plugin") + clang_tidy_path = os.path.join(source_dir, "clang-tools-extra/clang-tidy") + sys.path.append(clang_plugin_path) + from import_mozilla_checks import do_import + + import_options = { + "alpha": build_clang_tidy_alpha, + "external": build_clang_tidy_external, + } + do_import(clang_plugin_path, clang_tidy_path, import_options) + + +def build_package(package_build_dir, cmake_args): + if not os.path.exists(package_build_dir): + os.mkdir(package_build_dir) + # If CMake has already been run, it may have been run with different + # arguments, so we need to re-run it. Make sure the cached copy of the + # previous CMake run is cleared before running it again. + if os.path.exists(package_build_dir + "/CMakeCache.txt"): + os.remove(package_build_dir + "/CMakeCache.txt") + if os.path.exists(package_build_dir + "/CMakeFiles"): + shutil.rmtree(package_build_dir + "/CMakeFiles") + + run_in(package_build_dir, ["cmake"] + cmake_args) + run_in(package_build_dir, ["ninja", "install", "-v"]) + + +@contextmanager +def updated_env(env): + old_env = os.environ.copy() + os.environ.update(env) + yield + os.environ.clear() + os.environ.update(old_env) + + +def build_tar_package(name, base, directory): + name = os.path.realpath(name) + print("tarring {} from {}/{}".format(name, base, directory), file=sys.stderr) + assert name.endswith(".tar.zst") + + cctx = zstandard.ZstdCompressor() + with open(name, "wb") as f, cctx.stream_writer(f) as z: + with tarfile.open(mode="w|", fileobj=z) as tf: + with chdir(base): + tf.add(directory) + + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as e: + if e.errno != errno.EEXIST or not os.path.isdir(path): + raise + + +def delete(path): + if os.path.isdir(path): + shutil.rmtree(path) + else: + try: + os.unlink(path) + except Exception: + pass + + +def install_import_library(build_dir, clang_dir): + shutil.copy2( + os.path.join(build_dir, "lib", "clang.lib"), os.path.join(clang_dir, "lib") + ) + + +def is_darwin(target): + return "-apple-darwin" in target + + +def is_linux(target): + return "-linux-gnu" in target + + +def is_windows(target): + return "-windows-msvc" in target + + +def is_cross_compile(target): + return SUPPORTED_TARGETS[target] != (platform.system(), platform.machine()) + + +def build_one_stage( + cc, + cxx, + asm, + ar, + ranlib, + ldflags, + src_dir, + stage_dir, + package_name, + build_type, + assertions, + target, + targets, + is_final_stage=False, + profile=None, +): + if not os.path.exists(stage_dir): + os.mkdir(stage_dir) + + build_dir = stage_dir + "/build" + inst_dir = stage_dir + "/" + package_name + + # cmake doesn't deal well with backslashes in paths. + def slashify_path(path): + return path.replace("\\", "/") + + def cmake_base_args(cc, cxx, asm, ar, ranlib, ldflags, inst_dir): + machine_targets = targets if is_final_stage and targets else "X86" + + cmake_args = [ + "-GNinja", + "-DCMAKE_C_COMPILER=%s" % slashify_path(cc[0]), + "-DCMAKE_CXX_COMPILER=%s" % slashify_path(cxx[0]), + "-DCMAKE_ASM_COMPILER=%s" % slashify_path(asm[0]), + "-DCMAKE_AR=%s" % slashify_path(ar), + "-DCMAKE_C_FLAGS_INIT=%s" % " ".join(cc[1:]), + "-DCMAKE_CXX_FLAGS_INIT=%s" % " ".join(cxx[1:]), + "-DCMAKE_ASM_FLAGS_INIT=%s" % " ".join(asm[1:]), + "-DCMAKE_EXE_LINKER_FLAGS_INIT=%s" % " ".join(ldflags), + "-DCMAKE_SHARED_LINKER_FLAGS_INIT=%s" % " ".join(ldflags), + "-DCMAKE_BUILD_TYPE=%s" % build_type, + "-DCMAKE_INSTALL_PREFIX=%s" % inst_dir, + "-DLLVM_TARGETS_TO_BUILD=%s" % machine_targets, + "-DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF", + "-DLLVM_ENABLE_ASSERTIONS=%s" % ("ON" if assertions else "OFF"), + "-DLLVM_ENABLE_BINDINGS=OFF", + "-DLLVM_ENABLE_CURL=OFF", + "-DLLVM_INCLUDE_TESTS=OFF", + ] + if is_llvm_toolchain(cc[0], cxx[0]): + cmake_args += ["-DLLVM_ENABLE_LLD=ON"] + elif is_windows(target) and is_cross_compile(target): + raise Exception( + "Cannot cross-compile for Windows with a compiler that is not clang" + ) + + if "TASK_ID" in os.environ: + cmake_args += [ + "-DCLANG_REPOSITORY_STRING=taskcluster-%s" % os.environ["TASK_ID"], + ] + projects = ["clang", "lld"] + if is_final_stage: + projects.append("clang-tools-extra") + else: + cmake_args.append("-DLLVM_TOOL_LLI_BUILD=OFF") + + cmake_args.append("-DLLVM_ENABLE_PROJECTS=%s" % ";".join(projects)) + + # There is no libxml2 on Windows except if we build one ourselves. + # libxml2 is only necessary for llvm-mt, but Windows can just use the + # native MT tool. + if not is_windows(target) and is_final_stage: + cmake_args += ["-DLLVM_ENABLE_LIBXML2=FORCE_ON"] + if is_linux(target) and is_final_stage: + sysroot = os.path.join(os.environ.get("MOZ_FETCHES_DIR", ""), "sysroot") + if os.path.exists(sysroot): + cmake_args += ["-DLLVM_BINUTILS_INCDIR=/usr/include"] + cmake_args += ["-DCMAKE_SYSROOT=%s" % sysroot] + # Work around the LLVM build system not building the i386 compiler-rt + # because it doesn't allow to use a sysroot for that during the cmake + # checks. + cmake_args += ["-DCAN_TARGET_i386=1"] + cmake_args += ["-DLLVM_ENABLE_TERMINFO=OFF"] + if is_windows(target): + cmake_args.insert(-1, "-DLLVM_EXPORT_SYMBOLS_FOR_PLUGINS=ON") + cmake_args.insert(-1, "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded") + if is_cross_compile(target): + cmake_args += [ + f"-DCMAKE_TOOLCHAIN_FILE={src_dir}/cmake/platforms/WinMsvc.cmake", + f"-DLLVM_NATIVE_TOOLCHAIN={os.path.dirname(os.path.dirname(cc[0]))}", + f"-DHOST_ARCH={target[: -len('-pc-windows-msvc')]}", + f"-DLLVM_WINSYSROOT={os.environ['VSINSTALLDIR']}", + "-DLLVM_DISABLE_ASSEMBLY_FILES=ON", + ] + else: + # libllvm as a shared library is not supported on Windows + cmake_args += ["-DLLVM_LINK_LLVM_DYLIB=ON"] + if ranlib is not None: + cmake_args += ["-DCMAKE_RANLIB=%s" % slashify_path(ranlib)] + if is_darwin(target) and is_cross_compile(target): + arch = "arm64" if target.startswith("aarch64") else "x86_64" + cmake_args += [ + "-DCMAKE_SYSTEM_NAME=Darwin", + "-DCMAKE_SYSTEM_VERSION=%s" % os.environ["MACOSX_DEPLOYMENT_TARGET"], + "-DCMAKE_OSX_SYSROOT=%s" % slashify_path(os.getenv("CROSS_SYSROOT")), + "-DCMAKE_FIND_ROOT_PATH=%s" % slashify_path(os.getenv("CROSS_SYSROOT")), + "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER", + "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY", + "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY", + "-DCMAKE_MACOSX_RPATH=ON", + "-DCMAKE_OSX_ARCHITECTURES=%s" % arch, + "-DDARWIN_osx_ARCHS=%s" % arch, + "-DDARWIN_osx_SYSROOT=%s" % slashify_path(os.getenv("CROSS_SYSROOT")), + "-DLLVM_DEFAULT_TARGET_TRIPLE=%s" % target, + "-DCMAKE_C_COMPILER_TARGET=%s" % target, + "-DCMAKE_CXX_COMPILER_TARGET=%s" % target, + "-DCMAKE_ASM_COMPILER_TARGET=%s" % target, + ] + if arch == "arm64": + cmake_args += [ + "-DDARWIN_osx_BUILTIN_ARCHS=arm64", + ] + # Starting in LLVM 11 (which requires SDK 10.12) the build tries to + # detect the SDK version by calling xcrun. Cross-compiles don't have + # an xcrun, so we have to set the version explicitly. + cmake_args += [ + "-DDARWIN_macosx_OVERRIDE_SDK_VERSION=%s" + % os.environ["MACOSX_DEPLOYMENT_TARGET"], + ] + + if profile == "gen": + # Per https://releases.llvm.org/10.0.0/docs/HowToBuildWithPGO.html + cmake_args += [ + "-DLLVM_BUILD_INSTRUMENTED=IR", + "-DLLVM_BUILD_RUNTIME=No", + ] + elif profile: + cmake_args += [ + "-DLLVM_PROFDATA_FILE=%s" % profile, + ] + + # Using LTO for both profile generation and usage to avoid most + # "function control flow change detected (hash mismatch)" error. + if profile and not is_windows(target): + cmake_args.append("-DLLVM_ENABLE_LTO=Thin") + return cmake_args + + cmake_args = [] + cmake_args += cmake_base_args(cc, cxx, asm, ar, ranlib, ldflags, inst_dir) + cmake_args += [src_dir] + build_package(build_dir, cmake_args) + + # For some reasons the import library clang.lib of clang.exe is not + # installed, so we copy it by ourselves. + if is_windows(target) and is_final_stage: + install_import_library(build_dir, inst_dir) + + +# Return the absolute path of a build tool. We first look to see if the +# variable is defined in the config file, and if so we make sure it's an +# absolute path to an existing tool, otherwise we look for a program in +# $PATH named "key". +# +# This expects the name of the key in the config file to match the name of +# the tool in the default toolchain on the system (for example, "ld" on Unix +# and "link" on Windows). +def get_tool(config, key): + f = None + if key in config: + f = config[key].format(**os.environ) + if os.path.isabs(f): + if not os.path.exists(f): + raise ValueError("%s must point to an existing path" % key) + return f + + # Assume that we have the name of some program that should be on PATH. + tool = which(f) if f else which(key) + if not tool: + raise ValueError("%s not found on PATH" % (f or key)) + return tool + + +# This function is intended to be called on the final build directory when +# building clang-tidy. Also clang-format binaries are included that can be used +# in conjunction with clang-tidy. +# As a separate binary we also ship clangd for the language server protocol that +# can be used as a plugin in `vscode`. +# Its job is to remove all of the files which won't be used for clang-tidy or +# clang-format to reduce the download size. Currently when this function +# finishes its job, it will leave final_dir with a layout like this: +# +# clang/ +# bin/ +# clang-apply-replacements +# clang-format +# clang-tidy +# clangd +# run-clang-tidy +# include/ +# * (nothing will be deleted here) +# lib/ +# clang/ +# 4.0.0/ +# include/ +# * (nothing will be deleted here) +# share/ +# clang/ +# clang-format-diff.py +# clang-tidy-diff.py +# run-clang-tidy.py +def prune_final_dir_for_clang_tidy(final_dir, target): + # Make sure we only have what we expect. + dirs = [ + "bin", + "include", + "lib", + "lib32", + "libexec", + "msbuild-bin", + "share", + "tools", + ] + if is_linux(target): + dirs.append("x86_64-unknown-linux-gnu") + for f in glob.glob("%s/*" % final_dir): + if os.path.basename(f) not in dirs: + raise Exception("Found unknown file %s in the final directory" % f) + if not os.path.isdir(f): + raise Exception("Expected %s to be a directory" % f) + + kept_binaries = [ + "clang-apply-replacements", + "clang-format", + "clang-tidy", + "clangd", + "clang-query", + "run-clang-tidy", + ] + re_clang_tidy = re.compile(r"^(" + "|".join(kept_binaries) + r")(\.exe)?$", re.I) + for f in glob.glob("%s/bin/*" % final_dir): + if re_clang_tidy.search(os.path.basename(f)) is None: + delete(f) + + # Keep include/ intact. + + # Remove the target-specific files. + if is_linux(target): + if os.path.exists(os.path.join(final_dir, "x86_64-unknown-linux-gnu")): + shutil.rmtree(os.path.join(final_dir, "x86_64-unknown-linux-gnu")) + + # In lib/, only keep lib/clang/N.M.O/include and the LLVM shared library. + re_ver_num = re.compile(r"^\d+(?:\.\d+\.\d+)?$", re.I) + for f in glob.glob("%s/lib/*" % final_dir): + name = os.path.basename(f) + if name == "clang": + continue + if is_darwin(target) and name in ["libLLVM.dylib", "libclang-cpp.dylib"]: + continue + if is_linux(target) and ( + fnmatch.fnmatch(name, "libLLVM*.so") + or fnmatch.fnmatch(name, "libclang-cpp.so*") + ): + continue + delete(f) + for f in glob.glob("%s/lib/clang/*" % final_dir): + if re_ver_num.search(os.path.basename(f)) is None: + delete(f) + for f in glob.glob("%s/lib/clang/*/*" % final_dir): + if os.path.basename(f) != "include": + delete(f) + + # Completely remove libexec/, msbuild-bin and tools, if it exists. + shutil.rmtree(os.path.join(final_dir, "libexec")) + for d in ("msbuild-bin", "tools"): + d = os.path.join(final_dir, d) + if os.path.exists(d): + shutil.rmtree(d) + + # In share/, only keep share/clang/*tidy* + re_clang_tidy = re.compile(r"format|tidy", re.I) + for f in glob.glob("%s/share/*" % final_dir): + if os.path.basename(f) != "clang": + delete(f) + for f in glob.glob("%s/share/clang/*" % final_dir): + if re_clang_tidy.search(os.path.basename(f)) is None: + delete(f) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "-c", + "--config", + action="append", + required=True, + type=argparse.FileType("r"), + help="Clang configuration file", + ) + parser.add_argument( + "--clean", required=False, action="store_true", help="Clean the build directory" + ) + parser.add_argument( + "--skip-tar", + required=False, + action="store_true", + help="Skip tar packaging stage", + ) + parser.add_argument( + "--skip-patch", + required=False, + action="store_true", + help="Do not patch source", + ) + + args = parser.parse_args() + + if not os.path.exists("llvm/README.txt"): + raise Exception( + "The script must be run from the root directory of the llvm-project tree" + ) + source_dir = os.getcwd() + build_dir = source_dir + "/build" + + if args.clean: + shutil.rmtree(build_dir) + os.sys.exit(0) + + llvm_source_dir = source_dir + "/llvm" + + config = {} + # Merge all the configs we got from the command line. + for c in args.config: + this_config_dir = os.path.dirname(c.name) + this_config = json.load(c) + patches = this_config.get("patches") + if patches: + this_config["patches"] = [os.path.join(this_config_dir, p) for p in patches] + for key, value in this_config.items(): + old_value = config.get(key) + if old_value is None: + config[key] = value + elif value is None: + if key in config: + del config[key] + elif type(old_value) != type(value): + raise Exception( + "{} is overriding `{}` with a value of the wrong type".format( + c.name, key + ) + ) + elif isinstance(old_value, list): + for v in value: + if v not in old_value: + old_value.append(v) + elif isinstance(old_value, dict): + raise Exception("{} is setting `{}` to a dict?".format(c.name, key)) + else: + config[key] = value + + stages = 2 + if "stages" in config: + stages = int(config["stages"]) + if stages not in (1, 2, 3, 4): + raise ValueError("We only know how to build 1, 2, 3, or 4 stages.") + skip_stages = 0 + if "skip_stages" in config: + # The assumption here is that the compiler given in `cc` and other configs + # is the result of the last skip stage, built somewhere else. + skip_stages = int(config["skip_stages"]) + if skip_stages >= stages: + raise ValueError("Cannot skip more stages than are built.") + pgo = False + if "pgo" in config: + pgo = config["pgo"] + if pgo not in (True, False): + raise ValueError("Only boolean values are accepted for pgo.") + build_type = "Release" + if "build_type" in config: + build_type = config["build_type"] + if build_type not in ("Release", "Debug", "RelWithDebInfo", "MinSizeRel"): + raise ValueError( + "We only know how to do Release, Debug, RelWithDebInfo or " + "MinSizeRel builds" + ) + targets = config.get("targets") + build_clang_tidy = False + if "build_clang_tidy" in config: + build_clang_tidy = config["build_clang_tidy"] + if build_clang_tidy not in (True, False): + raise ValueError("Only boolean values are accepted for build_clang_tidy.") + build_clang_tidy_alpha = False + # check for build_clang_tidy_alpha only if build_clang_tidy is true + if build_clang_tidy and "build_clang_tidy_alpha" in config: + build_clang_tidy_alpha = config["build_clang_tidy_alpha"] + if build_clang_tidy_alpha not in (True, False): + raise ValueError( + "Only boolean values are accepted for build_clang_tidy_alpha." + ) + build_clang_tidy_external = False + # check for build_clang_tidy_external only if build_clang_tidy is true + if build_clang_tidy and "build_clang_tidy_external" in config: + build_clang_tidy_external = config["build_clang_tidy_external"] + if build_clang_tidy_external not in (True, False): + raise ValueError( + "Only boolean values are accepted for build_clang_tidy_external." + ) + assertions = False + if "assertions" in config: + assertions = config["assertions"] + if assertions not in (True, False): + raise ValueError("Only boolean values are accepted for assertions.") + + for t in SUPPORTED_TARGETS: + if not is_cross_compile(t): + host = t + break + else: + raise Exception( + f"Cannot use this script on {platform.system()} {platform.machine()}" + ) + + target = config.get("target", host) + if target not in SUPPORTED_TARGETS: + raise ValueError(f"{target} is not a supported target.") + + if is_cross_compile(target) and not is_linux(host): + raise Exception("Cross-compilation is only supported on Linux") + + if is_darwin(target): + os.environ["MACOSX_DEPLOYMENT_TARGET"] = ( + "11.0" if target.startswith("aarch64") else "10.12" + ) + + if is_windows(target): + exe_ext = ".exe" + cc_name = "clang-cl" + cxx_name = "clang-cl" + else: + exe_ext = "" + cc_name = "clang" + cxx_name = "clang++" + + cc = get_tool(config, "cc") + cxx = get_tool(config, "cxx") + asm = get_tool(config, "ml" if is_windows(target) else "as") + # Not using lld here as default here because it's not in PATH. But clang + # knows how to find it when they are installed alongside each others. + ar = get_tool(config, "lib" if is_windows(target) else "ar") + ranlib = None if is_windows(target) else get_tool(config, "ranlib") + + if not os.path.exists(source_dir): + os.makedirs(source_dir) + + if not args.skip_patch: + for p in config.get("patches", []): + patch(p, source_dir) + + package_name = "clang" + if build_clang_tidy: + package_name = "clang-tidy" + if not args.skip_patch: + import_clang_tidy( + source_dir, build_clang_tidy_alpha, build_clang_tidy_external + ) + + if not os.path.exists(build_dir): + os.makedirs(build_dir) + + stage1_dir = build_dir + "/stage1" + stage1_inst_dir = stage1_dir + "/" + package_name + + final_stage_dir = stage1_dir + + if is_darwin(target): + extra_cflags = [] + extra_cxxflags = [] + extra_cflags2 = [] + extra_cxxflags2 = [] + extra_asmflags = [] + # It's unfortunately required to specify the linker used here because + # the linker flags are used in LLVM's configure step before + # -DLLVM_ENABLE_LLD is actually processed. + extra_ldflags = [ + "-fuse-ld=lld", + "-Wl,-dead_strip", + ] + elif is_linux(target): + extra_cflags = [] + extra_cxxflags = [] + extra_cflags2 = ["-fPIC"] + # Silence clang's warnings about arguments not being used in compilation. + extra_cxxflags2 = [ + "-fPIC", + "-Qunused-arguments", + ] + extra_asmflags = [] + # Avoid libLLVM internal function calls going through the PLT. + extra_ldflags = ["-Wl,-Bsymbolic-functions"] + # For whatever reason, LLVM's build system will set things up to turn + # on -ffunction-sections and -fdata-sections, but won't turn on the + # corresponding option to strip unused sections. We do it explicitly + # here. LLVM's build system is also picky about turning on ICF, so + # we do that explicitly here, too. + + # It's unfortunately required to specify the linker used here because + # the linker flags are used in LLVM's configure step before + # -DLLVM_ENABLE_LLD is actually processed. + if is_llvm_toolchain(cc, cxx): + extra_ldflags += ["-fuse-ld=lld", "-Wl,--icf=safe"] + extra_ldflags += ["-Wl,--gc-sections"] + elif is_windows(target): + extra_cflags = [] + extra_cxxflags = [] + # clang-cl would like to figure out what it's supposed to be emulating + # by looking at an MSVC install, but we don't really have that here. + # Force things on based on WinMsvc.cmake. + # Ideally, we'd just use WinMsvc.cmake as a toolchain file, but it only + # really works for cross-compiles, which this is not. + with open(os.path.join(llvm_source_dir, "cmake/platforms/WinMsvc.cmake")) as f: + compat = [ + item + for line in f + for item in line.split() + if "-fms-compatibility-version=" in item + ][0] + extra_cflags2 = [compat] + extra_cxxflags2 = [compat] + extra_asmflags = [] + extra_ldflags = [] + + upload_dir = os.getenv("UPLOAD_DIR") + if assertions and upload_dir: + extra_cflags2 += ["-fcrash-diagnostics-dir=%s" % upload_dir] + extra_cxxflags2 += ["-fcrash-diagnostics-dir=%s" % upload_dir] + + if skip_stages < 1: + build_one_stage( + [cc] + extra_cflags, + [cxx] + extra_cxxflags, + [asm] + extra_asmflags, + ar, + ranlib, + extra_ldflags, + llvm_source_dir, + stage1_dir, + package_name, + build_type, + assertions, + target, + targets, + is_final_stage=(stages == 1), + ) + + if stages >= 2 and skip_stages < 2: + stage2_dir = build_dir + "/stage2" + stage2_inst_dir = stage2_dir + "/" + package_name + final_stage_dir = stage2_dir + if skip_stages < 1: + cc = stage1_inst_dir + "/bin/%s%s" % (cc_name, exe_ext) + cxx = stage1_inst_dir + "/bin/%s%s" % (cxx_name, exe_ext) + asm = stage1_inst_dir + "/bin/%s%s" % (cc_name, exe_ext) + build_one_stage( + [cc] + extra_cflags2, + [cxx] + extra_cxxflags2, + [asm] + extra_asmflags, + ar, + ranlib, + extra_ldflags, + llvm_source_dir, + stage2_dir, + package_name, + build_type, + assertions, + target, + targets, + is_final_stage=(stages == 2), + profile="gen" if pgo else None, + ) + + if stages >= 3 and skip_stages < 3: + stage3_dir = build_dir + "/stage3" + stage3_inst_dir = stage3_dir + "/" + package_name + final_stage_dir = stage3_dir + if skip_stages < 2: + cc = stage2_inst_dir + "/bin/%s%s" % (cc_name, exe_ext) + cxx = stage2_inst_dir + "/bin/%s%s" % (cxx_name, exe_ext) + asm = stage2_inst_dir + "/bin/%s%s" % (cc_name, exe_ext) + build_one_stage( + [cc] + extra_cflags2, + [cxx] + extra_cxxflags2, + [asm] + extra_asmflags, + ar, + ranlib, + extra_ldflags, + llvm_source_dir, + stage3_dir, + package_name, + build_type, + assertions, + target, + targets, + (stages == 3), + ) + if pgo: + llvm_profdata = stage2_inst_dir + "/bin/llvm-profdata%s" % exe_ext + merge_cmd = [llvm_profdata, "merge", "-o", "merged.profdata"] + profraw_files = glob.glob( + os.path.join(stage2_dir, "build", "profiles", "*.profraw") + ) + run_in(stage3_dir, merge_cmd + profraw_files) + if stages == 3: + mkdir_p(upload_dir) + shutil.copy2(os.path.join(stage3_dir, "merged.profdata"), upload_dir) + return + + if stages >= 4 and skip_stages < 4: + stage4_dir = build_dir + "/stage4" + final_stage_dir = stage4_dir + profile = None + if pgo: + if skip_stages == 3: + profile_dir = os.environ.get("MOZ_FETCHES_DIR", "") + else: + profile_dir = stage3_dir + profile = os.path.join(profile_dir, "merged.profdata") + if skip_stages < 3: + cc = stage3_inst_dir + "/bin/%s%s" % (cc_name, exe_ext) + cxx = stage3_inst_dir + "/bin/%s%s" % (cxx_name, exe_ext) + asm = stage3_inst_dir + "/bin/%s%s" % (cc_name, exe_ext) + build_one_stage( + [cc] + extra_cflags2, + [cxx] + extra_cxxflags2, + [asm] + extra_asmflags, + ar, + ranlib, + extra_ldflags, + llvm_source_dir, + stage4_dir, + package_name, + build_type, + assertions, + target, + targets, + (stages == 4), + profile=profile, + ) + + if build_clang_tidy: + prune_final_dir_for_clang_tidy( + os.path.join(final_stage_dir, package_name), target + ) + + if not args.skip_tar: + build_tar_package("%s.tar.zst" % package_name, final_stage_dir, package_name) + + +if __name__ == "__main__": + main() diff --git a/build/build-clang/clang-14.json b/build/build-clang/clang-14.json new file mode 100644 index 0000000000..b565fefc74 --- /dev/null +++ b/build/build-clang/clang-14.json @@ -0,0 +1,13 @@ +{ + "patches": [ + "find_symbolizer_linux_clang_10.patch", + "android-mangling-error_clang_12.patch", + "unpoison-thread-stacks_clang_10.patch", + "downgrade-mangling-error_clang_12.patch", + "Remove-FlushViewOfFile-when-unmaping-gcda-files.patch", + "fuzzing_ccov_build_clang_12.patch", + "llvmorg-15-init-16512-g4b1e3d193706.patch", + "win64-ret-null-on-commitment-limit_clang_14.patch", + "compiler-rt-rss-limit-heap-profile.patch" + ] +} diff --git a/build/build-clang/clang-17.json b/build/build-clang/clang-17.json new file mode 100644 index 0000000000..960c7c6754 --- /dev/null +++ b/build/build-clang/clang-17.json @@ -0,0 +1,18 @@ +{ + "patches": [ + "find_symbolizer_linux_clang_15.patch", + "android-mangling-error_clang_12.patch", + "unpoison-thread-stacks_clang_10.patch", + "downgrade-mangling-error_clang_12.patch", + "fuzzing_ccov_build_clang_12.patch", + "partial-revert-llvmorg-17-init-17713-gc8e055d485ea.patch", + "revert-llvmorg-17-init-4120-g02e8eb1a438b.patch", + "partial-revert-llvmorg-16-init-17151-gaa0883b59ae1_clang_17.patch", + "revert-llvmorg-16-init-11301-g163bb6d64e5f_clang_17.patch", + "revert-llvmorg-15-init-13446-g7524fe962e47.patch", + "revert-llvmorg-15-init-11205-gcead4eceb01b_clang_16.patch", + "D146664.patch", + "win64-ret-null-on-commitment-limit_clang_14.patch", + "compiler-rt-rss-limit-heap-profile.patch" + ] +} diff --git a/build/build-clang/clang-18.json b/build/build-clang/clang-18.json new file mode 100644 index 0000000000..5f66e58947 --- /dev/null +++ b/build/build-clang/clang-18.json @@ -0,0 +1,21 @@ +{ + "patches": [ + "allow-unversioned-android.patch", + "find_symbolizer_linux_clang_15.patch", + "android-mangling-error_clang_12.patch", + "unpoison-thread-stacks_clang_10.patch", + "downgrade-mangling-error_clang_12.patch", + "fuzzing_ccov_build_clang_12.patch", + "revert-llvmorg-18-init-6208-g2baf4a06ef06.patch", + "revert-llvmorg-18-init-6193-gb88cffeafd39.patch", + "revert-llvmorg-18-init-6188-gc649f29c24c9.patch", + "partial-revert-llvmorg-17-init-17713-gc8e055d485ea.patch", + "revert-llvmorg-17-init-4120-g02e8eb1a438b_clang_18.patch", + "partial-revert-llvmorg-16-init-17151-gaa0883b59ae1_clang_17.patch", + "revert-llvmorg-16-init-11301-g163bb6d64e5f_clang_18.patch", + "revert-llvmorg-15-init-13446-g7524fe962e47.patch", + "revert-llvmorg-15-init-11205-gcead4eceb01b_clang_18.patch", + "win64-ret-null-on-commitment-limit_clang_14.patch", + "compiler-rt-rss-limit-heap-profile.patch" + ] +} diff --git a/build/build-clang/clang-8-missing-header.patch b/build/build-clang/clang-8-missing-header.patch new file mode 100644 index 0000000000..a6f1fac040 --- /dev/null +++ b/build/build-clang/clang-8-missing-header.patch @@ -0,0 +1,12 @@ +diff --git a/llvm/utils/benchmark/src/benchmark_register.h b/llvm/utils/benchmark/src/benchmark_register.h +index 0705e219f2fa..4caa5ad4da07 100644 +--- a/llvm/utils/benchmark/src/benchmark_register.h ++++ b/llvm/utils/benchmark/src/benchmark_register.h +@@ -1,6 +1,7 @@ + #ifndef BENCHMARK_REGISTER_H + #define BENCHMARK_REGISTER_H + ++#include + #include + + #include "check.h" diff --git a/build/build-clang/clang-8.0.json b/build/build-clang/clang-8.0.json new file mode 100644 index 0000000000..77e71e837f --- /dev/null +++ b/build/build-clang/clang-8.0.json @@ -0,0 +1,10 @@ +{ + "cc": "/usr/bin/gcc", + "cxx": "/usr/bin/g++", + "as": "/usr/bin/gcc", + "targets": "X86;WebAssembly", + "patches": [ + "clang-8-missing-header.patch", + "llvmorg-10-init-136-gb288d90b39f4.patch" + ] +} diff --git a/build/build-clang/clang-tidy-ci.patch b/build/build-clang/clang-tidy-ci.patch new file mode 100644 index 0000000000..6c31752136 --- /dev/null +++ b/build/build-clang/clang-tidy-ci.patch @@ -0,0 +1,34 @@ +diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp +index 7de313ad4da6..697f98c362d1 100644 +--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp ++++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp +@@ -432,6 +432,7 @@ ClangTidyASTConsumerFactory::createASTConsumer( + + for (auto &Check : Checks) { + Check->registerMatchers(&*Finder); ++ Check->registerPPCallbacks(Compiler); + Check->registerPPCallbacks(*SM, PP, ModuleExpanderPP); + } + +diff --git a/clang-tools-extra/clang-tidy/ClangTidyCheck.h b/clang-tools-extra/clang-tidy/ClangTidyCheck.h +index 9b41e5836de7..d8938b8fe05e 100644 +--- a/clang-tools-extra/clang-tidy/ClangTidyCheck.h ++++ b/clang-tools-extra/clang-tidy/ClangTidyCheck.h +@@ -20,6 +20,7 @@ + + namespace clang { + ++class CompilerInstance; + class SourceManager; + + namespace tidy { +@@ -69,6 +70,9 @@ public: + return true; + } + ++ /// This has been deprecated in clang 9 - needed by mozilla-must-override ++ virtual void registerPPCallbacks(CompilerInstance &Compiler) {} ++ + /// Override this to register ``PPCallbacks`` in the preprocessor. + /// + /// This should be used for clang-tidy checks that analyze preprocessor- diff --git a/build/build-clang/clang-tidy-external-linux64.json b/build/build-clang/clang-tidy-external-linux64.json new file mode 100644 index 0000000000..897911d3e3 --- /dev/null +++ b/build/build-clang/clang-tidy-external-linux64.json @@ -0,0 +1,11 @@ +{ + "stages": "1", + "build_clang_tidy": true, + "cc": "{MOZ_FETCHES_DIR}/clang/bin/clang", + "cxx": "{MOZ_FETCHES_DIR}/clang/bin/clang++", + "as": "{MOZ_FETCHES_DIR}/clang/bin/clang", + "patches": [ + "clang-tidy-ci.patch" + ], + "build_clang_tidy_external": true +} diff --git a/build/build-clang/clang-tidy-linux64.json b/build/build-clang/clang-tidy-linux64.json new file mode 100644 index 0000000000..e654aeef92 --- /dev/null +++ b/build/build-clang/clang-tidy-linux64.json @@ -0,0 +1,10 @@ +{ + "stages": "1", + "build_clang_tidy": true, + "cc": "{MOZ_FETCHES_DIR}/clang/bin/clang", + "cxx": "{MOZ_FETCHES_DIR}/clang/bin/clang++", + "as": "{MOZ_FETCHES_DIR}/clang/bin/clang", + "patches": [ + "clang-tidy-ci.patch" + ] +} diff --git a/build/build-clang/clang-tidy-macosx64.json b/build/build-clang/clang-tidy-macosx64.json new file mode 100644 index 0000000000..6da85803f5 --- /dev/null +++ b/build/build-clang/clang-tidy-macosx64.json @@ -0,0 +1,7 @@ +{ + "stages": "1", + "build_clang_tidy": true, + "patches": [ + "clang-tidy-ci.patch" + ] +} diff --git a/build/build-clang/clang-tidy-win64.json b/build/build-clang/clang-tidy-win64.json new file mode 100644 index 0000000000..6da85803f5 --- /dev/null +++ b/build/build-clang/clang-tidy-win64.json @@ -0,0 +1,7 @@ +{ + "stages": "1", + "build_clang_tidy": true, + "patches": [ + "clang-tidy-ci.patch" + ] +} diff --git a/build/build-clang/clang-trunk.json b/build/build-clang/clang-trunk.json new file mode 100644 index 0000000000..5f66e58947 --- /dev/null +++ b/build/build-clang/clang-trunk.json @@ -0,0 +1,21 @@ +{ + "patches": [ + "allow-unversioned-android.patch", + "find_symbolizer_linux_clang_15.patch", + "android-mangling-error_clang_12.patch", + "unpoison-thread-stacks_clang_10.patch", + "downgrade-mangling-error_clang_12.patch", + "fuzzing_ccov_build_clang_12.patch", + "revert-llvmorg-18-init-6208-g2baf4a06ef06.patch", + "revert-llvmorg-18-init-6193-gb88cffeafd39.patch", + "revert-llvmorg-18-init-6188-gc649f29c24c9.patch", + "partial-revert-llvmorg-17-init-17713-gc8e055d485ea.patch", + "revert-llvmorg-17-init-4120-g02e8eb1a438b_clang_18.patch", + "partial-revert-llvmorg-16-init-17151-gaa0883b59ae1_clang_17.patch", + "revert-llvmorg-16-init-11301-g163bb6d64e5f_clang_18.patch", + "revert-llvmorg-15-init-13446-g7524fe962e47.patch", + "revert-llvmorg-15-init-11205-gcead4eceb01b_clang_18.patch", + "win64-ret-null-on-commitment-limit_clang_14.patch", + "compiler-rt-rss-limit-heap-profile.patch" + ] +} diff --git a/build/build-clang/compiler-rt-rss-limit-heap-profile.patch b/build/build-clang/compiler-rt-rss-limit-heap-profile.patch new file mode 100644 index 0000000000..f7dfdfcdae --- /dev/null +++ b/build/build-clang/compiler-rt-rss-limit-heap-profile.patch @@ -0,0 +1,49 @@ +diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp +index 8fd398564280..b7c4820971bb 100644 +--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp ++++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp +@@ -29,6 +29,7 @@ void *BackgroundThread(void *arg) { + const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb; + const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb; + const bool heap_profile = common_flags()->heap_profile; ++ const bool rss_limit_heap_profile = common_flags()->rss_limit_heap_profile; + uptr prev_reported_rss = 0; + uptr prev_reported_stack_depot_size = 0; + bool reached_soft_rss_limit = false; +@@ -56,6 +57,10 @@ void *BackgroundThread(void *arg) { + Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n", + SanitizerToolName, hard_rss_limit_mb, current_rss_mb); + DumpProcessMap(); ++ if (rss_limit_heap_profile) { ++ Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb); ++ __sanitizer_print_memory_profile(90, 20); ++ } + Die(); + } + if (soft_rss_limit_mb) { +@@ -63,6 +68,11 @@ void *BackgroundThread(void *arg) { + reached_soft_rss_limit = true; + Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n", + SanitizerToolName, soft_rss_limit_mb, current_rss_mb); ++ if (rss_limit_heap_profile) { ++ Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb); ++ __sanitizer_print_memory_profile(90, 20); ++ rss_during_last_reported_profile = current_rss_mb; ++ } + SetRssLimitExceeded(true); + } else if (soft_rss_limit_mb >= current_rss_mb && + reached_soft_rss_limit) { +diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc +index 6148ae56067c..a0fbb8e14bd5 100644 +--- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc ++++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc +@@ -147,6 +147,9 @@ COMMON_FLAG(uptr, max_allocation_size_mb, 0, + "If non-zero, malloc/new calls larger than this size will return " + "nullptr (or crash if allocator_may_return_null=false).") + COMMON_FLAG(bool, heap_profile, false, "Experimental heap profiler, asan-only") ++COMMON_FLAG(bool, rss_limit_heap_profile, false, ++ "Experimental heap profiler (only when hard/soft rss limit " ++ "exceeded, asan-only") + COMMON_FLAG(s32, allocator_release_to_os_interval_ms, + ((bool)SANITIZER_FUCHSIA || (bool)SANITIZER_WINDOWS) ? -1 : 5000, + "Only affects a 64-bit allocator. If set, tries to release unused " diff --git a/build/build-clang/downgrade-mangling-error_clang_12.patch b/build/build-clang/downgrade-mangling-error_clang_12.patch new file mode 100644 index 0000000000..ad31306ff3 --- /dev/null +++ b/build/build-clang/downgrade-mangling-error_clang_12.patch @@ -0,0 +1,23 @@ +Downgrade unimplemented mangling diagnostic from error to note. +This codepath is exercised by MozsearchIndexer.cpp (the searchfox +indexer) when indexing on Windows. We can do without having the +unimplemented bits for now as long the compiler doesn't fail the +build. See also https://bugs.llvm.org/show_bug.cgi?id=39294 + +diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp +index 4420f6a2c1c3..4d9a6434d245 100644 +--- a/clang/lib/AST/ItaniumMangle.cpp ++++ b/clang/lib/AST/ItaniumMangle.cpp +@@ -4028,10 +4028,11 @@ recurse: + if (!NullOut) { + // As bad as this diagnostic is, it's better than crashing. + DiagnosticsEngine &Diags = Context.getDiags(); +- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, ++ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Remark, + "cannot yet mangle expression type %0"); + Diags.Report(E->getExprLoc(), DiagID) + << E->getStmtClassName() << E->getSourceRange(); ++ Out << "MOZ_WE_HACKED_AROUND_BUG_1418415"; + return; + } + break; diff --git a/build/build-clang/find_symbolizer_linux_clang_10.patch b/build/build-clang/find_symbolizer_linux_clang_10.patch new file mode 100644 index 0000000000..1ddb02024d --- /dev/null +++ b/build/build-clang/find_symbolizer_linux_clang_10.patch @@ -0,0 +1,58 @@ +We currently need this patch because ASan only searches PATH to find the +llvm-symbolizer binary to symbolize ASan traces. On testing machines, this +can be installed in PATH easily. However, for e.g. the ASan Nightly Project, +where we ship an ASan build, including llvm-symbolizer, to the user, we +cannot expect llvm-symbolizer to be on PATH. Instead, we should try to look +it up next to the binary. This patch implements the functionality for Linux +only until there is similar functionality provided upstream. + +diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp +index 79930d79425..cfb4f90c0d5 100644 +--- a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp ++++ b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp +@@ -20,6 +20,10 @@ + #include "sanitizer_common.h" + #include "sanitizer_file.h" + ++#if SANITIZER_LINUX ++#include "sanitizer_posix.h" ++#endif ++ + namespace __sanitizer { + + void CatastrophicErrorWrite(const char *buffer, uptr length) { +@@ -194,6 +198,34 @@ char *FindPathToBinary(const char *name) { + if (*end == '\0') break; + beg = end + 1; + } ++ ++#if SANITIZER_LINUX ++ // If we cannot find the requested binary in PATH, we should try to locate ++ // it next to the binary, in case it is shipped with the build itself ++ // (e.g. llvm-symbolizer shipped with sanitizer build to symbolize on client. ++ if (internal_readlink("/proc/self/exe", buffer.data(), kMaxPathLength) < 0) ++ return nullptr; ++ ++ uptr buf_len = internal_strlen(buffer.data()); ++ ++ /* Avoid using dirname() here */ ++ while (buf_len > 0) { ++ if (buffer[buf_len - 1] == '/') ++ break; ++ buf_len--; ++ } ++ ++ if (!buf_len) ++ return nullptr; ++ ++ if (buf_len + name_len + 1 <= kMaxPathLength) { ++ internal_memcpy(&buffer[buf_len], name, name_len); ++ buffer[buf_len + name_len] = '\0'; ++ if (FileExists(buffer.data())) ++ return internal_strdup(buffer.data()); ++ } ++#endif ++ + return nullptr; + } + diff --git a/build/build-clang/find_symbolizer_linux_clang_15.patch b/build/build-clang/find_symbolizer_linux_clang_15.patch new file mode 100644 index 0000000000..63309e8f00 --- /dev/null +++ b/build/build-clang/find_symbolizer_linux_clang_15.patch @@ -0,0 +1,53 @@ +diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp +index 7ef499ce07b1..8fd682f943fe 100644 +--- a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp ++++ b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp +@@ -21,6 +21,10 @@ + #include "sanitizer_file.h" + # include "sanitizer_interface_internal.h" + ++#if SANITIZER_LINUX ++#include "sanitizer_posix.h" ++#endif ++ + namespace __sanitizer { + + void CatastrophicErrorWrite(const char *buffer, uptr length) { +@@ -206,11 +210,35 @@ char *FindPathToBinary(const char *name) { + return internal_strdup(name); + } + ++ uptr name_len = internal_strlen(name); ++ InternalMmapVector buffer(kMaxPathLength); ++ ++#if SANITIZER_LINUX ++ // If we cannot find the requested binary in PATH, we should try to locate ++ // it next to the binary, in case it is shipped with the build itself ++ // (e.g. llvm-symbolizer shipped with sanitizer build to symbolize on client. ++ if (internal_readlink("/proc/self/exe", buffer.data(), kMaxPathLength) >= 0) { ++ uptr buf_len = internal_strlen(buffer.data()); ++ ++ /* Avoid using dirname() here */ ++ while (buf_len > 0) { ++ if (buffer[buf_len - 1] == '/') ++ break; ++ buf_len--; ++ } ++ ++ if (buf_len && buf_len + name_len + 1 <= kMaxPathLength) { ++ internal_memcpy(&buffer[buf_len], name, name_len); ++ buffer[buf_len + name_len] = '\0'; ++ if (FileExists(buffer.data())) ++ return internal_strdup(buffer.data()); ++ } ++ } ++#endif ++ + const char *path = GetEnv("PATH"); + if (!path) + return nullptr; +- uptr name_len = internal_strlen(name); +- InternalMmapVector buffer(kMaxPathLength); + const char *beg = path; + while (true) { + const char *end = internal_strchrnul(beg, kPathSeparator); diff --git a/build/build-clang/fuzzing_ccov_build_clang_12.patch b/build/build-clang/fuzzing_ccov_build_clang_12.patch new file mode 100644 index 0000000000..1b60a95b91 --- /dev/null +++ b/build/build-clang/fuzzing_ccov_build_clang_12.patch @@ -0,0 +1,27 @@ +From 98bf90ef5ea3dd848ce7d81a662eb7499d11c91c Mon Sep 17 00:00:00 2001 +From: Calixte Denizet +Date: Fri, 16 Apr 2021 10:05:34 +0200 +Subject: [PATCH] [Gcov] Don't run global destructor in ccov builds when env + MOZ_FUZZING_CCOV is existing + +--- + compiler-rt/lib/profile/GCDAProfiling.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c +index 4293e8f7b5bf..6cda4bc7601f 100644 +--- a/compiler-rt/lib/profile/GCDAProfiling.c ++++ b/compiler-rt/lib/profile/GCDAProfiling.c +@@ -586,6 +586,9 @@ void llvm_writeout_files(void) { + __attribute__((destructor(100))) + #endif + static void llvm_writeout_and_clear(void) { ++ if (getenv("MOZ_FUZZING_CCOV")) { ++ return; ++ } + llvm_writeout_files(); + fn_list_remove(&writeout_fn_list); + } +-- +2.30.2 + diff --git a/build/build-clang/linux64.json b/build/build-clang/linux64.json new file mode 100644 index 0000000000..48690dbdaa --- /dev/null +++ b/build/build-clang/linux64.json @@ -0,0 +1,5 @@ +{ + "cc": "/usr/lib/llvm-13/bin/clang", + "cxx": "/usr/lib/llvm-13/bin/clang++", + "as": "/usr/lib/llvm-13/bin/clang" +} diff --git a/build/build-clang/llvmorg-10-init-136-gb288d90b39f4.patch b/build/build-clang/llvmorg-10-init-136-gb288d90b39f4.patch new file mode 100644 index 0000000000..c5ca0ba0ee --- /dev/null +++ b/build/build-clang/llvmorg-10-init-136-gb288d90b39f4.patch @@ -0,0 +1,37 @@ +From 79e6696d121b978b4482ce74119c6bbc7a9ce30f Mon Sep 17 00:00:00 2001 +From: Than McIntosh +Date: Fri, 19 Jul 2019 13:13:54 +0000 +Subject: [PATCH] [NFC] include cstdint/string prior to using uint8_t/string + +Summary: include proper header prior to use of uint8_t typedef +and std::string. + +Subscribers: llvm-commits + +Reviewers: cherry + +Tags: #llvm + +Differential Revision: https://reviews.llvm.org/D64937 + +llvm-svn: 366572 +--- + llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h b/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h +index 9e3478e9fd29..efd55339418b 100644 +--- a/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h ++++ b/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h +@@ -4,6 +4,8 @@ + #include "llvm/Demangle/Compiler.h" + #include "llvm/Demangle/StringView.h" + #include ++#include ++#include + + class OutputStream; + +-- +2.41.0.3.g1cb8d410ac + diff --git a/build/build-clang/llvmorg-15-init-16512-g4b1e3d193706.patch b/build/build-clang/llvmorg-15-init-16512-g4b1e3d193706.patch new file mode 100644 index 0000000000..5ddb6a52de --- /dev/null +++ b/build/build-clang/llvmorg-15-init-16512-g4b1e3d193706.patch @@ -0,0 +1,138 @@ +From 8482662676a4b6ef79a718c8c09943cb15241664 Mon Sep 17 00:00:00 2001 +From: Tom Stellard +Date: Tue, 21 Jun 2022 22:22:11 -0700 +Subject: [PATCH] [gold] Ignore bitcode from sections inside object files + +-fembed-bitcode will put bitcode into special sections within object +files, but this is not meant to be used by LTO, so the gold plugin +should ignore it. + +https://github.com/llvm/llvm-project/issues/47216 + +Reviewed By: tejohnson, MaskRay + +Differential Revision: https://reviews.llvm.org/D116995 +--- + llvm/docs/BitCodeFormat.rst | 3 ++- + llvm/docs/GoldPlugin.rst | 4 ++++ + .../tools/gold/X86/Inputs/bcsection-lib.ll | 6 +++++ + llvm/test/tools/gold/X86/Inputs/bcsection.s | 5 ++++ + llvm/test/tools/gold/X86/bcsection.ll | 23 +++++++++++++++---- + llvm/tools/gold/gold-plugin.cpp | 8 +++++++ + 6 files changed, 43 insertions(+), 6 deletions(-) + create mode 100644 llvm/test/tools/gold/X86/Inputs/bcsection-lib.ll + +diff --git a/llvm/docs/BitCodeFormat.rst b/llvm/docs/BitCodeFormat.rst +index 8e81a7daa459..df1f6915d7d5 100644 +--- a/llvm/docs/BitCodeFormat.rst ++++ b/llvm/docs/BitCodeFormat.rst +@@ -475,7 +475,8 @@ formats. This wrapper format is useful for accommodating LTO in compilation + pipelines where intermediate objects must be native object files which contain + metadata in other sections. + +-Not all tools support this format. ++Not all tools support this format. For example, lld and the gold plugin will ++ignore these sections when linking object files. + + .. _encoding of LLVM IR: + +diff --git a/llvm/docs/GoldPlugin.rst b/llvm/docs/GoldPlugin.rst +index ce310bc2cf3c..07d2fc203eba 100644 +--- a/llvm/docs/GoldPlugin.rst ++++ b/llvm/docs/GoldPlugin.rst +@@ -17,6 +17,10 @@ and above also supports LTO via plugins. However, usage of the LLVM + gold plugin with ld.bfd is not tested and therefore not officially + supported or recommended. + ++As of LLVM 15, the gold plugin will ignore bitcode from the ``.llvmbc`` ++section inside of ELF object files. However, LTO with bitcode files ++is still supported. ++ + .. _`gold linker`: http://sourceware.org/binutils + .. _`GCC LTO`: http://gcc.gnu.org/wiki/LinkTimeOptimization + .. _`gold plugin interface`: http://gcc.gnu.org/wiki/whopr/driver +diff --git a/llvm/test/tools/gold/X86/Inputs/bcsection-lib.ll b/llvm/test/tools/gold/X86/Inputs/bcsection-lib.ll +new file mode 100644 +index 000000000000..ef3557c19cdc +--- /dev/null ++++ b/llvm/test/tools/gold/X86/Inputs/bcsection-lib.ll +@@ -0,0 +1,6 @@ ++declare void @elf_func() ++ ++define i32 @lib_func() { ++ call void @elf_func() ++ ret i32 0 ++} +diff --git a/llvm/test/tools/gold/X86/Inputs/bcsection.s b/llvm/test/tools/gold/X86/Inputs/bcsection.s +index ede1e5c532dd..c523612563b4 100644 +--- a/llvm/test/tools/gold/X86/Inputs/bcsection.s ++++ b/llvm/test/tools/gold/X86/Inputs/bcsection.s +@@ -1,2 +1,7 @@ ++.global elf_func ++ ++elf_func: ++ ret ++ + .section .llvmbc + .incbin "bcsection.bc" +diff --git a/llvm/test/tools/gold/X86/bcsection.ll b/llvm/test/tools/gold/X86/bcsection.ll +index 6d3481f8f966..09882d83fe91 100644 +--- a/llvm/test/tools/gold/X86/bcsection.ll ++++ b/llvm/test/tools/gold/X86/bcsection.ll +@@ -2,16 +2,29 @@ + ; RUN: llvm-as -o %t/bcsection.bc %s + + ; RUN: llvm-mc -I=%t -filetype=obj -triple=x86_64-unknown-unknown -o %t/bcsection.bco %p/Inputs/bcsection.s +-; RUN: llvm-nm --no-llvm-bc %t/bcsection.bco 2>&1 | FileCheck %s -check-prefix=NO-SYMBOLS +-; NO-SYMBOLS: no symbols ++; RUN: llc -filetype=obj -mtriple=x86_64-unknown-unknown -o %t/bcsection-lib.o %p/Inputs/bcsection-lib.ll + +-; RUN: %gold -r -o %t/bcsection.o -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext %t/bcsection.bco +-; RUN: llvm-nm --no-llvm-bc %t/bcsection.o | FileCheck %s ++; RUN: %gold -shared --no-undefined -o %t/bcsection.so -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold%shlibext %t/bcsection.bco %t/bcsection-lib.o ++ ++; This test checks that the gold plugin does not attempt to use the bitcode ++; in the .llvmbc section for LTO. bcsection-lib.o calls a function that is ++; present the symbol table of bcsection.bco, but not included in the embedded ++; bitcode. If the linker were to use the bitcode, then the symbols in the ++; symbol table of bcsection.bco will be ignored and the link will fail. ++; ++; bcsection.bco: ++; .text: ++; elf_func ++; .llvmbc: ++; bitcode_func ++; ++; bcsection-lib.o: ++; calls elf_func() + + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-unknown" + + ; CHECK: main +-define i32 @main() { ++define i32 @bitcode_func() { + ret i32 0 + } +diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp +index 180c181368e3..294c7a3d6178 100644 +--- a/llvm/tools/gold/gold-plugin.cpp ++++ b/llvm/tools/gold/gold-plugin.cpp +@@ -540,6 +540,14 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, + BufferRef = Buffer->getMemBufferRef(); + } + ++ // Only use bitcode files for LTO. InputFile::create() will load bitcode ++ // from the .llvmbc section within a binary object, this bitcode is typically ++ // generated by -fembed-bitcode and is not to be used by LLVMgold.so for LTO. ++ if (identify_magic(BufferRef.getBuffer()) != file_magic::bitcode) { ++ *claimed = 0; ++ return LDPS_OK; ++ } ++ + *claimed = 1; + + Expected> ObjOrErr = InputFile::create(BufferRef); +-- +2.37.1.1.g659da70093 + diff --git a/build/build-clang/macosx64-aarch64.json b/build/build-clang/macosx64-aarch64.json new file mode 100644 index 0000000000..ecbb483e77 --- /dev/null +++ b/build/build-clang/macosx64-aarch64.json @@ -0,0 +1,3 @@ +{ + "target": "aarch64-apple-darwin" +} diff --git a/build/build-clang/macosx64.json b/build/build-clang/macosx64.json new file mode 100644 index 0000000000..2576c0c05f --- /dev/null +++ b/build/build-clang/macosx64.json @@ -0,0 +1,9 @@ +{ + "target": "x86_64-apple-darwin", + "cc": "{MOZ_FETCHES_DIR}/clang/bin/clang", + "cxx": "{MOZ_FETCHES_DIR}/clang/bin/clang++", + "as": "{MOZ_FETCHES_DIR}/clang/bin/clang", + "ar": "{MOZ_FETCHES_DIR}/clang/bin/llvm-ar", + "ranlib": "{MOZ_FETCHES_DIR}/clang/bin/llvm-ranlib", + "ld": "{MOZ_FETCHES_DIR}/clang/bin/clang" +} diff --git a/build/build-clang/partial-revert-llvmorg-16-init-17151-gaa0883b59ae1_clang_17.patch b/build/build-clang/partial-revert-llvmorg-16-init-17151-gaa0883b59ae1_clang_17.patch new file mode 100644 index 0000000000..f95caa508b --- /dev/null +++ b/build/build-clang/partial-revert-llvmorg-16-init-17151-gaa0883b59ae1_clang_17.patch @@ -0,0 +1,13 @@ +diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp +index fdae7e4bd1b7..ac607cfb1100 100644 +--- a/lld/MachO/LTO.cpp ++++ b/lld/MachO/LTO.cpp +@@ -64,8 +64,6 @@ static lto::Config createConfig() { + pm.add(createObjCARCContractPass()); + }; + +- c.AlwaysEmitRegularLTOObj = !config->ltoObjPath.empty(); +- + c.TimeTraceEnabled = config->timeTraceEnabled; + c.TimeTraceGranularity = config->timeTraceGranularity; + c.DebugPassManager = config->ltoDebugPassManager; diff --git a/build/build-clang/partial-revert-llvmorg-17-init-17713-gc8e055d485ea.patch b/build/build-clang/partial-revert-llvmorg-17-init-17713-gc8e055d485ea.patch new file mode 100644 index 0000000000..96ac988380 --- /dev/null +++ b/build/build-clang/partial-revert-llvmorg-17-init-17713-gc8e055d485ea.patch @@ -0,0 +1,33 @@ +Revert the parts of c8e055d485eabf1c8830d77797e3686ced0f7754 that require +cead4eceb01b935fae07bf4a7e91911b344d2fec, which we revert. + +diff --git a/llvm/include/llvm/DebugInfo/BTF/BTFContext.h b/llvm/include/llvm/DebugInfo/BTF/BTFContext.h +index c16bee613322..7b0412b91c2e 100644 +--- a/llvm/include/llvm/DebugInfo/BTF/BTFContext.h ++++ b/llvm/include/llvm/DebugInfo/BTF/BTFContext.h +@@ -34,9 +34,6 @@ public: + object::SectionedAddress Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + +- DILineInfo +- getLineInfoForDataAddress(object::SectionedAddress Address) override; +- + DILineInfoTable getLineInfoForAddressRange( + object::SectionedAddress Address, uint64_t Size, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; +diff --git a/llvm/lib/DebugInfo/BTF/BTFContext.cpp b/llvm/lib/DebugInfo/BTF/BTFContext.cpp +index 24898739b824..da0f9982881f 100644 +--- a/llvm/lib/DebugInfo/BTF/BTFContext.cpp ++++ b/llvm/lib/DebugInfo/BTF/BTFContext.cpp +@@ -34,11 +34,6 @@ DILineInfo BTFContext::getLineInfoForAddress(SectionedAddress Address, + return Result; + } + +-DILineInfo BTFContext::getLineInfoForDataAddress(SectionedAddress Address) { +- // BTF does not convey such information. +- return {}; +-} +- + DILineInfoTable + BTFContext::getLineInfoForAddressRange(SectionedAddress Address, uint64_t Size, + DILineInfoSpecifier Specifier) { diff --git a/build/build-clang/profile.json b/build/build-clang/profile.json new file mode 100644 index 0000000000..746aa92452 --- /dev/null +++ b/build/build-clang/profile.json @@ -0,0 +1,6 @@ +{ + "stages": "3", + "pgo": true, + "ranlib": "{MOZ_FETCHES_DIR}/clang/bin/llvm-ranlib", + "ar": "{MOZ_FETCHES_DIR}/clang/bin/llvm-ar" +} diff --git a/build/build-clang/revert-llvmorg-15-init-11205-gcead4eceb01b_clang_16.patch b/build/build-clang/revert-llvmorg-15-init-11205-gcead4eceb01b_clang_16.patch new file mode 100644 index 0000000000..93c7e7d767 --- /dev/null +++ b/build/build-clang/revert-llvmorg-15-init-11205-gcead4eceb01b_clang_16.patch @@ -0,0 +1,1027 @@ +From cb411520cb7cd5e6e25966911ca55feb5de779e0 Mon Sep 17 00:00:00 2001 +From: Mike Hommey +Date: Fri, 4 Nov 2022 14:51:38 +0900 +Subject: [PATCH] Revert "[symbolizer] Parse DW_TAG_variable DIs to show line + info for globals" + +This reverts commit cead4eceb01b935fae07bf4a7e91911b344d2fec for causing +yet unidentified problems on some webrtc tests under TSan (bug 1798613). +--- + llvm/include/llvm/DebugInfo/DIContext.h | 4 - + .../llvm/DebugInfo/DWARF/DWARFContext.h | 2 - + llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h | 7 - + llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h | 14 - + llvm/include/llvm/DebugInfo/PDB/PDBContext.h | 2 - + llvm/lib/DebugInfo/DWARF/DWARFContext.cpp | 97 ++-- + llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 60 --- + llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 97 ---- + llvm/lib/DebugInfo/PDB/PDBContext.cpp | 7 - + llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp | 4 - + .../Symbolize/SymbolizableObjectFile.cpp | 8 - + .../Symbolize/ELF/data-command-symtab.yaml | 3 - + .../tools/llvm-symbolizer/data-location.yaml | 450 ------------------ + llvm/test/tools/llvm-symbolizer/data.s | 3 - + 14 files changed, 61 insertions(+), 697 deletions(-) + delete mode 100644 llvm/test/tools/llvm-symbolizer/data-location.yaml + +diff --git a/llvm/include/llvm/DebugInfo/DIContext.h b/llvm/include/llvm/DebugInfo/DIContext.h +index 9b278b696073..a9f98588cf2d 100644 +--- a/llvm/include/llvm/DebugInfo/DIContext.h ++++ b/llvm/include/llvm/DebugInfo/DIContext.h +@@ -114,8 +114,6 @@ struct DIGlobal { + std::string Name; + uint64_t Start = 0; + uint64_t Size = 0; +- std::string DeclFile; +- uint64_t DeclLine = 0; + + DIGlobal() : Name(DILineInfo::BadString) {} + }; +@@ -241,8 +239,6 @@ public: + virtual DILineInfo getLineInfoForAddress( + object::SectionedAddress Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; +- virtual DILineInfo +- getLineInfoForDataAddress(object::SectionedAddress Address) = 0; + virtual DILineInfoTable getLineInfoForAddressRange( + object::SectionedAddress Address, uint64_t Size, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; +diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +index bf591ed554c6..3365ef8d8ee3 100644 +--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h ++++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +@@ -364,8 +364,6 @@ public: + DILineInfo getLineInfoForAddress( + object::SectionedAddress Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; +- DILineInfo +- getLineInfoForDataAddress(object::SectionedAddress Address) override; + DILineInfoTable getLineInfoForAddressRange( + object::SectionedAddress Address, uint64_t Size, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; +diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h +index 149c5ef4e493..4a4d105a2b23 100644 +--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h ++++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h +@@ -280,13 +280,6 @@ public: + /// \returns an iterator range for the attributes of the current DIE. + iterator_range attributes() const; + +- /// Gets the type size (in bytes) for this DIE. +- /// +- /// \param PointerSize the pointer size of the containing CU. +- /// \returns if this is a type DIE, or this DIE contains a DW_AT_type, returns +- /// the size of the type. +- std::optional getTypeSize(uint64_t PointerSize); +- + class iterator; + + iterator begin() const; +diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h +index 9188865b4d77..0341344bc7b8 100644 +--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h ++++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h +@@ -9,7 +9,6 @@ + #ifndef LLVM_DEBUGINFO_DWARF_DWARFUNIT_H + #define LLVM_DEBUGINFO_DWARF_DWARFUNIT_H + +-#include "llvm/ADT/DenseSet.h" + #include "llvm/ADT/STLExtras.h" + #include "llvm/ADT/SmallVector.h" + #include "llvm/ADT/StringRef.h" +@@ -28,7 +27,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -242,11 +240,6 @@ class DWARFUnit { + /// std::map::upper_bound for address range lookup. + std::map> AddrDieMap; + +- /// Map from the location (interpreted DW_AT_location) of a DW_TAG_variable, +- /// to the end address and the corresponding DIE. +- std::map> VariableDieMap; +- DenseSet RootsParsedForVariables; +- + using die_iterator_range = + iterator_range::iterator>; + +@@ -329,9 +322,6 @@ public: + /// Recursively update address to Die map. + void updateAddressDieMap(DWARFDie Die); + +- /// Recursively update address to variable Die map. +- void updateVariableDieMap(DWARFDie Die); +- + void setRangesSection(const DWARFSection *RS, uint64_t Base) { + RangeSection = RS; + RangeSectionBase = Base; +@@ -446,10 +436,6 @@ public: + /// cleared. + DWARFDie getSubroutineForAddress(uint64_t Address); + +- /// Returns variable DIE for the address provided. The pointer is alive as +- /// long as parsed compile unit DIEs are not cleared. +- DWARFDie getVariableForAddress(uint64_t Address); +- + /// getInlinedChainForAddress - fetches inlined chain for a given address. + /// Returns empty chain if there is no subprogram containing address. The + /// chain is valid as long as parsed compile unit DIEs are not cleared. +diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBContext.h b/llvm/include/llvm/DebugInfo/PDB/PDBContext.h +index 3163c0a1dae0..7b6793f0a639 100644 +--- a/llvm/include/llvm/DebugInfo/PDB/PDBContext.h ++++ b/llvm/include/llvm/DebugInfo/PDB/PDBContext.h +@@ -45,8 +45,6 @@ namespace pdb { + DILineInfo getLineInfoForAddress( + object::SectionedAddress Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; +- DILineInfo +- getLineInfoForDataAddress(object::SectionedAddress Address) override; + DILineInfoTable getLineInfoForAddressRange( + object::SectionedAddress Address, uint64_t Size, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; +diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +index 19d7d659a86a..1bcfdecfd588 100644 +--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp ++++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +@@ -1053,25 +1053,7 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) { + // First, get the offset of the compile unit. + uint64_t CUOffset = getDebugAranges()->findAddress(Address); + // Retrieve the compile unit. +- if (DWARFCompileUnit *OffsetCU = getCompileUnitForOffset(CUOffset)) +- return OffsetCU; +- +- // Global variables are often not found by the above search, for one of two +- // reasons: +- // 1. .debug_aranges may not include global variables. On clang, it seems we +- // put the globals in the aranges, but this isn't true for gcc. +- // 2. Even if the global variable is in a .debug_arange, global variables +- // may not be captured in the [start, end) addresses described by the +- // parent compile unit. +- // +- // So, we walk the CU's and their child DI's manually, looking for the +- // specific global variable. +- for (std::unique_ptr &CU : compile_units()) { +- if (DWARFDie Die = CU->getVariableForAddress(Address)) { +- return static_cast(CU.get()); +- } +- } +- return nullptr; ++ return getCompileUnitForOffset(CUOffset); + } + + DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) { +@@ -1141,6 +1123,64 @@ static bool getFunctionNameAndStartLineForAddress( + return FoundResult; + } + ++static std::optional getTypeSize(DWARFDie Type, uint64_t PointerSize) { ++ if (auto SizeAttr = Type.find(DW_AT_byte_size)) ++ if (std::optional Size = SizeAttr->getAsUnsignedConstant()) ++ return Size; ++ ++ switch (Type.getTag()) { ++ case DW_TAG_pointer_type: ++ case DW_TAG_reference_type: ++ case DW_TAG_rvalue_reference_type: ++ return PointerSize; ++ case DW_TAG_ptr_to_member_type: { ++ if (DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type)) ++ if (BaseType.getTag() == DW_TAG_subroutine_type) ++ return 2 * PointerSize; ++ return PointerSize; ++ } ++ case DW_TAG_const_type: ++ case DW_TAG_immutable_type: ++ case DW_TAG_volatile_type: ++ case DW_TAG_restrict_type: ++ case DW_TAG_typedef: { ++ if (DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type)) ++ return getTypeSize(BaseType, PointerSize); ++ break; ++ } ++ case DW_TAG_array_type: { ++ DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type); ++ if (!BaseType) ++ return std::optional(); ++ std::optional BaseSize = getTypeSize(BaseType, PointerSize); ++ if (!BaseSize) ++ return std::optional(); ++ uint64_t Size = *BaseSize; ++ for (DWARFDie Child : Type) { ++ if (Child.getTag() != DW_TAG_subrange_type) ++ continue; ++ ++ if (auto ElemCountAttr = Child.find(DW_AT_count)) ++ if (std::optional ElemCount = ++ ElemCountAttr->getAsUnsignedConstant()) ++ Size *= *ElemCount; ++ if (auto UpperBoundAttr = Child.find(DW_AT_upper_bound)) ++ if (std::optional UpperBound = ++ UpperBoundAttr->getAsSignedConstant()) { ++ int64_t LowerBound = 0; ++ if (auto LowerBoundAttr = Child.find(DW_AT_lower_bound)) ++ LowerBound = LowerBoundAttr->getAsSignedConstant().value_or(0); ++ Size *= *UpperBound - LowerBound + 1; ++ } ++ } ++ return Size; ++ } ++ default: ++ break; ++ } ++ return std::optional(); ++} ++ + static std::optional + getExpressionFrameOffset(ArrayRef Expr, + std::optional FrameBaseReg) { +@@ -1201,7 +1241,7 @@ void DWARFContext::addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, + if (std::optional Name = dwarf::toString(*NameAttr)) + Local.Name = *Name; + if (auto Type = Die.getAttributeValueAsReferencedDie(DW_AT_type)) +- Local.Size = Type.getTypeSize(getCUAddrSize()); ++ Local.Size = getTypeSize(Type, getCUAddrSize()); + if (auto DeclFileAttr = Die.find(DW_AT_decl_file)) { + if (const auto *LT = CU->getContext().getLineTableForUnit(CU)) + LT->getFileNameByIndex( +@@ -1242,6 +1282,7 @@ DWARFContext::getLocalsForAddress(object::SectionedAddress Address) { + DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address, + DILineInfoSpecifier Spec) { + DILineInfo Result; ++ + DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Result; +@@ -1256,22 +1297,6 @@ DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address, + Spec.FLIKind, Result); + } + } +- +- return Result; +-} +- +-DILineInfo +-DWARFContext::getLineInfoForDataAddress(object::SectionedAddress Address) { +- DILineInfo Result; +- DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); +- if (!CU) +- return Result; +- +- if (DWARFDie Die = CU->getVariableForAddress(Address.Address)) { +- Result.FileName = Die.getDeclFile(FileLineInfoKind::AbsoluteFilePath); +- Result.Line = Die.getDeclLine(); +- } +- + return Result; + } + +diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +index 15a2d23c4fd2..9bf15c30f714 100644 +--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp ++++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +@@ -492,66 +492,6 @@ void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, + CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0); + } + +-std::optional DWARFDie::getTypeSize(uint64_t PointerSize) { +- if (auto SizeAttr = find(DW_AT_byte_size)) +- if (std::optional Size = SizeAttr->getAsUnsignedConstant()) +- return Size; +- +- switch (getTag()) { +- case DW_TAG_pointer_type: +- case DW_TAG_reference_type: +- case DW_TAG_rvalue_reference_type: +- return PointerSize; +- case DW_TAG_ptr_to_member_type: { +- if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type)) +- if (BaseType.getTag() == DW_TAG_subroutine_type) +- return 2 * PointerSize; +- return PointerSize; +- } +- case DW_TAG_const_type: +- case DW_TAG_immutable_type: +- case DW_TAG_volatile_type: +- case DW_TAG_restrict_type: +- case DW_TAG_typedef: { +- if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type)) +- return BaseType.getTypeSize(PointerSize); +- break; +- } +- case DW_TAG_array_type: { +- DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type); +- if (!BaseType) +- return std::nullopt; +- std::optional BaseSize = BaseType.getTypeSize(PointerSize); +- if (!BaseSize) +- return std::nullopt; +- uint64_t Size = *BaseSize; +- for (DWARFDie Child : *this) { +- if (Child.getTag() != DW_TAG_subrange_type) +- continue; +- +- if (auto ElemCountAttr = Child.find(DW_AT_count)) +- if (std::optional ElemCount = +- ElemCountAttr->getAsUnsignedConstant()) +- Size *= *ElemCount; +- if (auto UpperBoundAttr = Child.find(DW_AT_upper_bound)) +- if (std::optional UpperBound = +- UpperBoundAttr->getAsSignedConstant()) { +- int64_t LowerBound = 0; +- if (auto LowerBoundAttr = Child.find(DW_AT_lower_bound)) +- LowerBound = LowerBoundAttr->getAsSignedConstant().value_or(0); +- Size *= *UpperBound - LowerBound + 1; +- } +- } +- return Size; +- } +- default: +- if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type)) +- return BaseType.getTypeSize(PointerSize); +- break; +- } +- return std::nullopt; +-} +- + /// Helper to dump a DIE with all of its parents, but no siblings. + static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent, + DIDumpOptions DumpOpts, unsigned Depth = 0) { +diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +index 74667fcb92bc..148711f0246f 100644 +--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp ++++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +@@ -9,7 +9,6 @@ + #include "llvm/DebugInfo/DWARF/DWARFUnit.h" + #include "llvm/ADT/SmallString.h" + #include "llvm/ADT/StringRef.h" +-#include "llvm/BinaryFormat/Dwarf.h" + #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" + #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" + #include "llvm/DebugInfo/DWARF/DWARFContext.h" +@@ -19,13 +18,11 @@ + #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" + #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" + #include "llvm/DebugInfo/DWARF/DWARFDie.h" +-#include "llvm/DebugInfo/DWARF/DWARFExpression.h" + #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" + #include "llvm/DebugInfo/DWARF/DWARFListTable.h" + #include "llvm/DebugInfo/DWARF/DWARFObject.h" + #include "llvm/DebugInfo/DWARF/DWARFSection.h" + #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" +-#include "llvm/Object/ObjectFile.h" + #include "llvm/Support/DataExtractor.h" + #include "llvm/Support/Errc.h" + #include "llvm/Support/Path.h" +@@ -752,100 +749,6 @@ DWARFDie DWARFUnit::getSubroutineForAddress(uint64_t Address) { + return R->second.second; + } + +-void DWARFUnit::updateVariableDieMap(DWARFDie Die) { +- for (DWARFDie Child : Die) { +- if (isType(Child.getTag())) +- continue; +- updateVariableDieMap(Child); +- } +- +- if (Die.getTag() != DW_TAG_variable) +- return; +- +- Expected Locations = +- Die.getLocations(DW_AT_location); +- if (!Locations) { +- // Missing DW_AT_location is fine here. +- consumeError(Locations.takeError()); +- return; +- } +- +- uint64_t Address = UINT64_MAX; +- +- for (const DWARFLocationExpression &Location : *Locations) { +- uint8_t AddressSize = getAddressByteSize(); +- DataExtractor Data(Location.Expr, /*IsLittleEndian=*/true, AddressSize); +- DWARFExpression Expr(Data, AddressSize); +- auto It = Expr.begin(); +- if (It == Expr.end()) +- continue; +- +- // Match exactly the main sequence used to describe global variables: +- // `DW_OP_addr[x] [+ DW_OP_plus_uconst]`. Currently, this is the sequence +- // that LLVM produces for DILocalVariables and DIGlobalVariables. If, in +- // future, the DWARF producer (`DwarfCompileUnit::addLocationAttribute()` is +- // a good starting point) is extended to use further expressions, this code +- // needs to be updated. +- uint64_t LocationAddr; +- if (It->getCode() == dwarf::DW_OP_addr) { +- LocationAddr = It->getRawOperand(0); +- } else if (It->getCode() == dwarf::DW_OP_addrx) { +- uint64_t DebugAddrOffset = It->getRawOperand(0); +- if (auto Pointer = getAddrOffsetSectionItem(DebugAddrOffset)) { +- LocationAddr = Pointer->Address; +- } +- } else { +- continue; +- } +- +- // Read the optional 2nd operand, a DW_OP_plus_uconst. +- if (++It != Expr.end()) { +- if (It->getCode() != dwarf::DW_OP_plus_uconst) +- continue; +- +- LocationAddr += It->getRawOperand(0); +- +- // Probe for a 3rd operand, if it exists, bail. +- if (++It != Expr.end()) +- continue; +- } +- +- Address = LocationAddr; +- break; +- } +- +- // Get the size of the global variable. If all else fails (i.e. the global has +- // no type), then we use a size of one to still allow symbolization of the +- // exact address. +- uint64_t GVSize = 1; +- if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type)) +- if (std::optional Size = Die.getTypeSize(getAddressByteSize())) +- GVSize = *Size; +- +- if (Address != UINT64_MAX) +- VariableDieMap[Address] = {Address + GVSize, Die}; +-} +- +-DWARFDie DWARFUnit::getVariableForAddress(uint64_t Address) { +- extractDIEsIfNeeded(false); +- +- auto RootDie = getUnitDIE(); +- +- auto RootLookup = RootsParsedForVariables.insert(RootDie.getOffset()); +- if (RootLookup.second) +- updateVariableDieMap(RootDie); +- +- auto R = VariableDieMap.upper_bound(Address); +- if (R == VariableDieMap.begin()) +- return DWARFDie(); +- +- // upper_bound's previous item contains Address. +- --R; +- if (Address >= R->second.first) +- return DWARFDie(); +- return R->second.second; +-} +- + void + DWARFUnit::getInlinedChainForAddress(uint64_t Address, + SmallVectorImpl &InlinedChain) { +diff --git a/llvm/lib/DebugInfo/PDB/PDBContext.cpp b/llvm/lib/DebugInfo/PDB/PDBContext.cpp +index e600fb7385f1..0444093d7622 100644 +--- a/llvm/lib/DebugInfo/PDB/PDBContext.cpp ++++ b/llvm/lib/DebugInfo/PDB/PDBContext.cpp +@@ -64,13 +64,6 @@ DILineInfo PDBContext::getLineInfoForAddress(object::SectionedAddress Address, + return Result; + } + +-DILineInfo +-PDBContext::getLineInfoForDataAddress(object::SectionedAddress Address) { +- // Unimplemented. S_GDATA and S_LDATA in CodeView (used to describe global +- // variables) aren't capable of carrying line information. +- return DILineInfo(); +-} +- + DILineInfoTable + PDBContext::getLineInfoForAddressRange(object::SectionedAddress Address, + uint64_t Size, +diff --git a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp +index 877380213f21..496c8149782e 100644 +--- a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp ++++ b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp +@@ -206,10 +206,6 @@ void PlainPrinterBase::print(const Request &Request, const DIGlobal &Global) { + Name = DILineInfo::Addr2LineBadString; + OS << Name << "\n"; + OS << Global.Start << " " << Global.Size << "\n"; +- if (Global.DeclFile.empty()) +- OS << "??:?\n"; +- else +- OS << Global.DeclFile << ":" << Global.DeclLine << "\n"; + printFooter(); + } + +diff --git a/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp b/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp +index d8ee9264b64f..fcff531895a2 100644 +--- a/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp ++++ b/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp +@@ -327,14 +327,6 @@ DIGlobal SymbolizableObjectFile::symbolizeData( + std::string FileName; + getNameFromSymbolTable(ModuleOffset.Address, Res.Name, Res.Start, Res.Size, + FileName); +- Res.DeclFile = FileName; +- +- // Try and get a better filename:lineno pair from the debuginfo, if present. +- DILineInfo DL = DebugInfoContext->getLineInfoForDataAddress(ModuleOffset); +- if (DL.Line != 0) { +- Res.DeclFile = DL.FileName; +- Res.DeclLine = DL.Line; +- } + return Res; + } + +diff --git a/llvm/test/DebugInfo/Symbolize/ELF/data-command-symtab.yaml b/llvm/test/DebugInfo/Symbolize/ELF/data-command-symtab.yaml +index 83af3111c5dd..984e444b2fda 100644 +--- a/llvm/test/DebugInfo/Symbolize/ELF/data-command-symtab.yaml ++++ b/llvm/test/DebugInfo/Symbolize/ELF/data-command-symtab.yaml +@@ -7,15 +7,12 @@ + + # CHECK: func + # CHECK-NEXT: 4096 1 +-# CHECK-NEXT: ??:? + # CHECK-EMPTY: + # CHECK-NEXT: data + # CHECK-NEXT: 8192 2 +-# CHECK-NEXT: ??:? + # CHECK-EMPTY: + # CHECK-NEXT: notype + # CHECK-NEXT: 8194 3 +-# CHECK-NEXT: ??:? + # CHECK-EMPTY: + + --- !ELF +diff --git a/llvm/test/tools/llvm-symbolizer/data-location.yaml b/llvm/test/tools/llvm-symbolizer/data-location.yaml +deleted file mode 100644 +index 54f7d9be44a1..000000000000 +--- a/llvm/test/tools/llvm-symbolizer/data-location.yaml ++++ /dev/null +@@ -1,450 +0,0 @@ +-## Show that when "DATA" is used with an address, it forces the found location +-## to be symbolized as data, including the source information. +- +-# RUN: yaml2obj %s -o %t.so +- +-# RUN: llvm-symbolizer 'DATA 0x304d0' 'DATA 0x304d1' 'DATA 0x304d3' \ +-# RUN: 'DATA 0x304c0' 'DATA 0x304c8' 'DATA 0x304d4' 'DATA 0x304dc' \ +-# RUN: 'DATA 0x304d8' --obj=%t.so | FileCheck %s +- +-# CHECK: bss_global +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:1 +-# CHECK-EMPTY: +- +-## Check that lookups in the middle of the symbol are also resolved correctly. +-# CHECK: bss_global +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:1 +-# CHECK-EMPTY: +-# CHECK: bss_global +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:1 +-# CHECK-EMPTY: +- +-## Now, the remainder of the symbols. +-# CHECK-NEXT: data_global +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:2 +-# CHECK-EMPTY: +-# CHECK-NEXT: str +-# CHECK-NEXT: {{[0-9]+}} 8 +-# CHECK-NEXT: /tmp/file.cpp:4 +-# CHECK-EMPTY: +-# CHECK-NEXT: f()::function_global +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:8 +-# CHECK-EMPTY: +- +-## Including the one that includes an addend. +-# CHECK-NEXT: alpha +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:12 +-# CHECK-EMPTY: +-# CHECK-NEXT: beta +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:13 +-# CHECK-EMPTY: +- +-## Ensure there's still a global that's offset-based. +-# RUN: llvm-dwarfdump --debug-info %t.so | FileCheck %s --check-prefix=OFFSET +- +-# OFFSET: DW_AT_location (DW_OP_addrx 0x4, DW_OP_plus_uconst 0x4) +- +-################################################################################ +-## File below was generated using: +-## +-## $ clang++ -g -O3 /tmp/file.cpp -shared -fuse-ld=lld -nostdlib \ +-## -target aarch64-linux-gnuabi -mllvm -global-merge-ignore-single-use \ +-## -o /tmp/file.so +-## +-## With /tmp/file.cpp as: +-## 1: int bss_global; +-## 2: int data_global = 2; +-## 3: +-## 4: const char* str = +-## 5: "12345678"; +-## 6: +-## 7: int* f() { +-## 8: static int function_global; +-## 9: return &function_global; +-## 10: } +-## 11: +-## 12: static int alpha; +-## 13: static int beta; +-## 14: int *f(bool b) { return beta ? &alpha : β } +-## 15: +-## +-## ... then, one can get the offsets using `nm`, like: +-## $ nm out.so | grep bss_global +-## 00000000000038fc B bss_global +-## +-## Note the use of the aarch64 target (with -nostdlib in order to allow linkage +-## without libraries for cross-compilation) as well as -O3 and +-## -global-merge-ignore-single-use. This is a specific combination that makes +-## the compiler emit the `alpha` global variable with a more complex +-## DW_AT_location than just a DW_OP_addr/DW_OP_addrx. In this instance, it +-## outputs a `DW_AT_location (DW_OP_addrx 0x4, DW_OP_plus_uconst 0x4)`. +-## +-## Ideally, this would be tested by invoking clang directly on a C source file, +-## but unfortunately there's no way to do that for LLVM tests. The other option +-## is to compile IR to an objfile, but llvm-symbolizer doesn't understand that +-## two symbols can have the same address in different sections. In the code +-## above, for example, we'd have bss_global at .bss+0x0, and data_global at +-## .data+0x0, and so the symbolizer would only print one of them. Hence, we have +-## the ugly dso-to-yaml blob below. +-## +-## For now, constant strings don't have a debuginfo entry, and so can't be +-## symbolized correctly. In future (if D123534 gets merged), this can be updated +-## to include a check that llvm-symbolizer can also symbolize constant strings, +-## like `str` above (basically that &"12345678" should be symbolizable) +-## to the specific line. Then, you can find the address of the constant string +-## from the relocation: +-## +-## $ nm out.so | grep str +-## 00000000000038c0 D str +-## $ llvm-objdump -R out.so | grep 38c0 +-## 00000000000038c0 R_X86_64_RELATIVE *ABS*+0x4f8 # <-- 0x4f8 +-################################################################################ +- +---- !ELF +-FileHeader: +- Class: ELFCLASS64 +- Data: ELFDATA2LSB +- Type: ET_DYN +- Machine: EM_AARCH64 +-ProgramHeaders: +- - Type: PT_PHDR +- Flags: [ PF_R ] +- VAddr: 0x40 +- Align: 0x8 +- - Type: PT_LOAD +- Flags: [ PF_R ] +- FirstSec: .dynsym +- LastSec: .eh_frame +- Align: 0x10000 +- - Type: PT_LOAD +- Flags: [ PF_X, PF_R ] +- FirstSec: .text +- LastSec: .text +- VAddr: 0x103E4 +- Align: 0x10000 +- - Type: PT_LOAD +- Flags: [ PF_W, PF_R ] +- FirstSec: .dynamic +- LastSec: .dynamic +- VAddr: 0x20410 +- Align: 0x10000 +- - Type: PT_LOAD +- Flags: [ PF_W, PF_R ] +- FirstSec: .data +- LastSec: .bss +- VAddr: 0x304C0 +- Align: 0x10000 +- - Type: PT_DYNAMIC +- Flags: [ PF_W, PF_R ] +- FirstSec: .dynamic +- LastSec: .dynamic +- VAddr: 0x20410 +- Align: 0x8 +- - Type: PT_GNU_RELRO +- Flags: [ PF_R ] +- FirstSec: .dynamic +- LastSec: .dynamic +- VAddr: 0x20410 +- - Type: PT_GNU_EH_FRAME +- Flags: [ PF_R ] +- FirstSec: .eh_frame_hdr +- LastSec: .eh_frame_hdr +- VAddr: 0x37C +- Align: 0x4 +- - Type: PT_GNU_STACK +- Flags: [ PF_W, PF_R ] +- Align: 0x0 +-Sections: +- - Name: .dynsym +- Type: SHT_DYNSYM +- Flags: [ SHF_ALLOC ] +- Address: 0x238 +- Link: .dynstr +- AddressAlign: 0x8 +- - Name: .gnu.hash +- Type: SHT_GNU_HASH +- Flags: [ SHF_ALLOC ] +- Address: 0x2C8 +- Link: .dynsym +- AddressAlign: 0x8 +- Header: +- SymNdx: 0x1 +- Shift2: 0x1A +- BloomFilter: [ 0x400188002180000C ] +- HashBuckets: [ 0x1 ] +- HashValues: [ 0xEE8502A, 0xEE85016, 0xC033991C, 0x61F7372E, 0xB88AB7F ] +- - Name: .hash +- Type: SHT_HASH +- Flags: [ SHF_ALLOC ] +- Address: 0x2F8 +- Link: .dynsym +- AddressAlign: 0x4 +- Bucket: [ 5, 0, 4, 0, 3, 0 ] +- Chain: [ 0, 0, 0, 1, 2, 0 ] +- - Name: .dynstr +- Type: SHT_STRTAB +- Flags: [ SHF_ALLOC ] +- Address: 0x330 +- AddressAlign: 0x1 +- - Name: .rela.dyn +- Type: SHT_RELA +- Flags: [ SHF_ALLOC ] +- Address: 0x358 +- Link: .dynsym +- AddressAlign: 0x8 +- Relocations: +- - Offset: 0x304C8 +- Type: R_AARCH64_RELATIVE +- Addend: 880 +- - Name: .rodata +- Type: SHT_PROGBITS +- Flags: [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ] +- Address: 0x370 +- AddressAlign: 0x1 +- EntSize: 0x1 +- Content: '313233343536373800' +- - Name: .eh_frame_hdr +- Type: SHT_PROGBITS +- Flags: [ SHF_ALLOC ] +- Address: 0x37C +- AddressAlign: 0x4 +- Content: 011B033B18000000020000006800010034000000740001004C000000 +- - Name: .eh_frame +- Type: SHT_PROGBITS +- Flags: [ SHF_ALLOC ] +- Address: 0x398 +- AddressAlign: 0x8 +- Content: 1400000000000000017A5200017C1E011B0C1F0000000000140000001C0000002C0001000C00000000000000000000001400000034000000200001001C000000000000000000000000000000 +- - Name: .text +- Type: SHT_PROGBITS +- Flags: [ SHF_ALLOC, SHF_EXECINSTR ] +- Address: 0x103E4 +- AddressAlign: 0x4 +- Content: 0001009000501391C0035FD60801009008611391E90308AA2A4540B85F0100710001899AC0035FD6 +- - Name: .dynamic +- Type: SHT_DYNAMIC +- Flags: [ SHF_WRITE, SHF_ALLOC ] +- Address: 0x20410 +- Link: .dynstr +- AddressAlign: 0x8 +- Entries: +- - Tag: DT_RELA +- Value: 0x358 +- - Tag: DT_RELASZ +- Value: 0x18 +- - Tag: DT_RELAENT +- Value: 0x18 +- - Tag: DT_RELACOUNT +- Value: 0x1 +- - Tag: DT_SYMTAB +- Value: 0x238 +- - Tag: DT_SYMENT +- Value: 0x18 +- - Tag: DT_STRTAB +- Value: 0x330 +- - Tag: DT_STRSZ +- Value: 0x28 +- - Tag: DT_GNU_HASH +- Value: 0x2C8 +- - Tag: DT_HASH +- Value: 0x2F8 +- - Tag: DT_NULL +- Value: 0x0 +- - Name: .data +- Type: SHT_PROGBITS +- Flags: [ SHF_WRITE, SHF_ALLOC ] +- Address: 0x304C0 +- AddressAlign: 0x8 +- Content: '02000000000000000000000000000000' +- - Name: .bss +- Type: SHT_NOBITS +- Flags: [ SHF_WRITE, SHF_ALLOC ] +- Address: 0x304D0 +- AddressAlign: 0x4 +- Size: 0x10 +- - Name: .debug_abbrev +- Type: SHT_PROGBITS +- AddressAlign: 0x1 +- Content: 011101252513050325721710171B25111B120673170000023400032549133F193A0B3B0B0218000003240003253E0B0B0B0000040F004913000005260049130000062E01111B120640187A196E2503253A0B3B0B49133F190000073400032549133A0B3B0B02180000083400032549133A0B3B0B02186E25000009050003253A0B3B0B4913000000 +- - Name: .debug_info +- Type: SHT_PROGBITS +- AddressAlign: 0x1 +- Content: AB0000000500010800000000010021000108000000000000000205280000000800000002032E000000000102A1000304050402052E000000000202A101020648000000000402A102044D00000005520000000307080106050C000000016F0D0E0007A500000007082E000000000802A1030008092E000000000D02A1040A080B2E000000000C04A10423040C06061C000000016F0F0E000EA50000000910000EAA00000000042E0000000311020100 +- - Name: .debug_str_offsets +- Type: SHT_PROGBITS +- AddressAlign: 0x1 +- Content: 4C00000005000000A2000000000000002C00000059000000280000001C00000072000000640000008C0000008700000069000000140000007B0000009C0000001A0000000E0000008500000076000000 +- - Name: .comment +- Type: SHT_PROGBITS +- Flags: [ SHF_MERGE, SHF_STRINGS ] +- AddressAlign: 0x1 +- EntSize: 0x1 +- Content: 4C696E6B65723A204C4C442031352E302E300000636C616E672076657273696F6E2031352E302E30202868747470733A2F2F6769746875622E636F6D2F6C6C766D2F6C6C766D2D70726F6A6563742E67697420306462616566363162353666306566306162306366333865613932666663316633356265653366662900 +- - Name: .debug_line +- Type: SHT_PROGBITS +- AddressAlign: 0x1 +- Content: 620000000500080037000000010101FB0E0D00010101010000000100000101011F010E00000003011F020F051E0100000000006C97BBE59F7DC6A9EA956633431DA63E0400000902E4030100000000001805030A140500BF05190A0105120608740204000101 +- - Name: .debug_line_str +- Type: SHT_PROGBITS +- Flags: [ SHF_MERGE, SHF_STRINGS ] +- AddressAlign: 0x1 +- EntSize: 0x1 +- Content: 2F746D702F66696C652E637070002F7573722F6C6F63616C2F676F6F676C652F686F6D652F6D69746368702F6C6C766D2D6275696C642F6F707400 +-Symbols: +- - Name: file.cpp +- Type: STT_FILE +- Index: SHN_ABS +- - Name: '$x.0' +- Section: .text +- Value: 0x103E4 +- - Name: _ZZ1fvE15function_global +- Type: STT_OBJECT +- Section: .bss +- Value: 0x304D4 +- Size: 0x4 +- - Name: '$d.1' +- Section: .bss +- Value: 0x304D0 +- - Name: '$d.2' +- Section: .data +- Value: 0x304C0 +- - Name: '$d.3' +- Section: .rodata +- Value: 0x370 +- - Name: '$d.4' +- Section: .debug_abbrev +- - Name: '$d.5' +- Section: .debug_info +- - Name: '$d.6' +- Section: .debug_str_offsets +- - Name: '$d.7' +- Section: .debug_str +- Value: 0xA2 +- - Name: '$d.8' +- Section: .debug_addr +- - Name: _ZL4beta +- Type: STT_OBJECT +- Section: .bss +- Value: 0x304D8 +- Size: 0x4 +- - Name: _ZL5alpha +- Type: STT_OBJECT +- Section: .bss +- Value: 0x304DC +- Size: 0x4 +- - Name: '$d.9' +- Section: .comment +- Value: 0x13 +- - Name: '$d.10' +- Section: .eh_frame +- Value: 0x398 +- - Name: '$d.11' +- Section: .debug_line +- - Name: '$d.12' +- Section: .debug_line_str +- Value: 0xE +- - Name: _DYNAMIC +- Section: .dynamic +- Value: 0x20410 +- Other: [ STV_HIDDEN ] +- - Name: _Z1fv +- Type: STT_FUNC +- Section: .text +- Binding: STB_GLOBAL +- Value: 0x103E4 +- Size: 0xC +- - Name: _Z1fb +- Type: STT_FUNC +- Section: .text +- Binding: STB_GLOBAL +- Value: 0x103F0 +- Size: 0x1C +- - Name: bss_global +- Type: STT_OBJECT +- Section: .bss +- Binding: STB_GLOBAL +- Value: 0x304D0 +- Size: 0x4 +- - Name: data_global +- Type: STT_OBJECT +- Section: .data +- Binding: STB_GLOBAL +- Value: 0x304C0 +- Size: 0x4 +- - Name: str +- Type: STT_OBJECT +- Section: .data +- Binding: STB_GLOBAL +- Value: 0x304C8 +- Size: 0x8 +-DynamicSymbols: +- - Name: _Z1fv +- Type: STT_FUNC +- Section: .text +- Binding: STB_GLOBAL +- Value: 0x103E4 +- Size: 0xC +- - Name: _Z1fb +- Type: STT_FUNC +- Section: .text +- Binding: STB_GLOBAL +- Value: 0x103F0 +- Size: 0x1C +- - Name: bss_global +- Type: STT_OBJECT +- Section: .bss +- Binding: STB_GLOBAL +- Value: 0x304D0 +- Size: 0x4 +- - Name: data_global +- Type: STT_OBJECT +- Section: .data +- Binding: STB_GLOBAL +- Value: 0x304C0 +- Size: 0x4 +- - Name: str +- Type: STT_OBJECT +- Section: .data +- Binding: STB_GLOBAL +- Value: 0x304C8 +- Size: 0x8 +-DWARF: +- debug_str: +- - '/tmp/file.cpp' +- - _Z1fb +- - alpha +- - f +- - data_global +- - int +- - '/usr/local/google/home/mitchp/llvm-build/opt' +- - bss_global +- - char +- - _ZL4beta +- - str +- - bool +- - _ZL5alpha +- - b +- - beta +- - function_global +- - _Z1fv +- - 'clang version 15.0.0 (https://github.com/llvm/llvm-project.git 0dbaef61b56f0ef0ab0cf38ea92ffc1f35bee3ff)' +- debug_addr: +- - Length: 0x3C +- Version: 0x5 +- AddressSize: 0x8 +- Entries: +- - Address: 0x304D0 +- - Address: 0x304C0 +- - Address: 0x304C8 +- - Address: 0x304D4 +- - Address: 0x304D8 +- - Address: 0x103E4 +- - Address: 0x103F0 +-... +diff --git a/llvm/test/tools/llvm-symbolizer/data.s b/llvm/test/tools/llvm-symbolizer/data.s +index cc9503c59141..e8039f146dbd 100644 +--- a/llvm/test/tools/llvm-symbolizer/data.s ++++ b/llvm/test/tools/llvm-symbolizer/data.s +@@ -7,12 +7,9 @@ + + # CHECK: d1 + # CHECK-NEXT: 0 8 +-# CHECK-NEXT: ??:? + # CHECK-EMPTY: + # CHECK-NEXT: d2 + # CHECK-NEXT: 8 4 +-# CHECK-NEXT: ??:? +-# CHECK-EMPTY: + + d1: + .quad 0x1122334455667788 +-- +2.38.1.1.g6d9df9d320 + diff --git a/build/build-clang/revert-llvmorg-15-init-11205-gcead4eceb01b_clang_18.patch b/build/build-clang/revert-llvmorg-15-init-11205-gcead4eceb01b_clang_18.patch new file mode 100644 index 0000000000..908374789c --- /dev/null +++ b/build/build-clang/revert-llvmorg-15-init-11205-gcead4eceb01b_clang_18.patch @@ -0,0 +1,972 @@ +From cb411520cb7cd5e6e25966911ca55feb5de779e0 Mon Sep 17 00:00:00 2001 +From: Mike Hommey +Date: Fri, 4 Nov 2022 14:51:38 +0900 +Subject: [PATCH] Revert "[symbolizer] Parse DW_TAG_variable DIs to show line + info for globals" + +This reverts commit cead4eceb01b935fae07bf4a7e91911b344d2fec for causing +yet unidentified problems on some webrtc tests under TSan (bug 1798613). +--- + llvm/include/llvm/DebugInfo/DIContext.h | 4 - + .../llvm/DebugInfo/DWARF/DWARFContext.h | 2 - + llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h | 7 - + llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h | 14 - + llvm/include/llvm/DebugInfo/PDB/PDBContext.h | 2 - + llvm/lib/DebugInfo/DWARF/DWARFContext.cpp | 97 ++-- + llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 60 --- + llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 97 ---- + llvm/lib/DebugInfo/PDB/PDBContext.cpp | 7 - + llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp | 4 - + .../Symbolize/SymbolizableObjectFile.cpp | 8 - + .../Symbolize/ELF/data-command-symtab.yaml | 3 - + .../tools/llvm-symbolizer/data-location.yaml | 450 ------------------ + llvm/test/tools/llvm-symbolizer/data.s | 3 - + 14 files changed, 61 insertions(+), 697 deletions(-) + delete mode 100644 llvm/test/tools/llvm-symbolizer/data-location.yaml + +diff --git a/llvm/include/llvm/DebugInfo/DIContext.h b/llvm/include/llvm/DebugInfo/DIContext.h +index 9b278b696073..a9f98588cf2d 100644 +--- a/llvm/include/llvm/DebugInfo/DIContext.h ++++ b/llvm/include/llvm/DebugInfo/DIContext.h +@@ -114,8 +114,6 @@ struct DIGlobal { + std::string Name; + uint64_t Start = 0; + uint64_t Size = 0; +- std::string DeclFile; +- uint64_t DeclLine = 0; + + DIGlobal() : Name(DILineInfo::BadString) {} + }; +@@ -241,8 +239,6 @@ public: + virtual DILineInfo getLineInfoForAddress( + object::SectionedAddress Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; +- virtual DILineInfo +- getLineInfoForDataAddress(object::SectionedAddress Address) = 0; + virtual DILineInfoTable getLineInfoForAddressRange( + object::SectionedAddress Address, uint64_t Size, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; +diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +index bf591ed554c6..3365ef8d8ee3 100644 +--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h ++++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +@@ -364,8 +364,6 @@ public: + DILineInfo getLineInfoForAddress( + object::SectionedAddress Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; +- DILineInfo +- getLineInfoForDataAddress(object::SectionedAddress Address) override; + DILineInfoTable getLineInfoForAddressRange( + object::SectionedAddress Address, uint64_t Size, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; +diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h +index 149c5ef4e493..4a4d105a2b23 100644 +--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h ++++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h +@@ -280,13 +280,6 @@ public: + /// \returns an iterator range for the attributes of the current DIE. + iterator_range attributes() const; + +- /// Gets the type size (in bytes) for this DIE. +- /// +- /// \param PointerSize the pointer size of the containing CU. +- /// \returns if this is a type DIE, or this DIE contains a DW_AT_type, returns +- /// the size of the type. +- std::optional getTypeSize(uint64_t PointerSize); +- + class iterator; + + iterator begin() const; +diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h +index 9188865b4d77..0341344bc7b8 100644 +--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h ++++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h +@@ -9,7 +9,6 @@ + #ifndef LLVM_DEBUGINFO_DWARF_DWARFUNIT_H + #define LLVM_DEBUGINFO_DWARF_DWARFUNIT_H + +-#include "llvm/ADT/DenseSet.h" + #include "llvm/ADT/STLExtras.h" + #include "llvm/ADT/SmallVector.h" + #include "llvm/ADT/StringRef.h" +@@ -28,7 +27,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -242,11 +240,6 @@ class DWARFUnit { + /// std::map::upper_bound for address range lookup. + std::map> AddrDieMap; + +- /// Map from the location (interpreted DW_AT_location) of a DW_TAG_variable, +- /// to the end address and the corresponding DIE. +- std::map> VariableDieMap; +- DenseSet RootsParsedForVariables; +- + using die_iterator_range = + iterator_range::iterator>; + +@@ -329,9 +322,6 @@ public: + /// Recursively update address to Die map. + void updateAddressDieMap(DWARFDie Die); + +- /// Recursively update address to variable Die map. +- void updateVariableDieMap(DWARFDie Die); +- + void setRangesSection(const DWARFSection *RS, uint64_t Base) { + RangeSection = RS; + RangeSectionBase = Base; +@@ -446,10 +436,6 @@ public: + /// cleared. + DWARFDie getSubroutineForAddress(uint64_t Address); + +- /// Returns variable DIE for the address provided. The pointer is alive as +- /// long as parsed compile unit DIEs are not cleared. +- DWARFDie getVariableForAddress(uint64_t Address); +- + /// getInlinedChainForAddress - fetches inlined chain for a given address. + /// Returns empty chain if there is no subprogram containing address. The + /// chain is valid as long as parsed compile unit DIEs are not cleared. +diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBContext.h b/llvm/include/llvm/DebugInfo/PDB/PDBContext.h +index 3163c0a1dae0..7b6793f0a639 100644 +--- a/llvm/include/llvm/DebugInfo/PDB/PDBContext.h ++++ b/llvm/include/llvm/DebugInfo/PDB/PDBContext.h +@@ -45,8 +45,6 @@ namespace pdb { + DILineInfo getLineInfoForAddress( + object::SectionedAddress Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; +- DILineInfo +- getLineInfoForDataAddress(object::SectionedAddress Address) override; + DILineInfoTable getLineInfoForAddressRange( + object::SectionedAddress Address, uint64_t Size, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; +diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +index 19d7d659a86a..1bcfdecfd588 100644 +--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp ++++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +@@ -1053,25 +1053,7 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) { + // First, get the offset of the compile unit. + uint64_t CUOffset = getDebugAranges()->findAddress(Address); + // Retrieve the compile unit. +- if (DWARFCompileUnit *OffsetCU = getCompileUnitForOffset(CUOffset)) +- return OffsetCU; +- +- // Global variables are often not found by the above search, for one of two +- // reasons: +- // 1. .debug_aranges may not include global variables. On clang, it seems we +- // put the globals in the aranges, but this isn't true for gcc. +- // 2. Even if the global variable is in a .debug_arange, global variables +- // may not be captured in the [start, end) addresses described by the +- // parent compile unit. +- // +- // So, we walk the CU's and their child DI's manually, looking for the +- // specific global variable. +- for (std::unique_ptr &CU : compile_units()) { +- if (CU->getVariableForAddress(Address)) { +- return static_cast(CU.get()); +- } +- } +- return nullptr; ++ return getCompileUnitForOffset(CUOffset); + } + + DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address, +@@ -1141,6 +1123,64 @@ static bool getFunctionNameAndStartLineForAddress( + return FoundResult; + } + ++static std::optional getTypeSize(DWARFDie Type, uint64_t PointerSize) { ++ if (auto SizeAttr = Type.find(DW_AT_byte_size)) ++ if (std::optional Size = SizeAttr->getAsUnsignedConstant()) ++ return Size; ++ ++ switch (Type.getTag()) { ++ case DW_TAG_pointer_type: ++ case DW_TAG_reference_type: ++ case DW_TAG_rvalue_reference_type: ++ return PointerSize; ++ case DW_TAG_ptr_to_member_type: { ++ if (DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type)) ++ if (BaseType.getTag() == DW_TAG_subroutine_type) ++ return 2 * PointerSize; ++ return PointerSize; ++ } ++ case DW_TAG_const_type: ++ case DW_TAG_immutable_type: ++ case DW_TAG_volatile_type: ++ case DW_TAG_restrict_type: ++ case DW_TAG_typedef: { ++ if (DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type)) ++ return getTypeSize(BaseType, PointerSize); ++ break; ++ } ++ case DW_TAG_array_type: { ++ DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type); ++ if (!BaseType) ++ return std::optional(); ++ std::optional BaseSize = getTypeSize(BaseType, PointerSize); ++ if (!BaseSize) ++ return std::optional(); ++ uint64_t Size = *BaseSize; ++ for (DWARFDie Child : Type) { ++ if (Child.getTag() != DW_TAG_subrange_type) ++ continue; ++ ++ if (auto ElemCountAttr = Child.find(DW_AT_count)) ++ if (std::optional ElemCount = ++ ElemCountAttr->getAsUnsignedConstant()) ++ Size *= *ElemCount; ++ if (auto UpperBoundAttr = Child.find(DW_AT_upper_bound)) ++ if (std::optional UpperBound = ++ UpperBoundAttr->getAsSignedConstant()) { ++ int64_t LowerBound = 0; ++ if (auto LowerBoundAttr = Child.find(DW_AT_lower_bound)) ++ LowerBound = LowerBoundAttr->getAsSignedConstant().value_or(0); ++ Size *= *UpperBound - LowerBound + 1; ++ } ++ } ++ return Size; ++ } ++ default: ++ break; ++ } ++ return std::optional(); ++} ++ + static std::optional + getExpressionFrameOffset(ArrayRef Expr, + std::optional FrameBaseReg) { +@@ -1201,7 +1241,7 @@ void DWARFContext::addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, + if (std::optional Name = dwarf::toString(*NameAttr)) + Local.Name = *Name; + if (auto Type = Die.getAttributeValueAsReferencedDie(DW_AT_type)) +- Local.Size = Type.getTypeSize(getCUAddrSize()); ++ Local.Size = getTypeSize(Type, getCUAddrSize()); + if (auto DeclFileAttr = Die.find(DW_AT_decl_file)) { + if (const auto *LT = CU->getContext().getLineTableForUnit(CU)) + LT->getFileNameByIndex( +@@ -1242,6 +1282,7 @@ DWARFContext::getLocalsForAddress(object::SectionedAddress Address) { + DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address, + DILineInfoSpecifier Spec) { + DILineInfo Result; ++ + DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Result; +@@ -1256,22 +1297,6 @@ DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address, + Spec.FLIKind, Result); + } + } +- +- return Result; +-} +- +-DILineInfo +-DWARFContext::getLineInfoForDataAddress(object::SectionedAddress Address) { +- DILineInfo Result; +- DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); +- if (!CU) +- return Result; +- +- if (DWARFDie Die = CU->getVariableForAddress(Address.Address)) { +- Result.FileName = Die.getDeclFile(FileLineInfoKind::AbsoluteFilePath); +- Result.Line = Die.getDeclLine(); +- } +- + return Result; + } + +diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +index 66492f7bf804..357b172bf99b 100644 +--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp ++++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +@@ -556,11 +556,6 @@ getTypeSizeImpl(DWARFDie Die, uint64_t PointerSize, + return std::nullopt; + } + +-std::optional DWARFDie::getTypeSize(uint64_t PointerSize) { +- SmallPtrSet Visited; +- return getTypeSizeImpl(*this, PointerSize, Visited); +-} +- + /// Helper to dump a DIE with all of its parents, but no siblings. + static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent, + DIDumpOptions DumpOpts, unsigned Depth = 0) { +diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +index 74667fcb92bc..148711f0246f 100644 +--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp ++++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +@@ -9,7 +9,6 @@ + #include "llvm/DebugInfo/DWARF/DWARFUnit.h" + #include "llvm/ADT/SmallString.h" + #include "llvm/ADT/StringRef.h" +-#include "llvm/BinaryFormat/Dwarf.h" + #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" + #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" + #include "llvm/DebugInfo/DWARF/DWARFContext.h" +@@ -19,13 +18,11 @@ + #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" + #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" + #include "llvm/DebugInfo/DWARF/DWARFDie.h" +-#include "llvm/DebugInfo/DWARF/DWARFExpression.h" + #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" + #include "llvm/DebugInfo/DWARF/DWARFListTable.h" + #include "llvm/DebugInfo/DWARF/DWARFObject.h" + #include "llvm/DebugInfo/DWARF/DWARFSection.h" + #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" +-#include "llvm/Object/ObjectFile.h" + #include "llvm/Support/DataExtractor.h" + #include "llvm/Support/Errc.h" + #include "llvm/Support/Path.h" +@@ -752,100 +749,6 @@ DWARFDie DWARFUnit::getSubroutineForAddress(uint64_t Address) { + return R->second.second; + } + +-void DWARFUnit::updateVariableDieMap(DWARFDie Die) { +- for (DWARFDie Child : Die) { +- if (isType(Child.getTag())) +- continue; +- updateVariableDieMap(Child); +- } +- +- if (Die.getTag() != DW_TAG_variable) +- return; +- +- Expected Locations = +- Die.getLocations(DW_AT_location); +- if (!Locations) { +- // Missing DW_AT_location is fine here. +- consumeError(Locations.takeError()); +- return; +- } +- +- uint64_t Address = UINT64_MAX; +- +- for (const DWARFLocationExpression &Location : *Locations) { +- uint8_t AddressSize = getAddressByteSize(); +- DataExtractor Data(Location.Expr, isLittleEndian(), AddressSize); +- DWARFExpression Expr(Data, AddressSize); +- auto It = Expr.begin(); +- if (It == Expr.end()) +- continue; +- +- // Match exactly the main sequence used to describe global variables: +- // `DW_OP_addr[x] [+ DW_OP_plus_uconst]`. Currently, this is the sequence +- // that LLVM produces for DILocalVariables and DIGlobalVariables. If, in +- // future, the DWARF producer (`DwarfCompileUnit::addLocationAttribute()` is +- // a good starting point) is extended to use further expressions, this code +- // needs to be updated. +- uint64_t LocationAddr; +- if (It->getCode() == dwarf::DW_OP_addr) { +- LocationAddr = It->getRawOperand(0); +- } else if (It->getCode() == dwarf::DW_OP_addrx) { +- uint64_t DebugAddrOffset = It->getRawOperand(0); +- if (auto Pointer = getAddrOffsetSectionItem(DebugAddrOffset)) { +- LocationAddr = Pointer->Address; +- } +- } else { +- continue; +- } +- +- // Read the optional 2nd operand, a DW_OP_plus_uconst. +- if (++It != Expr.end()) { +- if (It->getCode() != dwarf::DW_OP_plus_uconst) +- continue; +- +- LocationAddr += It->getRawOperand(0); +- +- // Probe for a 3rd operand, if it exists, bail. +- if (++It != Expr.end()) +- continue; +- } +- +- Address = LocationAddr; +- break; +- } +- +- // Get the size of the global variable. If all else fails (i.e. the global has +- // no type), then we use a size of one to still allow symbolization of the +- // exact address. +- uint64_t GVSize = 1; +- if (Die.getAttributeValueAsReferencedDie(DW_AT_type)) +- if (std::optional Size = Die.getTypeSize(getAddressByteSize())) +- GVSize = *Size; +- +- if (Address != UINT64_MAX) +- VariableDieMap[Address] = {Address + GVSize, Die}; +-} +- +-DWARFDie DWARFUnit::getVariableForAddress(uint64_t Address) { +- extractDIEsIfNeeded(false); +- +- auto RootDie = getUnitDIE(); +- +- auto RootLookup = RootsParsedForVariables.insert(RootDie.getOffset()); +- if (RootLookup.second) +- updateVariableDieMap(RootDie); +- +- auto R = VariableDieMap.upper_bound(Address); +- if (R == VariableDieMap.begin()) +- return DWARFDie(); +- +- // upper_bound's previous item contains Address. +- --R; +- if (Address >= R->second.first) +- return DWARFDie(); +- return R->second.second; +-} +- + void + DWARFUnit::getInlinedChainForAddress(uint64_t Address, + SmallVectorImpl &InlinedChain) { +diff --git a/llvm/lib/DebugInfo/PDB/PDBContext.cpp b/llvm/lib/DebugInfo/PDB/PDBContext.cpp +index e600fb7385f1..0444093d7622 100644 +--- a/llvm/lib/DebugInfo/PDB/PDBContext.cpp ++++ b/llvm/lib/DebugInfo/PDB/PDBContext.cpp +@@ -64,13 +64,6 @@ DILineInfo PDBContext::getLineInfoForAddress(object::SectionedAddress Address, + return Result; + } + +-DILineInfo +-PDBContext::getLineInfoForDataAddress(object::SectionedAddress Address) { +- // Unimplemented. S_GDATA and S_LDATA in CodeView (used to describe global +- // variables) aren't capable of carrying line information. +- return DILineInfo(); +-} +- + DILineInfoTable + PDBContext::getLineInfoForAddressRange(object::SectionedAddress Address, + uint64_t Size, +diff --git a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp +index 877380213f21..496c8149782e 100644 +--- a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp ++++ b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp +@@ -206,10 +206,6 @@ void PlainPrinterBase::print(const Request &Request, const DIGlobal &Global) { + Name = DILineInfo::Addr2LineBadString; + OS << Name << "\n"; + OS << Global.Start << " " << Global.Size << "\n"; +- if (Global.DeclFile.empty()) +- OS << "??:?\n"; +- else +- OS << Global.DeclFile << ":" << Global.DeclLine << "\n"; + printFooter(); + } + +diff --git a/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp b/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp +index d8ee9264b64f..fcff531895a2 100644 +--- a/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp ++++ b/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp +@@ -327,14 +327,6 @@ DIGlobal SymbolizableObjectFile::symbolizeData( + std::string FileName; + getNameFromSymbolTable(ModuleOffset.Address, Res.Name, Res.Start, Res.Size, + FileName); +- Res.DeclFile = FileName; +- +- // Try and get a better filename:lineno pair from the debuginfo, if present. +- DILineInfo DL = DebugInfoContext->getLineInfoForDataAddress(ModuleOffset); +- if (DL.Line != 0) { +- Res.DeclFile = DL.FileName; +- Res.DeclLine = DL.Line; +- } + return Res; + } + +diff --git a/llvm/test/DebugInfo/Symbolize/ELF/data-command-symtab.yaml b/llvm/test/DebugInfo/Symbolize/ELF/data-command-symtab.yaml +index 83af3111c5dd..984e444b2fda 100644 +--- a/llvm/test/DebugInfo/Symbolize/ELF/data-command-symtab.yaml ++++ b/llvm/test/DebugInfo/Symbolize/ELF/data-command-symtab.yaml +@@ -7,15 +7,12 @@ + + # CHECK: func + # CHECK-NEXT: 4096 1 +-# CHECK-NEXT: ??:? + # CHECK-EMPTY: + # CHECK-NEXT: data + # CHECK-NEXT: 8192 2 +-# CHECK-NEXT: ??:? + # CHECK-EMPTY: + # CHECK-NEXT: notype + # CHECK-NEXT: 8194 3 +-# CHECK-NEXT: ??:? + # CHECK-EMPTY: + + --- !ELF +diff --git a/llvm/test/tools/llvm-symbolizer/data-location.yaml b/llvm/test/tools/llvm-symbolizer/data-location.yaml +deleted file mode 100644 +index 54f7d9be44a1..000000000000 +--- a/llvm/test/tools/llvm-symbolizer/data-location.yaml ++++ /dev/null +@@ -1,450 +0,0 @@ +-## Show that when "DATA" is used with an address, it forces the found location +-## to be symbolized as data, including the source information. +- +-# RUN: yaml2obj %s -o %t.so +- +-# RUN: llvm-symbolizer 'DATA 0x304d0' 'DATA 0x304d1' 'DATA 0x304d3' \ +-# RUN: 'DATA 0x304c0' 'DATA 0x304c8' 'DATA 0x304d4' 'DATA 0x304dc' \ +-# RUN: 'DATA 0x304d8' --obj=%t.so | FileCheck %s +- +-# CHECK: bss_global +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:1 +-# CHECK-EMPTY: +- +-## Check that lookups in the middle of the symbol are also resolved correctly. +-# CHECK: bss_global +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:1 +-# CHECK-EMPTY: +-# CHECK: bss_global +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:1 +-# CHECK-EMPTY: +- +-## Now, the remainder of the symbols. +-# CHECK-NEXT: data_global +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:2 +-# CHECK-EMPTY: +-# CHECK-NEXT: str +-# CHECK-NEXT: {{[0-9]+}} 8 +-# CHECK-NEXT: /tmp/file.cpp:4 +-# CHECK-EMPTY: +-# CHECK-NEXT: f()::function_global +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:8 +-# CHECK-EMPTY: +- +-## Including the one that includes an addend. +-# CHECK-NEXT: alpha +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:12 +-# CHECK-EMPTY: +-# CHECK-NEXT: beta +-# CHECK-NEXT: {{[0-9]+}} 4 +-# CHECK-NEXT: /tmp/file.cpp:13 +-# CHECK-EMPTY: +- +-## Ensure there's still a global that's offset-based. +-# RUN: llvm-dwarfdump --debug-info %t.so | FileCheck %s --check-prefix=OFFSET +- +-# OFFSET: DW_AT_location (DW_OP_addrx 0x4, DW_OP_plus_uconst 0x4) +- +-################################################################################ +-## File below was generated using: +-## +-## $ clang++ -g -O3 /tmp/file.cpp -shared -fuse-ld=lld -nostdlib \ +-## -target aarch64-linux-gnuabi -mllvm -global-merge-ignore-single-use \ +-## -o /tmp/file.so +-## +-## With /tmp/file.cpp as: +-## 1: int bss_global; +-## 2: int data_global = 2; +-## 3: +-## 4: const char* str = +-## 5: "12345678"; +-## 6: +-## 7: int* f() { +-## 8: static int function_global; +-## 9: return &function_global; +-## 10: } +-## 11: +-## 12: static int alpha; +-## 13: static int beta; +-## 14: int *f(bool b) { return beta ? &alpha : β } +-## 15: +-## +-## ... then, one can get the offsets using `nm`, like: +-## $ nm out.so | grep bss_global +-## 00000000000038fc B bss_global +-## +-## Note the use of the aarch64 target (with -nostdlib in order to allow linkage +-## without libraries for cross-compilation) as well as -O3 and +-## -global-merge-ignore-single-use. This is a specific combination that makes +-## the compiler emit the `alpha` global variable with a more complex +-## DW_AT_location than just a DW_OP_addr/DW_OP_addrx. In this instance, it +-## outputs a `DW_AT_location (DW_OP_addrx 0x4, DW_OP_plus_uconst 0x4)`. +-## +-## Ideally, this would be tested by invoking clang directly on a C source file, +-## but unfortunately there's no way to do that for LLVM tests. The other option +-## is to compile IR to an objfile, but llvm-symbolizer doesn't understand that +-## two symbols can have the same address in different sections. In the code +-## above, for example, we'd have bss_global at .bss+0x0, and data_global at +-## .data+0x0, and so the symbolizer would only print one of them. Hence, we have +-## the ugly dso-to-yaml blob below. +-## +-## For now, constant strings don't have a debuginfo entry, and so can't be +-## symbolized correctly. In future (if D123534 gets merged), this can be updated +-## to include a check that llvm-symbolizer can also symbolize constant strings, +-## like `str` above (basically that &"12345678" should be symbolizable) +-## to the specific line. Then, you can find the address of the constant string +-## from the relocation: +-## +-## $ nm out.so | grep str +-## 00000000000038c0 D str +-## $ llvm-objdump -R out.so | grep 38c0 +-## 00000000000038c0 R_X86_64_RELATIVE *ABS*+0x4f8 # <-- 0x4f8 +-################################################################################ +- +---- !ELF +-FileHeader: +- Class: ELFCLASS64 +- Data: ELFDATA2LSB +- Type: ET_DYN +- Machine: EM_AARCH64 +-ProgramHeaders: +- - Type: PT_PHDR +- Flags: [ PF_R ] +- VAddr: 0x40 +- Align: 0x8 +- - Type: PT_LOAD +- Flags: [ PF_R ] +- FirstSec: .dynsym +- LastSec: .eh_frame +- Align: 0x10000 +- - Type: PT_LOAD +- Flags: [ PF_X, PF_R ] +- FirstSec: .text +- LastSec: .text +- VAddr: 0x103E4 +- Align: 0x10000 +- - Type: PT_LOAD +- Flags: [ PF_W, PF_R ] +- FirstSec: .dynamic +- LastSec: .dynamic +- VAddr: 0x20410 +- Align: 0x10000 +- - Type: PT_LOAD +- Flags: [ PF_W, PF_R ] +- FirstSec: .data +- LastSec: .bss +- VAddr: 0x304C0 +- Align: 0x10000 +- - Type: PT_DYNAMIC +- Flags: [ PF_W, PF_R ] +- FirstSec: .dynamic +- LastSec: .dynamic +- VAddr: 0x20410 +- Align: 0x8 +- - Type: PT_GNU_RELRO +- Flags: [ PF_R ] +- FirstSec: .dynamic +- LastSec: .dynamic +- VAddr: 0x20410 +- - Type: PT_GNU_EH_FRAME +- Flags: [ PF_R ] +- FirstSec: .eh_frame_hdr +- LastSec: .eh_frame_hdr +- VAddr: 0x37C +- Align: 0x4 +- - Type: PT_GNU_STACK +- Flags: [ PF_W, PF_R ] +- Align: 0x0 +-Sections: +- - Name: .dynsym +- Type: SHT_DYNSYM +- Flags: [ SHF_ALLOC ] +- Address: 0x238 +- Link: .dynstr +- AddressAlign: 0x8 +- - Name: .gnu.hash +- Type: SHT_GNU_HASH +- Flags: [ SHF_ALLOC ] +- Address: 0x2C8 +- Link: .dynsym +- AddressAlign: 0x8 +- Header: +- SymNdx: 0x1 +- Shift2: 0x1A +- BloomFilter: [ 0x400188002180000C ] +- HashBuckets: [ 0x1 ] +- HashValues: [ 0xEE8502A, 0xEE85016, 0xC033991C, 0x61F7372E, 0xB88AB7F ] +- - Name: .hash +- Type: SHT_HASH +- Flags: [ SHF_ALLOC ] +- Address: 0x2F8 +- Link: .dynsym +- AddressAlign: 0x4 +- Bucket: [ 5, 0, 4, 0, 3, 0 ] +- Chain: [ 0, 0, 0, 1, 2, 0 ] +- - Name: .dynstr +- Type: SHT_STRTAB +- Flags: [ SHF_ALLOC ] +- Address: 0x330 +- AddressAlign: 0x1 +- - Name: .rela.dyn +- Type: SHT_RELA +- Flags: [ SHF_ALLOC ] +- Address: 0x358 +- Link: .dynsym +- AddressAlign: 0x8 +- Relocations: +- - Offset: 0x304C8 +- Type: R_AARCH64_RELATIVE +- Addend: 880 +- - Name: .rodata +- Type: SHT_PROGBITS +- Flags: [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ] +- Address: 0x370 +- AddressAlign: 0x1 +- EntSize: 0x1 +- Content: '313233343536373800' +- - Name: .eh_frame_hdr +- Type: SHT_PROGBITS +- Flags: [ SHF_ALLOC ] +- Address: 0x37C +- AddressAlign: 0x4 +- Content: 011B033B18000000020000006800010034000000740001004C000000 +- - Name: .eh_frame +- Type: SHT_PROGBITS +- Flags: [ SHF_ALLOC ] +- Address: 0x398 +- AddressAlign: 0x8 +- Content: 1400000000000000017A5200017C1E011B0C1F0000000000140000001C0000002C0001000C00000000000000000000001400000034000000200001001C000000000000000000000000000000 +- - Name: .text +- Type: SHT_PROGBITS +- Flags: [ SHF_ALLOC, SHF_EXECINSTR ] +- Address: 0x103E4 +- AddressAlign: 0x4 +- Content: 0001009000501391C0035FD60801009008611391E90308AA2A4540B85F0100710001899AC0035FD6 +- - Name: .dynamic +- Type: SHT_DYNAMIC +- Flags: [ SHF_WRITE, SHF_ALLOC ] +- Address: 0x20410 +- Link: .dynstr +- AddressAlign: 0x8 +- Entries: +- - Tag: DT_RELA +- Value: 0x358 +- - Tag: DT_RELASZ +- Value: 0x18 +- - Tag: DT_RELAENT +- Value: 0x18 +- - Tag: DT_RELACOUNT +- Value: 0x1 +- - Tag: DT_SYMTAB +- Value: 0x238 +- - Tag: DT_SYMENT +- Value: 0x18 +- - Tag: DT_STRTAB +- Value: 0x330 +- - Tag: DT_STRSZ +- Value: 0x28 +- - Tag: DT_GNU_HASH +- Value: 0x2C8 +- - Tag: DT_HASH +- Value: 0x2F8 +- - Tag: DT_NULL +- Value: 0x0 +- - Name: .data +- Type: SHT_PROGBITS +- Flags: [ SHF_WRITE, SHF_ALLOC ] +- Address: 0x304C0 +- AddressAlign: 0x8 +- Content: '02000000000000000000000000000000' +- - Name: .bss +- Type: SHT_NOBITS +- Flags: [ SHF_WRITE, SHF_ALLOC ] +- Address: 0x304D0 +- AddressAlign: 0x4 +- Size: 0x10 +- - Name: .debug_abbrev +- Type: SHT_PROGBITS +- AddressAlign: 0x1 +- Content: 011101252513050325721710171B25111B120673170000023400032549133F193A0B3B0B0218000003240003253E0B0B0B0000040F004913000005260049130000062E01111B120640187A196E2503253A0B3B0B49133F190000073400032549133A0B3B0B02180000083400032549133A0B3B0B02186E25000009050003253A0B3B0B4913000000 +- - Name: .debug_info +- Type: SHT_PROGBITS +- AddressAlign: 0x1 +- Content: AB0000000500010800000000010021000108000000000000000205280000000800000002032E000000000102A1000304050402052E000000000202A101020648000000000402A102044D00000005520000000307080106050C000000016F0D0E0007A500000007082E000000000802A1030008092E000000000D02A1040A080B2E000000000C04A10423040C06061C000000016F0F0E000EA50000000910000EAA00000000042E0000000311020100 +- - Name: .debug_str_offsets +- Type: SHT_PROGBITS +- AddressAlign: 0x1 +- Content: 4C00000005000000A2000000000000002C00000059000000280000001C00000072000000640000008C0000008700000069000000140000007B0000009C0000001A0000000E0000008500000076000000 +- - Name: .comment +- Type: SHT_PROGBITS +- Flags: [ SHF_MERGE, SHF_STRINGS ] +- AddressAlign: 0x1 +- EntSize: 0x1 +- Content: 4C696E6B65723A204C4C442031352E302E300000636C616E672076657273696F6E2031352E302E30202868747470733A2F2F6769746875622E636F6D2F6C6C766D2F6C6C766D2D70726F6A6563742E67697420306462616566363162353666306566306162306366333865613932666663316633356265653366662900 +- - Name: .debug_line +- Type: SHT_PROGBITS +- AddressAlign: 0x1 +- Content: 620000000500080037000000010101FB0E0D00010101010000000100000101011F010E00000003011F020F051E0100000000006C97BBE59F7DC6A9EA956633431DA63E0400000902E4030100000000001805030A140500BF05190A0105120608740204000101 +- - Name: .debug_line_str +- Type: SHT_PROGBITS +- Flags: [ SHF_MERGE, SHF_STRINGS ] +- AddressAlign: 0x1 +- EntSize: 0x1 +- Content: 2F746D702F66696C652E637070002F7573722F6C6F63616C2F676F6F676C652F686F6D652F6D69746368702F6C6C766D2D6275696C642F6F707400 +-Symbols: +- - Name: file.cpp +- Type: STT_FILE +- Index: SHN_ABS +- - Name: '$x.0' +- Section: .text +- Value: 0x103E4 +- - Name: _ZZ1fvE15function_global +- Type: STT_OBJECT +- Section: .bss +- Value: 0x304D4 +- Size: 0x4 +- - Name: '$d.1' +- Section: .bss +- Value: 0x304D0 +- - Name: '$d.2' +- Section: .data +- Value: 0x304C0 +- - Name: '$d.3' +- Section: .rodata +- Value: 0x370 +- - Name: '$d.4' +- Section: .debug_abbrev +- - Name: '$d.5' +- Section: .debug_info +- - Name: '$d.6' +- Section: .debug_str_offsets +- - Name: '$d.7' +- Section: .debug_str +- Value: 0xA2 +- - Name: '$d.8' +- Section: .debug_addr +- - Name: _ZL4beta +- Type: STT_OBJECT +- Section: .bss +- Value: 0x304D8 +- Size: 0x4 +- - Name: _ZL5alpha +- Type: STT_OBJECT +- Section: .bss +- Value: 0x304DC +- Size: 0x4 +- - Name: '$d.9' +- Section: .comment +- Value: 0x13 +- - Name: '$d.10' +- Section: .eh_frame +- Value: 0x398 +- - Name: '$d.11' +- Section: .debug_line +- - Name: '$d.12' +- Section: .debug_line_str +- Value: 0xE +- - Name: _DYNAMIC +- Section: .dynamic +- Value: 0x20410 +- Other: [ STV_HIDDEN ] +- - Name: _Z1fv +- Type: STT_FUNC +- Section: .text +- Binding: STB_GLOBAL +- Value: 0x103E4 +- Size: 0xC +- - Name: _Z1fb +- Type: STT_FUNC +- Section: .text +- Binding: STB_GLOBAL +- Value: 0x103F0 +- Size: 0x1C +- - Name: bss_global +- Type: STT_OBJECT +- Section: .bss +- Binding: STB_GLOBAL +- Value: 0x304D0 +- Size: 0x4 +- - Name: data_global +- Type: STT_OBJECT +- Section: .data +- Binding: STB_GLOBAL +- Value: 0x304C0 +- Size: 0x4 +- - Name: str +- Type: STT_OBJECT +- Section: .data +- Binding: STB_GLOBAL +- Value: 0x304C8 +- Size: 0x8 +-DynamicSymbols: +- - Name: _Z1fv +- Type: STT_FUNC +- Section: .text +- Binding: STB_GLOBAL +- Value: 0x103E4 +- Size: 0xC +- - Name: _Z1fb +- Type: STT_FUNC +- Section: .text +- Binding: STB_GLOBAL +- Value: 0x103F0 +- Size: 0x1C +- - Name: bss_global +- Type: STT_OBJECT +- Section: .bss +- Binding: STB_GLOBAL +- Value: 0x304D0 +- Size: 0x4 +- - Name: data_global +- Type: STT_OBJECT +- Section: .data +- Binding: STB_GLOBAL +- Value: 0x304C0 +- Size: 0x4 +- - Name: str +- Type: STT_OBJECT +- Section: .data +- Binding: STB_GLOBAL +- Value: 0x304C8 +- Size: 0x8 +-DWARF: +- debug_str: +- - '/tmp/file.cpp' +- - _Z1fb +- - alpha +- - f +- - data_global +- - int +- - '/usr/local/google/home/mitchp/llvm-build/opt' +- - bss_global +- - char +- - _ZL4beta +- - str +- - bool +- - _ZL5alpha +- - b +- - beta +- - function_global +- - _Z1fv +- - 'clang version 15.0.0 (https://github.com/llvm/llvm-project.git 0dbaef61b56f0ef0ab0cf38ea92ffc1f35bee3ff)' +- debug_addr: +- - Length: 0x3C +- Version: 0x5 +- AddressSize: 0x8 +- Entries: +- - Address: 0x304D0 +- - Address: 0x304C0 +- - Address: 0x304C8 +- - Address: 0x304D4 +- - Address: 0x304D8 +- - Address: 0x103E4 +- - Address: 0x103F0 +-... +diff --git a/llvm/test/tools/llvm-symbolizer/data.s b/llvm/test/tools/llvm-symbolizer/data.s +index cc9503c59141..e8039f146dbd 100644 +--- a/llvm/test/tools/llvm-symbolizer/data.s ++++ b/llvm/test/tools/llvm-symbolizer/data.s +@@ -7,12 +7,9 @@ + + # CHECK: d1 + # CHECK-NEXT: 0 8 +-# CHECK-NEXT: ??:? + # CHECK-EMPTY: + # CHECK-NEXT: d2 + # CHECK-NEXT: 8 4 +-# CHECK-NEXT: ??:? +-# CHECK-EMPTY: + + d1: + .quad 0x1122334455667788 +-- +2.38.1.1.g6d9df9d320 + diff --git a/build/build-clang/revert-llvmorg-15-init-13446-g7524fe962e47.patch b/build/build-clang/revert-llvmorg-15-init-13446-g7524fe962e47.patch new file mode 100644 index 0000000000..5bd4601827 --- /dev/null +++ b/build/build-clang/revert-llvmorg-15-init-13446-g7524fe962e47.patch @@ -0,0 +1,39 @@ +From 12f64ca10837bd68ec30804ebfa21653925ad5cf Mon Sep 17 00:00:00 2001 +From: Mike Hommey +Date: Thu, 16 Jun 2022 12:51:29 +0900 +Subject: [PATCH] Revert "[libFuzzer] Use the compiler to link the relocatable + object" + +This reverts commit 7524fe962e479416fd6318407eff4eed5b96a40b. +--- + compiler-rt/lib/fuzzer/CMakeLists.txt | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/compiler-rt/lib/fuzzer/CMakeLists.txt b/compiler-rt/lib/fuzzer/CMakeLists.txt +index 856cd732d517..d51de53f5acc 100644 +--- a/compiler-rt/lib/fuzzer/CMakeLists.txt ++++ b/compiler-rt/lib/fuzzer/CMakeLists.txt +@@ -138,15 +138,15 @@ if(OS_NAME MATCHES "Linux|Fuchsia" AND + COMPILER_RT_LIBCXX_PATH AND + COMPILER_RT_LIBCXXABI_PATH) + macro(partially_link_libcxx name dir arch) +- get_target_flags_for_arch(${arch} target_cflags) +- if(CMAKE_CXX_COMPILER_ID MATCHES Clang) +- get_compiler_rt_target(${arch} target) +- set(target_cflags --target=${target} ${target_cflags}) ++ if(${arch} MATCHES "i386") ++ set(EMULATION_ARGUMENT "-m" "elf_i386") ++ else() ++ set(EMULATION_ARGUMENT "") + endif() + set(cxx_${arch}_merge_dir "${CMAKE_CURRENT_BINARY_DIR}/cxx_${arch}_merge.dir") + file(MAKE_DIRECTORY ${cxx_${arch}_merge_dir}) + add_custom_command(TARGET clang_rt.${name}-${arch} POST_BUILD +- COMMAND ${CMAKE_CXX_COMPILER} ${target_cflags} -Wl,--whole-archive "$" -Wl,--no-whole-archive ${dir}/lib/libc++.a -r -o ${name}.o ++ COMMAND ${CMAKE_LINKER} ${EMULATION_ARGUMENT} --whole-archive "$" --no-whole-archive ${dir}/lib/libc++.a -r -o ${name}.o + COMMAND ${CMAKE_OBJCOPY} --localize-hidden ${name}.o + COMMAND ${CMAKE_COMMAND} -E remove "$" + COMMAND ${CMAKE_AR} qcs "$" ${name}.o +-- +2.36.0.1.g2bbe56bd8d + diff --git a/build/build-clang/revert-llvmorg-16-init-11301-g163bb6d64e5f_clang_17.patch b/build/build-clang/revert-llvmorg-16-init-11301-g163bb6d64e5f_clang_17.patch new file mode 100644 index 0000000000..4e217dcf3d --- /dev/null +++ b/build/build-clang/revert-llvmorg-16-init-11301-g163bb6d64e5f_clang_17.patch @@ -0,0 +1,172 @@ +From cf00b30288c4c81b2c6a5af01c38f236148777a0 Mon Sep 17 00:00:00 2001 +From: Mike Hommey +Date: Tue, 28 Mar 2023 06:13:36 +0900 +Subject: [PATCH] Revert "[Passes][VectorCombine] enable early run generally + and try load folds" + +This reverts commit 163bb6d64e5f1220777c3ec2a8b58c0666a74d91. +It causes various reftest regressions. +--- + llvm/lib/Passes/PassBuilderPipelines.cpp | 7 ++++--- + llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 8 ++------ + llvm/test/Other/new-pm-defaults.ll | 2 +- + .../Other/new-pm-thinlto-postlink-defaults.ll | 1 - + .../Other/new-pm-thinlto-postlink-pgo-defaults.ll | 1 - + .../new-pm-thinlto-postlink-samplepgo-defaults.ll | 1 - + .../Other/new-pm-thinlto-prelink-pgo-defaults.ll | 1 - + .../new-pm-thinlto-prelink-samplepgo-defaults.ll | 1 - + .../PhaseOrdering/X86/vec-load-combine.ll | 15 +++++++++++---- + 9 files changed, 18 insertions(+), 19 deletions(-) + +diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp +index eed29c25714b..b925448cd6c0 100644 +--- a/llvm/lib/Passes/PassBuilderPipelines.cpp ++++ b/llvm/lib/Passes/PassBuilderPipelines.cpp +@@ -611,9 +611,10 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level, + // Delete small array after loop unroll. + FPM.addPass(SROAPass(SROAOptions::ModifyCFG)); + +- // Try vectorization/scalarization transforms that are both improvements +- // themselves and can allow further folds with GVN and InstCombine. +- FPM.addPass(VectorCombinePass(/*TryEarlyFoldsOnly=*/true)); ++ // The matrix extension can introduce large vector operations early, which can ++ // benefit from running vector-combine early on. ++ if (EnableMatrix) ++ FPM.addPass(VectorCombinePass(/*TryEarlyFoldsOnly=*/true)); + + // Eliminate redundancies. + FPM.addPass(MergedLoadStoreMotionPass()); +diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp +index 2e489757ebc1..810a9f92bb7a 100644 +--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp ++++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp +@@ -1720,12 +1720,6 @@ bool VectorCombine::run() { + // dispatching to folding functions if there's no chance of matching. + if (IsFixedVectorType) { + switch (Opcode) { +- case Instruction::InsertElement: +- MadeChange |= vectorizeLoadInsert(I); +- break; +- case Instruction::ShuffleVector: +- MadeChange |= widenSubvectorLoad(I); +- break; + case Instruction::Load: + MadeChange |= scalarizeLoadExtract(I); + break; +@@ -1754,9 +1748,11 @@ bool VectorCombine::run() { + if (IsFixedVectorType) { + switch (Opcode) { + case Instruction::InsertElement: ++ MadeChange |= vectorizeLoadInsert(I); + MadeChange |= foldInsExtFNeg(I); + break; + case Instruction::ShuffleVector: ++ MadeChange |= widenSubvectorLoad(I); + MadeChange |= foldShuffleOfBinops(I); + MadeChange |= foldSelectShuffle(I); + break; +diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll +index 13612c3bb459..5f84d28af4a6 100644 +--- a/llvm/test/Other/new-pm-defaults.ll ++++ b/llvm/test/Other/new-pm-defaults.ll +@@ -186,7 +186,7 @@ + ; CHECK-O-NEXT: Running pass: LoopFullUnrollPass + ; CHECK-EP-LOOP-END-NEXT: Running pass: NoOpLoopPass + ; CHECK-O-NEXT: Running pass: SROAPass on foo +-; CHECK-O23SZ-NEXT: Running pass: VectorCombinePass ++; CHECK-MATRIX: Running pass: VectorCombinePass + ; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass + ; CHECK-O23SZ-NEXT: Running pass: GVNPass + ; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis +diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll +index 3f5d2d5b153d..ea07128c9f6a 100644 +--- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll ++++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll +@@ -159,7 +159,6 @@ + ; CHECK-O-NEXT: Running pass: LoopDeletionPass + ; CHECK-O-NEXT: Running pass: LoopFullUnrollPass + ; CHECK-O-NEXT: Running pass: SROAPass on foo +-; CHECK-O23SZ-NEXT: Running pass: VectorCombinePass + ; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass + ; CHECK-O23SZ-NEXT: Running pass: GVNPass + ; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis +diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll +index 29021ceace54..43e943cb6011 100644 +--- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll ++++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll +@@ -121,7 +121,6 @@ + ; CHECK-O-NEXT: Running pass: LoopDeletionPass + ; CHECK-O-NEXT: Running pass: LoopFullUnrollPass + ; CHECK-O-NEXT: Running pass: SROAPass on foo +-; CHECK-O23SZ-NEXT: Running pass: VectorCombinePass + ; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass + ; CHECK-O23SZ-NEXT: Running pass: GVNPass + ; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis +diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll +index daf3141a1f2c..78914d1c23b2 100644 +--- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll ++++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll +@@ -130,7 +130,6 @@ + ; CHECK-O-NEXT: Running pass: LoopDeletionPass + ; CHECK-O-NEXT: Running pass: LoopFullUnrollPass + ; CHECK-O-NEXT: Running pass: SROAPass on foo +-; CHECK-O23SZ-NEXT: Running pass: VectorCombinePass + ; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass + ; CHECK-O23SZ-NEXT: Running pass: GVNPass + ; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis +diff --git a/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll +index bfe80902f806..5b62ba39add3 100644 +--- a/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll ++++ b/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll +@@ -160,7 +160,6 @@ + ; CHECK-O-NEXT: Running pass: LoopDeletionPass + ; CHECK-O-NEXT: Running pass: LoopFullUnrollPass + ; CHECK-O-NEXT: Running pass: SROAPass on foo +-; CHECK-O23SZ-NEXT: Running pass: VectorCombinePass + ; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass + ; CHECK-O23SZ-NEXT: Running pass: GVNPass + ; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis +diff --git a/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll +index c7daf7aa46b1..17475423d696 100644 +--- a/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll ++++ b/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll +@@ -124,7 +124,6 @@ + ; CHECK-O-NEXT: Running pass: IndVarSimplifyPass + ; CHECK-O-NEXT: Running pass: LoopDeletionPass + ; CHECK-O-NEXT: Running pass: SROAPass on foo +-; CHECK-O23SZ-NEXT: Running pass: VectorCombinePass + ; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass + ; CHECK-O23SZ-NEXT: Running pass: GVNPass + ; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis +diff --git a/llvm/test/Transforms/PhaseOrdering/X86/vec-load-combine.ll b/llvm/test/Transforms/PhaseOrdering/X86/vec-load-combine.ll +index 77cbc70ff369..dd7164febea4 100644 +--- a/llvm/test/Transforms/PhaseOrdering/X86/vec-load-combine.ll ++++ b/llvm/test/Transforms/PhaseOrdering/X86/vec-load-combine.ll +@@ -12,13 +12,20 @@ $getAt = comdat any + define dso_local noundef <4 x float> @ConvertVectors_ByRef(ptr noundef nonnull align 16 dereferenceable(16) %0) #0 { + ; SSE-LABEL: @ConvertVectors_ByRef( + ; SSE-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[TMP0:%.*]], align 16 +-; SSE-NEXT: [[TMP3:%.*]] = shufflevector <4 x float> [[TMP2]], <4 x float> poison, <4 x i32> +-; SSE-NEXT: ret <4 x float> [[TMP3]] ++; SSE-NEXT: [[TMP3:%.*]] = getelementptr inbounds [4 x float], ptr [[TMP0]], i64 0, i64 1 ++; SSE-NEXT: [[TMP4:%.*]] = load <2 x float>, ptr [[TMP3]], align 4 ++; SSE-NEXT: [[TMP5:%.*]] = shufflevector <2 x float> [[TMP4]], <2 x float> poison, <4 x i32> ++; SSE-NEXT: [[TMP6:%.*]] = shufflevector <4 x float> [[TMP2]], <4 x float> [[TMP5]], <4 x i32> ++; SSE-NEXT: [[TMP7:%.*]] = shufflevector <4 x float> [[TMP6]], <4 x float> [[TMP5]], <4 x i32> ++; SSE-NEXT: ret <4 x float> [[TMP7]] + ; + ; AVX-LABEL: @ConvertVectors_ByRef( + ; AVX-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[TMP0:%.*]], align 16 +-; AVX-NEXT: [[TMP3:%.*]] = shufflevector <4 x float> [[TMP2]], <4 x float> poison, <4 x i32> +-; AVX-NEXT: ret <4 x float> [[TMP3]] ++; AVX-NEXT: [[TMP3:%.*]] = getelementptr inbounds [4 x float], ptr [[TMP0]], i64 0, i64 2 ++; AVX-NEXT: [[TMP4:%.*]] = load float, ptr [[TMP3]], align 8 ++; AVX-NEXT: [[TMP5:%.*]] = insertelement <4 x float> [[TMP2]], float [[TMP4]], i64 2 ++; AVX-NEXT: [[TMP6:%.*]] = insertelement <4 x float> [[TMP5]], float [[TMP4]], i64 3 ++; AVX-NEXT: ret <4 x float> [[TMP6]] + ; + %2 = alloca ptr, align 8 + %3 = alloca <4 x float>, align 16 +-- +2.39.0.1.g6739ec1790 + diff --git a/build/build-clang/revert-llvmorg-16-init-11301-g163bb6d64e5f_clang_18.patch b/build/build-clang/revert-llvmorg-16-init-11301-g163bb6d64e5f_clang_18.patch new file mode 100644 index 0000000000..6449fe14bc --- /dev/null +++ b/build/build-clang/revert-llvmorg-16-init-11301-g163bb6d64e5f_clang_18.patch @@ -0,0 +1,183 @@ +From cf00b30288c4c81b2c6a5af01c38f236148777a0 Mon Sep 17 00:00:00 2001 +From: Mike Hommey +Date: Tue, 28 Mar 2023 06:13:36 +0900 +Subject: [PATCH] Revert "[Passes][VectorCombine] enable early run generally + and try load folds" + +This reverts commit 163bb6d64e5f1220777c3ec2a8b58c0666a74d91. +It causes various reftest regressions. +--- + llvm/lib/Passes/PassBuilderPipelines.cpp | 7 ++++--- + llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 8 ++------ + llvm/test/Other/new-pm-defaults.ll | 2 +- + .../Other/new-pm-thinlto-postlink-defaults.ll | 1 - + .../Other/new-pm-thinlto-postlink-pgo-defaults.ll | 1 - + .../new-pm-thinlto-postlink-samplepgo-defaults.ll | 1 - + .../Other/new-pm-thinlto-prelink-pgo-defaults.ll | 1 - + .../new-pm-thinlto-prelink-samplepgo-defaults.ll | 1 - + .../PhaseOrdering/X86/vec-load-combine.ll | 15 +++++++++++---- + 9 files changed, 18 insertions(+), 19 deletions(-) + +diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp +index eed29c25714b..b925448cd6c0 100644 +--- a/llvm/lib/Passes/PassBuilderPipelines.cpp ++++ b/llvm/lib/Passes/PassBuilderPipelines.cpp +@@ -611,9 +611,10 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level, + // Delete small array after loop unroll. + FPM.addPass(SROAPass(SROAOptions::ModifyCFG)); + +- // Try vectorization/scalarization transforms that are both improvements +- // themselves and can allow further folds with GVN and InstCombine. +- FPM.addPass(VectorCombinePass(/*TryEarlyFoldsOnly=*/true)); ++ // The matrix extension can introduce large vector operations early, which can ++ // benefit from running vector-combine early on. ++ if (EnableMatrix) ++ FPM.addPass(VectorCombinePass(/*TryEarlyFoldsOnly=*/true)); + + // Eliminate redundancies. + FPM.addPass(MergedLoadStoreMotionPass()); +diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp +index 2e489757ebc1..810a9f92bb7a 100644 +--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp ++++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp +@@ -1715,23 +1715,6 @@ bool VectorCombine::run() { + bool IsFixedVectorType = isa(I.getType()); + auto Opcode = I.getOpcode(); + +- // These folds should be beneficial regardless of when this pass is run +- // in the optimization pipeline. +- // The type checking is for run-time efficiency. We can avoid wasting time +- // dispatching to folding functions if there's no chance of matching. +- if (IsFixedVectorType) { +- switch (Opcode) { +- case Instruction::InsertElement: +- MadeChange |= vectorizeLoadInsert(I); +- break; +- case Instruction::ShuffleVector: +- MadeChange |= widenSubvectorLoad(I); +- break; +- default: +- break; +- } +- } +- + // This transform works with scalable and fixed vectors + // TODO: Identify and allow other scalable transforms + if (isa(I.getType())) { +@@ -1753,9 +1736,11 @@ bool VectorCombine::run() { + if (IsFixedVectorType) { + switch (Opcode) { + case Instruction::InsertElement: ++ MadeChange |= vectorizeLoadInsert(I); + MadeChange |= foldInsExtFNeg(I); + break; + case Instruction::ShuffleVector: ++ MadeChange |= widenSubvectorLoad(I); + MadeChange |= foldShuffleOfBinops(I); + MadeChange |= foldSelectShuffle(I); + break; +diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll +index 13612c3bb459..5f84d28af4a6 100644 +--- a/llvm/test/Other/new-pm-defaults.ll ++++ b/llvm/test/Other/new-pm-defaults.ll +@@ -186,7 +186,7 @@ + ; CHECK-O-NEXT: Running pass: LoopFullUnrollPass + ; CHECK-EP-LOOP-END-NEXT: Running pass: NoOpLoopPass + ; CHECK-O-NEXT: Running pass: SROAPass on foo +-; CHECK-O23SZ-NEXT: Running pass: VectorCombinePass ++; CHECK-MATRIX: Running pass: VectorCombinePass + ; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass + ; CHECK-O23SZ-NEXT: Running pass: GVNPass + ; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis +diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll +index 3f5d2d5b153d..ea07128c9f6a 100644 +--- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll ++++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll +@@ -159,7 +159,6 @@ + ; CHECK-O-NEXT: Running pass: LoopDeletionPass + ; CHECK-O-NEXT: Running pass: LoopFullUnrollPass + ; CHECK-O-NEXT: Running pass: SROAPass on foo +-; CHECK-O23SZ-NEXT: Running pass: VectorCombinePass + ; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass + ; CHECK-O23SZ-NEXT: Running pass: GVNPass + ; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis +diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll +index 29021ceace54..43e943cb6011 100644 +--- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll ++++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll +@@ -121,7 +121,6 @@ + ; CHECK-O-NEXT: Running pass: LoopDeletionPass + ; CHECK-O-NEXT: Running pass: LoopFullUnrollPass + ; CHECK-O-NEXT: Running pass: SROAPass on foo +-; CHECK-O23SZ-NEXT: Running pass: VectorCombinePass + ; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass + ; CHECK-O23SZ-NEXT: Running pass: GVNPass + ; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis +diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll +index daf3141a1f2c..78914d1c23b2 100644 +--- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll ++++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll +@@ -130,7 +130,6 @@ + ; CHECK-O-NEXT: Running pass: LoopDeletionPass + ; CHECK-O-NEXT: Running pass: LoopFullUnrollPass + ; CHECK-O-NEXT: Running pass: SROAPass on foo +-; CHECK-O23SZ-NEXT: Running pass: VectorCombinePass + ; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass + ; CHECK-O23SZ-NEXT: Running pass: GVNPass + ; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis +diff --git a/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll +index bfe80902f806..5b62ba39add3 100644 +--- a/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll ++++ b/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll +@@ -160,7 +160,6 @@ + ; CHECK-O-NEXT: Running pass: LoopDeletionPass + ; CHECK-O-NEXT: Running pass: LoopFullUnrollPass + ; CHECK-O-NEXT: Running pass: SROAPass on foo +-; CHECK-O23SZ-NEXT: Running pass: VectorCombinePass + ; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass + ; CHECK-O23SZ-NEXT: Running pass: GVNPass + ; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis +diff --git a/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll +index c7daf7aa46b1..17475423d696 100644 +--- a/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll ++++ b/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll +@@ -124,7 +124,6 @@ + ; CHECK-O-NEXT: Running pass: IndVarSimplifyPass + ; CHECK-O-NEXT: Running pass: LoopDeletionPass + ; CHECK-O-NEXT: Running pass: SROAPass on foo +-; CHECK-O23SZ-NEXT: Running pass: VectorCombinePass + ; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass + ; CHECK-O23SZ-NEXT: Running pass: GVNPass + ; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis +diff --git a/llvm/test/Transforms/PhaseOrdering/X86/vec-load-combine.ll b/llvm/test/Transforms/PhaseOrdering/X86/vec-load-combine.ll +index 77cbc70ff369..dd7164febea4 100644 +--- a/llvm/test/Transforms/PhaseOrdering/X86/vec-load-combine.ll ++++ b/llvm/test/Transforms/PhaseOrdering/X86/vec-load-combine.ll +@@ -12,13 +12,20 @@ $getAt = comdat any + define dso_local noundef <4 x float> @ConvertVectors_ByRef(ptr noundef nonnull align 16 dereferenceable(16) %0) #0 { + ; SSE-LABEL: @ConvertVectors_ByRef( + ; SSE-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[TMP0:%.*]], align 16 +-; SSE-NEXT: [[TMP3:%.*]] = shufflevector <4 x float> [[TMP2]], <4 x float> poison, <4 x i32> +-; SSE-NEXT: ret <4 x float> [[TMP3]] ++; SSE-NEXT: [[TMP3:%.*]] = getelementptr inbounds [4 x float], ptr [[TMP0]], i64 0, i64 1 ++; SSE-NEXT: [[TMP4:%.*]] = load <2 x float>, ptr [[TMP3]], align 4 ++; SSE-NEXT: [[TMP5:%.*]] = shufflevector <2 x float> [[TMP4]], <2 x float> poison, <4 x i32> ++; SSE-NEXT: [[TMP6:%.*]] = shufflevector <4 x float> [[TMP2]], <4 x float> [[TMP5]], <4 x i32> ++; SSE-NEXT: [[TMP7:%.*]] = shufflevector <4 x float> [[TMP6]], <4 x float> [[TMP5]], <4 x i32> ++; SSE-NEXT: ret <4 x float> [[TMP7]] + ; + ; AVX-LABEL: @ConvertVectors_ByRef( + ; AVX-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[TMP0:%.*]], align 16 +-; AVX-NEXT: [[TMP3:%.*]] = shufflevector <4 x float> [[TMP2]], <4 x float> poison, <4 x i32> +-; AVX-NEXT: ret <4 x float> [[TMP3]] ++; AVX-NEXT: [[TMP3:%.*]] = getelementptr inbounds [4 x float], ptr [[TMP0]], i64 0, i64 2 ++; AVX-NEXT: [[TMP4:%.*]] = load float, ptr [[TMP3]], align 8 ++; AVX-NEXT: [[TMP5:%.*]] = insertelement <4 x float> [[TMP2]], float [[TMP4]], i64 2 ++; AVX-NEXT: [[TMP6:%.*]] = insertelement <4 x float> [[TMP5]], float [[TMP4]], i64 3 ++; AVX-NEXT: ret <4 x float> [[TMP6]] + ; + %2 = alloca ptr, align 8 + %3 = alloca <4 x float>, align 16 +-- +2.39.0.1.g6739ec1790 + diff --git a/build/build-clang/revert-llvmorg-17-init-4120-g02e8eb1a438b.patch b/build/build-clang/revert-llvmorg-17-init-4120-g02e8eb1a438b.patch new file mode 100644 index 0000000000..63e59ee68b --- /dev/null +++ b/build/build-clang/revert-llvmorg-17-init-4120-g02e8eb1a438b.patch @@ -0,0 +1,118 @@ +From 2836e92ea557be53fcd91e38cb05a989ad0167e9 Mon Sep 17 00:00:00 2001 +From: Mike Hommey +Date: Wed, 8 Mar 2023 14:44:58 +0900 +Subject: [PATCH] Revert "Split getCompileUnitFor{Data,Code}Address." + +This reverts commit 02e8eb1a438bdb1dc9a97aea75a8c9c748048039, which +applies on top of cead4eceb01b935fae07bf4a7e91911b344d2fec, that we +revert too. +--- + .../llvm/DebugInfo/DWARF/DWARFContext.h | 11 +-------- + llvm/lib/DebugInfo/DWARF/DWARFContext.cpp | 23 ++++++++----------- + 2 files changed, 11 insertions(+), 23 deletions(-) + +diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +index 4eba79a7215f..df903b967ef6 100644 +--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h ++++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +@@ -445,16 +445,7 @@ public: + /// address. + /// TODO: change input parameter from "uint64_t Address" + /// into "SectionedAddress Address" +- DWARFCompileUnit *getCompileUnitForCodeAddress(uint64_t Address); +- +- /// Return the compile unit which contains data with the provided address. +- /// Note: This is more expensive than `getCompileUnitForAddress`, as if +- /// `Address` isn't found in the CU ranges (which is cheap), then it falls +- /// back to an expensive O(n) walk of all CU's looking for data that spans the +- /// address. +- /// TODO: change input parameter from "uint64_t Address" into +- /// "SectionedAddress Address" +- DWARFCompileUnit *getCompileUnitForDataAddress(uint64_t Address); ++ DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address); + + /// Returns whether CU/TU should be populated manually. TU Index populated + /// manually only for DWARF5. +diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +index f648ef8ff770..dd86144d16e0 100644 +--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp ++++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +@@ -1118,17 +1118,14 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint64_t Offset) { + NormalUnits.getUnitForOffset(Offset)); + } + +-DWARFCompileUnit *DWARFContext::getCompileUnitForCodeAddress(uint64_t Address) { +- uint64_t CUOffset = getDebugAranges()->findAddress(Address); +- return getCompileUnitForOffset(CUOffset); +-} +- +-DWARFCompileUnit *DWARFContext::getCompileUnitForDataAddress(uint64_t Address) { ++DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) { ++ // First, get the offset of the compile unit. + uint64_t CUOffset = getDebugAranges()->findAddress(Address); ++ // Retrieve the compile unit. + if (DWARFCompileUnit *OffsetCU = getCompileUnitForOffset(CUOffset)) + return OffsetCU; + +- // Global variables are often missed by the above search, for one of two ++ // Global variables are often not found by the above search, for one of two + // reasons: + // 1. .debug_aranges may not include global variables. On clang, it seems we + // put the globals in the aranges, but this isn't true for gcc. +@@ -1149,7 +1146,7 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForDataAddress(uint64_t Address) { + DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) { + DIEsForAddress Result; + +- DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address); ++ DWARFCompileUnit *CU = getCompileUnitForAddress(Address); + if (!CU) + return Result; + +@@ -1300,7 +1297,7 @@ void DWARFContext::addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, + std::vector + DWARFContext::getLocalsForAddress(object::SectionedAddress Address) { + std::vector Result; +- DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address.Address); ++ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Result; + +@@ -1313,7 +1310,7 @@ DWARFContext::getLocalsForAddress(object::SectionedAddress Address) { + DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address, + DILineInfoSpecifier Spec) { + DILineInfo Result; +- DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address.Address); ++ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Result; + +@@ -1334,7 +1331,7 @@ DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address, + DILineInfo + DWARFContext::getLineInfoForDataAddress(object::SectionedAddress Address) { + DILineInfo Result; +- DWARFCompileUnit *CU = getCompileUnitForDataAddress(Address.Address); ++ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Result; + +@@ -1349,7 +1346,7 @@ DWARFContext::getLineInfoForDataAddress(object::SectionedAddress Address) { + DILineInfoTable DWARFContext::getLineInfoForAddressRange( + object::SectionedAddress Address, uint64_t Size, DILineInfoSpecifier Spec) { + DILineInfoTable Lines; +- DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address.Address); ++ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Lines; + +@@ -1405,7 +1402,7 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address, + DILineInfoSpecifier Spec) { + DIInliningInfo InliningInfo; + +- DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address.Address); ++ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return InliningInfo; + +-- +2.39.0.1.g6739ec1790 + diff --git a/build/build-clang/revert-llvmorg-17-init-4120-g02e8eb1a438b_clang_18.patch b/build/build-clang/revert-llvmorg-17-init-4120-g02e8eb1a438b_clang_18.patch new file mode 100644 index 0000000000..098c410790 --- /dev/null +++ b/build/build-clang/revert-llvmorg-17-init-4120-g02e8eb1a438b_clang_18.patch @@ -0,0 +1,115 @@ +From 2836e92ea557be53fcd91e38cb05a989ad0167e9 Mon Sep 17 00:00:00 2001 +From: Mike Hommey +Date: Wed, 8 Mar 2023 14:44:58 +0900 +Subject: [PATCH] Revert "Split getCompileUnitFor{Data,Code}Address." + +This reverts commit 02e8eb1a438bdb1dc9a97aea75a8c9c748048039, which +applies on top of cead4eceb01b935fae07bf4a7e91911b344d2fec, that we +revert too. +--- + .../llvm/DebugInfo/DWARF/DWARFContext.h | 11 +-------- + llvm/lib/DebugInfo/DWARF/DWARFContext.cpp | 23 ++++++++----------- + 2 files changed, 11 insertions(+), 23 deletions(-) + +diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +index 4bd8394e6b4e..3f49fadc2b98 100644 +--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h ++++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +@@ -459,16 +459,7 @@ public: + /// address. + /// TODO: change input parameter from "uint64_t Address" + /// into "SectionedAddress Address" +- DWARFCompileUnit *getCompileUnitForCodeAddress(uint64_t Address); +- +- /// Return the compile unit which contains data with the provided address. +- /// Note: This is more expensive than `getCompileUnitForAddress`, as if +- /// `Address` isn't found in the CU ranges (which is cheap), then it falls +- /// back to an expensive O(n) walk of all CU's looking for data that spans the +- /// address. +- /// TODO: change input parameter from "uint64_t Address" into +- /// "SectionedAddress Address" +- DWARFCompileUnit *getCompileUnitForDataAddress(uint64_t Address); ++ DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address); + + /// Returns whether CU/TU should be populated manually. TU Index populated + /// manually only for DWARF5. +diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +index a45ed0e56553..692304ac6774 100644 +--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp ++++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +@@ -1492,17 +1492,14 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint64_t Offset) { + State->getNormalUnits().getUnitForOffset(Offset)); + } + +-DWARFCompileUnit *DWARFContext::getCompileUnitForCodeAddress(uint64_t Address) { +- uint64_t CUOffset = getDebugAranges()->findAddress(Address); +- return getCompileUnitForOffset(CUOffset); +-} +- +-DWARFCompileUnit *DWARFContext::getCompileUnitForDataAddress(uint64_t Address) { ++DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) { ++ // First, get the offset of the compile unit. + uint64_t CUOffset = getDebugAranges()->findAddress(Address); ++ // Retrieve the compile unit. + if (DWARFCompileUnit *OffsetCU = getCompileUnitForOffset(CUOffset)) + return OffsetCU; + +- // Global variables are often missed by the above search, for one of two ++ // Global variables are often not found by the above search, for one of two + // reasons: + // 1. .debug_aranges may not include global variables. On clang, it seems we + // put the globals in the aranges, but this isn't true for gcc. +@@ -1523,7 +1520,7 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForDataAddress(uint64_t Address) { + bool CheckDWO) { + DIEsForAddress Result; + +- DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address); ++ DWARFCompileUnit *CU = getCompileUnitForAddress(Address); + if (!CU) + return Result; + +@@ -1674,7 +1671,7 @@ void DWARFContext::addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, + std::vector + DWARFContext::getLocalsForAddress(object::SectionedAddress Address) { + std::vector Result; +- DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address.Address); ++ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Result; + +@@ -1687,7 +1684,7 @@ DWARFContext::getLocalsForAddress(object::SectionedAddress Address) { + DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address, + DILineInfoSpecifier Spec) { + DILineInfo Result; +- DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address.Address); ++ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Result; + +@@ -1708,7 +1705,7 @@ DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address, + DILineInfo + DWARFContext::getLineInfoForDataAddress(object::SectionedAddress Address) { + DILineInfo Result; +- DWARFCompileUnit *CU = getCompileUnitForDataAddress(Address.Address); ++ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Result; + +@@ -1723,7 +1720,7 @@ DWARFContext::getLineInfoForDataAddress(object::SectionedAddress Address) { + DILineInfoTable DWARFContext::getLineInfoForAddressRange( + object::SectionedAddress Address, uint64_t Size, DILineInfoSpecifier Spec) { + DILineInfoTable Lines; +- DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address.Address); ++ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Lines; + +@@ -1779,7 +1776,7 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address, + DILineInfoSpecifier Spec) { + DIInliningInfo InliningInfo; + +- DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address.Address); ++ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return InliningInfo; + diff --git a/build/build-clang/revert-llvmorg-18-init-6188-gc649f29c24c9.patch b/build/build-clang/revert-llvmorg-18-init-6188-gc649f29c24c9.patch new file mode 100644 index 0000000000..290c65f4b5 --- /dev/null +++ b/build/build-clang/revert-llvmorg-18-init-6188-gc649f29c24c9.patch @@ -0,0 +1,466 @@ +From c3994286d37f4273d6d7a4cb578828d64a25a341 Mon Sep 17 00:00:00 2001 +From: Mike Hommey +Date: Wed, 20 Sep 2023 10:08:22 +0900 +Subject: [PATCH 3/3] Revert "[llvm-nm] Add --line-numbers flag" + +This reverts commit c649f29c24c9fc1502d8d53e0c96c3d24b31de1a because it +depends on cead4eceb01b935fae07bf4a7e91911b344d2fec, which we revert. +--- + llvm/docs/CommandGuide/llvm-nm.rst | 6 - + llvm/test/tools/llvm-nm/X86/line-numbers.test | 240 ------------------ + llvm/tools/llvm-nm/CMakeLists.txt | 1 - + llvm/tools/llvm-nm/Opts.td | 2 - + llvm/tools/llvm-nm/llvm-nm.cpp | 92 +------ + 6 files changed, 5 insertions(+), 339 deletions(-) + delete mode 100644 llvm/test/tools/llvm-nm/X86/line-numbers.test + +diff --git a/llvm/docs/CommandGuide/llvm-nm.rst b/llvm/docs/CommandGuide/llvm-nm.rst +index 7067bb0a29a1..4b1290a15665 100644 +--- a/llvm/docs/CommandGuide/llvm-nm.rst ++++ b/llvm/docs/CommandGuide/llvm-nm.rst +@@ -190,12 +190,6 @@ OPTIONS + + Print just the symbol names. Alias for `--format=just-symbols``. + +-.. option:: --line-numbers, -l +- +- Use debugging information to print the filenames and line numbers where +- symbols are defined. Undefined symbols have the location of their first +- relocation printed instead. +- + .. option:: -m + + Use Darwin format. Alias for ``--format=darwin``. +diff --git a/llvm/test/tools/llvm-nm/X86/line-numbers.test b/llvm/test/tools/llvm-nm/X86/line-numbers.test +deleted file mode 100644 +index 4b9817ab5c62..000000000000 +--- a/llvm/test/tools/llvm-nm/X86/line-numbers.test ++++ /dev/null +@@ -1,240 +0,0 @@ +-## Check that printing line numbers isn't attempted for files like bitcode, +-## which have symbols but limited/no section or debug info. +-# RUN: llvm-nm --line-numbers %p/Inputs/test.IRobj-x86_64 | FileCheck %s --check-prefix=BITCODE --match-full-lines --implicit-check-not={{.}} +-# BITCODE: ---------------- S _global_const +-# BITCODE-NEXT: ---------------- D _global_data +-# BITCODE-NEXT: ---------------- T _global_func +-# BITCODE-NEXT: ---------------- S _hidden_const +-# BITCODE-NEXT: ---------------- D _hidden_data +-# BITCODE-NEXT: ---------------- T _hidden_func +-# BITCODE-NEXT: ---------------- s _static_const +-# BITCODE-NEXT: ---------------- d _static_data +-# BITCODE-NEXT: ---------------- t _static_func +- +-## Check that various symbol types can use debug information if available to +-## print line numbers, and if unavailable, don't print anything erroneous. The +-## specific cases checked are given by the symbol names below. Other test cases +-## place requirements on the contents of the whole file, so they are kept out +-## of main.o. +-# RUN: rm -rf %t +-# RUN: split-file %s %t +-# RUN: llvm-mc -g --filetype=obj %t/main.s -o %t/main.o +-# RUN: llvm-nm -l %t/main.o | FileCheck %s --match-full-lines --implicit-check-not={{.}} +-# RUN: llvm-nm --line-numbers %t/main.o | FileCheck %s --match-full-lines --implicit-check-not={{.}} +- +-# CHECK: 0000000000001234 a absolute_symbol +-# CHECK-NEXT: 0000000000000000 d data_no_dwarf +-# CHECK-NEXT: 0000000000000000 T defined_global_function [[FILENAME:.*main.s]]:4 +-# CHECK-NEXT: 0000000000000001 t defined_local_function [[FILENAME]]:7 +-# CHECK-NEXT: 0000000000000000 t function_no_dwarf +-# CHECK-NEXT: U undef1 [[FILENAME]]:12 +-# CHECK-NEXT: U undef2 [[FILENAME]]:14 +-# CHECK-NEXT: U undef_no_reloc +-# CHECK-NEXT: 0000000000000002 t undefined_references [[FILENAME]]:12 +- +-## Check that in the absence of DWARF in the whole object, no line number +-## information is printed. +-# RUN: llvm-mc --filetype=obj %t/main.s -o %t/no-dwarf.o +-# RUN: llvm-nm -l %t/no-dwarf.o | FileCheck %s --check-prefix=NO-DWARF --match-full-lines --implicit-check-not={{.}} +- +-# NO-DWARF: 0000000000001234 a absolute_symbol +-# NO-DWARF-NEXT: 0000000000000000 d data_no_dwarf +-# NO-DWARF-NEXT: 0000000000000000 T defined_global_function +-# NO-DWARF-NEXT: 0000000000000001 t defined_local_function +-# NO-DWARF-NEXT: 0000000000000000 t function_no_dwarf +-# NO-DWARF-NEXT: U undef1 +-# NO-DWARF-NEXT: U undef2 +-# NO-DWARF-NEXT: U undef_no_reloc +-# NO-DWARF-NEXT: 0000000000000002 t undefined_references +- +-## Check that printing line numbers for undefined values is not attempted in +-## the absence of any relocation section. +-# RUN: llvm-mc --filetype=obj %t/undef-no-reloc-sections.s -o %t/undef-no-reloc-sections.o +-# RUN: llvm-nm --line-numbers %t/undef-no-reloc-sections.o | FileCheck %s --check-prefix=UNDEF-NO-RELOC-SECTIONS --match-full-lines --implicit-check-not={{.}} +- +-# UNDEF-NO-RELOC-SECTIONS: U undef +- +-## Check that printing line numbers for undefined values does not include +-## relocations for non-text sections. This is broken out of main.s to ensure +-## that the data relocation for undef comes first. +-# RUN: llvm-mc -g --filetype=obj %t/undef-data-reloc.s -o %t/undef-data-reloc.o +-# RUN: llvm-nm --line-numbers %t/undef-data-reloc.o | FileCheck %s --check-prefix=UNDEF-DATA-RELOC --match-full-lines --implicit-check-not={{.}} +- +-# UNDEF-DATA-RELOC: 0000000000000000 r data_reloc +-# UNDEF-DATA-RELOC-NEXT: U undef +- +-## Check that line numbers can be printed for data definitions. These are broken +-## out of main.s since their DWARF cannot be generated with llvm-mc -g. +-# RUN: llvm-mc -g --filetype=obj %t/data-dwarf.s -o %t/data-dwarf.o +-# RUN: llvm-nm --line-numbers %t/data-dwarf.o | FileCheck %s --check-prefix=DATA-DWARF --match-full-lines --implicit-check-not={{.}} +- +-# DATA-DWARF: 0000000000000000 D defined_data /tmp/tmp.c:1 +- +-#--- main.s +-.text +-.globl defined_global_function +-defined_global_function: +- ret +- +-defined_local_function: +- ret +- +-absolute_symbol = 0x1234 +- +-undefined_references: +- nop +- .long undef1 +- nop +- .long undef2 +- ret +- +-# Note: llvm-mc -g produces no DWARF for data. +-.data +-data_no_dwarf: +- .byte 0 +- +-.globl undef_no_reloc +- +-# Note: llvm-mc -g does not produce DWARF for non-SHF_ALLOC sections. +-.section no_alloc_text,"x",@progbits +-function_no_dwarf: +- ret +- +-#--- undef-no-reloc-sections.s +-.globl undef +- +-#--- undef-data-reloc.s +-.globl undef +-.rodata +-data_reloc: +- .long undef +- +-#--- data-dwarf.s +-# char defined_data = 42 +- .text +- .file "tmp.c" +- .file 0 "/tmp" "/tmp/tmp.c" md5 0x39602a53b15a32d6a622ca86936e88d7 +- .file 1 "tmp.c" md5 0x39602a53b15a32d6a622ca86936e88d7 +- .type defined_data,@object # @defined_data +- .data +- .globl defined_data +-defined_data: +- .byte 42 # 0x2a +- .size defined_data, 1 +- +- .section .debug_abbrev,"",@progbits +- .byte 1 # Abbreviation Code +- .byte 17 # DW_TAG_compile_unit +- .byte 1 # DW_CHILDREN_yes +- .byte 37 # DW_AT_producer +- .byte 37 # DW_FORM_strx1 +- .byte 19 # DW_AT_language +- .byte 5 # DW_FORM_data2 +- .byte 3 # DW_AT_name +- .byte 37 # DW_FORM_strx1 +- .byte 114 # DW_AT_str_offsets_base +- .byte 23 # DW_FORM_sec_offset +- .byte 16 # DW_AT_stmt_list +- .byte 23 # DW_FORM_sec_offset +- .byte 27 # DW_AT_comp_dir +- .byte 37 # DW_FORM_strx1 +- .byte 115 # DW_AT_addr_base +- .byte 23 # DW_FORM_sec_offset +- .byte 0 # EOM(1) +- .byte 0 # EOM(2) +- .byte 2 # Abbreviation Code +- .byte 52 # DW_TAG_variable +- .byte 0 # DW_CHILDREN_no +- .byte 3 # DW_AT_name +- .byte 37 # DW_FORM_strx1 +- .byte 73 # DW_AT_type +- .byte 19 # DW_FORM_ref4 +- .byte 63 # DW_AT_external +- .byte 25 # DW_FORM_flag_present +- .byte 58 # DW_AT_decl_file +- .byte 11 # DW_FORM_data1 +- .byte 59 # DW_AT_decl_line +- .byte 11 # DW_FORM_data1 +- .byte 2 # DW_AT_location +- .byte 24 # DW_FORM_exprloc +- .byte 0 # EOM(1) +- .byte 0 # EOM(2) +- .byte 3 # Abbreviation Code +- .byte 36 # DW_TAG_base_type +- .byte 0 # DW_CHILDREN_no +- .byte 3 # DW_AT_name +- .byte 37 # DW_FORM_strx1 +- .byte 62 # DW_AT_encoding +- .byte 11 # DW_FORM_data1 +- .byte 11 # DW_AT_byte_size +- .byte 11 # DW_FORM_data1 +- .byte 0 # EOM(1) +- .byte 0 # EOM(2) +- .byte 0 # EOM(3) +- .section .debug_info,"",@progbits +-.Lcu_begin0: +- .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +-.Ldebug_info_start0: +- .short 5 # DWARF version number +- .byte 1 # DWARF Unit Type +- .byte 8 # Address Size (in bytes) +- .long .debug_abbrev # Offset Into Abbrev. Section +- .byte 1 # Abbrev [1] 0xc:0x22 DW_TAG_compile_unit +- .byte 0 # DW_AT_producer +- .short 12 # DW_AT_language +- .byte 1 # DW_AT_name +- .long .Lstr_offsets_base0 # DW_AT_str_offsets_base +- .long .Lline_table_start0 # DW_AT_stmt_list +- .byte 2 # DW_AT_comp_dir +- .long .Laddr_table_base0 # DW_AT_addr_base +- .byte 2 # Abbrev [2] 0x1e:0xb DW_TAG_variable +- .byte 3 # DW_AT_name +- .long 41 # DW_AT_type +- # DW_AT_external +- .byte 1 # DW_AT_decl_file +- .byte 1 # DW_AT_decl_line +- .byte 2 # DW_AT_location +- .byte 161 +- .byte 0 +- .byte 3 # Abbrev [3] 0x29:0x4 DW_TAG_base_type +- .byte 4 # DW_AT_name +- .byte 6 # DW_AT_encoding +- .byte 1 # DW_AT_byte_size +- .byte 0 # End Of Children Mark +-.Ldebug_info_end0: +- .section .debug_str_offsets,"",@progbits +- .long 24 # Length of String Offsets Set +- .short 5 +- .short 0 +-.Lstr_offsets_base0: +- .section .debug_str,"MS",@progbits,1 +-.Linfo_string0: +- .asciz "Debian clang version 14.0.6" # string offset=0 +-.Linfo_string1: +- .asciz "/tmp/tmp.c" # string offset=28 +-.Linfo_string2: +- .asciz "/tmp" # string offset=39 +-.Linfo_string3: +- .asciz "defined_data" # string offset=44 +-.Linfo_string4: +- .asciz "char" # string offset=57 +- .section .debug_str_offsets,"",@progbits +- .long .Linfo_string0 +- .long .Linfo_string1 +- .long .Linfo_string2 +- .long .Linfo_string3 +- .long .Linfo_string4 +- .section .debug_addr,"",@progbits +- .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +-.Ldebug_addr_start0: +- .short 5 # DWARF version number +- .byte 8 # Address size +- .byte 0 # Segment selector size +-.Laddr_table_base0: +- .quad defined_data +-.Ldebug_addr_end0: +- .ident "Debian clang version 14.0.6" +- .section ".note.GNU-stack","",@progbits +- .addrsig +- .section .debug_line,"",@progbits +-.Lline_table_start0: +diff --git a/llvm/tools/llvm-nm/CMakeLists.txt b/llvm/tools/llvm-nm/CMakeLists.txt +index 5191e138d1c0..ec04f1e9d234 100644 +--- a/llvm/tools/llvm-nm/CMakeLists.txt ++++ b/llvm/tools/llvm-nm/CMakeLists.txt +@@ -8,7 +8,6 @@ set(LLVM_LINK_COMPONENTS + Object + Option + Support +- Symbolize + TargetParser + TextAPI + ) +diff --git a/llvm/tools/llvm-nm/Opts.td b/llvm/tools/llvm-nm/Opts.td +index 04d9f5db5cf8..60ac134269b3 100644 +--- a/llvm/tools/llvm-nm/Opts.td ++++ b/llvm/tools/llvm-nm/Opts.td +@@ -22,7 +22,6 @@ def export_symbols : FF<"export-symbols", "Export symbol list for all inputs">; + def extern_only : FF<"extern-only", "Show only external symbols">; + defm format : Eq<"format", "Specify output format: bsd (default), posix, sysv, darwin, just-symbols">, MetaVarName<"">; + def help : FF<"help", "Display this help">; +-def line_numbers : FF<"line-numbers", "Use debugging information to print symbols' filenames and line numbers">; + def no_llvm_bc : FF<"no-llvm-bc", "Disable LLVM bitcode reader">; + def no_sort : FF<"no-sort", "Show symbols in order encountered">; + def no_weak : FF<"no-weak", "Show only non-weak symbols">; +@@ -68,7 +67,6 @@ def : JoinedOrSeparate<["-"], "f">, HelpText<"Alias for --format">, Alias, Alias; + def : F<"g", "Alias for --extern-only">, Alias; + def : F<"j", "Alias for --format=just-symbols">, Alias, AliasArgs<["just-symbols"]>; +-def : F<"l", "Alias for --line-numbers">, Alias; + def : F<"m", "Alias for --format=darwin">, Alias, AliasArgs<["darwin"]>; + def : F<"M", "Deprecated alias for --print-armap">, Alias, Flags<[HelpHidden]>; + def : F<"n", "Alias for --numeric-sort">, Alias; +diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp +index 051fa3e5bfa5..9a9e8bd146bb 100644 +--- a/llvm/tools/llvm-nm/llvm-nm.cpp ++++ b/llvm/tools/llvm-nm/llvm-nm.cpp +@@ -19,7 +19,6 @@ + #include "llvm/BinaryFormat/COFF.h" + #include "llvm/BinaryFormat/MachO.h" + #include "llvm/BinaryFormat/XCOFF.h" +-#include "llvm/DebugInfo/Symbolize/Symbolize.h" + #include "llvm/Demangle/Demangle.h" + #include "llvm/IR/Function.h" + #include "llvm/IR/LLVMContext.h" +@@ -98,7 +97,6 @@ static bool Demangle; + static bool DynamicSyms; + static bool ExportSymbols; + static bool ExternalOnly; +-static bool LineNumbers; + static OutputFormatTy OutputFormat; + static bool NoLLVMBitcode; + static bool NoSort; +@@ -553,6 +551,8 @@ static void darwinPrintSymbol(SymbolicFile &Obj, const NMSymbol &S, + } + } + } ++ ++ outs() << "\n"; + } + + // Table that maps Darwin's Mach-O stab constants to strings to allow printing. +@@ -689,88 +689,9 @@ static void printExportSymbolList(const std::vector &SymbolList) { + } + } + +-static void printLineNumbers(symbolize::LLVMSymbolizer &Symbolizer, +- const NMSymbol &S) { +- const auto *Obj = dyn_cast(S.Sym.getObject()); +- if (!Obj) +- return; +- const SymbolRef Sym(S.Sym); +- uint64_t SectionIndex = object::SectionedAddress::UndefSection; +- section_iterator Sec = cantFail(Sym.getSection()); +- if (Sec != Obj->section_end()) +- SectionIndex = Sec->getIndex(); +- object::SectionedAddress Address = {cantFail(Sym.getAddress()), SectionIndex}; +- +- std::string FileName; +- uint32_t Line; +- switch (S.TypeChar) { +- // For undefined symbols, find the first relocation for that symbol with a +- // line number. +- case 'U': { +- for (const SectionRef RelocsSec : Obj->sections()) { +- if (RelocsSec.relocations().empty()) +- continue; +- SectionRef TextSec = *cantFail(RelocsSec.getRelocatedSection()); +- if (!TextSec.isText()) +- continue; +- for (const RelocationRef R : RelocsSec.relocations()) { +- if (R.getSymbol() != Sym) +- continue; +- Expected ResOrErr = Symbolizer.symbolizeCode( +- *Obj, {TextSec.getAddress() + R.getOffset(), SectionIndex}); +- if (!ResOrErr) { +- error(ResOrErr.takeError(), Obj->getFileName()); +- return; +- } +- if (ResOrErr->FileName == DILineInfo::BadString) +- return; +- FileName = std::move(ResOrErr->FileName); +- Line = ResOrErr->Line; +- break; +- } +- if (!FileName.empty()) +- break; +- } +- if (FileName.empty()) +- return; +- break; +- } +- case 't': +- case 'T': { +- Expected ResOrErr = Symbolizer.symbolizeCode(*Obj, Address); +- if (!ResOrErr) { +- error(ResOrErr.takeError(), Obj->getFileName()); +- return; +- } +- if (ResOrErr->FileName == DILineInfo::BadString) +- return; +- FileName = std::move(ResOrErr->FileName); +- Line = ResOrErr->Line; +- break; +- } +- default: { +- Expected ResOrErr = Symbolizer.symbolizeData(*Obj, Address); +- if (!ResOrErr) { +- error(ResOrErr.takeError(), Obj->getFileName()); +- return; +- } +- if (ResOrErr->DeclFile.empty()) +- return; +- FileName = std::move(ResOrErr->DeclFile); +- Line = ResOrErr->DeclLine; +- break; +- } +- } +- outs() << '\t' << FileName << ':' << Line; +-} +- + static void printSymbolList(SymbolicFile &Obj, + std::vector &SymbolList, bool printName, + StringRef ArchiveName, StringRef ArchitectureName) { +- std::optional Symbolizer; +- if (LineNumbers) +- Symbolizer.emplace(); +- + if (!PrintFileName) { + if ((OutputFormat == bsd || OutputFormat == posix || + OutputFormat == just_symbols) && +@@ -877,7 +798,7 @@ static void printSymbolList(SymbolicFile &Obj, + printFormat); + } else if (OutputFormat == posix) { + outs() << Name << " " << S.TypeChar << " " << SymbolAddrStr << " " +- << (MachO ? "0" : SymbolSizeStr); ++ << (MachO ? "0" : SymbolSizeStr) << "\n"; + } else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) { + if (PrintAddress) + outs() << SymbolAddrStr << ' '; +@@ -898,14 +819,12 @@ static void printSymbolList(SymbolicFile &Obj, + } else + outs() << S.IndirectName << ")"; + } ++ outs() << "\n"; + } else if (OutputFormat == sysv) { + outs() << left_justify(Name, 20) << "|" << SymbolAddrStr << "| " + << S.TypeChar << " |" << right_justify(S.TypeName, 18) << "|" +- << SymbolSizeStr << "| |" << S.SectionName; ++ << SymbolSizeStr << "| |" << S.SectionName << "\n"; + } +- if (LineNumbers) +- printLineNumbers(*Symbolizer, S); +- outs() << '\n'; + } + + SymbolList.clear(); +@@ -2496,7 +2415,6 @@ int llvm_nm_main(int argc, char **argv, const llvm::ToolContext &) { + else + error("--format value should be one of: bsd, posix, sysv, darwin, " + "just-symbols"); +- LineNumbers = Args.hasArg(OPT_line_numbers); + NoLLVMBitcode = Args.hasArg(OPT_no_llvm_bc); + NoSort = Args.hasArg(OPT_no_sort); + NoWeakSymbols = Args.hasArg(OPT_no_weak); +-- +2.41.0.3.g1cb8d410ac + diff --git a/build/build-clang/revert-llvmorg-18-init-6193-gb88cffeafd39.patch b/build/build-clang/revert-llvmorg-18-init-6193-gb88cffeafd39.patch new file mode 100644 index 0000000000..a3ad8e0ed3 --- /dev/null +++ b/build/build-clang/revert-llvmorg-18-init-6193-gb88cffeafd39.patch @@ -0,0 +1,63 @@ +From be338a0b7be5040a7814d10d424f1555604cce7c Mon Sep 17 00:00:00 2001 +From: Mike Hommey +Date: Wed, 20 Sep 2023 10:08:21 +0900 +Subject: [PATCH 2/3] Revert "Explicitly set triple on line-numbers.test" + +This reverts commit b88cffeafd393d54f85feb641c4f8fd4fdb73fe4 because it +depends on c649f29c24c9fc1502d8d53e0c96c3d24b31de1a which we revert. +--- + llvm/test/tools/llvm-nm/X86/line-numbers.test | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/llvm/test/tools/llvm-nm/X86/line-numbers.test b/llvm/test/tools/llvm-nm/X86/line-numbers.test +index 4acda8afb2a4..4b9817ab5c62 100644 +--- a/llvm/test/tools/llvm-nm/X86/line-numbers.test ++++ b/llvm/test/tools/llvm-nm/X86/line-numbers.test +@@ -18,7 +18,7 @@ + ## of main.o. + # RUN: rm -rf %t + # RUN: split-file %s %t +-# RUN: llvm-mc -g --filetype=obj -triple=x86_64-pc-linux %t/main.s -o %t/main.o ++# RUN: llvm-mc -g --filetype=obj %t/main.s -o %t/main.o + # RUN: llvm-nm -l %t/main.o | FileCheck %s --match-full-lines --implicit-check-not={{.}} + # RUN: llvm-nm --line-numbers %t/main.o | FileCheck %s --match-full-lines --implicit-check-not={{.}} + +@@ -34,7 +34,7 @@ + + ## Check that in the absence of DWARF in the whole object, no line number + ## information is printed. +-# RUN: llvm-mc --filetype=obj %t/main.s -triple=x86_64-pc-linux -o %t/no-dwarf.o ++# RUN: llvm-mc --filetype=obj %t/main.s -o %t/no-dwarf.o + # RUN: llvm-nm -l %t/no-dwarf.o | FileCheck %s --check-prefix=NO-DWARF --match-full-lines --implicit-check-not={{.}} + + # NO-DWARF: 0000000000001234 a absolute_symbol +@@ -49,7 +49,7 @@ + + ## Check that printing line numbers for undefined values is not attempted in + ## the absence of any relocation section. +-# RUN: llvm-mc --filetype=obj %t/undef-no-reloc-sections.s -triple=x86_64-pc-linux -o %t/undef-no-reloc-sections.o ++# RUN: llvm-mc --filetype=obj %t/undef-no-reloc-sections.s -o %t/undef-no-reloc-sections.o + # RUN: llvm-nm --line-numbers %t/undef-no-reloc-sections.o | FileCheck %s --check-prefix=UNDEF-NO-RELOC-SECTIONS --match-full-lines --implicit-check-not={{.}} + + # UNDEF-NO-RELOC-SECTIONS: U undef +@@ -57,7 +57,7 @@ + ## Check that printing line numbers for undefined values does not include + ## relocations for non-text sections. This is broken out of main.s to ensure + ## that the data relocation for undef comes first. +-# RUN: llvm-mc -g --filetype=obj %t/undef-data-reloc.s -triple=x86_64-pc-linux -o %t/undef-data-reloc.o ++# RUN: llvm-mc -g --filetype=obj %t/undef-data-reloc.s -o %t/undef-data-reloc.o + # RUN: llvm-nm --line-numbers %t/undef-data-reloc.o | FileCheck %s --check-prefix=UNDEF-DATA-RELOC --match-full-lines --implicit-check-not={{.}} + + # UNDEF-DATA-RELOC: 0000000000000000 r data_reloc +@@ -65,7 +65,7 @@ + + ## Check that line numbers can be printed for data definitions. These are broken + ## out of main.s since their DWARF cannot be generated with llvm-mc -g. +-# RUN: llvm-mc -g --filetype=obj %t/data-dwarf.s -triple=x86_64-pc-linux -o %t/data-dwarf.o ++# RUN: llvm-mc -g --filetype=obj %t/data-dwarf.s -o %t/data-dwarf.o + # RUN: llvm-nm --line-numbers %t/data-dwarf.o | FileCheck %s --check-prefix=DATA-DWARF --match-full-lines --implicit-check-not={{.}} + + # DATA-DWARF: 0000000000000000 D defined_data /tmp/tmp.c:1 +-- +2.41.0.3.g1cb8d410ac + diff --git a/build/build-clang/revert-llvmorg-18-init-6208-g2baf4a06ef06.patch b/build/build-clang/revert-llvmorg-18-init-6208-g2baf4a06ef06.patch new file mode 100644 index 0000000000..ba2116d4ba --- /dev/null +++ b/build/build-clang/revert-llvmorg-18-init-6208-g2baf4a06ef06.patch @@ -0,0 +1,28 @@ +From 9d81bf8d2e457540b8bd93859baef79a043c8482 Mon Sep 17 00:00:00 2001 +From: Mike Hommey +Date: Wed, 20 Sep 2023 10:08:13 +0900 +Subject: [PATCH 1/3] Revert "Fix test added in D150987 to account for + different path separators which was causing the test to fail on Windows." + +This reverts commit 2baf4a06ef06c51c2ef09f981f204983b0f8082c because it +depends on c649f29c24c9fc1502d8d53e0c96c3d24b31de1a which we revert. +--- + llvm/test/tools/llvm-nm/X86/line-numbers.test | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/llvm/test/tools/llvm-nm/X86/line-numbers.test b/llvm/test/tools/llvm-nm/X86/line-numbers.test +index e254df67f955..4acda8afb2a4 100644 +--- a/llvm/test/tools/llvm-nm/X86/line-numbers.test ++++ b/llvm/test/tools/llvm-nm/X86/line-numbers.test +@@ -68,7 +68,7 @@ + # RUN: llvm-mc -g --filetype=obj %t/data-dwarf.s -triple=x86_64-pc-linux -o %t/data-dwarf.o + # RUN: llvm-nm --line-numbers %t/data-dwarf.o | FileCheck %s --check-prefix=DATA-DWARF --match-full-lines --implicit-check-not={{.}} + +-# DATA-DWARF: 0000000000000000 D defined_data /tmp{{\\|/}}tmp.c:1 ++# DATA-DWARF: 0000000000000000 D defined_data /tmp/tmp.c:1 + + #--- main.s + .text +-- +2.41.0.3.g1cb8d410ac + diff --git a/build/build-clang/skip-3-stages.json b/build/build-clang/skip-3-stages.json new file mode 100644 index 0000000000..79b1bf193f --- /dev/null +++ b/build/build-clang/skip-3-stages.json @@ -0,0 +1,6 @@ +{ + "skip_stages": "3", + "cc": "{MOZ_FETCHES_DIR}/clang/bin/clang", + "cxx": "{MOZ_FETCHES_DIR}/clang/bin/clang++", + "as": "{MOZ_FETCHES_DIR}/clang/bin/clang" +} diff --git a/build/build-clang/skip-stage-1-win64.json b/build/build-clang/skip-stage-1-win64.json new file mode 100644 index 0000000000..8dee151003 --- /dev/null +++ b/build/build-clang/skip-stage-1-win64.json @@ -0,0 +1,7 @@ +{ + "skip_stages": "1", + "cc": "{MOZ_FETCHES_DIR}/clang/bin/clang-cl.exe", + "cxx": "{MOZ_FETCHES_DIR}/clang/bin/clang-cl.exe", + "ml": "{MOZ_FETCHES_DIR}/clang/bin/clang-cl.exe", + "lib": "{MOZ_FETCHES_DIR}/clang/bin/llvm-lib.exe" +} diff --git a/build/build-clang/skip-stage-1.json b/build/build-clang/skip-stage-1.json new file mode 100644 index 0000000000..aa1101b13b --- /dev/null +++ b/build/build-clang/skip-stage-1.json @@ -0,0 +1,6 @@ +{ + "skip_stages": "1", + "cc": "{MOZ_FETCHES_DIR}/clang/bin/clang", + "cxx": "{MOZ_FETCHES_DIR}/clang/bin/clang++", + "as": "{MOZ_FETCHES_DIR}/clang/bin/clang" +} diff --git a/build/build-clang/unpoison-thread-stacks_clang_10.patch b/build/build-clang/unpoison-thread-stacks_clang_10.patch new file mode 100644 index 0000000000..563fa1d7bf --- /dev/null +++ b/build/build-clang/unpoison-thread-stacks_clang_10.patch @@ -0,0 +1,64 @@ +[winasan] Unpoison the stack in NtTerminateThread + +In long-running builds we've seen some ASan complaints during thread creation +that we suspect are due to leftover poisoning from previous threads whose stacks +occupied that memory. This patch adds a hook that unpoisons the stack just +before the NtTerminateThread syscall. + +Differential Revision: https://reviews.llvm.org/D52091 + +** Update for clang 9 ** : After some backouts, this patch eventually landed +upstream in a different form, as the TLS handler `asan_thread_exit`, but that +variant causes failures in our test suite, so revert the TLS handler in favor of +the interceptor approach from the first patch. + +diff --git a/compiler-rt/lib/asan/asan_win.cpp b/compiler-rt/lib/asan/asan_win.cpp +index 417892aaedd..5fe86db44f4 100644 +--- a/compiler-rt/lib/asan/asan_win.cpp ++++ b/compiler-rt/lib/asan/asan_win.cpp +@@ -154,6 +154,14 @@ INTERCEPTOR_WINAPI(HANDLE, CreateThread, LPSECURITY_ATTRIBUTES security, + thr_flags, tid); + } + ++INTERCEPTOR_WINAPI(void, NtTerminateThread, void *rcx) { ++ // Unpoison the terminating thread's stack because the memory may be re-used. ++ NT_TIB *tib = (NT_TIB *)NtCurrentTeb(); ++ uptr stackSize = (uptr)tib->StackBase - (uptr)tib->StackLimit; ++ __asan_unpoison_memory_region(tib->StackLimit, stackSize); ++ return REAL(NtTerminateThread(rcx)); ++} ++ + // }}} + + namespace __asan { +@@ -168,7 +176,9 @@ void InitializePlatformInterceptors() { + + ASAN_INTERCEPT_FUNC(CreateThread); + ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter); +- ++ CHECK(::__interception::OverrideFunction("NtTerminateThread", ++ (uptr)WRAP(NtTerminateThread), ++ (uptr *)&REAL(NtTerminateThread))); + #ifdef _WIN64 + ASAN_INTERCEPT_FUNC(__C_specific_handler); + #else +@@ -380,19 +390,6 @@ __declspec(allocate(".CRT$XLAB")) void(NTAPI *__asan_tls_init)( + void *, unsigned long, void *) = asan_thread_init; + #endif + +-static void NTAPI asan_thread_exit(void *module, DWORD reason, void *reserved) { +- if (reason == DLL_THREAD_DETACH) { +- // Unpoison the thread's stack because the memory may be re-used. +- NT_TIB *tib = (NT_TIB *)NtCurrentTeb(); +- uptr stackSize = (uptr)tib->StackBase - (uptr)tib->StackLimit; +- __asan_unpoison_memory_region(tib->StackLimit, stackSize); +- } +-} +- +-#pragma section(".CRT$XLY", long, read) +-__declspec(allocate(".CRT$XLY")) void(NTAPI *__asan_tls_exit)( +- void *, unsigned long, void *) = asan_thread_exit; +- + WIN_FORCE_LINK(__asan_dso_reg_hook) + + // }}} diff --git a/build/build-clang/win64-ret-null-on-commitment-limit_clang_14.patch b/build/build-clang/win64-ret-null-on-commitment-limit_clang_14.patch new file mode 100644 index 0000000000..23b001bc68 --- /dev/null +++ b/build/build-clang/win64-ret-null-on-commitment-limit_clang_14.patch @@ -0,0 +1,14 @@ +diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +index 7c84cdc22ce4..e13fff03489e 100644 +--- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp ++++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +@@ -157,7 +157,8 @@ void UnmapOrDie(void *addr, uptr size) { + static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type, + const char *mmap_type) { + error_t last_error = GetLastError(); +- if (last_error == ERROR_NOT_ENOUGH_MEMORY) ++ if (last_error == ERROR_NOT_ENOUGH_MEMORY || ++ last_error == ERROR_COMMITMENT_LIMIT) + return nullptr; + ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error); + } diff --git a/build/build-clang/win64.json b/build/build-clang/win64.json new file mode 100644 index 0000000000..9d4dcc589e --- /dev/null +++ b/build/build-clang/win64.json @@ -0,0 +1,7 @@ +{ + "target": "x86_64-pc-windows-msvc", + "cc": "{MOZ_FETCHES_DIR}/clang/bin/clang-cl", + "cxx": "{MOZ_FETCHES_DIR}/clang/bin/clang-cl", + "ml": "{MOZ_FETCHES_DIR}/clang/bin/clang-cl", + "lib": "{MOZ_FETCHES_DIR}/clang/bin/llvm-lib" +} diff --git a/build/build-rust/README b/build/build-rust/README new file mode 100644 index 0000000000..34f7af63a5 --- /dev/null +++ b/build/build-rust/README @@ -0,0 +1,3 @@ +This directory is for patches to rust toolchains, see these docs for details: + +https://firefox-source-docs.mozilla.org/build/buildsystem/toolchains.html \ No newline at end of file diff --git a/build/build-rust/cargo-vendor-std.patch b/build/build-rust/cargo-vendor-std.patch new file mode 100644 index 0000000000..1a79846d61 --- /dev/null +++ b/build/build-rust/cargo-vendor-std.patch @@ -0,0 +1,413 @@ +Teaches Cargo to source all std dependencies from vendored sources in the rust-src +component, making -Zbuild-std compatible with vendored builds. + +This was originally landed in https://github.com/rust-lang/cargo/pull/8834 +but was backed out for causing breakage in other situations. It works fine +for Firefox's usecase, though. + +Most of these changes just add/edit tests for the functionality. Only the +change to src/cargo/core/compiler/standard_lib.rs is important. + +diff --git a/src/cargo/core/compiler/standard_lib.rs b/src/cargo/core/compiler/standard_lib.rs +index c456c58d5..333389bc8 100644 +--- a/src/cargo/core/compiler/standard_lib.rs ++++ b/src/cargo/core/compiler/standard_lib.rs +@@ -11,6 +11,7 @@ use crate::ops::{self, Packages}; + use crate::util::errors::CargoResult; + use crate::Config; + use std::collections::{HashMap, HashSet}; ++use std::fs; + use std::path::PathBuf; + + use super::BuildConfig; +@@ -73,27 +74,45 @@ pub fn resolve_std<'cfg>( + } + + let src_path = detect_sysroot_src_path(target_data)?; +- let to_patch = [ +- "rustc-std-workspace-core", +- "rustc-std-workspace-alloc", +- "rustc-std-workspace-std", +- ]; +- let patches = to_patch +- .iter() +- .map(|&name| { +- let source_path = SourceId::for_path(&src_path.join("library").join(name))?; +- let dep = Dependency::parse(name, None, source_path)?; ++ ++ // Special std packages should be pulled from `library/` and should be ++ // prefixed with `rustc-std-workspace-` in certain places. ++ let libs_prefix = "library/"; ++ let special_std_prefix = "rustc-std-workspace-"; ++ let libs_path = src_path.join(libs_prefix); ++ ++ // Crates in rust-src to build. libsysroot is in some sense the "root" package ++ // of std, as nothing else depends on it, so it must be explicitly added. ++ let mut members = vec![format!("{}sysroot", libs_prefix)]; ++ ++ // If rust-src contains a "vendor" directory, then patch in all the crates it contains. ++ let vendor_path = src_path.join("vendor"); ++ let vendor_dir = fs::read_dir(vendor_path)?; ++ let patches = vendor_dir ++ .into_iter() ++ .map(|entry| { ++ let entry = entry?; ++ let name = entry ++ .file_name() ++ .into_string() ++ .map_err(|_| anyhow::anyhow!("package name wasn't utf8"))?; ++ ++ // Remap the rustc-std-workspace crates to the actual rust-src libraries ++ let path = if let Some(real_name) = name.strip_prefix(special_std_prefix) { ++ // Record this crate as something to build in the workspace ++ members.push(format!("{}{}", libs_prefix, real_name)); ++ libs_path.join(&name) ++ } else { ++ entry.path() ++ }; ++ let source_path = SourceId::for_path(&path)?; ++ let dep = Dependency::parse(&name, None, source_path)?; + Ok(dep) + }) + .collect::>>()?; ++ + let crates_io_url = crate::sources::CRATES_IO_INDEX.parse().unwrap(); + let patch = HashMap::from([(crates_io_url, patches)]); +- let members = vec![ +- String::from("library/std"), +- String::from("library/core"), +- String::from("library/alloc"), +- String::from("library/sysroot"), +- ]; + let ws_config = crate::core::WorkspaceConfig::Root(crate::core::WorkspaceRootConfig::new( + &src_path, + &Some(members), +diff --git a/tests/testsuite/mock-std/library/test/Cargo.toml b/tests/testsuite/mock-std/library/test/Cargo.toml +index b9f51eda7..fed5f3973 100644 +--- a/tests/testsuite/mock-std/library/test/Cargo.toml ++++ b/tests/testsuite/mock-std/library/test/Cargo.toml +@@ -9,3 +9,4 @@ std = { path = "../std" } + panic_unwind = { path = "../panic_unwind" } + compiler_builtins = { path = "../compiler_builtins" } + registry-dep-using-std = { version = "*", features = ['mockbuild'] } ++registry-dep-only-used-by-test = { version = "*" } +diff --git a/tests/testsuite/mock-std/library/test/src/lib.rs b/tests/testsuite/mock-std/library/test/src/lib.rs +index a112855f5..224b89bb2 100644 +--- a/tests/testsuite/mock-std/library/test/src/lib.rs ++++ b/tests/testsuite/mock-std/library/test/src/lib.rs +@@ -7,4 +7,5 @@ extern crate test; + pub use test::*; + + pub fn custom_api() { ++ registry_dep_only_used_by_test::wow_testing_is_so_easy(); + } +diff --git a/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/Cargo.toml b/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/Cargo.toml +new file mode 100644 +index 000000000..31ba65a98 +--- /dev/null ++++ b/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/Cargo.toml +@@ -0,0 +1,9 @@ ++[package] ++name = "registry-dep-only-used-by-test" ++version = "1.0.0" ++authors = ["Alex Crichton "] ++edition = "2018" ++ ++[dependencies] ++ ++[features] +diff --git a/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/src/lib.rs b/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/src/lib.rs +new file mode 100644 +index 000000000..a68d2aeef +--- /dev/null ++++ b/tests/testsuite/mock-std/vendor/registry-dep-only-used-by-test/src/lib.rs +@@ -0,0 +1,2 @@ ++pub fn wow_testing_is_so_easy() { ++} +\ No newline at end of file +diff --git a/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/Cargo.toml b/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/Cargo.toml +new file mode 100644 +index 000000000..f7e4ab232 +--- /dev/null ++++ b/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/Cargo.toml +@@ -0,0 +1,12 @@ ++[package] ++name = "registry-dep-using-alloc" ++version = "1.0.0" ++authors = ["Alex Crichton "] ++edition = "2018" ++ ++[dependencies] ++rustc-std-workspace-alloc = { version = "*", optional = true } ++rustc-std-workspace-core = { version = "*", optional = true } ++ ++[features] ++mockbuild = ["rustc-std-workspace-alloc", "rustc-std-workspace-core"] +\ No newline at end of file +diff --git a/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/src/lib.rs b/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/src/lib.rs +new file mode 100644 +index 000000000..b9ab30339 +--- /dev/null ++++ b/tests/testsuite/mock-std/vendor/registry-dep-using-alloc/src/lib.rs +@@ -0,0 +1,9 @@ ++#[cfg(feature = "mockbuild")] ++pub fn custom_api() { ++} ++ ++#[cfg(not(feature = "mockbuild"))] ++pub fn non_sysroot_api() { ++ core::custom_api(); ++ alloc::custom_api(); ++} +\ No newline at end of file +diff --git a/tests/testsuite/mock-std/vendor/registry-dep-using-core/Cargo.toml b/tests/testsuite/mock-std/vendor/registry-dep-using-core/Cargo.toml +new file mode 100644 +index 000000000..befb83a63 +--- /dev/null ++++ b/tests/testsuite/mock-std/vendor/registry-dep-using-core/Cargo.toml +@@ -0,0 +1,11 @@ ++[package] ++name = "registry-dep-using-core" ++version = "1.0.0" ++authors = ["Alex Crichton "] ++edition = "2018" ++ ++[dependencies] ++rustc-std-workspace-core = { version = "*", optional = true } ++ ++[features] ++mockbuild = ["rustc-std-workspace-core"] +\ No newline at end of file +diff --git a/tests/testsuite/mock-std/vendor/registry-dep-using-core/src/lib.rs b/tests/testsuite/mock-std/vendor/registry-dep-using-core/src/lib.rs +new file mode 100644 +index 000000000..f9dbac0f4 +--- /dev/null ++++ b/tests/testsuite/mock-std/vendor/registry-dep-using-core/src/lib.rs +@@ -0,0 +1,8 @@ ++#[cfg(feature = "mockbuild")] ++pub fn custom_api() { ++} ++ ++#[cfg(not(feature = "mockbuild"))] ++pub fn non_sysroot_api() { ++ core::custom_api(); ++} +\ No newline at end of file +diff --git a/tests/testsuite/mock-std/vendor/registry-dep-using-std/Cargo.toml b/tests/testsuite/mock-std/vendor/registry-dep-using-std/Cargo.toml +new file mode 100644 +index 000000000..71ef0a42f +--- /dev/null ++++ b/tests/testsuite/mock-std/vendor/registry-dep-using-std/Cargo.toml +@@ -0,0 +1,11 @@ ++[package] ++name = "registry-dep-using-std" ++version = "1.0.0" ++authors = ["Alex Crichton "] ++edition = "2018" ++ ++[dependencies] ++rustc-std-workspace-std = { version = "*", optional = true } ++ ++[features] ++mockbuild = ["rustc-std-workspace-std"] +\ No newline at end of file +diff --git a/tests/testsuite/mock-std/vendor/registry-dep-using-std/src/lib.rs b/tests/testsuite/mock-std/vendor/registry-dep-using-std/src/lib.rs +new file mode 100644 +index 000000000..f3af39178 +--- /dev/null ++++ b/tests/testsuite/mock-std/vendor/registry-dep-using-std/src/lib.rs +@@ -0,0 +1,8 @@ ++#[cfg(feature = "mockbuild")] ++pub fn custom_api() { ++} ++ ++#[cfg(not(feature = "mockbuild"))] ++pub fn non_sysroot_api() { ++ std::custom_api(); ++} +\ No newline at end of file +diff --git a/tests/testsuite/mock-std/vendor/rustc-std-workspace-alloc/Cargo.toml b/tests/testsuite/mock-std/vendor/rustc-std-workspace-alloc/Cargo.toml +new file mode 100644 +index 000000000..4465a08a8 +--- /dev/null ++++ b/tests/testsuite/mock-std/vendor/rustc-std-workspace-alloc/Cargo.toml +@@ -0,0 +1 @@ ++this file shouldn't be read +\ No newline at end of file +diff --git a/tests/testsuite/mock-std/vendor/rustc-std-workspace-core/Cargo.toml b/tests/testsuite/mock-std/vendor/rustc-std-workspace-core/Cargo.toml +new file mode 100644 +index 000000000..4465a08a8 +--- /dev/null ++++ b/tests/testsuite/mock-std/vendor/rustc-std-workspace-core/Cargo.toml +@@ -0,0 +1 @@ ++this file shouldn't be read +\ No newline at end of file +diff --git a/tests/testsuite/mock-std/vendor/rustc-std-workspace-std/Cargo.toml b/tests/testsuite/mock-std/vendor/rustc-std-workspace-std/Cargo.toml +new file mode 100644 +index 000000000..4465a08a8 +--- /dev/null ++++ b/tests/testsuite/mock-std/vendor/rustc-std-workspace-std/Cargo.toml +@@ -0,0 +1 @@ ++this file shouldn't be read +\ No newline at end of file +diff --git a/tests/testsuite/standard_lib.rs b/tests/testsuite/standard_lib.rs +index d3be303ea..486a9b4e0 100644 +--- a/tests/testsuite/standard_lib.rs ++++ b/tests/testsuite/standard_lib.rs +@@ -15,71 +15,18 @@ struct Setup { + } + + fn setup() -> Setup { +- // Our mock sysroot requires a few packages from crates.io, so make sure +- // they're "published" to crates.io. Also edit their code a bit to make sure +- // that they have access to our custom crates with custom apis. ++ // Register a version of one of the std dependencies that doesn't compile. ++ // This ensures that the mock-std's vendor is actually being used. + Package::new("registry-dep-using-core", "1.0.0") + .file( + "src/lib.rs", + " +- #![no_std] +- +- #[cfg(feature = \"mockbuild\")] +- pub fn custom_api() { +- } +- +- #[cfg(not(feature = \"mockbuild\"))] +- pub fn non_sysroot_api() { +- core::custom_api(); +- } ++ don't compile me bro!! + ", + ) + .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true)) + .feature("mockbuild", &["rustc-std-workspace-core"]) + .publish(); +- Package::new("registry-dep-using-alloc", "1.0.0") +- .file( +- "src/lib.rs", +- " +- #![no_std] +- +- extern crate alloc; +- +- #[cfg(feature = \"mockbuild\")] +- pub fn custom_api() { +- } +- +- #[cfg(not(feature = \"mockbuild\"))] +- pub fn non_sysroot_api() { +- core::custom_api(); +- alloc::custom_api(); +- } +- ", +- ) +- .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true)) +- .add_dep(Dependency::new("rustc-std-workspace-alloc", "*").optional(true)) +- .feature( +- "mockbuild", +- &["rustc-std-workspace-core", "rustc-std-workspace-alloc"], +- ) +- .publish(); +- Package::new("registry-dep-using-std", "1.0.0") +- .file( +- "src/lib.rs", +- " +- #[cfg(feature = \"mockbuild\")] +- pub fn custom_api() { +- } +- +- #[cfg(not(feature = \"mockbuild\"))] +- pub fn non_sysroot_api() { +- std::custom_api(); +- } +- ", +- ) +- .add_dep(Dependency::new("rustc-std-workspace-std", "*").optional(true)) +- .feature("mockbuild", &["rustc-std-workspace-std"]) +- .publish(); + + let p = ProjectBuilder::new(paths::root().join("rustc-wrapper")) + .file( +@@ -335,6 +282,81 @@ fn depend_same_as_std() { + fn test() { + let setup = setup(); + ++ // Our mock sysroot requires a few packages from crates.io, so make sure ++ // they're "published" to crates.io. Also edit their code a bit to make sure ++ // that they have access to our custom crates with custom apis. ++ Package::new("registry-dep-using-core", "1.0.0") ++ .file( ++ "src/lib.rs", ++ " ++ #![no_std] ++ ++ #[cfg(feature = \"mockbuild\")] ++ pub fn custom_api() { ++ } ++ ++ #[cfg(not(feature = \"mockbuild\"))] ++ pub fn non_sysroot_api() { ++ core::custom_api(); ++ } ++ ", ++ ) ++ .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true)) ++ .feature("mockbuild", &["rustc-std-workspace-core"]) ++ .publish(); ++ Package::new("registry-dep-using-alloc", "1.0.0") ++ .file( ++ "src/lib.rs", ++ " ++ #![no_std] ++ ++ extern crate alloc; ++ ++ #[cfg(feature = \"mockbuild\")] ++ pub fn custom_api() { ++ } ++ ++ #[cfg(not(feature = \"mockbuild\"))] ++ pub fn non_sysroot_api() { ++ core::custom_api(); ++ alloc::custom_api(); ++ } ++ ", ++ ) ++ .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true)) ++ .add_dep(Dependency::new("rustc-std-workspace-alloc", "*").optional(true)) ++ .feature( ++ "mockbuild", ++ &["rustc-std-workspace-core", "rustc-std-workspace-alloc"], ++ ) ++ .publish(); ++ Package::new("registry-dep-using-std", "1.0.0") ++ .file( ++ "src/lib.rs", ++ " ++ #[cfg(feature = \"mockbuild\")] ++ pub fn custom_api() { ++ } ++ ++ #[cfg(not(feature = \"mockbuild\"))] ++ pub fn non_sysroot_api() { ++ std::custom_api(); ++ } ++ ", ++ ) ++ .add_dep(Dependency::new("rustc-std-workspace-std", "*").optional(true)) ++ .feature("mockbuild", &["rustc-std-workspace-std"]) ++ .publish(); ++ Package::new("registry-dep-only-used-by-test", "1.0.0") ++ .file( ++ "src/lib.rs", ++ " ++ pub fn wow_testing_is_so_easy() { ++ } ++ ", ++ ) ++ .publish(); ++ + let p = project() + .file( + "src/lib.rs", diff --git a/build/build-rust/example.patch b/build/build-rust/example.patch new file mode 100644 index 0000000000..09a00bf22f --- /dev/null +++ b/build/build-rust/example.patch @@ -0,0 +1,12 @@ +diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md +index 2a4c42ea0a4..c94b24e9cb1 100644 +--- a/CONTRIBUTING.md ++++ b/CONTRIBUTING.md +@@ -1,5 +1,7 @@ + # Contributing to Rust + ++Hello this is a harmless little example patch! ++ + Thank you for your interest in contributing to Rust! + + To get started, read the [Getting Started] guide in the [rustc-dev-guide]. diff --git a/build/build-rust/rust-vendor-std.patch b/build/build-rust/rust-vendor-std.patch new file mode 100644 index 0000000000..e3ad25d1b0 --- /dev/null +++ b/build/build-rust/rust-vendor-std.patch @@ -0,0 +1,81 @@ +Teaches Rust's build system to vendor std's dependencies into the +rust-src component. + +This was originally landed in https://github.com/rust-lang/rust/pull/78790 +but was backed out for causing some breakage for distro maintainers who +need to build Rust itself in a vendored/offline context. It doesn't actually +fetch anything interesting from crates.io, just the magic fake std/core crates +that exist to make the build work right. Those crates *are* vendored but +their contents are ignored in favour of the actual stdlib. + +For firefox's purposes, these patches still work fine, and are necessary +to make -Zbuild-std work in a vendored environment. + +diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs +index 3cb0eccd324..a3b8154c024 100644 +--- a/src/bootstrap/src/core/build_steps/dist.rs ++++ b/src/bootstrap/src/core/build_steps/dist.rs +@@ -905,6 +905,31 @@ fn run(self, builder: &Builder<'_>) -> GeneratedTarball { + builder.copy(&builder.src.join(file), &dst_src.join(file)); + } + ++ // libsysroot includes std and everything else, so vendoring it ++ // creates exactly what's needed for `cargo -Zbuild-std` or any ++ // other analysis of the stdlib's source. Cargo also needs help ++ // finding the lock, so we copy it to libsysroot temporarily. ++ // ++ // Note that this requires std to only have one version of each ++ // crate. e.g. two versions of getopts won't be patchable. ++ let dst_libsysroot = dst_src.join("library/sysroot"); ++ let dst_vendor = dst_src.join("vendor"); ++ let root_lock = dst_src.join("Cargo.lock"); ++ let temp_lock = dst_libsysroot.join("Cargo.lock"); ++ ++ // `cargo vendor` will delete everything from the lockfile that ++ // isn't used by libsysroot, so we need to not use any links! ++ builder.really_copy(&root_lock, &temp_lock); ++ ++ let mut cmd = Command::new(&builder.initial_cargo); ++ cmd.arg("vendor").arg(dst_vendor).current_dir(&dst_libsysroot); ++ cmd.env("RUSTC_BOOTSTRAP", "1"); ++ builder.info("Dist src"); ++ let _time = timeit(builder); ++ builder.run(&mut cmd); ++ ++ builder.remove(&temp_lock); ++ + tarball.generate() + } + } +diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs +index 3ed53452309..1fc0d887748 100644 +--- a/src/bootstrap/src/lib.rs ++++ b/src/bootstrap/src/lib.rs +@@ -1437,6 +1437,27 @@ fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> { + paths + } + ++ /// Copies a file from `src` to `dst` and doesn't use links, so ++ /// that the copy can be modified without affecting the original. ++ pub fn really_copy(&self, src: &Path, dst: &Path) { ++ if self.config.dry_run() { ++ return; ++ } ++ self.verbose_than(1, &format!("Copy {:?} to {:?}", src, dst)); ++ if src == dst { ++ return; ++ } ++ let _ = fs::remove_file(&dst); ++ let metadata = t!(src.symlink_metadata()); ++ if let Err(e) = fs::copy(src, dst) { ++ panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e) ++ } ++ t!(fs::set_permissions(dst, metadata.permissions())); ++ let atime = FileTime::from_last_access_time(&metadata); ++ let mtime = FileTime::from_last_modification_time(&metadata); ++ t!(filetime::set_file_times(dst, atime, mtime)); ++ } ++ + /// Copies a file from `src` to `dst` + pub fn copy(&self, src: &Path, dst: &Path) { + self.copy_internal(src, dst, false); diff --git a/build/buildconfig.py b/build/buildconfig.py new file mode 100644 index 0000000000..527690c2b0 --- /dev/null +++ b/build/buildconfig.py @@ -0,0 +1,19 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import sys + +from mozbuild.backend.configenvironment import PartialConfigEnvironment +from mozbuild.base import MozbuildObject + +config = MozbuildObject.from_environment() +partial_config = PartialConfigEnvironment(config.topobjdir) + +for var in ("topsrcdir", "topobjdir"): + value = getattr(config, var) + setattr(sys.modules[__name__], var, value) + +for var in ("defines", "substs", "get_dependencies"): + value = getattr(partial_config, var) + setattr(sys.modules[__name__], var, value) diff --git a/build/cargo-host-linker b/build/cargo-host-linker new file mode 100755 index 0000000000..cbd0472bf7 --- /dev/null +++ b/build/cargo-host-linker @@ -0,0 +1,3 @@ +#!/bin/sh +# See comment in cargo-linker. +eval ${MOZ_CARGO_WRAP_HOST_LD} ${MOZ_CARGO_WRAP_HOST_LDFLAGS} '"$@"' diff --git a/build/cargo-host-linker.bat b/build/cargo-host-linker.bat new file mode 100644 index 0000000000..80e6eab273 --- /dev/null +++ b/build/cargo-host-linker.bat @@ -0,0 +1,3 @@ +@echo off +REM See comment in cargo-linker (without extension) +%MOZ_CARGO_WRAP_HOST_LD% %MOZ_CARGO_WRAP_HOST_LDFLAGS% %* diff --git a/build/cargo-linker b/build/cargo-linker new file mode 100755 index 0000000000..898e21d482 --- /dev/null +++ b/build/cargo-linker @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 + +# If you want to use a custom linker with Cargo, Cargo requires that you +# specify it in Cargo.toml or via the matching environment variable. +# Passing extra options to the linker is possible with Cargo via +# RUSTFLAGS='-C link-args', but testing showed that doing this reliably +# was difficult. +# +# Our solution to these problems is to use this wrapper script. We pass +# in the LD and the LDFLAGS to use via environment variables. +# +# * MOZ_CARGO_WRAP_LD is equivalent to CC on Unix-y platforms, and CC +# frequently has additional arguments in addition to the compiler +# itself. +# +# * MOZ_CARGO_WRAP_LDFLAGS contains space-separated arguments to pass, +# and not quoting it ensures that each of those arguments is passed +# as a separate argument to the actual LD. +# +# * In rare cases, we also need MOZ_CARGO_WRAP_LD_CXX, which is the +# equivalent of CXX, when linking C++ code. Usually, this should +# simply work by the use of CC and -lstdc++ (added by cc-rs). +# However, in the case of sanitizer runtimes, there is a separate +# runtime for C and C++ and linking C++ code with the C runtime can +# fail if the requested feature is in the C++ runtime only (bug 1747298). + +import os +import sys + +# This is not necessarily run with a virtualenv python, so add +# the necessary directory for the shellutil module. +base_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) +sys.path.insert(0, os.path.join(base_dir, "python", "mozbuild")) +from mozbuild.shellutil import split + + +SANITIZERS = { + "asan": "address", + "hwasan": "hwaddress", + "lsan": "leak", + "msan": "memory", + "tsan": "thread", +} + +use_clang_sanitizer = os.environ.get("MOZ_CLANG_NEWER_THAN_RUSTC_LLVM") +wrap_ld = os.environ["MOZ_CARGO_WRAP_LD"] +args = split(os.environ["MOZ_CARGO_WRAP_LDFLAGS"]) +for arg in sys.argv[1:]: + if arg in ["-lc++", "-lstdc++"]: + wrap_ld = os.environ["MOZ_CARGO_WRAP_LD_CXX"] + elif use_clang_sanitizer and arg.endswith("san.a"): + # When clang is newer than rustc's LLVM, we replace rust's sanitizer + # runtimes with clang's. + filename = os.path.basename(arg) + prefix, dot, suffix = filename[:-2].rpartition(".") + if ( + prefix.startswith("librustc-") + and prefix.endswith("_rt") and dot == "." + ): + args.append(f"-fsanitize={SANITIZERS[suffix]}") + continue + args.append(arg) + +wrap_ld = split(wrap_ld) +os.execvp(wrap_ld[0], wrap_ld + args) diff --git a/build/cargo-linker.bat b/build/cargo-linker.bat new file mode 100644 index 0000000000..36ab80dac3 --- /dev/null +++ b/build/cargo-linker.bat @@ -0,0 +1,2 @@ +@echo off +%MOZ_CARGO_WRAP_LD% %MOZ_CARGO_WRAP_LDFLAGS% %* diff --git a/build/cargo/cargo-audit.yaml b/build/cargo/cargo-audit.yaml new file mode 100644 index 0000000000..8efb56acff --- /dev/null +++ b/build/cargo/cargo-audit.yaml @@ -0,0 +1,6 @@ +--- +command: cargo-audit +continue_on_error: false +cargo_build_flags: + - -f + - "{topsrcdir}/Cargo.lock" diff --git a/build/cargo/cargo-check.yaml b/build/cargo/cargo-check.yaml new file mode 100644 index 0000000000..54fe0fb825 --- /dev/null +++ b/build/cargo/cargo-check.yaml @@ -0,0 +1,5 @@ +--- +command: cargo-check +continue_on_error: true +# cargo_build_flags: [] +requires_export: true diff --git a/build/cargo/cargo-clippy.yaml b/build/cargo/cargo-clippy.yaml new file mode 100644 index 0000000000..74e57cdedf --- /dev/null +++ b/build/cargo/cargo-clippy.yaml @@ -0,0 +1,5 @@ +--- +command: cargo-clippy +continue_on_error: true +requires_export: true +# cargo_build_flags: [] diff --git a/build/cargo/cargo-deny.yaml b/build/cargo/cargo-deny.yaml new file mode 100644 index 0000000000..fde45e37d9 --- /dev/null +++ b/build/cargo/cargo-deny.yaml @@ -0,0 +1,10 @@ +--- +command: cargo-deny +continue_on_error: true +cargo_build_flags: + - --frozen + - --manifest-path + - "{manifest}" + - --target={arch} + - --features + - "{features}" diff --git a/build/cargo/cargo-machete.yaml b/build/cargo/cargo-machete.yaml new file mode 100644 index 0000000000..42ec301ee0 --- /dev/null +++ b/build/cargo/cargo-machete.yaml @@ -0,0 +1,4 @@ +--- +command: cargo-machete +continue_on_error: true +cargo_build_flags: ["{topsrcdir}/{directory}/Cargo.toml"] diff --git a/build/cargo/cargo-udeps.yaml b/build/cargo/cargo-udeps.yaml new file mode 100644 index 0000000000..a33cfcf873 --- /dev/null +++ b/build/cargo/cargo-udeps.yaml @@ -0,0 +1,4 @@ +--- +command: cargo-udeps +continue_on_error: true +# cargo_build_flags: [] diff --git a/build/checksums.py b/build/checksums.py new file mode 100755 index 0000000000..1a393b4a6d --- /dev/null +++ b/build/checksums.py @@ -0,0 +1,154 @@ +#!/usr/bin/python +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import hashlib +import logging +import os +from optparse import OptionParser + +logger = logging.getLogger("checksums.py") + + +def digest_file(filename, digest, chunk_size=131072): + """Produce a checksum for the file specified by 'filename'. 'filename' + is a string path to a file that is opened and read in this function. The + checksum algorithm is specified by 'digest' and is a valid OpenSSL + algorithm. If the digest used is not valid or Python's hashlib doesn't + work, the None object will be returned instead. The size of blocks + that this function will read from the file object it opens based on + 'filename' can be specified by 'chunk_size', which defaults to 1K""" + assert not os.path.isdir(filename), "this function only works with files" + + logger.debug("Creating new %s object" % digest) + h = hashlib.new(digest) + with open(filename, "rb") as f: + while True: + data = f.read(chunk_size) + if not data: + logger.debug("Finished reading in file") + break + h.update(data) + hash = h.hexdigest() + logger.debug("Hash for %s is %s" % (filename, hash)) + return hash + + +def process_files(dirs, output_filename, digests): + """This function takes a list of directory names, 'drs'. It will then + compute the checksum for each of the files in these by by opening the files. + Once each file is read and its checksum is computed, this function + will write the information to the file specified by 'output_filename'. + The path written in the output file will have anything specified by 'strip' + removed from the path. The output file is closed before returning nothing + The algorithm to compute checksums with can be specified by 'digests' + and needs to be a list of valid OpenSSL algorithms. + + The output file is written in the format: + + Example: + d1fa09ae4220 sha1 14250744 firefox-4.0b6pre.en-US.mac64.dmg + """ + + if os.path.exists(output_filename): + logger.debug('Overwriting existing checksums file "%s"' % output_filename) + else: + logger.debug('Creating a new checksums file "%s"' % output_filename) + with open(output_filename, "w+") as output: + for d in dirs: + for root, dirs, files in os.walk(d): + for f in files: + full = os.path.join(root, f) + rel = os.path.relpath(full, d) + + for digest in digests: + hash = digest_file(full, digest) + + output.write( + "%s %s %s %s\n" % (hash, digest, os.path.getsize(full), rel) + ) + + +def setup_logging(level=logging.DEBUG): + """This function sets up the logging module using a speficiable logging + module logging level. The default log level is DEBUG. + + The output is in the format: + - + Example: + DEBUG - Finished reading in file""" + + logger = logging.getLogger("checksums.py") + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler() + handler.setLevel(level) + formatter = logging.Formatter("%(levelname)s - %(message)s") + handler.setFormatter(formatter) + logger.addHandler(handler) + + +def main(): + """This is a main function that parses arguments, sets up logging + and generates a checksum file""" + # Parse command line arguments + parser = OptionParser() + parser.add_option( + "-d", + "--digest", + help="checksum algorithm to use", + action="append", + dest="digests", + ) + parser.add_option( + "-o", + "--output", + help="output file to use", + action="store", + dest="outfile", + default="checksums", + ) + parser.add_option( + "-v", + "--verbose", + help="Be noisy (takes precedence over quiet)", + action="store_true", + dest="verbose", + default=False, + ) + parser.add_option( + "-q", + "--quiet", + help="Be quiet", + action="store_true", + dest="quiet", + default=False, + ) + + options, args = parser.parse_args() + + # Figure out which logging level to use + if options.verbose: + loglevel = logging.DEBUG + elif options.quiet: + loglevel = logging.ERROR + else: + loglevel = logging.INFO + + # Set up logging + setup_logging(loglevel) + + # Validate the digest type to use + if not options.digests: + options.digests = ["sha1"] + + for i in args: + if not os.path.isdir(i): + logger.error("%s is not a directory" % i) + exit(1) + + process_files(args, options.outfile, options.digests) + + +if __name__ == "__main__": + main() diff --git a/build/clang-plugin/.clang-format b/build/clang-plugin/.clang-format new file mode 100644 index 0000000000..9b3aa8b721 --- /dev/null +++ b/build/clang-plugin/.clang-format @@ -0,0 +1 @@ +BasedOnStyle: LLVM diff --git a/build/clang-plugin/ArithmeticArgChecker.cpp b/build/clang-plugin/ArithmeticArgChecker.cpp new file mode 100644 index 0000000000..0042961b32 --- /dev/null +++ b/build/clang-plugin/ArithmeticArgChecker.cpp @@ -0,0 +1,60 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ArithmeticArgChecker.h" +#include "CustomMatchers.h" + +void ArithmeticArgChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + callExpr(allOf(hasDeclaration(noArithmeticExprInArgs()), + anyOf(hasDescendant( + binaryOperator( + allOf(binaryArithmeticOperator(), + hasLHS(hasDescendant(declRefExpr())), + hasRHS(hasDescendant(declRefExpr())))) + .bind("node")), + hasDescendant( + unaryOperator( + allOf(unaryArithmeticOperator(), + hasUnaryOperand(allOf( + hasType(builtinType()), + anyOf(hasDescendant(declRefExpr()), + declRefExpr()))))) + .bind("node"))))) + .bind("call"), + this); + AstMatcher->addMatcher( + cxxConstructExpr( + allOf(hasDeclaration(noArithmeticExprInArgs()), + anyOf(hasDescendant( + binaryOperator( + allOf(binaryArithmeticOperator(), + hasLHS(hasDescendant(declRefExpr())), + hasRHS(hasDescendant(declRefExpr())))) + .bind("node")), + hasDescendant( + unaryOperator( + allOf(unaryArithmeticOperator(), + hasUnaryOperand(allOf( + hasType(builtinType()), + anyOf(hasDescendant(declRefExpr()), + declRefExpr()))))) + .bind("node"))))) + .bind("call"), + this); +} + +void ArithmeticArgChecker::check(const MatchFinder::MatchResult &Result) { + const char *Error = + "cannot pass an arithmetic expression of built-in types to %0"; + const Expr *Expression = Result.Nodes.getNodeAs("node"); + if (const CallExpr *Call = Result.Nodes.getNodeAs("call")) { + diag(Expression->getBeginLoc(), Error, DiagnosticIDs::Error) + << Call->getDirectCallee(); + } else if (const CXXConstructExpr *Ctr = + Result.Nodes.getNodeAs("call")) { + diag(Expression->getBeginLoc(), Error, DiagnosticIDs::Error) + << Ctr->getConstructor(); + } +} diff --git a/build/clang-plugin/ArithmeticArgChecker.h b/build/clang-plugin/ArithmeticArgChecker.h new file mode 100644 index 0000000000..62165b716b --- /dev/null +++ b/build/clang-plugin/ArithmeticArgChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ArithmeticArgChecker_h__ +#define ArithmeticArgChecker_h__ + +#include "plugin.h" + +class ArithmeticArgChecker : public BaseCheck { +public: + ArithmeticArgChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/AssertAssignmentChecker.cpp b/build/clang-plugin/AssertAssignmentChecker.cpp new file mode 100644 index 0000000000..467de28d63 --- /dev/null +++ b/build/clang-plugin/AssertAssignmentChecker.cpp @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AssertAssignmentChecker.h" +#include "CustomMatchers.h" + +void AssertAssignmentChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + callExpr(isAssertAssignmentTestFunc()).bind("funcCall"), this); +} + +void AssertAssignmentChecker::check(const MatchFinder::MatchResult &Result) { + const CallExpr *FuncCall = Result.Nodes.getNodeAs("funcCall"); + + if (FuncCall && hasSideEffectAssignment(FuncCall)) { + diag(FuncCall->getBeginLoc(), "Forbidden assignment in assert expression", + DiagnosticIDs::Error); + } +} diff --git a/build/clang-plugin/AssertAssignmentChecker.h b/build/clang-plugin/AssertAssignmentChecker.h new file mode 100644 index 0000000000..5e47b62183 --- /dev/null +++ b/build/clang-plugin/AssertAssignmentChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef AssertAssignmentChecker_h__ +#define AssertAssignmentChecker_h__ + +#include "plugin.h" + +class AssertAssignmentChecker : public BaseCheck { +public: + AssertAssignmentChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/BaseCheck.h b/build/clang-plugin/BaseCheck.h new file mode 100644 index 0000000000..867b82d2ad --- /dev/null +++ b/build/clang-plugin/BaseCheck.h @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BaseCheck_h__ +#define BaseCheck_h__ + +class MozContext {}; +typedef MozContext ContextType; + +class BaseCheck : public MatchFinder::MatchCallback { +public: + BaseCheck(StringRef CheckName, ContextType *Context) {} + virtual void registerMatchers(MatchFinder *Finder) {} + virtual void registerPPCallbacks(CompilerInstance &CI) {} + virtual void check(const MatchFinder::MatchResult &Result) {} + DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, + DiagnosticIDs::Level Level = DiagnosticIDs::Warning) { + DiagnosticsEngine &Diag = Context->getDiagnostics(); + unsigned ID = Diag.getDiagnosticIDs()->getCustomDiagID(Level, Description); + return Diag.Report(Loc, ID); + } + +private: + void run(const MatchFinder::MatchResult &Result) override { + Context = Result.Context; + check(Result); + } + +private: + ASTContext *Context; +}; + +#endif diff --git a/build/clang-plugin/CanRunScriptChecker.cpp b/build/clang-plugin/CanRunScriptChecker.cpp new file mode 100644 index 0000000000..613fe81e19 --- /dev/null +++ b/build/clang-plugin/CanRunScriptChecker.cpp @@ -0,0 +1,450 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This checker implements the "can run script" analysis. The idea is to detect + * functions that can run script that are being passed reference-counted + * arguments (including "this") whose refcount might go to zero as a result of + * the script running. We want to prevent that. + * + * The approach is to attempt to enforce the following invariants on the call + * graph: + * + * 1) Any caller of a MOZ_CAN_RUN_SCRIPT function is itself MOZ_CAN_RUN_SCRIPT. + * 2) If a virtual MOZ_CAN_RUN_SCRIPT method overrides a base class method, + * that base class method is also MOZ_CAN_RUN_SCRIPT. + * + * Invariant 2 ensures that we don't accidentally call a MOZ_CAN_RUN_SCRIPT + * function via a base-class virtual call. Invariant 1 ensures that + * the property of being able to run script propagates up the callstack. There + * is an opt-out for invariant 1: A function (declaration _or_ implementation) + * can be decorated with MOZ_CAN_RUN_SCRIPT_BOUNDARY to indicate that we do not + * require it or any of its callers to be MOZ_CAN_RUN_SCRIPT even if it calls + * MOZ_CAN_RUN_SCRIPT functions. + * + * There are two known holes in invariant 1, apart from the + * MOZ_CAN_RUN_SCRIPT_BOUNDARY opt-out: + * + * - Functions called via function pointers can be MOZ_CAN_RUN_SCRIPT even if + * their caller is not, because we have no way to determine from the function + * pointer what function is being called. + * - MOZ_CAN_RUN_SCRIPT destructors can happen in functions that are not + * MOZ_CAN_RUN_SCRIPT. + * https://bugzilla.mozilla.org/show_bug.cgi?id=1535523 tracks this. + * + * Given those invariants we then require that when calling a MOZ_CAN_RUN_SCRIPT + * function all refcounted arguments (including "this") satisfy one of these + * conditions: + * a) The argument is held via a strong pointer on the stack. + * b) The argument is a const strong pointer member of "this". We know "this" + * is being kept alive, and a const strong pointer member can't drop its ref + * until "this" dies. + * c) The argument is an argument of the caller (and hence held by a strong + * pointer somewhere higher up the callstack). + * d) The argument is explicitly annotated with MOZ_KnownLive, which indicates + * that something is guaranteed to keep it alive (e.g. it's rooted via a JS + * reflector). + * e) The argument is constexpr and therefore cannot disappear. + */ + +#include "CanRunScriptChecker.h" +#include "CustomMatchers.h" +#include "clang/Lex/Lexer.h" + +void CanRunScriptChecker::registerMatchers(MatchFinder *AstMatcher) { + auto Refcounted = qualType(hasDeclaration(cxxRecordDecl(isRefCounted()))); + auto StackSmartPtr = ignoreTrivials(declRefExpr(to(varDecl( + hasAutomaticStorageDuration(), hasType(isSmartPtrToRefCounted()))))); + auto ConstMemberOfThisSmartPtr = + memberExpr(hasType(isSmartPtrToRefCounted()), hasType(isConstQualified()), + hasObjectExpression(cxxThisExpr())); + // A smartptr can be known-live for three reasons: + // 1) It's declared on the stack. + // 2) It's a const member of "this". We know "this" is alive (recursively) + // and const members can't change their value hence can't drop their + // reference until "this" gets destroyed. + // 3) It's an immediate temporary being constructed at the point where the + // call is happening. + auto KnownLiveSmartPtr = anyOf( + StackSmartPtr, ConstMemberOfThisSmartPtr, + ignoreTrivials(cxxConstructExpr(hasType(isSmartPtrToRefCounted())))); + + auto MozKnownLiveCall = + ignoreTrivials(callExpr(callee(functionDecl(hasName("MOZ_KnownLive"))))); + + // Params of the calling function are presumed live, because it itself should + // be MOZ_CAN_RUN_SCRIPT. Note that this is subject to + // https://bugzilla.mozilla.org/show_bug.cgi?id=1537656 at the moment. + auto KnownLiveParam = anyOf( + // "this" is OK + cxxThisExpr(), + // A parameter of the calling function is OK. + declRefExpr(to(parmVarDecl()))); + + auto KnownLiveMemberOfParam = + memberExpr(hasKnownLiveAnnotation(), + hasObjectExpression(anyOf( + ignoreTrivials(KnownLiveParam), + declRefExpr(to(varDecl(hasAutomaticStorageDuration())))))); + + // A matcher that matches various things that are known to be live directly, + // without making any assumptions about operators. + auto KnownLiveBaseExceptRef = anyOf( + // Things that are known to be a stack or immutable refptr. + KnownLiveSmartPtr, + // MOZ_KnownLive() calls. + MozKnownLiveCall, + // Params of the caller function. + KnownLiveParam, + // Members of the params that are marked as MOZ_KNOWN_LIVE + KnownLiveMemberOfParam, + // Constexpr things. + declRefExpr(to(varDecl(isConstexpr())))); + + // A reference of smart ptr which is initialized with known live thing is OK. + // FIXME: This does not allow nested references. + auto RefToKnownLivePtr = ignoreTrivials(declRefExpr(to(varDecl( + hasAutomaticStorageDuration(), hasType(referenceType()), + hasInitializer(anyOf( + KnownLiveSmartPtr, KnownLiveParam, KnownLiveMemberOfParam, + conditionalOperator( + hasFalseExpression(ignoreTrivials(anyOf( + KnownLiveSmartPtr, KnownLiveParam, KnownLiveMemberOfParam, + declRefExpr(to(varDecl(isConstexpr()))), + // E.g., for RefPtr::operator*() + cxxOperatorCallExpr( + hasOverloadedOperatorName("*"), + hasAnyArgument( + anyOf(KnownLiveBaseExceptRef, + ignoreTrivials(KnownLiveMemberOfParam))), + argumentCountIs(1)), + // E.g., for *T + unaryOperator(unaryDereferenceOperator(), + hasUnaryOperand( + ignoreTrivials(KnownLiveBaseExceptRef)))))), + hasTrueExpression(ignoreTrivials(anyOf( + KnownLiveSmartPtr, KnownLiveParam, KnownLiveMemberOfParam, + declRefExpr(to(varDecl(isConstexpr()))), + // E.g., for RefPtr::operator*() + cxxOperatorCallExpr( + hasOverloadedOperatorName("*"), + hasAnyArgument( + anyOf(KnownLiveBaseExceptRef, + ignoreTrivials(KnownLiveMemberOfParam))), + argumentCountIs(1)), + // E.g., for *T + unaryOperator(unaryDereferenceOperator(), + hasUnaryOperand(ignoreTrivials( + KnownLiveBaseExceptRef))))))))))))); + + // A matcher that matches various things that are known to be live directly, + // without making any assumptions about operators. + auto KnownLiveBase = + anyOf(KnownLiveBaseExceptRef, + // Smart pointer refs initialized with known live smart ptrs. + RefToKnownLivePtr); + + // A matcher that matches various known-live things that don't involve + // non-unary operators. + auto KnownLiveSimple = anyOf( + // Things that are just known live. + KnownLiveBase, + // Method calls on a live things that are smart ptrs. Note that we don't + // want to allow general method calls on live things, because those can + // return non-live objects (e.g. consider "live_pointer->foo()" as an + // example). For purposes of this analysis we are assuming the method + // calls on smart ptrs all just return the pointer inside, + cxxMemberCallExpr( + on(anyOf(allOf(hasType(isSmartPtrToRefCounted()), KnownLiveBase), + // Allow it if calling a member method which is marked as + // MOZ_KNOWN_LIVE + KnownLiveMemberOfParam))), + // operator* or operator-> on a thing that is already known to be live. + cxxOperatorCallExpr( + hasAnyOverloadedOperatorName("*", "->"), + hasAnyArgument( + anyOf(KnownLiveBase, ignoreTrivials(KnownLiveMemberOfParam))), + argumentCountIs(1)), + // A dereference on a thing that is known to be live. This is _not_ + // caught by the "operator* or operator->" clause above, because + // cxxOperatorCallExpr() only catches cases when a class defines + // operator*. The default (built-in) operator* matches unaryOperator() + // instead.), + unaryOperator( + unaryDereferenceOperator(), + hasUnaryOperand( + // If we're doing *someArg, the argument of the dereference is an + // ImplicitCastExpr LValueToRValue which has the DeclRefExpr as an + // argument. We could try to match that explicitly with a custom + // matcher (none of the built-in matchers seem to match on the + // thing being cast for an implicitCastExpr), but it's simpler to + // just use ignoreTrivials to strip off the cast. + ignoreTrivials(KnownLiveBase))), + // Taking a pointer to a live reference. We explicitly want to exclude + // things that are not of type reference-to-refcounted or type refcounted, + // because if someone takes a pointer to a pointer to refcounted or a + // pointer to a smart ptr and passes those in to a callee that definitely + // does not guarantee liveness; in fact the callee could modify those + // things! In practice they would be the wrong type anyway, though, so + // it's hard to add a test for this. + unaryOperator(hasOperatorName("&"), + hasUnaryOperand(allOf(anyOf(hasType(references(Refcounted)), + hasType(Refcounted)), + ignoreTrivials(KnownLiveBase))))); + + auto KnownLive = anyOf( + // Anything above, of course. + KnownLiveSimple, + // Conditional operators where both arms are live. + conditionalOperator(hasFalseExpression(ignoreTrivials(KnownLiveSimple)), + hasTrueExpression(ignoreTrivials(KnownLiveSimple))) + // We're not handling cases like a dereference of a conditional operator, + // mostly because handling a dereference in general is so ugly. I + // _really_ wish I could just write a recursive matcher here easily. + ); + + auto InvalidArg = ignoreTrivialsConditional( + // We want to consider things if there is anything refcounted involved, + // including in any of the trivials that we otherwise strip off. + anyOf(hasType(Refcounted), hasType(pointsTo(Refcounted)), + hasType(references(Refcounted)), hasType(isSmartPtrToRefCounted())), + // We want to find any expression, + expr( + // which is not known live, + unless(KnownLive), + // and which is not a default arg with value nullptr, since those are + // always safe, + unless(cxxDefaultArgExpr(isNullDefaultArg())), + // and which is not a literal nullptr, + unless(cxxNullPtrLiteralExpr()), expr().bind("invalidArg"))); + + // A matcher which will mark the first invalid argument it finds invalid, but + // will always match, even if it finds no invalid arguments, so it doesn't + // preclude other matchers from running and maybe finding invalid args. + auto OptionalInvalidExplicitArg = anyOf( + // We want to find any argument which is invalid. + hasAnyArgument(InvalidArg), + + // This makes this matcher optional. + anything()); + + // Please note that the hasCanRunScriptAnnotation() matchers are not present + // directly in the cxxMemberCallExpr, callExpr and constructExpr matchers + // because we check that the corresponding functions can run script later in + // the checker code. + AstMatcher->addMatcher( + expr( + anyOf( + // We want to match a method call expression, + cxxMemberCallExpr( + // which optionally has an invalid arg, + OptionalInvalidExplicitArg, + // or which optionally has an invalid this argument, + anyOf(on(InvalidArg), anything()), expr().bind("callExpr")), + // or a regular call expression, + callExpr( + // which optionally has an invalid arg. + OptionalInvalidExplicitArg, expr().bind("callExpr")), + // or a construct expression, + cxxConstructExpr( + // which optionally has an invalid arg. + OptionalInvalidExplicitArg, expr().bind("constructExpr"))), + + anyOf( + // We want to match the parent function. + forFunction(functionDecl().bind("nonCanRunScriptParentFunction")), + + // ... optionally. + anything())), + this); +} + +void CanRunScriptChecker::onStartOfTranslationUnit() { + IsFuncSetBuilt = false; + CanRunScriptFuncs.clear(); +} + +namespace { +/// This class is a callback used internally to match function declarations with +/// the MOZ_CAN_RUN_SCRIPT annotation, adding these functions to the +/// can-run-script function set and making sure the functions they override (if +/// any) also have the annotation. +class FuncSetCallback : public MatchFinder::MatchCallback { +public: + FuncSetCallback(CanRunScriptChecker &Checker, + std::unordered_set &FuncSet) + : CanRunScriptFuncs(FuncSet), Checker(Checker) {} + + void run(const MatchFinder::MatchResult &Result) override; + +private: + /// This method checks the methods overriden by the given parameter. + void checkOverriddenMethods(const CXXMethodDecl *Method); + + std::unordered_set &CanRunScriptFuncs; + CanRunScriptChecker &Checker; +}; + +void FuncSetCallback::run(const MatchFinder::MatchResult &Result) { + const FunctionDecl *Func; + if (auto *Lambda = Result.Nodes.getNodeAs("lambda")) { + Func = Lambda->getCallOperator(); + if (!Func || !hasCustomAttribute(Func)) + return; + } else { + Func = Result.Nodes.getNodeAs("canRunScriptFunction"); + + const char *ErrorAttrInDefinition = + "MOZ_CAN_RUN_SCRIPT must be put in front " + "of the declaration, not the definition"; + const char *NoteAttrInDefinition = "The first declaration exists here"; + if (!Func->isFirstDecl() && + !hasCustomAttribute(Func)) { + const FunctionDecl *FirstDecl = Func->getFirstDecl(); + if (!hasCustomAttribute(FirstDecl)) { + Checker.diag(Func->getLocation(), ErrorAttrInDefinition, + DiagnosticIDs::Error); + Checker.diag(FirstDecl->getLocation(), NoteAttrInDefinition, + DiagnosticIDs::Note); + } + } + } + + CanRunScriptFuncs.insert(Func); + + // If this is a method, we check the methods it overrides. + if (auto *Method = dyn_cast(Func)) { + checkOverriddenMethods(Method); + } +} + +void FuncSetCallback::checkOverriddenMethods(const CXXMethodDecl *Method) { + for (auto OverriddenMethod : Method->overridden_methods()) { + if (!hasCustomAttribute(OverriddenMethod)) { + const char *ErrorNonCanRunScriptOverridden = + "functions marked as MOZ_CAN_RUN_SCRIPT cannot override functions " + "that are not marked MOZ_CAN_RUN_SCRIPT"; + const char *NoteNonCanRunScriptOverridden = + "overridden function declared here"; + + Checker.diag(Method->getLocation(), ErrorNonCanRunScriptOverridden, + DiagnosticIDs::Error); + Checker.diag(OverriddenMethod->getLocation(), + NoteNonCanRunScriptOverridden, DiagnosticIDs::Note); + } + } +} +} // namespace + +void CanRunScriptChecker::buildFuncSet(ASTContext *Context) { + // We create a match finder. + MatchFinder Finder; + // We create the callback which will be called when we find a function with + // a MOZ_CAN_RUN_SCRIPT annotation. + FuncSetCallback Callback(*this, CanRunScriptFuncs); + // We add the matcher to the finder, linking it to our callback. + Finder.addMatcher( + functionDecl(hasCanRunScriptAnnotation()).bind("canRunScriptFunction"), + &Callback); + Finder.addMatcher(lambdaExpr().bind("lambda"), &Callback); + // We start the analysis, given the ASTContext our main checker is in. + Finder.matchAST(*Context); +} + +void CanRunScriptChecker::check(const MatchFinder::MatchResult &Result) { + + // If the set of functions which can run script is not yet built, then build + // it. + if (!IsFuncSetBuilt) { + buildFuncSet(Result.Context); + IsFuncSetBuilt = true; + } + + const char *ErrorInvalidArg = + "arguments must all be strong refs or caller's parameters when calling a " + "function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object " + "argument). '%0' is neither."; + + const char *ErrorNonCanRunScriptParent = + "functions marked as MOZ_CAN_RUN_SCRIPT can only be called from " + "functions also marked as MOZ_CAN_RUN_SCRIPT"; + const char *NoteNonCanRunScriptParent = "caller function declared here"; + + const Expr *InvalidArg; + if (const CXXDefaultArgExpr *defaultArg = + Result.Nodes.getNodeAs("invalidArg")) { + InvalidArg = defaultArg->getExpr(); + } else { + InvalidArg = Result.Nodes.getNodeAs("invalidArg"); + } + + const CallExpr *Call = Result.Nodes.getNodeAs("callExpr"); + // If we don't find the FunctionDecl linked to this call or if it's not marked + // as can-run-script, consider that we didn't find a match. + if (Call && (!Call->getDirectCallee() || + !CanRunScriptFuncs.count(Call->getDirectCallee()))) { + Call = nullptr; + } + + const CXXConstructExpr *Construct = + Result.Nodes.getNodeAs("constructExpr"); + + // If we don't find the CXXConstructorDecl linked to this construct expression + // or if it's not marked as can-run-script, consider that we didn't find a + // match. + if (Construct && (!Construct->getConstructor() || + !CanRunScriptFuncs.count(Construct->getConstructor()))) { + Construct = nullptr; + } + + const FunctionDecl *ParentFunction = + Result.Nodes.getNodeAs("nonCanRunScriptParentFunction"); + // If the parent function can run script, consider that we didn't find a match + // because we only care about parent functions which can't run script. + // + // In addition, If the parent function is annotated as a + // CAN_RUN_SCRIPT_BOUNDARY, we don't want to complain about it calling a + // CAN_RUN_SCRIPT function. This is a mechanism to opt out of the infectious + // nature of CAN_RUN_SCRIPT which is necessary in some tricky code like + // Bindings. + if (ParentFunction && + (CanRunScriptFuncs.count(ParentFunction) || + hasCustomAttribute(ParentFunction))) { + ParentFunction = nullptr; + } + + // Get the call range from either the CallExpr or the ConstructExpr. + SourceRange CallRange; + if (Call) { + CallRange = Call->getSourceRange(); + } else if (Construct) { + CallRange = Construct->getSourceRange(); + } else { + // If we have neither a Call nor a Construct, we have nothing do to here. + return; + } + + // If we have an invalid argument in the call, we emit the diagnostic to + // signal it. + if (InvalidArg) { + const StringRef invalidArgText = Lexer::getSourceText( + CharSourceRange::getTokenRange(InvalidArg->getSourceRange()), + Result.Context->getSourceManager(), Result.Context->getLangOpts()); + diag(InvalidArg->getExprLoc(), ErrorInvalidArg, DiagnosticIDs::Error) + << InvalidArg->getSourceRange() << invalidArgText; + } + + // If the parent function is not marked as MOZ_CAN_RUN_SCRIPT, we emit an + // error and a not indicating it. + if (ParentFunction) { + assert(!hasCustomAttribute(ParentFunction) && + "Matcher missed something"); + + diag(CallRange.getBegin(), ErrorNonCanRunScriptParent, DiagnosticIDs::Error) + << CallRange; + + diag(ParentFunction->getCanonicalDecl()->getLocation(), + NoteNonCanRunScriptParent, DiagnosticIDs::Note); + } +} diff --git a/build/clang-plugin/CanRunScriptChecker.h b/build/clang-plugin/CanRunScriptChecker.h new file mode 100644 index 0000000000..4516609999 --- /dev/null +++ b/build/clang-plugin/CanRunScriptChecker.h @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CanRunScriptChecker_h__ +#define CanRunScriptChecker_h__ + +#include "plugin.h" +#include + +class CanRunScriptChecker : public BaseCheck { +public: + CanRunScriptChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; + + // Simply initialize the can-run-script function set at the beginning of each + // translation unit. + void onStartOfTranslationUnit() override; + +private: + /// Runs the inner matcher on the AST to find all the can-run-script + /// functions using custom rules (not only the annotation). + void buildFuncSet(ASTContext *Context); + + bool IsFuncSetBuilt; + std::unordered_set CanRunScriptFuncs; +}; + +#endif diff --git a/build/clang-plugin/Checks.inc b/build/clang-plugin/Checks.inc new file mode 100644 index 0000000000..97c77547ac --- /dev/null +++ b/build/clang-plugin/Checks.inc @@ -0,0 +1,44 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// The list of checker classes that are compatible with clang-tidy. + +CHECK(ArithmeticArgChecker, "arithmetic-argument") +CHECK(AssertAssignmentChecker, "assignment-in-assert") +CHECK(CanRunScriptChecker, "can-run-script") +CHECK(DanglingOnTemporaryChecker, "dangling-on-temporary") +CHECK(ExplicitImplicitChecker, "implicit-constructor") +CHECK(ExplicitOperatorBoolChecker, "explicit-operator-bool") +CHECK(JSHandleRootedTypedefChecker, "js-handle-rooted-typedef") +CHECK(KungFuDeathGripChecker, "kungfu-death-grip") +CHECK(KnownLiveChecker, "known-live") +#ifdef TARGET_IS_WINDOWS +CHECK(LoadLibraryUsageChecker, "load-library-usage") +CHECK(FopenUsageChecker, "fopen-usage") +#endif +CHECK(MustOverrideChecker, "must-override") +CHECK(MustReturnFromCallerChecker, "must-return-from-caller") +CHECK(NaNExprChecker, "nan-expr") +CHECK(NoPrincipalGetURI, "no-principal-geturi") +CHECK(NeedsNoVTableTypeChecker, "needs-no-vtable-type") +CHECK(NoAddRefReleaseOnReturnChecker, "no-addref-release-on-return") +CHECK(NoAutoTypeChecker, "no-auto-type") +CHECK(NoDuplicateRefCntMemberChecker, "no-duplicate-refcnt-member") +CHECK(NoExplicitMoveConstructorChecker, "no-explicit-move-constructor") +CHECK(NoNewThreadsChecker, "no-new-threads") +CHECK(NonMemMovableMemberChecker, "non-memmovable-member") +CHECK(NonMemMovableTemplateArgChecker, "non-memmovable-template-arg") +CHECK(NoUsingNamespaceMozillaJavaChecker, "no-using-namespace-mozilla-java") +CHECK(NonParamInsideFunctionDeclChecker, "non-memmovable-template-arg") +CHECK(NonTrivialTypeInFfiChecker, "non-trivial-type-in-ffi-boundary") +CHECK(OverrideBaseCallChecker, "override-base-call") +CHECK(OverrideBaseCallUsageChecker, "override-base-call-usage") +CHECK(ParamTraitsEnumChecker, "paramtraits-enum") +CHECK(RefCountedCopyConstructorChecker, "refcounted-copy-constructor") +CHECK(RefCountedInsideLambdaChecker, "refcounted-inside-lambda") +CHECK(RefCountedThisInsideConstructorChecker, "refcount-within-constructor") +CHECK(ScopeChecker, "scope") +CHECK(SprintfLiteralChecker, "sprintf-literal") +CHECK(TrivialCtorDtorChecker, "trivial-constructor-destructor") +CHECK(TrivialDtorChecker, "trivial-destructor") diff --git a/build/clang-plugin/ChecksIncludes.inc b/build/clang-plugin/ChecksIncludes.inc new file mode 100644 index 0000000000..d029d6ea30 --- /dev/null +++ b/build/clang-plugin/ChecksIncludes.inc @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// The list of #include directives necessary for the checker classes that +// are compatible with clang-tidy. + +#include "ArithmeticArgChecker.h" +#include "AssertAssignmentChecker.h" +#include "CanRunScriptChecker.h" +#include "DanglingOnTemporaryChecker.h" +#include "ExplicitImplicitChecker.h" +#include "ExplicitOperatorBoolChecker.h" +#ifdef TARGET_IS_WINDOWS +#include "LoadLibraryUsageChecker.h" +#include "FopenUsageChecker.h" +#endif +#include "JSHandleRootedTypedefChecker.h" +#include "KungFuDeathGripChecker.h" +#include "KnownLiveChecker.h" +#include "MustOverrideChecker.h" +#include "MustReturnFromCallerChecker.h" +#include "NaNExprChecker.h" +#include "NoPrincipalGetURI.h" +#include "NeedsNoVTableTypeChecker.h" +#include "NoAddRefReleaseOnReturnChecker.h" +#include "NoAutoTypeChecker.h" +#include "NoDuplicateRefCntMemberChecker.h" +#include "NoExplicitMoveConstructorChecker.h" +#include "NoNewThreadsChecker.h" +#include "NonMemMovableMemberChecker.h" +#include "NonMemMovableTemplateArgChecker.h" +#include "NonParamInsideFunctionDeclChecker.h" +#include "NonTrivialTypeInFfiChecker.h" +#include "NoUsingNamespaceMozillaJavaChecker.h" +#include "OverrideBaseCallChecker.h" +#include "OverrideBaseCallUsageChecker.h" +#include "ParamTraitsEnumChecker.h" +#include "RefCountedCopyConstructorChecker.h" +#include "RefCountedInsideLambdaChecker.h" +#include "RefCountedThisInsideConstructorChecker.h" +#include "ScopeChecker.h" +#include "SprintfLiteralChecker.h" +#include "TrivialCtorDtorChecker.h" +#include "TrivialDtorChecker.h" diff --git a/build/clang-plugin/CustomAttributes.cpp b/build/clang-plugin/CustomAttributes.cpp new file mode 100644 index 0000000000..d143f5856d --- /dev/null +++ b/build/clang-plugin/CustomAttributes.cpp @@ -0,0 +1,126 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CustomAttributes.h" +#include "plugin.h" +#include "clang/Frontend/FrontendPluginRegistry.h" +#include + +/* Having annotations in the AST unexpectedly impacts codegen. + * Ideally, we'd avoid having annotations at all, by using an API such as + * the one from https://reviews.llvm.org/D31338, and storing the attributes + * data separately from the AST on our own. Unfortunately, there is no such + * API currently in clang, so we must do without. + * We can do something similar, though, where we go through the AST before + * running the checks, create a mapping of AST nodes to attributes, and + * remove the attributes/annotations from the AST nodes. + * Not all declarations can be reached from the decl() AST matcher, though, + * so we do our best effort (getting the other declarations we look at in + * checks). We emit a warning when checks look at a note that still has + * annotations attached (aka, hasn't been seen during our first pass), + * so that those don't go unnoticed. (-Werror should then take care of + * making that an error) + */ + +using namespace clang; +using namespace llvm; + +static DenseMap AttributesCache; + +static CustomAttributesSet CacheAttributes(const Decl *D) { + CustomAttributesSet attrs = {}; + for (auto Attr : D->specific_attrs()) { + auto annotation = Attr->getAnnotation(); +#define ATTR(a) \ + if (annotation == #a) { \ + attrs.has_##a = true; \ + } else +#include "CustomAttributes.inc" +#include "external/CustomAttributes.inc" +#undef ATTR + {} + } + const_cast(D)->dropAttr(); + AttributesCache.insert(std::make_pair(D, attrs)); + return attrs; +} + +#ifndef CLANG_TIDY +static void Report(const Decl *D, const char *message) { + ASTContext &Context = D->getASTContext(); + DiagnosticsEngine &Diag = Context.getDiagnostics(); + unsigned ID = + Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Warning, message); + Diag.Report(D->getBeginLoc(), ID); +} + +class CustomAttributesMatcher + : public ast_matchers::MatchFinder::MatchCallback { +public: + void run(const ast_matchers::MatchFinder::MatchResult &Result) final { + if (auto D = Result.Nodes.getNodeAs("decl")) { + CacheAttributes(D); + } else if (auto L = Result.Nodes.getNodeAs("lambda")) { + CacheAttributes(L->getCallOperator()); + CacheAttributes(L->getLambdaClass()); + } + } +}; + +class CustomAttributesAction : public PluginASTAction { +public: + ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, + StringRef FileName) override { + auto &Context = CI.getASTContext(); + auto AstMatcher = new (Context.Allocate()) MatchFinder(); + auto Matcher = new (Context.Allocate()) + CustomAttributesMatcher(); + AstMatcher->addMatcher(decl().bind("decl"), Matcher); + AstMatcher->addMatcher(lambdaExpr().bind("lambda"), Matcher); + return AstMatcher->newASTConsumer(); + } + + bool ParseArgs(const CompilerInstance &CI, + const std::vector &Args) override { + return true; + } + + ActionType getActionType() override { return AddBeforeMainAction; } +}; + +static FrontendPluginRegistry::Add + X("moz-custom-attributes", "prepare custom attributes for moz-check"); +#endif + +CustomAttributesSet GetAttributes(const Decl *D) { + CustomAttributesSet attrs = {}; + if (D->hasAttr()) { +// If we are not in clang-tidy env push warnings, most likely we are in the +// build environment and this should have been done in AstMatcher - +// CustomAttributesMatcher +#ifndef CLANG_TIDY + Report(D, "Declaration has unhandled annotations."); +#endif + attrs = CacheAttributes(D); + } else { + auto attributes = AttributesCache.find(D); + if (attributes != AttributesCache.end()) { + attrs = attributes->second; + } + } + return attrs; +} + +bool hasCustomAttribute(const clang::Decl *D, CustomAttributes A) { + CustomAttributesSet attrs = GetAttributes(D); + switch (A) { +#define ATTR(a) \ + case a: \ + return attrs.has_##a; +#include "CustomAttributes.inc" +#include "external/CustomAttributes.inc" +#undef ATTR + } + return false; +} diff --git a/build/clang-plugin/CustomAttributes.h b/build/clang-plugin/CustomAttributes.h new file mode 100644 index 0000000000..04c95b7184 --- /dev/null +++ b/build/clang-plugin/CustomAttributes.h @@ -0,0 +1,41 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CustomAttributes_h__ +#define CustomAttributes_h__ + +#include "clang/AST/DeclBase.h" +#include "llvm/ADT/StringRef.h" + +enum CustomAttributes { +#define ATTR(a) a, +#include "CustomAttributes.inc" +#include "external/CustomAttributes.inc" +#undef ATTR +}; + +struct CustomAttributesSet { +#define ATTR(a) bool has_##a : 1; +#include "CustomAttributes.inc" +#include "external/CustomAttributes.inc" +#undef ATTR +}; + +template bool hasCustomAttribute(const clang::Decl *D) { + return false; +} + +extern CustomAttributesSet GetAttributes(const clang::Decl *D); + +#define ATTR(name) \ + template <> inline bool hasCustomAttribute(const clang::Decl *D) { \ + return GetAttributes(D).has_##name; \ + } +#include "CustomAttributes.inc" +#include "external/CustomAttributes.inc" +#undef ATTR + +extern bool hasCustomAttribute(const clang::Decl *D, CustomAttributes A); + +#endif /* CustomAttributes_h__ */ diff --git a/build/clang-plugin/CustomAttributes.inc b/build/clang-plugin/CustomAttributes.inc new file mode 100644 index 0000000000..883676e9c5 --- /dev/null +++ b/build/clang-plugin/CustomAttributes.inc @@ -0,0 +1,31 @@ +ATTR(moz_allow_temporary) +ATTR(moz_can_run_script) +ATTR(moz_can_run_script_for_definition) +ATTR(moz_can_run_script_boundary) +ATTR(moz_global_class) +ATTR(moz_heap_allocator) +ATTR(moz_heap_class) +ATTR(moz_implicit) +ATTR(moz_inherit_type_annotations_from_template_args) +ATTR(moz_is_smartptr_to_refcounted) +ATTR(moz_known_live) +ATTR(moz_may_call_after_must_return) +ATTR(moz_must_override) +ATTR(moz_must_return_from_caller_if_this_is_arg) +ATTR(moz_needs_memmovable_members) +ATTR(moz_needs_memmovable_type) +ATTR(moz_needs_no_vtable_type) +ATTR(moz_no_addref_release_on_return) +ATTR(moz_no_arith_expr_in_arg) +ATTR(moz_no_dangling_on_temporaries) +ATTR(moz_non_autoable) +ATTR(moz_non_memmovable) +ATTR(moz_non_param) +ATTR(moz_non_temporary_class) +ATTR(moz_nonheap_class) +ATTR(moz_required_base_method) +ATTR(moz_stack_class) +ATTR(moz_static_local_class) +ATTR(moz_temporary_class) +ATTR(moz_trivial_ctor_dtor) +ATTR(moz_trivial_dtor) diff --git a/build/clang-plugin/CustomMatchers.h b/build/clang-plugin/CustomMatchers.h new file mode 100644 index 0000000000..97caf4d59c --- /dev/null +++ b/build/clang-plugin/CustomMatchers.h @@ -0,0 +1,494 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CustomMatchers_h__ +#define CustomMatchers_h__ + +#include "MemMoveAnnotation.h" +#include "Utils.h" + +#if CLANG_VERSION_FULL >= 1300 +// Starting with clang-13 Expr::isRValue has been renamed to Expr::isPRValue +#define isRValue isPRValue +#endif + +namespace clang { +namespace ast_matchers { + +/// This matcher will match any function declaration that is declared as a heap +/// allocator. +AST_MATCHER(FunctionDecl, heapAllocator) { + return hasCustomAttribute(&Node); +} + +/// This matcher will match any declaration that is marked as not accepting +/// arithmetic expressions in its arguments. +AST_MATCHER(Decl, noArithmeticExprInArgs) { + return hasCustomAttribute(&Node); +} + +/// This matcher will match any C++ class that is marked as having a trivial +/// constructor and destructor. +AST_MATCHER(CXXRecordDecl, hasTrivialCtorDtor) { + return hasCustomAttribute(&Node); +} + +/// This matcher will match any C++ class that is marked as having a trivial +/// destructor. +AST_MATCHER(CXXRecordDecl, hasTrivialDtor) { + return hasCustomAttribute(&Node); +} + +AST_MATCHER(CXXConstructExpr, allowsTemporary) { + return hasCustomAttribute(Node.getConstructor()); +} + +/// This matcher will match lvalue-ref-qualified methods. +AST_MATCHER(CXXMethodDecl, isLValueRefQualified) { + return Node.getRefQualifier() == RQ_LValue; +} + +/// This matcher will match rvalue-ref-qualified methods. +AST_MATCHER(CXXMethodDecl, isRValueRefQualified) { + return Node.getRefQualifier() == RQ_RValue; +} + +AST_POLYMORPHIC_MATCHER(isFirstParty, + AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt)) { + return !inThirdPartyPath(&Node, &Finder->getASTContext()) && + !ASTIsInSystemHeader(Finder->getASTContext(), Node); +} + +AST_MATCHER(DeclaratorDecl, isNotSpiderMonkey) { + // Detect SpiderMonkey path. Not as strict as isFirstParty, but this is + // expected to disappear soon by getting a common style guide between DOM and + // SpiderMonkey. + std::string Path = Node.getBeginLoc().printToString( + Finder->getASTContext().getSourceManager()); + return Path.find("js") == std::string::npos && + Path.find("xpc") == std::string::npos && + Path.find("XPC") == std::string::npos; +} + +/// This matcher will match temporary expressions. +/// We need this matcher for compatibility with clang 3.* (clang 4 and above +/// insert a MaterializeTemporaryExpr everywhere). +AST_MATCHER(Expr, isTemporary) { + return Node.isRValue() || Node.isXValue() || + isa(&Node); +} + +/// This matcher will match any method declaration that is marked as returning +/// a pointer deleted by the destructor of the class. +AST_MATCHER(CXXMethodDecl, noDanglingOnTemporaries) { + return hasCustomAttribute(&Node); +} + +/// This matcher will match any function declaration that is marked to prohibit +/// calling AddRef or Release on its return value. +AST_MATCHER(FunctionDecl, hasNoAddRefReleaseOnReturnAttr) { + return hasCustomAttribute(&Node); +} + +/// This matcher will match any function declaration that is marked as being +/// allowed to run script. +AST_MATCHER(FunctionDecl, hasCanRunScriptAnnotation) { + return hasCustomAttribute(&Node); +} + +/// This matcher will match all arithmetic binary operators. +AST_MATCHER(BinaryOperator, binaryArithmeticOperator) { + BinaryOperatorKind OpCode = Node.getOpcode(); + return OpCode == BO_Mul || OpCode == BO_Div || OpCode == BO_Rem || + OpCode == BO_Add || OpCode == BO_Sub || OpCode == BO_Shl || + OpCode == BO_Shr || OpCode == BO_And || OpCode == BO_Xor || + OpCode == BO_Or || OpCode == BO_MulAssign || OpCode == BO_DivAssign || + OpCode == BO_RemAssign || OpCode == BO_AddAssign || + OpCode == BO_SubAssign || OpCode == BO_ShlAssign || + OpCode == BO_ShrAssign || OpCode == BO_AndAssign || + OpCode == BO_XorAssign || OpCode == BO_OrAssign; +} + +/// This matcher will match all arithmetic unary operators. +AST_MATCHER(UnaryOperator, unaryArithmeticOperator) { + UnaryOperatorKind OpCode = Node.getOpcode(); + return OpCode == UO_PostInc || OpCode == UO_PostDec || OpCode == UO_PreInc || + OpCode == UO_PreDec || OpCode == UO_Plus || OpCode == UO_Minus || + OpCode == UO_Not; +} + +/// This matcher will match the unary dereference operator +AST_MATCHER(UnaryOperator, unaryDereferenceOperator) { + UnaryOperatorKind OpCode = Node.getOpcode(); + return OpCode == UO_Deref; +} + +/// This matcher will match == and != binary operators. +AST_MATCHER(BinaryOperator, binaryEqualityOperator) { + BinaryOperatorKind OpCode = Node.getOpcode(); + return OpCode == BO_EQ || OpCode == BO_NE; +} + +/// This matcher will match comma operator. +AST_MATCHER(BinaryOperator, binaryCommaOperator) { + BinaryOperatorKind OpCode = Node.getOpcode(); + return OpCode == BO_Comma; +} + +/// This matcher will match floating point types. +AST_MATCHER(QualType, isFloat) { return Node->isRealFloatingType(); } + +/// This matcher will match locations in system headers. This is adopted from +/// isExpansionInSystemHeader in newer clangs, but modified in order to work +/// with old clangs that we use on infra. +AST_POLYMORPHIC_MATCHER(isInSystemHeader, + AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt)) { + return ASTIsInSystemHeader(Finder->getASTContext(), Node); +} + +/// This matcher will match a file "gtest-port.h". The file contains +/// known fopen usages that are OK. +AST_MATCHER(CallExpr, isInWhitelistForFopenUsage) { + static const char Whitelist[] = "gtest-port.h"; + SourceLocation Loc = Node.getBeginLoc(); + StringRef FileName = + getFilename(Finder->getASTContext().getSourceManager(), Loc); + + return llvm::sys::path::rbegin(FileName)->equals(Whitelist); +} + +/// This matcher will match a list of files. These files contain +/// known NaN-testing expressions which we would like to whitelist. +AST_MATCHER(BinaryOperator, isInWhitelistForNaNExpr) { + const char *whitelist[] = {"SkScalar.h", "json_writer.cpp", "State.cpp"}; + + SourceLocation Loc = Node.getOperatorLoc(); + StringRef FileName = + getFilename(Finder->getASTContext().getSourceManager(), Loc); + for (auto itr = std::begin(whitelist); itr != std::end(whitelist); itr++) { + if (llvm::sys::path::rbegin(FileName)->equals(*itr)) { + return true; + } + } + + return false; +} + +AST_MATCHER(CallExpr, isInWhiteListForPrincipalGetUri) { + const auto Whitelist = {"nsIPrincipal.h", "BasePrincipal.cpp", + "ContentPrincipal.cpp"}; + SourceLocation Loc = Node.getBeginLoc(); + StringRef Filename = + getFilename(Finder->getASTContext().getSourceManager(), Loc); + + for (auto Exclusion : Whitelist) { + if (Filename.find(Exclusion) != std::string::npos) { + return true; + } + } + return false; +} + +/// This matcher will match a list of files which contain NS_NewNamedThread +/// code or names of existing threads that we would like to ignore. +AST_MATCHER(CallExpr, isInAllowlistForThreads) { + + // Get the source location of the call. + SourceLocation Loc = Node.getRParenLoc(); + StringRef FileName = + getFilename(Finder->getASTContext().getSourceManager(), Loc); + + const auto rbegin = [](StringRef s) { return llvm::sys::path::rbegin(s); }; + const auto rend = [](StringRef s) { return llvm::sys::path::rend(s); }; + + // Files in the allowlist are (definitionally) explicitly permitted to create + // new threads. + for (auto thread_file : allow_thread_files) { + // All the provided path-elements must match. + const bool match = [&] { + auto it1 = rbegin(FileName), it2 = rbegin(thread_file), + end1 = rend(FileName), end2 = rend(thread_file); + for (; it2 != end2; ++it1, ++it2) { + if (it1 == end1 || !it1->equals(*it2)) { + return false; + } + } + return true; + }(); + if (match) { + return true; + } + } + + // Check the first arg (the name of the thread). + const StringLiteral *nameArg = + dyn_cast(Node.getArg(0)->IgnoreImplicit()); + if (nameArg) { + const StringRef name = nameArg->getString(); + for (auto thread_name : allow_thread_names) { + if (name.equals(thread_name)) { + return true; + } + } + } + + return false; +} + +/// This matcher will match all accesses to AddRef or Release methods. +AST_MATCHER(MemberExpr, isAddRefOrRelease) { + ValueDecl *Member = Node.getMemberDecl(); + CXXMethodDecl *Method = dyn_cast(Member); + if (Method) { + const auto &Name = getNameChecked(Method); + return Name == "AddRef" || Name == "Release"; + } + return false; +} + +/// This matcher will select classes which are refcounted AND have an mRefCnt +/// member. +AST_MATCHER(CXXRecordDecl, hasRefCntMember) { + return isClassRefCounted(&Node) && getClassRefCntMember(&Node); +} + +/// This matcher will select classes which are refcounted. +AST_MATCHER(CXXRecordDecl, isRefCounted) { return isClassRefCounted(&Node); } + +AST_MATCHER(QualType, hasVTable) { return typeHasVTable(Node); } + +AST_MATCHER(CXXRecordDecl, hasNeedsNoVTableTypeAttr) { + return hasCustomAttribute(&Node); +} + +/// This matcher will select classes which are non-memmovable +AST_MATCHER(QualType, isNonMemMovable) { + return NonMemMovable.hasEffectiveAnnotation(Node); +} + +/// This matcher will select classes which require a memmovable template arg +AST_MATCHER(CXXRecordDecl, needsMemMovableTemplateArg) { + return hasCustomAttribute(&Node); +} + +/// This matcher will select classes which require all members to be memmovable +AST_MATCHER(CXXRecordDecl, needsMemMovableMembers) { + return hasCustomAttribute(&Node); +} + +AST_MATCHER(CXXConstructorDecl, isInterestingImplicitCtor) { + const CXXConstructorDecl *Declaration = Node.getCanonicalDecl(); + return + // Skip constructors in system headers + !ASTIsInSystemHeader(Declaration->getASTContext(), *Declaration) && + // Skip ignored namespaces and paths + !isInIgnoredNamespaceForImplicitCtor(Declaration) && + !inThirdPartyPath(Declaration) && + // We only want Converting constructors + Declaration->isConvertingConstructor(false) && + // We don't want copy of move constructors, as those are allowed to be + // implicit + !Declaration->isCopyOrMoveConstructor() && + // We don't want inheriting constructors, since using declarations can't + // have attributes + !Declaration->isInheritingConstructor() && + // We don't want deleted constructors. + !Declaration->isDeleted(); +} + +AST_MATCHER_P(Expr, ignoreTrivials, internal::Matcher, InnerMatcher) { + return InnerMatcher.matches(*IgnoreTrivials(&Node), Finder, Builder); +} + +// Takes two matchers: the first one is a condition; the second is a matcher to +// be applied once we are done unwrapping trivials. While the condition does +// not match and we're looking at a trivial, will keep unwrapping the trivial +// and trying again. Once the condition matches, we will go ahead and unwrap all +// trivials and apply the inner matcher to the result. +// +// The expected use here is if we want to condition a match on some typecheck +// but apply the match to only non-trivials, because there are trivials (e.g. +// casts) that can change types. +AST_MATCHER_P2(Expr, ignoreTrivialsConditional, internal::Matcher, + Condition, internal::Matcher, InnerMatcher) { + const Expr *node = &Node; + while (true) { + if (Condition.matches(*node, Finder, Builder)) { + return InnerMatcher.matches(*IgnoreTrivials(node), Finder, Builder); + } + const Expr *newNode = MaybeSkipOneTrivial(node); + if (newNode == node) { + return false; + } + node = newNode; + } +} + +// We can't call this "isImplicit" since it clashes with an existing matcher in +// clang. +AST_MATCHER(CXXConstructorDecl, isMarkedImplicit) { + return hasCustomAttribute(&Node); +} + +AST_MATCHER(CXXRecordDecl, isConcreteClass) { return !Node.isAbstract(); } + +AST_MATCHER(QualType, autoNonAutoableType) { + if (const AutoType *T = Node->getContainedAutoType()) { + if (const CXXRecordDecl *Rec = T->getAsCXXRecordDecl()) { + return hasCustomAttribute(Rec); + } + } + return false; +} + +AST_MATCHER(CXXConstructorDecl, isExplicitMoveConstructor) { + return Node.isExplicit() && Node.isMoveConstructor(); +} + +AST_MATCHER(CXXConstructorDecl, isCompilerProvidedCopyConstructor) { + return !Node.isUserProvided() && Node.isCopyConstructor(); +} + +AST_MATCHER(CallExpr, isAssertAssignmentTestFunc) { + static const std::string AssertName = "MOZ_AssertAssignmentTest"; + const FunctionDecl *Method = Node.getDirectCallee(); + + return Method && Method->getDeclName().isIdentifier() && + Method->getName() == AssertName; +} + +AST_MATCHER(CallExpr, isSnprintfLikeFunc) { + static const std::string Snprintf = "snprintf"; + static const std::string Vsnprintf = "vsnprintf"; + const FunctionDecl *Func = Node.getDirectCallee(); + + if (!Func || isa(Func)) { + return false; + } + + StringRef Name = getNameChecked(Func); + if (Name != Snprintf && Name != Vsnprintf) { + return false; + } + + return !inThirdPartyPath(Node.getBeginLoc(), + Finder->getASTContext().getSourceManager()) && + !isIgnoredPathForSprintfLiteral( + &Node, Finder->getASTContext().getSourceManager()); +} + +AST_MATCHER(CXXRecordDecl, isLambdaDecl) { return Node.isLambda(); } + +AST_MATCHER(QualType, isRefPtr) { return typeIsRefPtr(Node); } + +AST_MATCHER(QualType, isSmartPtrToRefCounted) { + auto *D = getNonTemplateSpecializedCXXRecordDecl(Node); + if (!D) { + return false; + } + + D = D->getCanonicalDecl(); + + return D && hasCustomAttribute(D); +} + +AST_MATCHER(ClassTemplateSpecializationDecl, isSmartPtrToRefCountedDecl) { + auto *D = dyn_cast_or_null( + Node.getSpecializedTemplate()->getTemplatedDecl()); + if (!D) { + return false; + } + + D = D->getCanonicalDecl(); + + return D && hasCustomAttribute(D); +} + +AST_MATCHER(CXXRecordDecl, hasBaseClasses) { + const CXXRecordDecl *Decl = Node.getCanonicalDecl(); + + // Must have definition and should inherit other classes + return Decl && Decl->hasDefinition() && Decl->getNumBases(); +} + +AST_MATCHER(CXXMethodDecl, isRequiredBaseMethod) { + const CXXMethodDecl *Decl = Node.getCanonicalDecl(); + return Decl && hasCustomAttribute(Decl); +} + +AST_MATCHER(CXXMethodDecl, isNonVirtual) { + const CXXMethodDecl *Decl = Node.getCanonicalDecl(); + return Decl && !Decl->isVirtual(); +} + +AST_MATCHER(FunctionDecl, isMozMustReturnFromCaller) { + const FunctionDecl *Decl = Node.getCanonicalDecl(); + return Decl && + hasCustomAttribute(Decl); +} + +/// This matcher will select default args which have nullptr as the value. +AST_MATCHER(CXXDefaultArgExpr, isNullDefaultArg) { + const Expr *Expr = Node.getExpr(); + return Expr && Expr->isNullPointerConstant(Finder->getASTContext(), + Expr::NPC_NeverValueDependent); +} + +AST_MATCHER(UsingDirectiveDecl, isUsingNamespaceMozillaJava) { + const NamespaceDecl *Namespace = Node.getNominatedNamespace(); + const std::string &FQName = Namespace->getQualifiedNameAsString(); + + static const char NAMESPACE[] = "mozilla::java"; + static const char PREFIX[] = "mozilla::java::"; + + // We match both the `mozilla::java` namespace itself as well as any other + // namespaces contained within the `mozilla::java` namespace. + return !FQName.compare(NAMESPACE) || + !FQName.compare(0, sizeof(PREFIX) - 1, PREFIX); +} + +AST_MATCHER(MemberExpr, hasKnownLiveAnnotation) { + ValueDecl *Member = Node.getMemberDecl(); + FieldDecl *Field = dyn_cast(Member); + return Field && hasCustomAttribute(Field); +} + +#define GENERATE_JSTYPEDEF_PAIR(templateName) \ + {templateName "Function", templateName ""}, \ + {templateName "Id", templateName ""}, \ + {templateName "Object", templateName ""}, \ + {templateName "Script", templateName ""}, \ + {templateName "String", templateName ""}, \ + {templateName "Symbol", templateName ""}, \ + {templateName "BigInt", templateName ""}, \ + {templateName "Value", templateName ""}, \ + {templateName "ValueVector", templateName "Vector"}, \ + {templateName "ObjectVector", templateName "Vector"}, { \ + templateName "IdVector", templateName "Vector" \ + } + +static const char *const JSHandleRootedTypedefMap[][2] = { + GENERATE_JSTYPEDEF_PAIR("JS::Handle"), + GENERATE_JSTYPEDEF_PAIR("JS::MutableHandle"), + GENERATE_JSTYPEDEF_PAIR("JS::Rooted"), + // Technically there is no PersistentRootedValueVector, and that's okay + GENERATE_JSTYPEDEF_PAIR("JS::PersistentRooted"), +}; + +AST_MATCHER(DeclaratorDecl, isUsingJSHandleRootedTypedef) { + QualType Type = Node.getType(); + std::string TypeName = Type.getAsString(); + for (auto &pair : JSHandleRootedTypedefMap) { + if (!TypeName.compare(pair[0])) { + return true; + } + } + return false; +} + +} // namespace ast_matchers +} // namespace clang + +#undef isRValue +#endif diff --git a/build/clang-plugin/CustomTypeAnnotation.cpp b/build/clang-plugin/CustomTypeAnnotation.cpp new file mode 100644 index 0000000000..6e0f44ce05 --- /dev/null +++ b/build/clang-plugin/CustomTypeAnnotation.cpp @@ -0,0 +1,182 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CustomTypeAnnotation.h" +#include "Utils.h" + +CustomTypeAnnotation StackClass = + CustomTypeAnnotation(moz_stack_class, "stack"); +CustomTypeAnnotation GlobalClass = + CustomTypeAnnotation(moz_global_class, "global"); +CustomTypeAnnotation NonHeapClass = + CustomTypeAnnotation(moz_nonheap_class, "non-heap"); +CustomTypeAnnotation HeapClass = CustomTypeAnnotation(moz_heap_class, "heap"); +CustomTypeAnnotation NonTemporaryClass = + CustomTypeAnnotation(moz_non_temporary_class, "non-temporary"); +CustomTypeAnnotation TemporaryClass = + CustomTypeAnnotation(moz_temporary_class, "temporary"); +CustomTypeAnnotation StaticLocalClass = + CustomTypeAnnotation(moz_static_local_class, "static-local"); + +void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck &Check, QualType T, + SourceLocation Loc) { + const char *Inherits = + "%1 is a %0 type because it inherits from a %0 type %2"; + const char *Member = "%1 is a %0 type because member %2 is a %0 type %3"; + const char *Array = "%1 is a %0 type because it is an array of %0 type %2"; + const char *Templ = + "%1 is a %0 type because it has a template argument %0 type %2"; + const char *Implicit = "%1 is a %0 type because %2"; + + AnnotationReason Reason = directAnnotationReason(T); + for (;;) { + switch (Reason.Kind) { + case RK_ArrayElement: + Check.diag(Loc, Array, DiagnosticIDs::Note) << Pretty << T << Reason.Type; + break; + case RK_BaseClass: { + const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl(); + assert(Declaration && "This type should be a C++ class"); + + Check.diag(Declaration->getLocation(), Inherits, DiagnosticIDs::Note) + << Pretty << T << Reason.Type; + break; + } + case RK_Field: + Check.diag(Reason.Field->getLocation(), Member, DiagnosticIDs::Note) + << Pretty << T << Reason.Field << Reason.Type; + break; + case RK_TemplateInherited: { + const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl(); + assert(Declaration && "This type should be a C++ class"); + + Check.diag(Declaration->getLocation(), Templ, DiagnosticIDs::Note) + << Pretty << T << Reason.Type; + break; + } + case RK_Implicit: { + const TagDecl *Declaration = T->getAsTagDecl(); + assert(Declaration && "This type should be a TagDecl"); + + Check.diag(Declaration->getLocation(), Implicit, DiagnosticIDs::Note) + << Pretty << T << Reason.ImplicitReason; + return; + } + default: + // FIXME (bug 1203263): note the original annotation. + return; + } + + T = Reason.Type; + Reason = directAnnotationReason(T); + } +} + +CustomTypeAnnotation::AnnotationReason +CustomTypeAnnotation::directAnnotationReason(QualType T) { + VisitFlags ToVisit = VISIT_FIELDS | VISIT_BASES; + + if (const TagDecl *D = T->getAsTagDecl()) { + // Recurse into template arguments if the annotation + // MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS is present + if (hasCustomAttribute( + D)) { + ToVisit |= VISIT_TMPL_ARGS; + } + + if (hasCustomAttribute(D, Attribute)) { + AnnotationReason Reason = {T, RK_Direct, nullptr, ""}; + return Reason; + } + + std::string ImplAnnotReason = getImplicitReason(D, ToVisit); + if (!ImplAnnotReason.empty()) { + AnnotationReason Reason = {T, RK_Implicit, nullptr, ImplAnnotReason}; + return Reason; + } + } + + // Check if we have a cached answer + void *Key = T.getAsOpaquePtr(); + ReasonCache::iterator Cached = Cache.find(T.getAsOpaquePtr()); + if (Cached != Cache.end()) { + return Cached->second; + } + + // Check if we have a type which we can recurse into + if (const clang::ArrayType *Array = T->getAsArrayTypeUnsafe()) { + if (hasEffectiveAnnotation(Array->getElementType())) { + AnnotationReason Reason{Array->getElementType(), RK_ArrayElement, nullptr, + ""}; + Cache[Key] = Reason; + return Reason; + } + } + + // Recurse into Base classes + if (const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl()) { + if (Declaration->hasDefinition()) { + Declaration = Declaration->getDefinition(); + + if (ToVisit & VISIT_BASES) { + for (const CXXBaseSpecifier &Base : Declaration->bases()) { + if (hasEffectiveAnnotation(Base.getType())) { + AnnotationReason Reason{Base.getType(), RK_BaseClass, nullptr, ""}; + Cache[Key] = Reason; + return Reason; + } + } + } + + if (ToVisit & VISIT_FIELDS) { + for (const FieldDecl *Field : Declaration->fields()) { + if (hasEffectiveAnnotation(Field->getType())) { + AnnotationReason Reason{Field->getType(), RK_Field, Field, ""}; + Cache[Key] = Reason; + return Reason; + } + } + } + + if (ToVisit & VISIT_TMPL_ARGS) { + const ClassTemplateSpecializationDecl *Spec = + dyn_cast(Declaration); + if (Spec) { + const TemplateArgumentList &Args = Spec->getTemplateArgs(); + + AnnotationReason Reason = tmplArgAnnotationReason(Args.asArray()); + if (Reason.Kind != RK_None) { + Cache[Key] = Reason; + return Reason; + } + } + } + } + } + + AnnotationReason Reason{QualType(), RK_None, nullptr, ""}; + Cache[Key] = Reason; + return Reason; +} + +CustomTypeAnnotation::AnnotationReason +CustomTypeAnnotation::tmplArgAnnotationReason(ArrayRef Args) { + for (const TemplateArgument &Arg : Args) { + if (Arg.getKind() == TemplateArgument::Type) { + QualType Type = Arg.getAsType(); + if (hasEffectiveAnnotation(Type)) { + AnnotationReason Reason = {Type, RK_TemplateInherited, nullptr, ""}; + return Reason; + } + } else if (Arg.getKind() == TemplateArgument::Pack) { + AnnotationReason Reason = tmplArgAnnotationReason(Arg.getPackAsArray()); + if (Reason.Kind != RK_None) { + return Reason; + } + } + } + + AnnotationReason Reason = {QualType(), RK_None, nullptr, ""}; + return Reason; +} diff --git a/build/clang-plugin/CustomTypeAnnotation.h b/build/clang-plugin/CustomTypeAnnotation.h new file mode 100644 index 0000000000..453976915a --- /dev/null +++ b/build/clang-plugin/CustomTypeAnnotation.h @@ -0,0 +1,92 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CustomTypeAnnotation_h__ +#define CustomTypeAnnotation_h__ + +#include "CustomAttributes.h" +#include "plugin.h" +#include "llvm/ADT/BitmaskEnum.h" + +class CustomTypeAnnotation { + enum ReasonKind { + RK_None, + RK_Direct, + RK_ArrayElement, + RK_BaseClass, + RK_Field, + RK_TemplateInherited, + RK_Implicit, + }; + struct AnnotationReason { + QualType Type; + ReasonKind Kind; + const FieldDecl *Field; + std::string ImplicitReason; + + bool valid() const { return Kind != RK_None; } + }; + typedef DenseMap ReasonCache; + + CustomAttributes Attribute; + const char *Pretty; + ReasonCache Cache; + +public: + CustomTypeAnnotation(CustomAttributes Attribute, const char *Pretty) + : Attribute(Attribute), Pretty(Pretty){}; + + virtual ~CustomTypeAnnotation() {} + + // Checks if this custom annotation "effectively affects" the given type. + bool hasEffectiveAnnotation(QualType T) { + return directAnnotationReason(T).valid(); + } + void dumpAnnotationReason(BaseCheck &Check, QualType T, SourceLocation Loc); + + void reportErrorIfPresent(BaseCheck &Check, QualType T, SourceLocation Loc, + const char *Error, const char *Note) { + if (hasEffectiveAnnotation(T)) { + Check.diag(Loc, Error, DiagnosticIDs::Error) << T; + Check.diag(Loc, Note, DiagnosticIDs::Note); + dumpAnnotationReason(Check, T, Loc); + } + } + +private: + AnnotationReason directAnnotationReason(QualType T); + AnnotationReason tmplArgAnnotationReason(ArrayRef Args); + +protected: + // Flags specifying which properties of the underlying type we want to visit. + enum VisitFlags { + VISIT_NONE = 0, + VISIT_FIELDS = 1, + VISIT_TMPL_ARGS = 2, + VISIT_BASES = 4, + LLVM_MARK_AS_BITMASK_ENUM(VISIT_BASES) + }; + + // Allow subclasses to apply annotations for reasons other than a direct + // annotation. A non-empty string return value means that the object D is + // annotated, and should contain the reason why. + // + // The subclass may also modify `VisitFlags` to change what properties of the + // type will be inspected to skip inspecting fields, force template arguments + // to be inspected, etc. + virtual std::string getImplicitReason(const TagDecl *D, + VisitFlags &Flags) const { + return ""; + } +}; + +extern CustomTypeAnnotation StackClass; +extern CustomTypeAnnotation GlobalClass; +extern CustomTypeAnnotation NonHeapClass; +extern CustomTypeAnnotation HeapClass; +extern CustomTypeAnnotation NonTemporaryClass; +extern CustomTypeAnnotation TemporaryClass; +extern CustomTypeAnnotation StaticLocalClass; + +#endif diff --git a/build/clang-plugin/DanglingOnTemporaryChecker.cpp b/build/clang-plugin/DanglingOnTemporaryChecker.cpp new file mode 100644 index 0000000000..96d85ef4c0 --- /dev/null +++ b/build/clang-plugin/DanglingOnTemporaryChecker.cpp @@ -0,0 +1,256 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DanglingOnTemporaryChecker.h" +#include "CustomMatchers.h" +#include "VariableUsageHelpers.h" + +void DanglingOnTemporaryChecker::registerMatchers(MatchFinder *AstMatcher) { + //////////////////////////////////////// + // Quick annotation conflict checkers // + //////////////////////////////////////// + + AstMatcher->addMatcher( + // This is a matcher on a method declaration, + cxxMethodDecl( + // which is marked as no dangling on temporaries, + noDanglingOnTemporaries(), + + // and which is && ref-qualified. + isRValueRefQualified(), + + decl().bind("invalidMethodRefQualified")), + this); + + AstMatcher->addMatcher( + // This is a matcher on a method declaration, + cxxMethodDecl( + // which is marked as no dangling on temporaries, + noDanglingOnTemporaries(), + + // which returns a primitive type, + returns(builtinType()), + + // and which doesn't return a pointer. + unless(returns(pointerType())), + + decl().bind("invalidMethodPointer")), + this); + + ////////////////// + // Main checker // + ////////////////// + + auto hasParentCall = hasParent( + expr(anyOf(cxxOperatorCallExpr( + // If we're in a lamda, we may have an operator call + // expression ancestor in the AST, but the temporary we're + // matching against is not going to have the same lifetime + // as the constructor call. + unless(has(expr(ignoreTrivials(lambdaExpr())))), + expr().bind("parentOperatorCallExpr")), + callExpr( + // If we're in a lamda, we may have a call expression + // ancestor in the AST, but the temporary we're matching + // against is not going to have the same lifetime as the + // function call. + unless(has(expr(ignoreTrivials(lambdaExpr())))), + expr().bind("parentCallExpr")), + objcMessageExpr( + // If we're in a lamda, we may have an objc message + // expression ancestor in the AST, but the temporary we're + // matching against is not going to have the same lifetime + // as the function call. + unless(has(expr(ignoreTrivials(lambdaExpr())))), + expr().bind("parentObjCMessageExpr")), + cxxConstructExpr( + // If we're in a lamda, we may have a construct expression + // ancestor in the AST, but the temporary we're matching + // against is not going to have the same lifetime as the + // constructor call. + unless(has(expr(ignoreTrivials(lambdaExpr())))), + expr().bind("parentConstructExpr"))))); + + AstMatcher->addMatcher( + // This is a matcher on a method call, + cxxMemberCallExpr( + // which is in first party code, + isFirstParty(), + + // and which is performed on a temporary, + on(allOf(unless(hasType(pointerType())), isTemporary(), + // but which is not `this`. + unless(cxxThisExpr()))), + + // and which is marked as no dangling on temporaries. + callee(cxxMethodDecl(noDanglingOnTemporaries())), + + expr().bind("memberCallExpr"), + + // We optionally match a parent call expression or a parent construct + // expression because using a temporary inside a call is fine as long + // as the pointer doesn't escape the function call. + anyOf( + // This is the case where the call is the direct parent, so we + // know that the member call expression is the argument. + allOf(hasParentCall, expr().bind("parentCallArg")), + + // This is the case where the call is not the direct parent, so we + // get its child to know in which argument tree we are. + hasAncestor(expr(hasParentCall, expr().bind("parentCallArg"))), + // To make it optional. + anything())), + this); +} + +void DanglingOnTemporaryChecker::check(const MatchFinder::MatchResult &Result) { + /////////////////////////////////////// + // Quick annotation conflict checker // + /////////////////////////////////////// + + const char *ErrorInvalidRefQualified = "methods annotated with " + "MOZ_NO_DANGLING_ON_TEMPORARIES " + "cannot be && ref-qualified"; + + const char *ErrorInvalidPointer = "methods annotated with " + "MOZ_NO_DANGLING_ON_TEMPORARIES must " + "return a pointer"; + + if (auto InvalidRefQualified = + Result.Nodes.getNodeAs("invalidMethodRefQualified")) { + diag(InvalidRefQualified->getLocation(), ErrorInvalidRefQualified, + DiagnosticIDs::Error); + return; + } + + if (auto InvalidPointer = + Result.Nodes.getNodeAs("invalidMethodPointer")) { + diag(InvalidPointer->getLocation(), ErrorInvalidPointer, + DiagnosticIDs::Error); + return; + } + + ////////////////// + // Main checker // + ////////////////// + + const char *Error = "calling `%0` on a temporary, potentially allowing use " + "after free of the raw pointer"; + + const char *EscapeStmtNote = + "the raw pointer escapes the function scope here"; + + const ObjCMessageExpr *ParentObjCMessageExpr = + Result.Nodes.getNodeAs("parentObjCMessageExpr"); + + // We don't care about cases in ObjC message expressions. + if (ParentObjCMessageExpr) { + return; + } + + const CXXMemberCallExpr *MemberCall = + Result.Nodes.getNodeAs("memberCallExpr"); + + const CallExpr *ParentCallExpr = + Result.Nodes.getNodeAs("parentCallExpr"); + const CXXConstructExpr *ParentConstructExpr = + Result.Nodes.getNodeAs("parentConstructExpr"); + const CXXOperatorCallExpr *ParentOperatorCallExpr = + Result.Nodes.getNodeAs("parentOperatorCallExpr"); + const Expr *ParentCallArg = Result.Nodes.getNodeAs("parentCallArg"); + + // Just in case. + if (!MemberCall) { + return; + } + + // If we have a parent call, we check whether or not we escape the function + // being called. + if (ParentOperatorCallExpr || ParentCallExpr || ParentConstructExpr) { + // Just in case. + if (!ParentCallArg) { + return; + } + + // No default constructor so we can't construct it using if/else. + auto FunctionEscapeData = + ParentOperatorCallExpr + ? escapesFunction(ParentCallArg, ParentOperatorCallExpr) + : ParentCallExpr + ? escapesFunction(ParentCallArg, ParentCallExpr) + : escapesFunction(ParentCallArg, ParentConstructExpr); + + // If there was an error in the escapesFunction call. + if (std::error_code ec = FunctionEscapeData.getError()) { + // FIXME: For now we ignore the variadic case and just consider that the + // argument doesn't escape the function. Same for the case where we can't + // find the function declaration or if the function is builtin. + if (static_cast(ec.value()) == + EscapesFunctionError::FunctionIsVariadic || + static_cast(ec.value()) == + EscapesFunctionError::FunctionDeclNotFound || + static_cast(ec.value()) == + EscapesFunctionError::FunctionIsBuiltin) { + return; + } + + // We emit the internal checker error and return. + diag(MemberCall->getExprLoc(), + std::string(ec.category().name()) + " error: " + ec.message(), + DiagnosticIDs::Error); + return; + } + + // We deconstruct the function escape data. + const Stmt *EscapeStmt; + const Decl *EscapeDecl; + std::tie(EscapeStmt, EscapeDecl) = *FunctionEscapeData; + + // If we didn't escape a parent function, we're done: we don't emit any + // diagnostic. + if (!EscapeStmt || !EscapeDecl) { + return; + } + + // We emit the error diagnostic indicating that we are calling the method + // temporary. + diag(MemberCall->getExprLoc(), Error, DiagnosticIDs::Error) + << MemberCall->getMethodDecl()->getName() + << MemberCall->getSourceRange(); + + // We indicate the escape statement. + diag(EscapeStmt->getBeginLoc(), EscapeStmtNote, DiagnosticIDs::Note) + << EscapeStmt->getSourceRange(); + + // We build the escape note along with its source range. + StringRef EscapeDeclNote; + SourceRange EscapeDeclRange; + if (isa(EscapeDecl)) { + EscapeDeclNote = "through the parameter declared here"; + EscapeDeclRange = EscapeDecl->getSourceRange(); + } else if (isa(EscapeDecl)) { + EscapeDeclNote = "through the variable declared here"; + EscapeDeclRange = EscapeDecl->getSourceRange(); + } else if (isa(EscapeDecl)) { + EscapeDeclNote = "through the field declared here"; + EscapeDeclRange = EscapeDecl->getSourceRange(); + } else if (auto FuncDecl = dyn_cast(EscapeDecl)) { + EscapeDeclNote = "through the return value of the function declared here"; + EscapeDeclRange = FuncDecl->getReturnTypeSourceRange(); + } else { + return; + } + + // We emit the declaration note indicating through which decl the argument + // escapes. + diag(EscapeDecl->getLocation(), EscapeDeclNote, DiagnosticIDs::Note) + << EscapeDeclRange; + } else { + // We emit the error diagnostic indicating that we are calling the method + // temporary. + diag(MemberCall->getExprLoc(), Error, DiagnosticIDs::Error) + << MemberCall->getMethodDecl()->getName() + << MemberCall->getSourceRange(); + } +} diff --git a/build/clang-plugin/DanglingOnTemporaryChecker.h b/build/clang-plugin/DanglingOnTemporaryChecker.h new file mode 100644 index 0000000000..43f19ebedc --- /dev/null +++ b/build/clang-plugin/DanglingOnTemporaryChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DanglingOnTemporaryChecker_h__ +#define DanglingOnTemporaryChecker_h__ + +#include "plugin.h" + +class DanglingOnTemporaryChecker : public BaseCheck { +public: + DanglingOnTemporaryChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/DiagnosticsMatcher.cpp b/build/clang-plugin/DiagnosticsMatcher.cpp new file mode 100644 index 0000000000..96d2f60440 --- /dev/null +++ b/build/clang-plugin/DiagnosticsMatcher.cpp @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DiagnosticsMatcher.h" + +DiagnosticsMatcher::DiagnosticsMatcher(CompilerInstance &CI) { +#define CHECK(cls, name) \ + cls##_.registerMatchers(&AstMatcher); \ + cls##_.registerPPCallbacks(CI); +#include "Checks.inc" +#include "external/ExternalChecks.inc" +#ifdef MOZ_CLANG_PLUGIN_ALPHA +#include "alpha/AlphaChecks.inc" +#endif +#undef CHECK +} diff --git a/build/clang-plugin/DiagnosticsMatcher.h b/build/clang-plugin/DiagnosticsMatcher.h new file mode 100644 index 0000000000..2738541f62 --- /dev/null +++ b/build/clang-plugin/DiagnosticsMatcher.h @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DiagnosticsMatcher_h__ +#define DiagnosticsMatcher_h__ + +#include "ChecksIncludes.inc" +#include "external/ExternalIncludes.inc" +#ifdef MOZ_CLANG_PLUGIN_ALPHA +#include "alpha/AlphaIncludes.inc" +#endif + +class DiagnosticsMatcher { +public: + DiagnosticsMatcher(CompilerInstance &CI); + + ASTConsumerPtr makeASTConsumer() { return AstMatcher.newASTConsumer(); } + +private: +#define CHECK(cls, name) cls cls##_{name}; +#include "Checks.inc" +#include "external/ExternalChecks.inc" +#ifdef MOZ_CLANG_PLUGIN_ALPHA +#include "alpha/AlphaChecks.inc" +#endif +#undef CHECK + MatchFinder AstMatcher; +}; + +#endif diff --git a/build/clang-plugin/ExplicitImplicitChecker.cpp b/build/clang-plugin/ExplicitImplicitChecker.cpp new file mode 100644 index 0000000000..e0620f502f --- /dev/null +++ b/build/clang-plugin/ExplicitImplicitChecker.cpp @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ExplicitImplicitChecker.h" +#include "CustomMatchers.h" + +void ExplicitImplicitChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + cxxConstructorDecl( + isInterestingImplicitCtor(), + ofClass(allOf(isConcreteClass(), decl().bind("class"))), + unless(isMarkedImplicit())) + .bind("ctor"), + this); +} + +void ExplicitImplicitChecker::check(const MatchFinder::MatchResult &Result) { + // We've already checked everything in the matcher, so we just have to report + // the error. + + const CXXConstructorDecl *Ctor = + Result.Nodes.getNodeAs("ctor"); + const CXXRecordDecl *Declaration = + Result.Nodes.getNodeAs("class"); + + FixItHint FixItHint = + FixItHint::CreateInsertion(Ctor->getLocation(), "explicit "); + diag(Ctor->getLocation(), "bad implicit conversion constructor for %0", + DiagnosticIDs::Error) + << Declaration->getDeclName(); + diag(Ctor->getLocation(), + "consider adding the explicit keyword to the constructor", + DiagnosticIDs::Note) + << FixItHint; +} diff --git a/build/clang-plugin/ExplicitImplicitChecker.h b/build/clang-plugin/ExplicitImplicitChecker.h new file mode 100644 index 0000000000..f1591c999e --- /dev/null +++ b/build/clang-plugin/ExplicitImplicitChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ExplicitImplicitChecker_h__ +#define ExplicitImplicitChecker_h__ + +#include "plugin.h" + +class ExplicitImplicitChecker : public BaseCheck { +public: + ExplicitImplicitChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/ExplicitOperatorBoolChecker.cpp b/build/clang-plugin/ExplicitOperatorBoolChecker.cpp new file mode 100644 index 0000000000..ed97335a00 --- /dev/null +++ b/build/clang-plugin/ExplicitOperatorBoolChecker.cpp @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ExplicitOperatorBoolChecker.h" +#include "CustomMatchers.h" + +void ExplicitOperatorBoolChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + cxxMethodDecl(allOf(isFirstParty(), hasName("operator bool"))) + .bind("node"), + this); +} + +void ExplicitOperatorBoolChecker::check( + const MatchFinder::MatchResult &Result) { + const CXXConversionDecl *Method = + Result.Nodes.getNodeAs("node"); + const CXXRecordDecl *Clazz = Method->getParent(); + + if (!Method->isExplicit() && !hasCustomAttribute(Method) && + !ASTIsInSystemHeader(Method->getASTContext(), *Method) && + isInterestingDeclForImplicitConversion(Method)) { + diag(Method->getBeginLoc(), "bad implicit conversion operator for %0", + DiagnosticIDs::Error) + << Clazz; + diag(Method->getBeginLoc(), "consider adding the explicit keyword to %0", + DiagnosticIDs::Note) + << "'operator bool'"; + } +} diff --git a/build/clang-plugin/ExplicitOperatorBoolChecker.h b/build/clang-plugin/ExplicitOperatorBoolChecker.h new file mode 100644 index 0000000000..90909e6296 --- /dev/null +++ b/build/clang-plugin/ExplicitOperatorBoolChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ExplicitOperatorBoolChecker_h__ +#define ExplicitOperatorBoolChecker_h__ + +#include "plugin.h" + +class ExplicitOperatorBoolChecker : public BaseCheck { +public: + ExplicitOperatorBoolChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/FopenUsageChecker.cpp b/build/clang-plugin/FopenUsageChecker.cpp new file mode 100644 index 0000000000..905fc91f47 --- /dev/null +++ b/build/clang-plugin/FopenUsageChecker.cpp @@ -0,0 +1,73 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FopenUsageChecker.h" +#include "CustomMatchers.h" + +void FopenUsageChecker::registerMatchers(MatchFinder *AstMatcher) { + + auto hasConstCharPtrParam = [](const unsigned int Position) { + return hasParameter( + Position, hasType(hasCanonicalType(pointsTo(asString("const char"))))); + }; + + auto hasParamOfType = [](const unsigned int Position, const char *Name) { + return hasParameter(Position, hasType(asString(Name))); + }; + + auto hasIntegerParam = [](const unsigned int Position) { + return hasParameter(Position, hasType(isInteger())); + }; + + AstMatcher->addMatcher( + callExpr( + allOf( + isFirstParty(), + callee(functionDecl(allOf( + isInSystemHeader(), + anyOf( + allOf(anyOf(allOf(hasName("fopen"), + hasConstCharPtrParam(0)), + allOf(hasName("fopen_s"), + hasParameter( + 0, hasType(pointsTo(pointsTo( + asString("FILE"))))), + hasConstCharPtrParam(2))), + hasConstCharPtrParam(1)), + allOf(anyOf(hasName("open"), + allOf(hasName("_open"), hasIntegerParam(2)), + allOf(hasName("_sopen"), hasIntegerParam(3))), + hasConstCharPtrParam(0), hasIntegerParam(1)), + allOf(hasName("_sopen_s"), + hasParameter(0, hasType(pointsTo(isInteger()))), + hasConstCharPtrParam(1), hasIntegerParam(2), + hasIntegerParam(3), hasIntegerParam(4)), + allOf(hasName("OpenFile"), hasConstCharPtrParam(0), + hasParamOfType(1, "LPOFSTRUCT"), + hasIntegerParam(2)), + allOf(hasName("CreateFileA"), hasConstCharPtrParam(0), + hasIntegerParam(1), hasIntegerParam(2), + hasParamOfType(3, "LPSECURITY_ATTRIBUTES"), + hasIntegerParam(4), hasIntegerParam(5), + hasParamOfType(6, "HANDLE")))))), + unless(isInWhitelistForFopenUsage()))) + .bind("funcCall"), + this); +} + +void FopenUsageChecker::check(const MatchFinder::MatchResult &Result) { + const CallExpr *FuncCall = Result.Nodes.getNodeAs("funcCall"); + static const char *ExtraInfo = + "On Windows executed functions: fopen, fopen_s, open, _open, _sopen, " + "_sopen_s, OpenFile, CreateFileA should never be used due to lossy " + "conversion from UTF8 to ANSI."; + + if (FuncCall) { + diag(FuncCall->getBeginLoc(), + "Usage of ASCII file functions (here %0) is forbidden on Windows.", + DiagnosticIDs::Warning) + << FuncCall->getDirectCallee()->getName(); + diag(FuncCall->getBeginLoc(), ExtraInfo, DiagnosticIDs::Note); + } +} diff --git a/build/clang-plugin/FopenUsageChecker.h b/build/clang-plugin/FopenUsageChecker.h new file mode 100644 index 0000000000..9dc71831ab --- /dev/null +++ b/build/clang-plugin/FopenUsageChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef FopenUsageChecker_h__ +#define FopenUsageChecker_h__ + +#include "plugin.h" + +class FopenUsageChecker : public BaseCheck { +public: + FopenUsageChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/JSHandleRootedTypedefChecker.cpp b/build/clang-plugin/JSHandleRootedTypedefChecker.cpp new file mode 100644 index 0000000000..3e3adf7906 --- /dev/null +++ b/build/clang-plugin/JSHandleRootedTypedefChecker.cpp @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "JSHandleRootedTypedefChecker.h" +#include "CustomMatchers.h" + +void JSHandleRootedTypedefChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + declaratorDecl(isUsingJSHandleRootedTypedef(), isNotSpiderMonkey()) + .bind("declaratorDecl"), + this); +} + +std::string getReplacement(std::string TypeName) { + for (auto &pair : JSHandleRootedTypedefMap) { + if (!TypeName.compare(pair[0])) { + return pair[1]; + } + } + llvm_unreachable("Unexpected type name"); +} + +void JSHandleRootedTypedefChecker::check( + const MatchFinder::MatchResult &Result) { + const char *Error = "The fully qualified types are preferred over the " + "shorthand typedefs for JS::Handle/JS::Rooted types " + "outside SpiderMonkey."; + + const DeclaratorDecl *Declarator = + Result.Nodes.getNodeAs("declaratorDecl"); + + std::string Replacement = getReplacement(Declarator->getType().getAsString()); + diag(Declarator->getBeginLoc(), Error, DiagnosticIDs::Error) + << FixItHint::CreateReplacement( + Declarator->getTypeSourceInfo()->getTypeLoc().getSourceRange(), + Replacement); +} diff --git a/build/clang-plugin/JSHandleRootedTypedefChecker.h b/build/clang-plugin/JSHandleRootedTypedefChecker.h new file mode 100644 index 0000000000..32fc8fff9b --- /dev/null +++ b/build/clang-plugin/JSHandleRootedTypedefChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BUILD_CLANG_PLUGIN_JSHANDLEROOTEDTYPEDEFCHECKER_H_ +#define BUILD_CLANG_PLUGIN_JSHANDLEROOTEDTYPEDEFCHECKER_H_ + +#include "plugin.h" + +class JSHandleRootedTypedefChecker : public BaseCheck { +public: + JSHandleRootedTypedefChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/KnownLiveChecker.cpp b/build/clang-plugin/KnownLiveChecker.cpp new file mode 100644 index 0000000000..be0c3739ec --- /dev/null +++ b/build/clang-plugin/KnownLiveChecker.cpp @@ -0,0 +1,35 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "KnownLiveChecker.h" +#include "CustomMatchers.h" + +void KnownLiveChecker::registerMatchers(MatchFinder *AstMatcher) { + // Note that this cannot catch mutations after pass-by-reference, and thus no + // error for cycle collection macros. + + auto KnownLiveLHS = hasLHS(memberExpr(hasKnownLiveAnnotation()).bind("lhs")); + auto ForGeneralFunctions = forFunction( + functionDecl(unless(anyOf(cxxConstructorDecl(), cxxDestructorDecl()))) + .bind("func")); + + auto Matcher = + allOf(isAssignmentOperator(), KnownLiveLHS, ForGeneralFunctions); + + AstMatcher->addMatcher(binaryOperator(Matcher), this); + AstMatcher->addMatcher(cxxOperatorCallExpr(Matcher), this); +} + +void KnownLiveChecker::check(const MatchFinder::MatchResult &Result) { + const char *Error = "MOZ_KNOWN_LIVE members can only be modified by " + "constructors and destructors"; + + if (const MemberExpr *Expr = Result.Nodes.getNodeAs("lhs")) { + diag(Expr->getBeginLoc(), Error, DiagnosticIDs::Error); + } + if (const CXXOperatorCallExpr *Expr = + Result.Nodes.getNodeAs("lhs")) { + diag(Expr->getBeginLoc(), Error, DiagnosticIDs::Error); + } +} diff --git a/build/clang-plugin/KnownLiveChecker.h b/build/clang-plugin/KnownLiveChecker.h new file mode 100644 index 0000000000..bd92d0b326 --- /dev/null +++ b/build/clang-plugin/KnownLiveChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BUILD_CLANG_PLUGIN_KNOWNLIVECHECKER_H_ +#define BUILD_CLANG_PLUGIN_KNOWNLIVECHECKER_H_ + +#include "plugin.h" + +class KnownLiveChecker : public BaseCheck { +public: + KnownLiveChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/KungFuDeathGripChecker.cpp b/build/clang-plugin/KungFuDeathGripChecker.cpp new file mode 100644 index 0000000000..03bb20514f --- /dev/null +++ b/build/clang-plugin/KungFuDeathGripChecker.cpp @@ -0,0 +1,114 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "KungFuDeathGripChecker.h" +#include "CustomMatchers.h" + +void KungFuDeathGripChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher(varDecl(allOf(hasType(isRefPtr()), hasLocalStorage(), + hasInitializer(anything()))) + .bind("decl"), + this); +} + +void KungFuDeathGripChecker::check(const MatchFinder::MatchResult &Result) { + const char *Error = "Unused \"kungFuDeathGrip\" %0 objects constructed from " + "%1 are prohibited"; + const char *Note = "Please switch all accesses to this %0 to go through " + "'%1', or explicitly pass '%1' to `mozilla::Unused`"; + + const VarDecl *D = Result.Nodes.getNodeAs("decl"); + if (D->isReferenced()) { + return; + } + + // Not interested in parameters. + if (isa(D) || isa(D)) { + return; + } + + const Expr *E = IgnoreTrivials(D->getInit()); + const CXXConstructExpr *CE = dyn_cast(E); + if (CE && CE->getNumArgs() == 0) { + // We don't report an error when we construct and don't use a nsCOMPtr / + // nsRefPtr with no arguments. We don't report it because the error is not + // related to the current check. In the future it may be reported through a + // more generic mechanism. + return; + } + + // We don't want to look at the single argument conversion constructors + // which are inbetween the declaration and the actual object which we are + // assigning into the nsCOMPtr/RefPtr. To do this, we repeatedly + // IgnoreTrivials, then look at the expression. If it is one of these + // conversion constructors, we ignore it and continue to dig. + while ((CE = dyn_cast(E)) && CE->getNumArgs() == 1) { + E = IgnoreTrivials(CE->getArg(0)); + } + + // If the argument expression is an xvalue, we are not taking a copy of + // anything. + if (E->isXValue()) { + return; + } + + // It is possible that the QualType doesn't point to a type yet so we are + // not interested. + if (E->getType().isNull()) { + return; + } + + // We allow taking a kungFuDeathGrip of `this` because it cannot change + // beneath us, so calling directly through `this` is OK. This is the same + // for local variable declarations. + // + // We also don't complain about unused RefPtrs which are constructed from + // the return value of a new expression, as these are required in order to + // immediately destroy the value created (which was presumably created for + // its side effects), and are not used as a death grip. + if (isa(E) || isa(E) || isa(E)) { + return; + } + + // These types are assigned into nsCOMPtr and RefPtr for their side effects, + // and not as a kungFuDeathGrip. We don't want to consider RefPtr and nsCOMPtr + // types which are initialized with these types as errors. + const TagDecl *TD = E->getType()->getAsTagDecl(); + if (TD && TD->getIdentifier()) { + static const char *IgnoreTypes[] = { + "already_AddRefed", + "nsGetServiceByCID", + "nsGetServiceByCIDWithError", + "nsGetServiceByContractID", + "nsGetServiceByContractIDWithError", + "nsCreateInstanceByCID", + "nsCreateInstanceByContractID", + "nsCreateInstanceFromFactory", + }; + + for (uint32_t i = 0; i < sizeof(IgnoreTypes) / sizeof(IgnoreTypes[0]); + ++i) { + if (TD->getName() == IgnoreTypes[i]) { + return; + } + } + } + + // Report the error + const char *ErrThing; + const char *NoteThing; + if (isa(E)) { + ErrThing = "members"; + NoteThing = "member"; + } else { + ErrThing = "temporary values"; + NoteThing = "value"; + } + + // We cannot provide the note if we don't have an initializer + diag(D->getBeginLoc(), Error, DiagnosticIDs::Error) + << D->getType() << ErrThing; + diag(E->getBeginLoc(), Note, DiagnosticIDs::Note) + << NoteThing << getNameChecked(D); +} diff --git a/build/clang-plugin/KungFuDeathGripChecker.h b/build/clang-plugin/KungFuDeathGripChecker.h new file mode 100644 index 0000000000..6bb2c76835 --- /dev/null +++ b/build/clang-plugin/KungFuDeathGripChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef KungFuDeathGripChecker_h__ +#define KungFuDeathGripChecker_h__ + +#include "plugin.h" + +class KungFuDeathGripChecker : public BaseCheck { +public: + KungFuDeathGripChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/LoadLibraryUsageChecker.cpp b/build/clang-plugin/LoadLibraryUsageChecker.cpp new file mode 100644 index 0000000000..1c7d336ea9 --- /dev/null +++ b/build/clang-plugin/LoadLibraryUsageChecker.cpp @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "LoadLibraryUsageChecker.h" +#include "CustomMatchers.h" + +// On MacOS the filesystem is UTF-8, on linux the canonical filename is 8-bit +// string. On Windows data loss conversion will occur. This checker restricts +// the use of ASCII file functions for loading libraries. + +void LoadLibraryUsageChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + callExpr( + allOf(isFirstParty(), + callee(functionDecl(anyOf( + allOf(isInSystemHeader(), anyOf(hasName("LoadLibraryA"), + hasName("LoadLibraryExA"))), + hasName("PR_LoadLibrary")))), + unless(hasArgument(0, stringLiteral())))) + .bind("funcCall"), + this); +} + +void LoadLibraryUsageChecker::check(const MatchFinder::MatchResult &Result) { + const CallExpr *FuncCall = Result.Nodes.getNodeAs("funcCall"); + + if (FuncCall) { + diag(FuncCall->getBeginLoc(), + "Usage of ASCII file functions (such as %0) is forbidden.", + DiagnosticIDs::Error) + << FuncCall->getDirectCallee()->getName(); + } +} diff --git a/build/clang-plugin/LoadLibraryUsageChecker.h b/build/clang-plugin/LoadLibraryUsageChecker.h new file mode 100644 index 0000000000..f7b60234be --- /dev/null +++ b/build/clang-plugin/LoadLibraryUsageChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef LoadLibraryUsageChecker_h__ +#define LoadLibraryUsageChecker_h__ + +#include "plugin.h" + +class LoadLibraryUsageChecker : public BaseCheck { +public: + LoadLibraryUsageChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif // !defined(LoadLibraryUsageChecker_h__) diff --git a/build/clang-plugin/Makefile.in b/build/clang-plugin/Makefile.in new file mode 100644 index 0000000000..b4c9d40de0 --- /dev/null +++ b/build/clang-plugin/Makefile.in @@ -0,0 +1,14 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include $(topsrcdir)/config/config.mk + +HOST_LDFLAGS += $(LLVM_LDFLAGS) $(CLANG_LDFLAGS) + +ifeq ($(HOST_OS_ARCH),WINNT) +# clang-plugin.dll needs to be deterministic for sccache hashes +HOST_LDFLAGS += -brepro +else +HOST_LDFLAGS += -shared +endif diff --git a/build/clang-plugin/MemMoveAnnotation.h b/build/clang-plugin/MemMoveAnnotation.h new file mode 100644 index 0000000000..0a1a96e8ff --- /dev/null +++ b/build/clang-plugin/MemMoveAnnotation.h @@ -0,0 +1,62 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MemMoveAnnotation_h__ +#define MemMoveAnnotation_h__ + +#include "CustomMatchers.h" +#include "CustomTypeAnnotation.h" +#include "Utils.h" + +#include + +class MemMoveAnnotation final : public CustomTypeAnnotation { +public: + MemMoveAnnotation() + : CustomTypeAnnotation(moz_non_memmovable, "non-memmove()able") {} + + virtual ~MemMoveAnnotation() {} + +protected: + std::string getImplicitReason(const TagDecl *D, + VisitFlags &ToVisit) const override { + // Annotate everything in ::std, with a few exceptions; see bug + // 1201314 for discussion. + if (getDeclarationNamespace(D) != "std") { + return ""; + } + + StringRef Name = getNameChecked(D); + + // If the type has a trivial move constructor and destructor, it is safe to + // memmove, and we don't need to visit any fields. + auto RD = dyn_cast(D); + if (RD && RD->isCompleteDefinition() && + (RD->hasTrivialMoveConstructor() || + (!RD->hasMoveConstructor() && RD->hasTrivialCopyConstructor())) && + RD->hasTrivialDestructor()) { + ToVisit = VISIT_NONE; + return ""; + } + + // This doesn't check that it's really ::std::pair and not + // ::std::something_else::pair, but should be good enough. + if (isNameExcepted(Name.data())) { + // If we're an excepted name, stop traversing within the type further, + // and only check template arguments for foreign types. + ToVisit = VISIT_TMPL_ARGS; + return ""; + } + return "it is an stl-provided type not guaranteed to be memmove-able"; + } + +private: + bool isNameExcepted(StringRef Name) const { + return Name == "pair" || Name == "atomic" || Name == "tuple"; + } +}; + +extern MemMoveAnnotation NonMemMovable; + +#endif diff --git a/build/clang-plugin/MozCheckAction.cpp b/build/clang-plugin/MozCheckAction.cpp new file mode 100644 index 0000000000..6ec8c92bd8 --- /dev/null +++ b/build/clang-plugin/MozCheckAction.cpp @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DiagnosticsMatcher.h" +#include "plugin.h" +#include "clang/Frontend/FrontendPluginRegistry.h" + +class MozCheckAction : public PluginASTAction { +public: + ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, + StringRef FileName) override { + void *Buffer = CI.getASTContext().Allocate(); + auto Matcher = new (Buffer) DiagnosticsMatcher(CI); + return Matcher->makeASTConsumer(); + } + + bool ParseArgs(const CompilerInstance &CI, + const std::vector &Args) override { + return true; + } +}; + +static FrontendPluginRegistry::Add X("moz-check", + "check moz action"); + +DenseMap InThirdPartyPathCache; diff --git a/build/clang-plugin/MozillaTidyModule.cpp b/build/clang-plugin/MozillaTidyModule.cpp new file mode 100644 index 0000000000..b1870e7454 --- /dev/null +++ b/build/clang-plugin/MozillaTidyModule.cpp @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef CLANG_TIDY + +#include "../ClangTidy.h" +#include "../ClangTidyModule.h" +#include "../ClangTidyModuleRegistry.h" +#include "ChecksIncludes.inc" +#include "external/ExternalIncludes.inc" +#ifdef MOZ_CLANG_PLUGIN_ALPHA +#include "alpha/AlphaIncludes.inc" +#endif + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { + +class MozillaModule : public ClangTidyModule { +public: + void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { +#define CHECK(cls, name) CheckFactories.registerCheck("mozilla-" name); +#include "Checks.inc" +#include "external/ExternalChecks.inc" +#ifdef MOZ_CLANG_PLUGIN_ALPHA +#include "alpha/AlphaChecks.inc" +#endif +#undef CHECK + } +}; + +// Register the MozillaTidyModule using this statically initialized variable. +static ClangTidyModuleRegistry::Add + X("mozilla-module", "Adds Mozilla lint checks."); + +} // namespace tidy +} // namespace clang + +// This anchor is used to force the linker to link in the generated object file +// and thus register the MozillaModule. +volatile int MozillaModuleAnchorSource = 0; + +#endif diff --git a/build/clang-plugin/MustOverrideChecker.cpp b/build/clang-plugin/MustOverrideChecker.cpp new file mode 100644 index 0000000000..b19ae94aac --- /dev/null +++ b/build/clang-plugin/MustOverrideChecker.cpp @@ -0,0 +1,60 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MustOverrideChecker.h" +#include "CustomMatchers.h" + +void MustOverrideChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher(cxxRecordDecl(isDefinition()).bind("class"), this); +} + +void MustOverrideChecker::registerPPCallbacks(CompilerInstance &CI) { + this->CI = &CI; +} + +void MustOverrideChecker::check(const MatchFinder::MatchResult &Result) { + auto D = Result.Nodes.getNodeAs("class"); + + // Look through all of our immediate bases to find methods that need to be + // overridden + typedef std::vector OverridesVector; + OverridesVector MustOverrides; + for (const auto &Base : D->bases()) { + // The base is either a class (CXXRecordDecl) or it's a templated class... + CXXRecordDecl *Parent = Base.getType() + .getDesugaredType(D->getASTContext()) + ->getAsCXXRecordDecl(); + // The parent might not be resolved to a type yet. In this case, we can't + // do any checking here. For complete correctness, we should visit + // template instantiations, but this case is likely to be rare, so we will + // ignore it until it becomes important. + if (!Parent) { + continue; + } + Parent = Parent->getDefinition(); + for (const auto &M : Parent->methods()) { + if (hasCustomAttribute(M)) + MustOverrides.push_back(M); + } + } + + for (auto &O : MustOverrides) { + bool Overridden = false; + for (const auto &M : D->methods()) { + // The way that Clang checks if a method M overrides its parent method + // is if the method has the same name but would not overload. + if (getNameChecked(M) == getNameChecked(O) && + !CI->getSema().IsOverload(M, O, false)) { + Overridden = true; + break; + } + } + if (!Overridden) { + diag(D->getLocation(), "%0 must override %1", DiagnosticIDs::Error) + << D->getDeclName() << O->getDeclName(); + diag(O->getLocation(), "function to override is here", + DiagnosticIDs::Note); + } + } +} diff --git a/build/clang-plugin/MustOverrideChecker.h b/build/clang-plugin/MustOverrideChecker.h new file mode 100644 index 0000000000..ed1835eb57 --- /dev/null +++ b/build/clang-plugin/MustOverrideChecker.h @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MustOverrideChecker_h__ +#define MustOverrideChecker_h__ + +#include "plugin.h" + +class MustOverrideChecker : public BaseCheck { +public: + MustOverrideChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context), CI(nullptr) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void registerPPCallbacks(CompilerInstance &CI) override; + void check(const MatchFinder::MatchResult &Result) override; + +private: + const CompilerInstance *CI; +}; + +#endif diff --git a/build/clang-plugin/MustReturnFromCallerChecker.cpp b/build/clang-plugin/MustReturnFromCallerChecker.cpp new file mode 100644 index 0000000000..df28ddb4d3 --- /dev/null +++ b/build/clang-plugin/MustReturnFromCallerChecker.cpp @@ -0,0 +1,136 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MustReturnFromCallerChecker.h" +#include "CustomMatchers.h" + +void MustReturnFromCallerChecker::registerMatchers(MatchFinder *AstMatcher) { + // Look for a call to a MOZ_MUST_RETURN_FROM_CALLER member + AstMatcher->addMatcher( + cxxMemberCallExpr( + on(declRefExpr(to(parmVarDecl()))), + callee(functionDecl(isMozMustReturnFromCaller())), + anyOf(hasAncestor(lambdaExpr().bind("containing-lambda")), + hasAncestor(functionDecl().bind("containing-func")))) + .bind("call"), + this); +} + +void MustReturnFromCallerChecker::check( + const MatchFinder::MatchResult &Result) { + const auto *ContainingLambda = + Result.Nodes.getNodeAs("containing-lambda"); + const auto *ContainingFunc = + Result.Nodes.getNodeAs("containing-func"); + const auto *Call = Result.Nodes.getNodeAs("call"); + + Stmt *Body = nullptr; + if (ContainingLambda) { + Body = ContainingLambda->getBody(); + } else if (ContainingFunc) { + Body = ContainingFunc->getBody(); + } else { + return; + } + assert(Body && "Should have a body by this point"); + + // Generate the CFG for the enclosing function or decl. + CFG::BuildOptions Options; + std::unique_ptr TheCFG = + CFG::buildCFG(nullptr, Body, Result.Context, Options); + if (!TheCFG) { + return; + } + + // Determine which block in the CFG we want to look at the successors of. + StmtToBlockMap BlockMap(TheCFG.get(), Result.Context); + size_t CallIndex; + const auto *Block = BlockMap.blockContainingStmt(Call, &CallIndex); + if (!Block) { + // This statement is not within the CFG! + return; + } + + if (!immediatelyReturns(Block, Result.Context, CallIndex + 1)) { + diag(Call->getBeginLoc(), + "You must immediately return after calling this function", + DiagnosticIDs::Error); + } +} + +bool MustReturnFromCallerChecker::isIgnorable(const Stmt *S) { + auto AfterTrivials = IgnoreTrivials(S); + + // After a call to MOZ_MUST_RETURN_FROM_CALLER function it's ok to have any of + // these expressions. + if (isa(AfterTrivials) || isa(AfterTrivials) || + isa(AfterTrivials) || isa(AfterTrivials) || + isa(AfterTrivials) || + isa(AfterTrivials) || + isa(AfterTrivials) || + isa(AfterTrivials)) { + return true; + } + + // Solitary `this` should be permited, like in the context `return this;` + if (auto TE = dyn_cast(AfterTrivials)) { + if (TE->child_begin() == TE->child_end()) { + return true; + } + return false; + } + + // For UnaryOperator make sure we only accept arithmetic operations. + if (auto UO = dyn_cast(AfterTrivials)) { + if (!UO->isArithmeticOp()) { + return false; + } + return isIgnorable(UO->getSubExpr()); + } + + // It's also OK to call any function or method which is annotated with + // MOZ_MAY_CALL_AFTER_MUST_RETURN. We consider all CXXConversionDecls + // to be MOZ_MAY_CALL_AFTER_MUST_RETURN (like operator T*()). + if (auto CE = dyn_cast(AfterTrivials)) { + auto Callee = CE->getDirectCallee(); + if (Callee && hasCustomAttribute(Callee)) { + return true; + } + + if (Callee && isa(Callee)) { + return true; + } + } + return false; +} + +bool MustReturnFromCallerChecker::immediatelyReturns( + RecurseGuard Block, ASTContext *TheContext, + size_t FromIdx) { + if (Block.isRepeat()) { + return false; + } + + for (size_t I = FromIdx; I < Block->size(); ++I) { + auto S = (*Block)[I].getAs(); + if (!S) { + continue; + } + + // Some statements should be ignored by default due to their CFG context. + if (isIgnorable(S->getStmt())) { + continue; + } + + // Otherwise, this expression is problematic. + return false; + } + + for (auto Succ = Block->succ_begin(); Succ != Block->succ_end(); ++Succ) { + if (!immediatelyReturns(Block.recurse(*Succ), TheContext, 0)) { + return false; + } + } + return true; +} diff --git a/build/clang-plugin/MustReturnFromCallerChecker.h b/build/clang-plugin/MustReturnFromCallerChecker.h new file mode 100644 index 0000000000..68630bf7a7 --- /dev/null +++ b/build/clang-plugin/MustReturnFromCallerChecker.h @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MustReturnFromCallerChecker_h__ +#define MustReturnFromCallerChecker_h__ + +#include "RecurseGuard.h" +#include "StmtToBlockMap.h" +#include "Utils.h" +#include "plugin.h" + +class MustReturnFromCallerChecker : public BaseCheck { +public: + MustReturnFromCallerChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; + +private: + bool isIgnorable(const Stmt *S); + bool immediatelyReturns(RecurseGuard Block, + ASTContext *TheContext, size_t FromIdx); +}; + +#endif diff --git a/build/clang-plugin/NaNExprChecker.cpp b/build/clang-plugin/NaNExprChecker.cpp new file mode 100644 index 0000000000..bacebc9155 --- /dev/null +++ b/build/clang-plugin/NaNExprChecker.cpp @@ -0,0 +1,54 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NaNExprChecker.h" +#include "CustomMatchers.h" + +void NaNExprChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + binaryOperator( + allOf(binaryEqualityOperator(), + hasLHS(has(ignoringParenImpCasts( + declRefExpr(hasType(qualType((isFloat())))).bind("lhs")))), + hasRHS(has(ignoringParenImpCasts( + declRefExpr(hasType(qualType((isFloat())))).bind("rhs")))), + unless(anyOf(isInSystemHeader(), isInWhitelistForNaNExpr())))) + .bind("node"), + this); +} + +void NaNExprChecker::check(const MatchFinder::MatchResult &Result) { + if (!Result.Context->getLangOpts().CPlusPlus) { + return; + } + + const BinaryOperator *Expression = + Result.Nodes.getNodeAs("node"); + const DeclRefExpr *LHS = Result.Nodes.getNodeAs("lhs"); + const DeclRefExpr *RHS = Result.Nodes.getNodeAs("rhs"); + const ImplicitCastExpr *LHSExpr = + dyn_cast(Expression->getLHS()); + const ImplicitCastExpr *RHSExpr = + dyn_cast(Expression->getRHS()); + // The AST subtree that we are looking for will look like this: + // -BinaryOperator ==/!= + // |-ImplicitCastExpr LValueToRValue + // | |-DeclRefExpr + // |-ImplicitCastExpr LValueToRValue + // |-DeclRefExpr + // The check below ensures that we are dealing with the correct AST subtree + // shape, and + // also that both of the found DeclRefExpr's point to the same declaration. + if (LHS->getFoundDecl() == RHS->getFoundDecl() && LHSExpr && RHSExpr && + std::distance(LHSExpr->child_begin(), LHSExpr->child_end()) == 1 && + std::distance(RHSExpr->child_begin(), RHSExpr->child_end()) == 1 && + *LHSExpr->child_begin() == LHS && *RHSExpr->child_begin() == RHS) { + diag(Expression->getBeginLoc(), + "comparing a floating point value to itself for " + "NaN checking can lead to incorrect results", + DiagnosticIDs::Error); + diag(Expression->getBeginLoc(), "consider using std::isnan instead", + DiagnosticIDs::Note); + } +} diff --git a/build/clang-plugin/NaNExprChecker.h b/build/clang-plugin/NaNExprChecker.h new file mode 100644 index 0000000000..313c3cb4cc --- /dev/null +++ b/build/clang-plugin/NaNExprChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NaNExprChecker_h__ +#define NaNExprChecker_h__ + +#include "plugin.h" + +class NaNExprChecker : public BaseCheck { +public: + NaNExprChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/NeedsNoVTableTypeChecker.cpp b/build/clang-plugin/NeedsNoVTableTypeChecker.cpp new file mode 100644 index 0000000000..9d5ad039ba --- /dev/null +++ b/build/clang-plugin/NeedsNoVTableTypeChecker.cpp @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NeedsNoVTableTypeChecker.h" +#include "CustomMatchers.h" + +void NeedsNoVTableTypeChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + classTemplateSpecializationDecl( + allOf(hasAnyTemplateArgument(refersToType(hasVTable())), + hasNeedsNoVTableTypeAttr())) + .bind("node"), + this); +} + +void NeedsNoVTableTypeChecker::check(const MatchFinder::MatchResult &Result) { + const ClassTemplateSpecializationDecl *Specialization = + Result.Nodes.getNodeAs("node"); + + // Get the offending template argument + QualType Offender; + const TemplateArgumentList &Args = + Specialization->getTemplateInstantiationArgs(); + for (unsigned i = 0; i < Args.size(); ++i) { + Offender = Args[i].getAsType(); + if (typeHasVTable(Offender)) { + break; + } + } + + diag(Specialization->getBeginLoc(), + "%0 cannot be instantiated because %1 has a VTable", + DiagnosticIDs::Error) + << Specialization << Offender; + diag(Specialization->getPointOfInstantiation(), + "bad instantiation of %0 requested here", DiagnosticIDs::Note) + << Specialization; +} diff --git a/build/clang-plugin/NeedsNoVTableTypeChecker.h b/build/clang-plugin/NeedsNoVTableTypeChecker.h new file mode 100644 index 0000000000..abff4d1554 --- /dev/null +++ b/build/clang-plugin/NeedsNoVTableTypeChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NeedsNoVTableTypeChecker_h__ +#define NeedsNoVTableTypeChecker_h__ + +#include "plugin.h" + +class NeedsNoVTableTypeChecker : public BaseCheck { +public: + NeedsNoVTableTypeChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/NoAddRefReleaseOnReturnChecker.cpp b/build/clang-plugin/NoAddRefReleaseOnReturnChecker.cpp new file mode 100644 index 0000000000..e1c38fa6b2 --- /dev/null +++ b/build/clang-plugin/NoAddRefReleaseOnReturnChecker.cpp @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NoAddRefReleaseOnReturnChecker.h" +#include "CustomMatchers.h" + +void NoAddRefReleaseOnReturnChecker::registerMatchers(MatchFinder *AstMatcher) { + // Look for all of the calls to AddRef() or Release() + AstMatcher->addMatcher( + memberExpr(isAddRefOrRelease(), hasParent(callExpr())).bind("member"), + this); +} + +void NoAddRefReleaseOnReturnChecker::check( + const MatchFinder::MatchResult &Result) { + const MemberExpr *Member = Result.Nodes.getNodeAs("member"); + const Expr *Base = IgnoreTrivials(Member->getBase()); + + // Check if the call to AddRef() or Release() was made on the result of a call + // to a MOZ_NO_ADDREF_RELEASE_ON_RETURN function or method. + if (auto *Call = dyn_cast(Base)) { + if (auto *Callee = Call->getDirectCallee()) { + if (hasCustomAttribute(Callee)) { + diag(Call->getBeginLoc(), + "%1 must not be called on the return value of '%0' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN", + DiagnosticIDs::Error) + << Callee->getQualifiedNameAsString() << dyn_cast(Member->getMemberDecl()); + } + } + } +} diff --git a/build/clang-plugin/NoAddRefReleaseOnReturnChecker.h b/build/clang-plugin/NoAddRefReleaseOnReturnChecker.h new file mode 100644 index 0000000000..525f769eff --- /dev/null +++ b/build/clang-plugin/NoAddRefReleaseOnReturnChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NoAddRefReleaseOnReturnChecker_h__ +#define NoAddRefReleaseOnReturnChecker_h__ + +#include "plugin.h" + +class NoAddRefReleaseOnReturnChecker : public BaseCheck { +public: + NoAddRefReleaseOnReturnChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/NoAutoTypeChecker.cpp b/build/clang-plugin/NoAutoTypeChecker.cpp new file mode 100644 index 0000000000..937c7c5742 --- /dev/null +++ b/build/clang-plugin/NoAutoTypeChecker.cpp @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NoAutoTypeChecker.h" +#include "CustomMatchers.h" + +void NoAutoTypeChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher(varDecl(hasType(autoNonAutoableType())).bind("node"), + this); +} + +void NoAutoTypeChecker::check(const MatchFinder::MatchResult &Result) { + const VarDecl *D = Result.Nodes.getNodeAs("node"); + + diag(D->getLocation(), "Cannot use auto to declare a variable of type %0", + DiagnosticIDs::Error) + << D->getType(); + diag(D->getLocation(), "Please write out this type explicitly", + DiagnosticIDs::Note); +} diff --git a/build/clang-plugin/NoAutoTypeChecker.h b/build/clang-plugin/NoAutoTypeChecker.h new file mode 100644 index 0000000000..0801503846 --- /dev/null +++ b/build/clang-plugin/NoAutoTypeChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NoAutoTypeChecker_h__ +#define NoAutoTypeChecker_h__ + +#include "plugin.h" + +class NoAutoTypeChecker : public BaseCheck { +public: + NoAutoTypeChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/NoDuplicateRefCntMemberChecker.cpp b/build/clang-plugin/NoDuplicateRefCntMemberChecker.cpp new file mode 100644 index 0000000000..eb78a3bd49 --- /dev/null +++ b/build/clang-plugin/NoDuplicateRefCntMemberChecker.cpp @@ -0,0 +1,65 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NoDuplicateRefCntMemberChecker.h" +#include "CustomMatchers.h" + +void NoDuplicateRefCntMemberChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher(cxxRecordDecl().bind("decl"), this); +} + +void NoDuplicateRefCntMemberChecker::check( + const MatchFinder::MatchResult &Result) { + const CXXRecordDecl *D = Result.Nodes.getNodeAs("decl"); + const FieldDecl *RefCntMember = getClassRefCntMember(D); + const FieldDecl *FoundRefCntBase = nullptr; + + if (!D->hasDefinition()) + return; + D = D->getDefinition(); + + // If we don't have an mRefCnt member, and we have less than 2 superclasses, + // we don't have to run this loop, as neither case will ever apply. + if (!RefCntMember && D->getNumBases() < 2) { + return; + } + + // Check every superclass for whether it has a base with a refcnt member, and + // warn for those which do + for (auto &Base : D->bases()) { + // Determine if this base class has an mRefCnt member + const FieldDecl *BaseRefCntMember = getBaseRefCntMember(Base.getType()); + + if (BaseRefCntMember) { + if (RefCntMember) { + // We have an mRefCnt, and superclass has an mRefCnt + const char *Error = "Refcounted record %0 has multiple mRefCnt members"; + const char *Note1 = "Superclass %0 also has an mRefCnt member"; + const char *Note2 = + "Consider using the _INHERITED macros for AddRef and Release here"; + + diag(D->getBeginLoc(), Error, DiagnosticIDs::Error) << D; + diag(BaseRefCntMember->getBeginLoc(), Note1, DiagnosticIDs::Note) + << BaseRefCntMember->getParent(); + diag(RefCntMember->getBeginLoc(), Note2, DiagnosticIDs::Note); + } + + if (FoundRefCntBase) { + const char *Error = "Refcounted record %0 has multiple superclasses " + "with mRefCnt members"; + const char *Note = "Superclass %0 has an mRefCnt member"; + + // superclass has mRefCnt, and another superclass also has an mRefCnt + diag(D->getBeginLoc(), Error, DiagnosticIDs::Error) << D; + diag(BaseRefCntMember->getBeginLoc(), Note, DiagnosticIDs::Note) + << BaseRefCntMember->getParent(); + diag(FoundRefCntBase->getBeginLoc(), Note, DiagnosticIDs::Note) + << FoundRefCntBase->getParent(); + } + + // Record that we've found a base with a mRefCnt member + FoundRefCntBase = BaseRefCntMember; + } + } +} diff --git a/build/clang-plugin/NoDuplicateRefCntMemberChecker.h b/build/clang-plugin/NoDuplicateRefCntMemberChecker.h new file mode 100644 index 0000000000..e038ca873b --- /dev/null +++ b/build/clang-plugin/NoDuplicateRefCntMemberChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NoDuplicateRefCntMemberChecker_h__ +#define NoDuplicateRefCntMemberChecker_h__ + +#include "plugin.h" + +class NoDuplicateRefCntMemberChecker : public BaseCheck { +public: + NoDuplicateRefCntMemberChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/NoExplicitMoveConstructorChecker.cpp b/build/clang-plugin/NoExplicitMoveConstructorChecker.cpp new file mode 100644 index 0000000000..69e324dee3 --- /dev/null +++ b/build/clang-plugin/NoExplicitMoveConstructorChecker.cpp @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NoExplicitMoveConstructorChecker.h" +#include "CustomMatchers.h" + +void NoExplicitMoveConstructorChecker::registerMatchers( + MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + cxxConstructorDecl(isExplicitMoveConstructor(), isFirstParty()) + .bind("node"), + this); +} + +void NoExplicitMoveConstructorChecker::check( + const MatchFinder::MatchResult &Result) { + // Everything we needed to know was checked in the matcher - we just report + // the error here + const CXXConstructorDecl *D = + Result.Nodes.getNodeAs("node"); + + diag(D->getLocation(), "Move constructors may not be marked explicit", + DiagnosticIDs::Error); +} diff --git a/build/clang-plugin/NoExplicitMoveConstructorChecker.h b/build/clang-plugin/NoExplicitMoveConstructorChecker.h new file mode 100644 index 0000000000..adc474c144 --- /dev/null +++ b/build/clang-plugin/NoExplicitMoveConstructorChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NoExplicitMoveConstructorChecker_h__ +#define NoExplicitMoveConstructorChecker_h__ + +#include "plugin.h" + +class NoExplicitMoveConstructorChecker : public BaseCheck { +public: + NoExplicitMoveConstructorChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/NoNewThreadsChecker.cpp b/build/clang-plugin/NoNewThreadsChecker.cpp new file mode 100644 index 0000000000..90c190f8d1 --- /dev/null +++ b/build/clang-plugin/NoNewThreadsChecker.cpp @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NoNewThreadsChecker.h" +#include "CustomMatchers.h" + +void NoNewThreadsChecker::registerMatchers(MatchFinder *AstMatcher) { + // The checker looks for: + // -Instances of NS_NewNamedThread that aren't in allowed files + // -Instances of NS_NewNamedThread that use names that aren't recognized + AstMatcher->addMatcher( + callExpr(allOf(isFirstParty(), + callee(functionDecl(hasName("NS_NewNamedThread"))), + unless(isInAllowlistForThreads()))) + .bind("funcCall"), + this); +} + +void NoNewThreadsChecker::check(const MatchFinder::MatchResult &Result) { + const CallExpr *FuncCall = Result.Nodes.getNodeAs("funcCall"); + + if (FuncCall) { + diag(FuncCall->getBeginLoc(), + "Thread name not recognized. Please use the background thread pool.", + DiagnosticIDs::Error) + << FuncCall->getDirectCallee()->getName(); + diag( + FuncCall->getBeginLoc(), + "NS_NewNamedThread has been deprecated in favor of background " + "task dispatch via NS_DispatchBackgroundTask and " + "NS_CreateBackgroundTaskQueue. If you must create a new ad-hoc thread, " + "have your thread name added to ThreadAllows.txt.", + DiagnosticIDs::Note); + } +} diff --git a/build/clang-plugin/NoNewThreadsChecker.h b/build/clang-plugin/NoNewThreadsChecker.h new file mode 100644 index 0000000000..e8dc13fece --- /dev/null +++ b/build/clang-plugin/NoNewThreadsChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NoNewThreadsChecker_h__ +#define NoNewThreadsChecker_h__ + +#include "plugin.h" + +class NoNewThreadsChecker : public BaseCheck { +public: + NoNewThreadsChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif // !defined(NoNewThreadsChecker_h__) diff --git a/build/clang-plugin/NoPrincipalGetURI.cpp b/build/clang-plugin/NoPrincipalGetURI.cpp new file mode 100644 index 0000000000..60e22abeb5 --- /dev/null +++ b/build/clang-plugin/NoPrincipalGetURI.cpp @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NoPrincipalGetURI.h" +#include "CustomMatchers.h" + +void NoPrincipalGetURI::registerMatchers(MatchFinder *AstMatcher) { + + AstMatcher->addMatcher( + cxxMemberCallExpr( + allOf(callee(cxxMethodDecl(hasName("GetURI"))), + anyOf(on(hasType(hasCanonicalType(asString("class nsIPrincipal *")))), + on(hasType(hasCanonicalType(asString("class nsIPrincipal"))))), + unless(isInWhiteListForPrincipalGetUri())), + argumentCountIs(1)) + .bind("id"), + this); +} + +void NoPrincipalGetURI::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("id"); + diag(MatchedDecl->getExprLoc(), + "Principal->GetURI is deprecated and will be removed soon. Please " + "consider using the new helper functions of nsIPrincipal", + DiagnosticIDs::Error); +} diff --git a/build/clang-plugin/NoPrincipalGetURI.h b/build/clang-plugin/NoPrincipalGetURI.h new file mode 100644 index 0000000000..2b39b74bed --- /dev/null +++ b/build/clang-plugin/NoPrincipalGetURI.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NoPrincipalGetURI_h__ +#define NoPrincipalGetURI_h__ + +#include "plugin.h" + +class NoPrincipalGetURI : public BaseCheck { +public: + NoPrincipalGetURI(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/NoUsingNamespaceMozillaJavaChecker.cpp b/build/clang-plugin/NoUsingNamespaceMozillaJavaChecker.cpp new file mode 100644 index 0000000000..20449dba92 --- /dev/null +++ b/build/clang-plugin/NoUsingNamespaceMozillaJavaChecker.cpp @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NoUsingNamespaceMozillaJavaChecker.h" +#include "CustomMatchers.h" + +void NoUsingNamespaceMozillaJavaChecker::registerMatchers( + MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + usingDirectiveDecl(isUsingNamespaceMozillaJava()).bind("directive"), + this); +} + +void NoUsingNamespaceMozillaJavaChecker::check( + const MatchFinder::MatchResult &Result) { + const UsingDirectiveDecl *Directive = + Result.Nodes.getNodeAs("directive"); + const NamespaceDecl *Namespace = Directive->getNominatedNamespace(); + + diag(Directive->getUsingLoc(), "using namespace %0 is forbidden", + DiagnosticIDs::Error) + << Namespace->getQualifiedNameAsString(); +} diff --git a/build/clang-plugin/NoUsingNamespaceMozillaJavaChecker.h b/build/clang-plugin/NoUsingNamespaceMozillaJavaChecker.h new file mode 100644 index 0000000000..7b68ba9333 --- /dev/null +++ b/build/clang-plugin/NoUsingNamespaceMozillaJavaChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NoUsingNamespaceMozillaJavaChecker_h__ +#define NoUsingNamespaceMozillaJavaChecker_h__ + +#include "plugin.h" + +class NoUsingNamespaceMozillaJavaChecker : public BaseCheck { +public: + NoUsingNamespaceMozillaJavaChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/NonMemMovableMemberChecker.cpp b/build/clang-plugin/NonMemMovableMemberChecker.cpp new file mode 100644 index 0000000000..232c634534 --- /dev/null +++ b/build/clang-plugin/NonMemMovableMemberChecker.cpp @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NonMemMovableMemberChecker.h" +#include "CustomMatchers.h" + +MemMoveAnnotation NonMemMovable = MemMoveAnnotation(); + +void NonMemMovableMemberChecker::registerMatchers(MatchFinder *AstMatcher) { + // Handle non-mem-movable members + AstMatcher->addMatcher(cxxRecordDecl(needsMemMovableMembers()).bind("decl"), + this); +} + +void NonMemMovableMemberChecker::check(const MatchFinder::MatchResult &Result) { + const char *Error = + "class %0 cannot have non-memmovable member %1 of type %2"; + + // Get the specialization + const CXXRecordDecl *Declaration = + Result.Nodes.getNodeAs("decl"); + + // Report an error for every member which is non-memmovable + for (const FieldDecl *Field : Declaration->fields()) { + QualType Type = Field->getType(); + if (NonMemMovable.hasEffectiveAnnotation(Type)) { + diag(Field->getLocation(), Error, DiagnosticIDs::Error) + << Declaration << Field << Type; + NonMemMovable.dumpAnnotationReason(*this, Type, + Declaration->getLocation()); + } + } +} diff --git a/build/clang-plugin/NonMemMovableMemberChecker.h b/build/clang-plugin/NonMemMovableMemberChecker.h new file mode 100644 index 0000000000..0fc9b1f87f --- /dev/null +++ b/build/clang-plugin/NonMemMovableMemberChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NonMemMovableMemberChecker_h__ +#define NonMemMovableMemberChecker_h__ + +#include "plugin.h" + +class NonMemMovableMemberChecker : public BaseCheck { +public: + NonMemMovableMemberChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/NonMemMovableTemplateArgChecker.cpp b/build/clang-plugin/NonMemMovableTemplateArgChecker.cpp new file mode 100644 index 0000000000..65afe21006 --- /dev/null +++ b/build/clang-plugin/NonMemMovableTemplateArgChecker.cpp @@ -0,0 +1,51 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NonMemMovableTemplateArgChecker.h" +#include "CustomMatchers.h" + +void NonMemMovableTemplateArgChecker::registerMatchers( + MatchFinder *AstMatcher) { + // Handle non-mem-movable template specializations + AstMatcher->addMatcher( + classTemplateSpecializationDecl( + allOf(needsMemMovableTemplateArg(), + hasAnyTemplateArgument(refersToType(isNonMemMovable())))) + .bind("specialization"), + this); +} + +void NonMemMovableTemplateArgChecker::check( + const MatchFinder::MatchResult &Result) { + const char *Error = + "Cannot instantiate %0 with non-memmovable template argument %1"; + const char *Note = "instantiation of %0 requested here"; + + // Get the specialization + const ClassTemplateSpecializationDecl *Specialization = + Result.Nodes.getNodeAs("specialization"); + SourceLocation RequestLoc = Specialization->getPointOfInstantiation(); + + // Report an error for every template argument which is non-memmovable + const TemplateArgumentList &Args = + Specialization->getTemplateInstantiationArgs(); + for (unsigned i = 0; i < Args.size(); ++i) { + QualType ArgType = Args[i].getAsType(); + if (NonMemMovable.hasEffectiveAnnotation(ArgType)) { + diag(Specialization->getLocation(), Error, DiagnosticIDs::Error) + << Specialization << ArgType; + // XXX It would be really nice if we could get the instantiation stack + // information + // from Sema such that we could print a full template instantiation stack, + // however, + // it seems as though that information is thrown out by the time we get + // here so we + // can only report one level of template specialization (which in many + // cases won't + // be useful) + diag(RequestLoc, Note, DiagnosticIDs::Note) << Specialization; + NonMemMovable.dumpAnnotationReason(*this, ArgType, RequestLoc); + } + } +} diff --git a/build/clang-plugin/NonMemMovableTemplateArgChecker.h b/build/clang-plugin/NonMemMovableTemplateArgChecker.h new file mode 100644 index 0000000000..cd94c95930 --- /dev/null +++ b/build/clang-plugin/NonMemMovableTemplateArgChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NonMemMovableTemplateArgChecker_h__ +#define NonMemMovableTemplateArgChecker_h__ + +#include "plugin.h" + +class NonMemMovableTemplateArgChecker : public BaseCheck { +public: + NonMemMovableTemplateArgChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/NonParamInsideFunctionDeclChecker.cpp b/build/clang-plugin/NonParamInsideFunctionDeclChecker.cpp new file mode 100644 index 0000000000..e74fd2bb08 --- /dev/null +++ b/build/clang-plugin/NonParamInsideFunctionDeclChecker.cpp @@ -0,0 +1,217 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NonParamInsideFunctionDeclChecker.h" +#include "CustomMatchers.h" +#include "clang/Basic/TargetInfo.h" + +class NonParamAnnotation : public CustomTypeAnnotation { +public: + NonParamAnnotation() : CustomTypeAnnotation(moz_non_param, "non-param"){}; + +protected: + // Helper for checking if a Decl has an explicitly specified alignment. + // Returns the alignment, in char units, of the largest alignment attribute, + // if it exceeds pointer alignment, and 0 otherwise. + static unsigned checkExplicitAlignment(const Decl *D) { + ASTContext &Context = D->getASTContext(); +#if CLANG_VERSION_FULL >= 1600 + unsigned PointerAlign = Context.getTargetInfo().getPointerAlign(LangAS::Default); +#else + unsigned PointerAlign = Context.getTargetInfo().getPointerAlign(0); +#endif + + // getMaxAlignment gets the largest alignment, in bits, specified by an + // alignment attribute directly on the declaration. If no alignment + // attribute is specified, it will return `0`. + unsigned MaxAlign = D->getMaxAlignment(); + if (MaxAlign > PointerAlign) { + return Context.toCharUnitsFromBits(MaxAlign).getQuantity(); + } + return 0; + } + + // This is directly derived from the logic in Clang's `canPassInRegisters` + // function, from `SemaDeclCXX`. It is used instead of `canPassInRegisters` to + // behave consistently on 64-bit windows platforms which are overly + // permissive, allowing too many types to be passed in registers. + // + // Types which can be passed in registers will be re-aligned in the called + // function by clang, so aren't impacted by the win32 object passing ABI + // alignment issue. + static bool canPassAsTemporary(const CXXRecordDecl *D) { + // Per C++ [class.temporary]p3: + // + // When an object of class type X is passed to or returned from a function, + // if X has at least one eligible copy or move constructor ([special]), each + // such constructor is trivial, and the destructor of X is either trivial or + // deleted, implementations are permitted to create a temporary object to + // hold the function parameter or result object. + // + // The temporary object is constructed from the function argument or return + // value, respectively, and the function's parameter or return object is + // initialized as if by using the eligible trivial constructor to copy the + // temporary (even if that constructor is inaccessible or would not be + // selected by overload resolution to perform a copy or move of the object). + bool HasNonDeletedCopyOrMove = false; + + if (D->needsImplicitCopyConstructor() && + !D->defaultedCopyConstructorIsDeleted()) { + if (!D->hasTrivialCopyConstructorForCall()) + return false; + HasNonDeletedCopyOrMove = true; + } + + if (D->needsImplicitMoveConstructor() && + !D->defaultedMoveConstructorIsDeleted()) { + if (!D->hasTrivialMoveConstructorForCall()) + return false; + HasNonDeletedCopyOrMove = true; + } + + if (D->needsImplicitDestructor() && !D->defaultedDestructorIsDeleted() && + !D->hasTrivialDestructorForCall()) + return false; + + for (const CXXMethodDecl *MD : D->methods()) { + if (MD->isDeleted()) + continue; + + auto *CD = dyn_cast(MD); + if (CD && CD->isCopyOrMoveConstructor()) + HasNonDeletedCopyOrMove = true; + else if (!isa(MD)) + continue; + + if (!MD->isTrivialForCall()) + return false; + } + + return HasNonDeletedCopyOrMove; + } + + // Adding alignas(_) on a struct implicitly marks it as MOZ_NON_PARAM, due to + // MSVC limitations which prevent passing explcitly aligned types by value as + // parameters. This overload of hasFakeAnnotation injects fake MOZ_NON_PARAM + // annotations onto these types. + std::string getImplicitReason(const TagDecl *D, + VisitFlags &ToVisit) const override { + // Some stdlib types are known to have alignments over the pointer size on + // non-win32 platforms, but should not be linted against. Clear any + // annotations on those types. + if (!D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft() && + getDeclarationNamespace(D) == "std") { + StringRef Name = getNameChecked(D); + if (Name == "function") { + ToVisit = VISIT_NONE; + return ""; + } + } + + // If the type doesn't have a destructor and can be passed with a temporary, + // clang will handle re-aligning it for us automatically, and we don't need + // to worry about the passed alignment. + auto RD = dyn_cast(D); + if (RD && RD->isCompleteDefinition() && canPassAsTemporary(RD)) { + return ""; + } + + // Check if the decl itself has an explicit alignment on it. + if (unsigned ExplicitAlign = checkExplicitAlignment(D)) { + return "it has an explicit alignment of '" + + std::to_string(ExplicitAlign) + "'"; + } + + // Check if any of the decl's fields have an explicit alignment on them. + if (auto RD = dyn_cast(D)) { + for (auto F : RD->fields()) { + if (unsigned ExplicitAlign = checkExplicitAlignment(F)) { + return ("member '" + F->getName() + + "' has an explicit alignment of '" + + std::to_string(ExplicitAlign) + "'") + .str(); + } + } + } + + // We don't need to check the types of fields, as the CustomTypeAnnotation + // infrastructure will handle that for us. + return ""; + } +}; +NonParamAnnotation NonParam; + +void NonParamInsideFunctionDeclChecker::registerMatchers( + MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + functionDecl( + anyOf(allOf(isDefinition(), + hasAncestor( + classTemplateSpecializationDecl().bind("spec"))), + isDefinition())) + .bind("func"), + this); + AstMatcher->addMatcher(lambdaExpr().bind("lambda"), this); +} + +void NonParamInsideFunctionDeclChecker::check( + const MatchFinder::MatchResult &Result) { + static DenseSet CheckedFunctionDecls; + + const FunctionDecl *func = Result.Nodes.getNodeAs("func"); + if (!func) { + const LambdaExpr *lambda = Result.Nodes.getNodeAs("lambda"); + if (lambda) { + func = lambda->getCallOperator(); + } + } + + if (!func) { + return; + } + + if (func->isDeleted()) { + return; + } + + // We need to skip decls which have these types as parameters in system + // headers, because presumably those headers act like an assertion that the + // alignment will be preserved in that situation. + if (getDeclarationNamespace(func) == "std") { + return; + } + + if (inThirdPartyPath(func)) { + return; + } + + // Don't report errors on the same declarations more than once. + if (CheckedFunctionDecls.count(func)) { + return; + } + CheckedFunctionDecls.insert(func); + + const ClassTemplateSpecializationDecl *Spec = + Result.Nodes.getNodeAs("spec"); + + for (ParmVarDecl *p : func->parameters()) { + QualType T = p->getType().withoutLocalFastQualifiers(); + if (NonParam.hasEffectiveAnnotation(T)) { + diag(p->getLocation(), "Type %0 must not be used as parameter", + DiagnosticIDs::Error) + << T; + diag(p->getLocation(), + "Please consider passing a const reference instead", + DiagnosticIDs::Note); + + if (Spec) { + diag(Spec->getPointOfInstantiation(), + "The bad argument was passed to %0 here", DiagnosticIDs::Note) + << Spec->getSpecializedTemplate(); + } + + NonParam.dumpAnnotationReason(*this, T, p->getLocation()); + } + } +} diff --git a/build/clang-plugin/NonParamInsideFunctionDeclChecker.h b/build/clang-plugin/NonParamInsideFunctionDeclChecker.h new file mode 100644 index 0000000000..ed11f3fe12 --- /dev/null +++ b/build/clang-plugin/NonParamInsideFunctionDeclChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NonParamInsideFunctionDeclChecker_h__ +#define NonParamInsideFunctionDeclChecker_h__ + +#include "plugin.h" + +class NonParamInsideFunctionDeclChecker : public BaseCheck { +public: + NonParamInsideFunctionDeclChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/NonTrivialTypeInFfiChecker.cpp b/build/clang-plugin/NonTrivialTypeInFfiChecker.cpp new file mode 100644 index 0000000000..f482fb131f --- /dev/null +++ b/build/clang-plugin/NonTrivialTypeInFfiChecker.cpp @@ -0,0 +1,56 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NonTrivialTypeInFfiChecker.h" +#include "CustomMatchers.h" + +void NonTrivialTypeInFfiChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher(functionDecl(isExternC()).bind("func"), this); +} + +void NonTrivialTypeInFfiChecker::check(const MatchFinder::MatchResult &Result) { + static DenseSet CheckedFunctionDecls; + + const FunctionDecl *func = Result.Nodes.getNodeAs("func"); + // Don't report errors on the same declarations more than once. + if (!CheckedFunctionDecls.insert(func).second) { + return; + } + + if (inThirdPartyPath(func)) { + return; + } + + auto NoteFor = [](const QualType &T) -> std::string { + std::string s = "Please consider using a pointer or reference"; + if (T->getAs()) { + s += ", or explicitly instantiating the template"; + } + return s + " instead"; + }; + + for (ParmVarDecl *p : func->parameters()) { + QualType T = p->getType().getUnqualifiedType(); + if (!T->isVoidType() && !T->isReferenceType() && + !T.isTriviallyCopyableType(*Result.Context)) { + diag(p->getLocation(), + "Type %0 must not be used as parameter to extern " + "\"C\" function", + DiagnosticIDs::Error) + << T; + diag(p->getLocation(), NoteFor(T), DiagnosticIDs::Note); + } + } + + QualType T = func->getReturnType().getUnqualifiedType(); + if (!T->isVoidType() && !T->isReferenceType() && + !T.isTriviallyCopyableType(*Result.Context)) { + diag(func->getLocation(), + "Type %0 must not be used as return type of " + "extern \"C\" function", + DiagnosticIDs::Error) + << T; + diag(func->getLocation(), NoteFor(T), DiagnosticIDs::Note); + } +} diff --git a/build/clang-plugin/NonTrivialTypeInFfiChecker.h b/build/clang-plugin/NonTrivialTypeInFfiChecker.h new file mode 100644 index 0000000000..106c64c021 --- /dev/null +++ b/build/clang-plugin/NonTrivialTypeInFfiChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NonTrivialTypeInFfiChecker_h__ +#define NonTrivialTypeInFfiChecker_h__ + +#include "plugin.h" + +class NonTrivialTypeInFfiChecker : public BaseCheck { +public: + NonTrivialTypeInFfiChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/OverrideBaseCallChecker.cpp b/build/clang-plugin/OverrideBaseCallChecker.cpp new file mode 100644 index 0000000000..600d431335 --- /dev/null +++ b/build/clang-plugin/OverrideBaseCallChecker.cpp @@ -0,0 +1,109 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "OverrideBaseCallChecker.h" +#include "CustomMatchers.h" + +void OverrideBaseCallChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher(cxxRecordDecl(hasBaseClasses()).bind("class"), this); +} + +bool OverrideBaseCallChecker::isRequiredBaseMethod( + const CXXMethodDecl *Method) { + return hasCustomAttribute(Method); +} + +void OverrideBaseCallChecker::evaluateExpression( + const Stmt *StmtExpr, std::list &MethodList) { + // Continue while we have methods in our list + if (!MethodList.size()) { + return; + } + + if (auto MemberFuncCall = dyn_cast(StmtExpr)) { + if (auto Method = + dyn_cast(MemberFuncCall->getDirectCallee())) { + findBaseMethodCall(Method, MethodList); + } + } + + for (auto S : StmtExpr->children()) { + if (S) { + evaluateExpression(S, MethodList); + } + } +} + +void OverrideBaseCallChecker::getRequiredBaseMethod( + const CXXMethodDecl *Method, + std::list &MethodsList) { + + if (isRequiredBaseMethod(Method)) { + MethodsList.push_back(Method); + } else { + // Loop through all it's base methods. + for (auto BaseMethod = Method->begin_overridden_methods(); + BaseMethod != Method->end_overridden_methods(); BaseMethod++) { + getRequiredBaseMethod(*BaseMethod, MethodsList); + } + } +} + +void OverrideBaseCallChecker::findBaseMethodCall( + const CXXMethodDecl *Method, + std::list &MethodsList) { + + MethodsList.remove(Method); + // Loop also through all it's base methods; + for (auto BaseMethod = Method->begin_overridden_methods(); + BaseMethod != Method->end_overridden_methods(); BaseMethod++) { + findBaseMethodCall(*BaseMethod, MethodsList); + } +} + +void OverrideBaseCallChecker::check(const MatchFinder::MatchResult &Result) { + const char *Error = + "Method %0 must be called in all overrides, but is not called in " + "this override defined for class %1"; + const CXXRecordDecl *Decl = Result.Nodes.getNodeAs("class"); + + // Loop through the methods and look for the ones that are overridden. + for (auto Method : Decl->methods()) { + // If this method doesn't override other methods or it doesn't have a body, + // continue to the next declaration. + if (!Method->size_overridden_methods() || !Method->hasBody()) { + continue; + } + + // Preferred the usage of list instead of vector in order to avoid + // calling erase-remove when deleting items + std::list MethodsList; + // For each overridden method push it to a list if it meets our + // criteria + for (auto BaseMethod = Method->begin_overridden_methods(); + BaseMethod != Method->end_overridden_methods(); BaseMethod++) { + getRequiredBaseMethod(*BaseMethod, MethodsList); + } + + // If no method has been found then no annotation was used + // so checking is not needed + if (!MethodsList.size()) { + continue; + } + + // Loop through the body of our method and search for calls to + // base methods + evaluateExpression(Method->getBody(), MethodsList); + + // If list is not empty pop up errors + for (auto BaseMethod : MethodsList) { + std::string QualName; + raw_string_ostream OS(QualName); + BaseMethod->printQualifiedName(OS); + + diag(Method->getLocation(), Error, DiagnosticIDs::Error) + << OS.str() << Decl->getName(); + } + } +} diff --git a/build/clang-plugin/OverrideBaseCallChecker.h b/build/clang-plugin/OverrideBaseCallChecker.h new file mode 100644 index 0000000000..e919af6749 --- /dev/null +++ b/build/clang-plugin/OverrideBaseCallChecker.h @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef OverrideBaseCallChecker_h__ +#define OverrideBaseCallChecker_h__ + +#include "plugin.h" + +class OverrideBaseCallChecker : public BaseCheck { +public: + OverrideBaseCallChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; + +private: + void evaluateExpression(const Stmt *StmtExpr, + std::list &MethodList); + void getRequiredBaseMethod(const CXXMethodDecl *Method, + std::list &MethodsList); + void findBaseMethodCall(const CXXMethodDecl *Method, + std::list &MethodsList); + bool isRequiredBaseMethod(const CXXMethodDecl *Method); +}; + +#endif diff --git a/build/clang-plugin/OverrideBaseCallUsageChecker.cpp b/build/clang-plugin/OverrideBaseCallUsageChecker.cpp new file mode 100644 index 0000000000..34b9cd16a9 --- /dev/null +++ b/build/clang-plugin/OverrideBaseCallUsageChecker.cpp @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "OverrideBaseCallUsageChecker.h" +#include "CustomMatchers.h" + +void OverrideBaseCallUsageChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + cxxMethodDecl(isNonVirtual(), isRequiredBaseMethod()).bind("method"), + this); +} + +void OverrideBaseCallUsageChecker::check( + const MatchFinder::MatchResult &Result) { + const char *Error = + "MOZ_REQUIRED_BASE_METHOD can be used only on virtual methods"; + const CXXMethodDecl *Method = Result.Nodes.getNodeAs("method"); + + diag(Method->getLocation(), Error, DiagnosticIDs::Error); +} diff --git a/build/clang-plugin/OverrideBaseCallUsageChecker.h b/build/clang-plugin/OverrideBaseCallUsageChecker.h new file mode 100644 index 0000000000..0e81d72387 --- /dev/null +++ b/build/clang-plugin/OverrideBaseCallUsageChecker.h @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef OverrideBaseCallUsageChecker_h__ +#define OverrideBaseCallUsageChecker_h__ + +#include "plugin.h" + +/* + * This is a companion checker for OverrideBaseCallChecker that rejects + * the usage of MOZ_REQUIRED_BASE_METHOD on non-virtual base methods. + */ +class OverrideBaseCallUsageChecker : public BaseCheck { +public: + OverrideBaseCallUsageChecker(StringRef CheckName = "override-base-call-usage", + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/ParamTraitsEnumChecker.cpp b/build/clang-plugin/ParamTraitsEnumChecker.cpp new file mode 100644 index 0000000000..7214e9fe5b --- /dev/null +++ b/build/clang-plugin/ParamTraitsEnumChecker.cpp @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ParamTraitsEnumChecker.h" +#include "CustomMatchers.h" + +void ParamTraitsEnumChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + classTemplateSpecializationDecl(hasName("ParamTraits")).bind("decl"), + this); +} + +void ParamTraitsEnumChecker::check(const MatchFinder::MatchResult &Result) { + const ClassTemplateSpecializationDecl *Decl = + Result.Nodes.getNodeAs("decl"); + + for (auto &Inner : Decl->decls()) { + if (auto *Def = dyn_cast(Inner)) { + QualType UnderlyingType = Def->getUnderlyingType(); + QualType CanonicalType = UnderlyingType.getCanonicalType(); + + const clang::Type *TypePtr = CanonicalType.getTypePtrOrNull(); + if (!TypePtr) { + return; + } + + if (TypePtr->isEnumeralType()) { + diag(Decl->getBeginLoc(), + "Custom ParamTraits implementation for an enum type", + DiagnosticIDs::Error); + diag(Decl->getBeginLoc(), + "Please use a helper class for example ContiguousEnumSerializer", + DiagnosticIDs::Note); + } + } + } +} diff --git a/build/clang-plugin/ParamTraitsEnumChecker.h b/build/clang-plugin/ParamTraitsEnumChecker.h new file mode 100644 index 0000000000..e89a7d2895 --- /dev/null +++ b/build/clang-plugin/ParamTraitsEnumChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ParamTraitsEnumChecker_h__ +#define ParamTraitsEnumChecker_h__ + +#include "plugin.h" + +class ParamTraitsEnumChecker : public BaseCheck { +public: + ParamTraitsEnumChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/RecurseGuard.h b/build/clang-plugin/RecurseGuard.h new file mode 100644 index 0000000000..5daf55a9e8 --- /dev/null +++ b/build/clang-plugin/RecurseGuard.h @@ -0,0 +1,56 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef RecurseGuard_h__ +#define RecurseGuard_h__ + +#include "Utils.h" + +// This class acts as a tracker for avoiding infinite recursion when traversing +// chains in CFGs etc. +// +// Constructing a RecurseGuard sets up a shared backing store which tracks the +// currently observed objects. Whenever recursing, use RecurseGuard.recurse(T) +// to construct another RecurseGuard with the same backing store. +// +// The RecurseGuard object will unregister its object when it is destroyed, and +// has a method `isRepeat()` which will return `true` if the item was already +// seen. +template class RecurseGuard { +public: + RecurseGuard(T Thing) : Thing(Thing), Set(new DenseSet()), Repeat(false) { + Set->insert(Thing); + } + RecurseGuard(T Thing, std::shared_ptr> &Set) + : Thing(Thing), Set(Set), Repeat(false) { + Repeat = !Set->insert(Thing).second; + } + RecurseGuard(const RecurseGuard &) = delete; + RecurseGuard(RecurseGuard &&Other) + : Thing(Other.Thing), Set(Other.Set), Repeat(Other.Repeat) { + Other.Repeat = true; + } + ~RecurseGuard() { + if (!Repeat) { + Set->erase(Thing); + } + } + + bool isRepeat() { return Repeat; } + + T get() { return Thing; } + + operator T() { return Thing; } + + T operator->() { return Thing; } + + RecurseGuard recurse(T NewThing) { return RecurseGuard(NewThing, Set); } + +private: + T Thing; + std::shared_ptr> Set; + bool Repeat; +}; + +#endif // RecurseGuard_h__ diff --git a/build/clang-plugin/RefCountedCopyConstructorChecker.cpp b/build/clang-plugin/RefCountedCopyConstructorChecker.cpp new file mode 100644 index 0000000000..569d4eecec --- /dev/null +++ b/build/clang-plugin/RefCountedCopyConstructorChecker.cpp @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RefCountedCopyConstructorChecker.h" +#include "CustomMatchers.h" + +void RefCountedCopyConstructorChecker::registerMatchers( + MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + cxxConstructExpr( + hasDeclaration(cxxConstructorDecl(isCompilerProvidedCopyConstructor(), + ofClass(hasRefCntMember())))) + .bind("node"), + this); +} + +void RefCountedCopyConstructorChecker::check( + const MatchFinder::MatchResult &Result) { + const char *Error = + "Invalid use of compiler-provided copy constructor on refcounted type"; + const char *Note = "The default copy constructor also copies the " + "default mRefCnt property, leading to reference " + "count imbalance issues. Please provide your own " + "copy constructor which only copies the fields which " + "need to be copied"; + + // Everything we needed to know was checked in the matcher - we just report + // the error here + const CXXConstructExpr *E = Result.Nodes.getNodeAs("node"); + + diag(E->getLocation(), Error, DiagnosticIDs::Error); + diag(E->getLocation(), Note, DiagnosticIDs::Note); +} diff --git a/build/clang-plugin/RefCountedCopyConstructorChecker.h b/build/clang-plugin/RefCountedCopyConstructorChecker.h new file mode 100644 index 0000000000..edae63534a --- /dev/null +++ b/build/clang-plugin/RefCountedCopyConstructorChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef RefCountedCopyConstructorChecker_h__ +#define RefCountedCopyConstructorChecker_h__ + +#include "plugin.h" + +class RefCountedCopyConstructorChecker : public BaseCheck { +public: + RefCountedCopyConstructorChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/RefCountedInsideLambdaChecker.cpp b/build/clang-plugin/RefCountedInsideLambdaChecker.cpp new file mode 100644 index 0000000000..3256aa8f04 --- /dev/null +++ b/build/clang-plugin/RefCountedInsideLambdaChecker.cpp @@ -0,0 +1,164 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RefCountedInsideLambdaChecker.h" +#include "CustomMatchers.h" + +RefCountedMap RefCountedClasses; + +void RefCountedInsideLambdaChecker::registerMatchers(MatchFinder *AstMatcher) { + // We want to reject any code which captures a pointer to an object of a + // refcounted type, and then lets that value escape. As a primitive analysis, + // we reject any occurances of the lambda as a template parameter to a class + // (which could allow it to escape), as well as any presence of such a lambda + // in a return value (either from lambdas, or in c++14, auto functions). + // + // We check these lambdas' capture lists for raw pointers to refcounted types. + AstMatcher->addMatcher(functionDecl(returns(recordType(hasDeclaration( + cxxRecordDecl(isLambdaDecl()).bind("decl"))))), + this); + AstMatcher->addMatcher(lambdaExpr().bind("lambdaExpr"), this); + AstMatcher->addMatcher( + classTemplateSpecializationDecl( + hasAnyTemplateArgument(refersToType(recordType( + hasDeclaration(cxxRecordDecl(isLambdaDecl()).bind("decl")))))), + this); +} + +void RefCountedInsideLambdaChecker::emitDiagnostics(SourceLocation Loc, + StringRef Name, + QualType Type) { + diag(Loc, + "Refcounted variable '%0' of type %1 cannot be captured by a lambda", + DiagnosticIDs::Error) + << Name << Type; + diag(Loc, "Please consider using a smart pointer", DiagnosticIDs::Note); +} + +static bool IsKnownLive(const VarDecl *Var) { + const Stmt *Init = Var->getInit(); + if (!Init) { + return false; + } + if (auto *Call = dyn_cast(Init)) { + const FunctionDecl *Callee = Call->getDirectCallee(); + return Callee && Callee->getName() == "MOZ_KnownLive"; + } + return false; +} + +void RefCountedInsideLambdaChecker::check( + const MatchFinder::MatchResult &Result) { + static DenseSet CheckedDecls; + + const CXXRecordDecl *Lambda = Result.Nodes.getNodeAs("decl"); + + if (const LambdaExpr *OuterLambda = + Result.Nodes.getNodeAs("lambdaExpr")) { + const CXXMethodDecl *OpCall = OuterLambda->getCallOperator(); + QualType ReturnTy = OpCall->getReturnType(); + if (const CXXRecordDecl *Record = ReturnTy->getAsCXXRecordDecl()) { + Lambda = Record; + } + } + + if (!Lambda || !Lambda->isLambda()) { + return; + } + + // Don't report errors on the same declarations more than once. + if (CheckedDecls.count(Lambda)) { + return; + } + CheckedDecls.insert(Lambda); + + bool StrongRefToThisCaptured = false; + + for (const LambdaCapture &Capture : Lambda->captures()) { + // Check if any of the captures are ByRef. If they are, we have nothing to + // report, as it's OK to capture raw pointers to refcounted objects so long + // as the Lambda doesn't escape the current scope, which is required by + // ByRef captures already. + if (Capture.getCaptureKind() == LCK_ByRef) { + return; + } + + // Check if this capture is byvalue, and captures a strong reference to + // this. + // XXX: Do we want to make sure that this type which we are capturing is a + // "Smart Pointer" somehow? + if (!StrongRefToThisCaptured && Capture.capturesVariable() && + Capture.getCaptureKind() == LCK_ByCopy) { + const VarDecl *Var = dyn_cast(Capture.getCapturedVar()); + if (Var->hasInit()) { + const Stmt *Init = Var->getInit(); + + // Ignore single argument constructors, and trivial nodes. + while (true) { + auto NewInit = IgnoreTrivials(Init); + if (auto ConstructExpr = dyn_cast(NewInit)) { + if (ConstructExpr->getNumArgs() == 1) { + NewInit = ConstructExpr->getArg(0); + } + } + if (Init == NewInit) { + break; + } + Init = NewInit; + } + + if (isa(Init)) { + StrongRefToThisCaptured = true; + } + } + } + } + + // Now we can go through and produce errors for any captured variables or this + // pointers. + for (const LambdaCapture &Capture : Lambda->captures()) { + if (Capture.capturesVariable()) { + const VarDecl *Var = dyn_cast(Capture.getCapturedVar()); + QualType Pointee = Var->getType()->getPointeeType(); + if (!Pointee.isNull() && isClassRefCounted(Pointee) && + !IsKnownLive(Var)) { + emitDiagnostics(Capture.getLocation(), Var->getName(), Pointee); + return; + } + } + + // The situation with captures of `this` is more complex. All captures of + // `this` look the same-ish (they are LCK_This). We want to complain about + // captures of `this` where `this` is a refcounted type, and the capture is + // actually used in the body of the lambda (if the capture isn't used, then + // we don't care, because it's only being captured in order to give access + // to private methods). + // + // In addition, we don't complain about this, even if it is used, if it was + // captured implicitly when the LambdaCaptureDefault was LCD_ByRef, as that + // expresses the intent that the lambda won't leave the enclosing scope. + bool ImplicitByRefDefaultedCapture = + Capture.isImplicit() && Lambda->getLambdaCaptureDefault() == LCD_ByRef; + if (Capture.capturesThis() && !ImplicitByRefDefaultedCapture && + !StrongRefToThisCaptured) { + ThisVisitor V(*this); + bool NotAborted = V.TraverseDecl( + const_cast(Lambda->getLambdaCallOperator())); + if (!NotAborted) { + return; + } + } + } +} + +bool RefCountedInsideLambdaChecker::ThisVisitor::VisitCXXThisExpr( + CXXThisExpr *This) { + QualType Pointee = This->getType()->getPointeeType(); + if (!Pointee.isNull() && isClassRefCounted(Pointee)) { + Checker.emitDiagnostics(This->getBeginLoc(), "this", Pointee); + return false; + } + + return true; +} diff --git a/build/clang-plugin/RefCountedInsideLambdaChecker.h b/build/clang-plugin/RefCountedInsideLambdaChecker.h new file mode 100644 index 0000000000..ed9419681a --- /dev/null +++ b/build/clang-plugin/RefCountedInsideLambdaChecker.h @@ -0,0 +1,33 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef RefCountedInsideLambdaChecker_h__ +#define RefCountedInsideLambdaChecker_h__ + +#include "plugin.h" + +class RefCountedInsideLambdaChecker : public BaseCheck { +public: + RefCountedInsideLambdaChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; + + void emitDiagnostics(SourceLocation Loc, StringRef Name, QualType Type); + +private: + class ThisVisitor : public RecursiveASTVisitor { + public: + explicit ThisVisitor(RefCountedInsideLambdaChecker &Checker) + : Checker(Checker) {} + + bool VisitCXXThisExpr(CXXThisExpr *This); + + private: + RefCountedInsideLambdaChecker &Checker; + }; +}; + +#endif diff --git a/build/clang-plugin/RefCountedThisInsideConstructorChecker.cpp b/build/clang-plugin/RefCountedThisInsideConstructorChecker.cpp new file mode 100644 index 0000000000..9607f41f10 --- /dev/null +++ b/build/clang-plugin/RefCountedThisInsideConstructorChecker.cpp @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RefCountedThisInsideConstructorChecker.h" +#include "CustomMatchers.h" + +void RefCountedThisInsideConstructorChecker::registerMatchers( + MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + cxxConstructExpr(hasType(isSmartPtrToRefCounted()), + hasArgument(0, cxxThisExpr()), + hasAncestor(cxxConstructorDecl().bind("constructor"))) + .bind("call"), + this); +} + +void RefCountedThisInsideConstructorChecker::check( + const MatchFinder::MatchResult &Result) { + const CXXConstructExpr *Call = + Result.Nodes.getNodeAs("call"); + + diag(Call->getBeginLoc(), + "Refcounting `this` inside the constructor is a footgun, `this` may be " + "destructed at the end of the constructor unless there's another strong " + "reference. Consider adding a separate Create function and do the work " + "there.", + DiagnosticIDs::Error); +} diff --git a/build/clang-plugin/RefCountedThisInsideConstructorChecker.h b/build/clang-plugin/RefCountedThisInsideConstructorChecker.h new file mode 100644 index 0000000000..f8ae68e2a5 --- /dev/null +++ b/build/clang-plugin/RefCountedThisInsideConstructorChecker.h @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BUILD_CLANG_PLUGIN_PREVENTADDREFWITHINCONSTRUCTORCHECKER_H +#define BUILD_CLANG_PLUGIN_PREVENTADDREFWITHINCONSTRUCTORCHECKER_H + +#include "plugin.h" + +class RefCountedThisInsideConstructorChecker : public BaseCheck { +public: + RefCountedThisInsideConstructorChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/ScopeChecker.cpp b/build/clang-plugin/ScopeChecker.cpp new file mode 100644 index 0000000000..962c252105 --- /dev/null +++ b/build/clang-plugin/ScopeChecker.cpp @@ -0,0 +1,180 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ScopeChecker.h" +#include "CustomMatchers.h" + +void ScopeChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher(varDecl().bind("node"), this); + AstMatcher->addMatcher(cxxNewExpr().bind("node"), this); + AstMatcher->addMatcher( + materializeTemporaryExpr( + unless(hasDescendant(cxxConstructExpr(allowsTemporary())))) + .bind("node"), + this); + AstMatcher->addMatcher( + callExpr(callee(functionDecl(heapAllocator()))).bind("node"), this); +} + +// These enum variants determine whether an allocation has occured in the code. +enum AllocationVariety { + AV_None, + AV_Global, + AV_Automatic, + AV_Temporary, + AV_Heap, +}; + +// XXX Currently the Decl* in the AutomaticTemporaryMap is unused, but it +// probably will be used at some point in the future, in order to produce better +// error messages. +typedef DenseMap + AutomaticTemporaryMap; +AutomaticTemporaryMap AutomaticTemporaries; + +void ScopeChecker::check(const MatchFinder::MatchResult &Result) { + // There are a variety of different reasons why something could be allocated + AllocationVariety Variety = AV_None; + SourceLocation Loc; + QualType T; + bool IsStaticLocal = false; + + if (const ParmVarDecl *D = Result.Nodes.getNodeAs("node")) { + if (D->hasUnparsedDefaultArg() || D->hasUninstantiatedDefaultArg()) { + return; + } + if (const Expr *Default = D->getDefaultArg()) { + if (const MaterializeTemporaryExpr *E = + dyn_cast(Default)) { + // We have just found a ParmVarDecl which has, as its default argument, + // a MaterializeTemporaryExpr. We mark that MaterializeTemporaryExpr as + // automatic, by adding it to the AutomaticTemporaryMap. + // Reporting on this type will occur when the MaterializeTemporaryExpr + // is matched against. + AutomaticTemporaries[E] = D; + } + } + return; + } + + // Determine the type of allocation which we detected + if (const VarDecl *D = Result.Nodes.getNodeAs("node")) { + if (D->hasGlobalStorage()) { + Variety = AV_Global; + } else { + Variety = AV_Automatic; + } + T = D->getType(); + Loc = D->getBeginLoc(); + IsStaticLocal = D->isStaticLocal(); + } else if (const CXXNewExpr *E = Result.Nodes.getNodeAs("node")) { + // New allocates things on the heap. + // We don't consider placement new to do anything, as it doesn't actually + // allocate the storage, and thus gives us no useful information. + if (!isPlacementNew(E)) { + Variety = AV_Heap; + T = E->getAllocatedType(); + Loc = E->getBeginLoc(); + } + } else if (const MaterializeTemporaryExpr *E = + Result.Nodes.getNodeAs("node")) { + // Temporaries can actually have varying storage durations, due to temporary + // lifetime extension. We consider the allocation variety of this temporary + // to be the same as the allocation variety of its lifetime. + + // XXX We maybe should mark these lifetimes as being due to a temporary + // which has had its lifetime extended, to improve the error messages. + switch (E->getStorageDuration()) { + case SD_FullExpression: { + // Check if this temporary is allocated as a default argument! + // if it is, we want to pretend that it is automatic. + AutomaticTemporaryMap::iterator AutomaticTemporary = + AutomaticTemporaries.find(E); + if (AutomaticTemporary != AutomaticTemporaries.end()) { + Variety = AV_Automatic; + } else { + Variety = AV_Temporary; + } + } break; + case SD_Automatic: + Variety = AV_Automatic; + break; + case SD_Thread: + case SD_Static: + Variety = AV_Global; + break; + case SD_Dynamic: + assert(false && "I don't think that this ever should occur..."); + Variety = AV_Heap; + break; + } + T = E->getType().getUnqualifiedType(); + Loc = E->getBeginLoc(); + } else if (const CallExpr *E = Result.Nodes.getNodeAs("node")) { + T = E->getType()->getPointeeType(); + if (!T.isNull()) { + // This will always allocate on the heap, as the heapAllocator() check + // was made in the matcher + Variety = AV_Heap; + Loc = E->getBeginLoc(); + } + } + + // Error messages for incorrect allocations. + const char *Stack = "variable of type %0 only valid on the stack"; + const char *Global = "variable of type %0 only valid as global"; + const char *Heap = "variable of type %0 only valid on the heap"; + const char *NonHeap = "variable of type %0 is not valid on the heap"; + const char *NonTemporary = "variable of type %0 is not valid in a temporary"; + const char *Temporary = "variable of type %0 is only valid as a temporary"; + const char *StaticLocal = "variable of type %0 is only valid as a static " + "local"; + + const char *StackNote = + "value incorrectly allocated in an automatic variable"; + const char *GlobalNote = "value incorrectly allocated in a global variable"; + const char *HeapNote = "value incorrectly allocated on the heap"; + const char *TemporaryNote = "value incorrectly allocated in a temporary"; + + // Report errors depending on the annotations on the input types. + switch (Variety) { + case AV_None: + return; + + case AV_Global: + StackClass.reportErrorIfPresent(*this, T, Loc, Stack, GlobalNote); + HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, GlobalNote); + TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, GlobalNote); + if (!IsStaticLocal) { + StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal, + GlobalNote); + } + break; + + case AV_Automatic: + GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, StackNote); + HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, StackNote); + TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, StackNote); + StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal, + StackNote); + break; + + case AV_Temporary: + GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, TemporaryNote); + HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, TemporaryNote); + NonTemporaryClass.reportErrorIfPresent(*this, T, Loc, NonTemporary, + TemporaryNote); + StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal, + TemporaryNote); + break; + + case AV_Heap: + GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, HeapNote); + StackClass.reportErrorIfPresent(*this, T, Loc, Stack, HeapNote); + NonHeapClass.reportErrorIfPresent(*this, T, Loc, NonHeap, HeapNote); + TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, HeapNote); + StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal, HeapNote); + break; + } +} diff --git a/build/clang-plugin/ScopeChecker.h b/build/clang-plugin/ScopeChecker.h new file mode 100644 index 0000000000..edab241f1c --- /dev/null +++ b/build/clang-plugin/ScopeChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ScopeChecker_h__ +#define ScopeChecker_h__ + +#include "plugin.h" + +class ScopeChecker : public BaseCheck { +public: + ScopeChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/SprintfLiteralChecker.cpp b/build/clang-plugin/SprintfLiteralChecker.cpp new file mode 100644 index 0000000000..94e8e2fd1b --- /dev/null +++ b/build/clang-plugin/SprintfLiteralChecker.cpp @@ -0,0 +1,84 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SprintfLiteralChecker.h" +#include "CustomMatchers.h" + +void SprintfLiteralChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + callExpr( + isSnprintfLikeFunc(), + allOf(hasArgument( + 0, ignoringParenImpCasts(declRefExpr().bind("buffer"))), + anyOf(hasArgument(1, sizeOfExpr(has(ignoringParenImpCasts( + declRefExpr().bind("size"))))), + hasArgument(1, integerLiteral().bind("immediate")), + hasArgument(1, declRefExpr(to(varDecl( + hasType(isConstQualified()), + hasInitializer(integerLiteral().bind( + "constant"))))))))) + .bind("funcCall"), + this); +} + +void SprintfLiteralChecker::check(const MatchFinder::MatchResult &Result) { + if (!Result.Context->getLangOpts().CPlusPlus) { + // SprintfLiteral is not usable in C, so there is no point in issuing these + // warnings. + return; + } + + const char *Error = + "Use %1 instead of %0 when writing into a character array."; + const char *Note = + "This will prevent passing in the wrong size to %0 accidentally."; + + const CallExpr *D = Result.Nodes.getNodeAs("funcCall"); + + StringRef Name = D->getDirectCallee()->getName(); + const char *Replacement; + if (Name == "snprintf") { + Replacement = "SprintfLiteral"; + } else { + assert(Name == "vsnprintf"); + Replacement = "VsprintfLiteral"; + } + + const DeclRefExpr *Buffer = Result.Nodes.getNodeAs("buffer"); + const DeclRefExpr *Size = Result.Nodes.getNodeAs("size"); + if (Size) { + // Match calls like snprintf(x, sizeof(x), ...). + if (Buffer->getFoundDecl() != Size->getFoundDecl()) { + return; + } + + diag(D->getBeginLoc(), Error, DiagnosticIDs::Error) << Name << Replacement; + diag(D->getBeginLoc(), Note, DiagnosticIDs::Note) << Name; + return; + } + + const QualType QType = Buffer->getType(); + const ConstantArrayType *Type = + dyn_cast(QType.getTypePtrOrNull()); + if (Type) { + // Match calls like snprintf(x, 100, ...), where x is int[100]; + const IntegerLiteral *Literal = + Result.Nodes.getNodeAs("immediate"); + if (!Literal) { + // Match calls like: const int y = 100; snprintf(x, y, ...); + Literal = Result.Nodes.getNodeAs("constant"); + } + + // We're going to assume here that the bitwidth of both of these values fits + // within 64 bits. and zero-extend both values to 64-bits before comparing + // them. + uint64_t Size = Type->getSize().getZExtValue(); + uint64_t Lit = Literal->getValue().getZExtValue(); + if (Size <= Lit) { + diag(D->getBeginLoc(), Error, DiagnosticIDs::Error) + << Name << Replacement; + diag(D->getBeginLoc(), Note, DiagnosticIDs::Note) << Name; + } + } +} diff --git a/build/clang-plugin/SprintfLiteralChecker.h b/build/clang-plugin/SprintfLiteralChecker.h new file mode 100644 index 0000000000..bf407987b3 --- /dev/null +++ b/build/clang-plugin/SprintfLiteralChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SprintfLiteralChecker_h__ +#define SprintfLiteralChecker_h__ + +#include "plugin.h" + +class SprintfLiteralChecker : public BaseCheck { +public: + SprintfLiteralChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/StmtToBlockMap.h b/build/clang-plugin/StmtToBlockMap.h new file mode 100644 index 0000000000..09b0cac415 --- /dev/null +++ b/build/clang-plugin/StmtToBlockMap.h @@ -0,0 +1,90 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef StmtToBlockMap_h__ +#define StmtToBlockMap_h__ + +#include "Utils.h" + +// This method is copied from clang-tidy's ExprSequence.cpp. +// +// Returns the Stmt nodes that are parents of 'S', skipping any potential +// intermediate non-Stmt nodes. +// +// In almost all cases, this function returns a single parent or no parents at +// all. +inline SmallVector getParentStmts(const Stmt *S, + ASTContext *Context) { + SmallVector Result; + + auto Parents = Context->getParents(*S); + + SmallVector NodesToProcess(Parents.begin(), + Parents.end()); + + while (!NodesToProcess.empty()) { + clang::DynTypedNode Node = NodesToProcess.back(); + NodesToProcess.pop_back(); + + if (const auto *S = Node.get()) { + Result.push_back(S); + } else { + Parents = Context->getParents(Node); + NodesToProcess.append(Parents.begin(), Parents.end()); + } + } + + return Result; +} + +// This class is a modified version of the class from clang-tidy's +// ExprSequence.cpp +// +// Maps `Stmt`s to the `CFGBlock` that contains them. Some `Stmt`s may be +// contained in more than one `CFGBlock`; in this case, they are mapped to the +// innermost block (i.e. the one that is furthest from the root of the tree). +// An optional outparameter provides the index into the block where the `Stmt` +// was found. +class StmtToBlockMap { +public: + // Initializes the map for the given `CFG`. + StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext) + : Context(TheContext) { + for (const auto *B : *TheCFG) { + for (size_t I = 0; I < B->size(); ++I) { + if (auto S = (*B)[I].getAs()) { + Map[S->getStmt()] = std::make_pair(B, I); + } + } + } + } + + // Returns the block that S is contained in. Some `Stmt`s may be contained + // in more than one `CFGBlock`; in this case, this function returns the + // innermost block (i.e. the one that is furthest from the root of the tree). + // + // The optional outparameter `Index` is set to the index into the block where + // the `Stmt` was found. + const CFGBlock *blockContainingStmt(const Stmt *S, + size_t *Index = nullptr) const { + while (!Map.count(S)) { + SmallVector Parents = getParentStmts(S, Context); + if (Parents.empty()) + return nullptr; + S = Parents[0]; + } + + const auto &E = Map.lookup(S); + if (Index) + *Index = E.second; + return E.first; + } + +private: + ASTContext *Context; + + llvm::DenseMap> Map; +}; + +#endif // StmtToBlockMap_h__ diff --git a/build/clang-plugin/ThirdPartyPaths.h b/build/clang-plugin/ThirdPartyPaths.h new file mode 100644 index 0000000000..6a497923f2 --- /dev/null +++ b/build/clang-plugin/ThirdPartyPaths.h @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ThirdPartyPaths_h__ +#define ThirdPartyPaths_h__ + +#include + +// These two values are defined in ThirdPartyPaths.cpp, which is a file +// generated by ThirdPartyPaths.py. + +extern const char *MOZ_THIRD_PARTY_PATHS[]; + +extern const uint32_t MOZ_THIRD_PARTY_PATHS_COUNT; + +#endif diff --git a/build/clang-plugin/ThirdPartyPaths.py b/build/clang-plugin/ThirdPartyPaths.py new file mode 100644 index 0000000000..caaa919d43 --- /dev/null +++ b/build/clang-plugin/ThirdPartyPaths.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +import json + + +def generate(output, *input_paths): + """ + This file generates a ThirdPartyPaths.cpp file from the ThirdPartyPaths.txt + file in /tools/rewriting, which is used by the Clang Plugin to help identify + sources which should be ignored. + """ + tpp_list = [] + lines = set() + + for path in input_paths: + with open(path) as f: + lines.update(f.readlines()) + + for line in lines: + line = line.strip() + if line.endswith("/"): + line = line[:-1] + tpp_list.append(line) + tpp_strings = ",\n ".join([json.dumps(tpp) for tpp in sorted(tpp_list)]) + + output.write( + """\ +/* THIS FILE IS GENERATED BY ThirdPartyPaths.py - DO NOT EDIT */ + +#include + +const char* MOZ_THIRD_PARTY_PATHS[] = { + %s +}; + +extern const uint32_t MOZ_THIRD_PARTY_PATHS_COUNT = %d; + +""" + % (tpp_strings, len(tpp_list)) + ) diff --git a/build/clang-plugin/ThreadAllows.py b/build/clang-plugin/ThreadAllows.py new file mode 100644 index 0000000000..f3e1ee894c --- /dev/null +++ b/build/clang-plugin/ThreadAllows.py @@ -0,0 +1,82 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. +import json +import os +import posixpath +from os import PathLike + +# `typing.Literal` not available until Python 3.8; +# `typing_extensions` not generally available here +from typing import Iterable, Set + +FIRST_LINE = "// This file was generated by {}. DO NOT EDIT.".format( + # `posixpath` for forward slashes, for presentation purposes + posixpath.relpath(__file__, os.getenv("TOPSRCDIR", "/")) +) + + +def generate_allowed_items( + which: str, # should be: Literal["files", "names"], + paths: Iterable[PathLike], +) -> str: + def remove_trailing_comment(s: str) -> str: + return s[0 : s.find("#")] + + def read_items_from_path(path: PathLike) -> Set[str]: + out = set() + with open(path) as file: + for line in file.readlines(): + line = remove_trailing_comment(line).strip() + if not line: + continue # comment or empty line; discard + out.add(line) + return out + + allowed = set().union(*(read_items_from_path(path) for path in paths)) + # BUG: `json.dumps` may not correctly handle use of the quote character in + # thread names + allowed_list_s = ",\n ".join(json.dumps(elem) for elem in sorted(allowed)) + + return f"""\ +static const char *allow_thread_{which}[] = {{ + {allowed_list_s} +}};""" + + +def generate_allows( + *, allowed_names: Iterable[PathLike], allowed_files: Iterable[PathLike] +) -> str: + """ + This function reads in the specified sets of files -- ordinarily, + ["ThreadAllows.txt"] and ["ThreadFileAllows.txt"] -- and generates the text + of a header file containing two arrays with their contents, for inclusion by + the thread-name checker. + + The checker will reject the creation of any thread via NS_NewNamedThread + unless either: + - the thread's name is a literal string which is found in the set of + allowed thread names; or + - the thread's creation occurs within a file which is found in the set of + unchecked files. + + The latter condition exists mostly for the definition of NS_NewNamedThread, + but there also exist a few cases where the thread name is dynamically + computed (and so can't be checked). + """ + output_string = ( + FIRST_LINE + + "\n\n" + + generate_allowed_items("files", allowed_files) + + "\n\n" + + generate_allowed_items("names", allowed_names) + + "\n" + ) + return output_string + + +# Entry point used by build/clang-plugin/moz.build (q.v.). +def generate_file(output, allowed_names, allowed_files): + output.write( + generate_allows(allowed_names=[allowed_names], allowed_files=[allowed_files]) + ) diff --git a/build/clang-plugin/ThreadAllows.txt b/build/clang-plugin/ThreadAllows.txt new file mode 100644 index 0000000000..801e57504f --- /dev/null +++ b/build/clang-plugin/ThreadAllows.txt @@ -0,0 +1,115 @@ +# This file is ingested by `ThreadAllows.py` to produce a list of thread names +# which our clang plugin will allow to be used with `NS_NewNamedThread`. +# +# Permitted thread names are a maximum of 15 characters in length, and must be +# string literals at their point-of-use in the code -- i.e., in the invocation +# of `NS_NewNamedThread`. +# +# Within this file, each permitted thread name is on a separate line. Comments +# begin with `#`, as seen here. Leading and trailing whitespace, trailing +# comments, and blank lines are ignored, and may be used freely. +# +# Please explain the addition of any new thread names in comments, preferably +# with a pointer to a relevant bug. (Do not add thread names only used in tests +# to this file; instead, add the test file to `ThreadFileAllows.txt`.) + +###### +# Gecko/Firefox thread names +# (See also "Unsorted thread names", below.) + +# Used by `nsUpdateProcessor` to check for updates. May also be used for polling +# the update process. +UpdateProcessor + +###### +# Thunderbird-only thread names +IMAP + +###### +# Other +Checker Test # used only as part of tests for the thread-checker itself +Testing Thread # used only as part of tests for toolkit/components/url-classifier/tests/gtest/ + +###### +# Unsorted thread names +# +# Thread names below this point are grandfathered in. Please do not add new +# thread names to this list -- and please remove any that you can, whether by +# documenting and moving them or by confirming that they are no longer required. +# +# In particular, if a thread name is only used for testing, please consider +# moving its declarator to `ThreadFileAllows.txt`. + +BGReadURLs +BHMgr Monitor +BHMgr Processor +COM Intcpt Log +COM MTA +Cache I/O +Cameras IPC +CanvasRenderer +Compositor +Cookie +CrashRep Inject +DDMediaLogs +DOMCacheThread +DataChannel IO +DataStorage +DesktopCapture +File Dialog +FileWatcher IO +Font Loader +FontEnumThread +Function Broker +GMPThread +Gamepad +GraphRunner +HTML5 Parser +ICS parser +IPC Launch +IPDL Background +IdentityCrypto +ImageBridgeChld +LS Thread +MDCDMThread +MediaCache +MediaTelemetry +MediaTrackGrph +MemoryPoller +mtransport +NamedPipeSrv +Netlink Monitor +OSKeyStore +OutputDrain +PaintThread +Permission +PlayEventSound +ProcessHangMon +ProfSymbolTable +ProfilerChild +ProxyResolution +RemoteLzyStream +RemVidChild +Renderer +ResetCleanup +SaveScripts +Socket Thread +SpeechWorker +StressRunner +SuicideManager +System Proxy +TelemetryModule +Timer +ToastBgThread +TRR Background +URL Classifier +VideoCapture +VRService +VsyncIOThread +Wifi Monitor +Worker Launcher +speechd init +thread +thread shutdown +wifi tickler +WMFCDMThread diff --git a/build/clang-plugin/ThreadFileAllows.txt b/build/clang-plugin/ThreadFileAllows.txt new file mode 100644 index 0000000000..a10cbbea3e --- /dev/null +++ b/build/clang-plugin/ThreadFileAllows.txt @@ -0,0 +1,75 @@ +# This file is ingested by `ThreadAllows.py` to produce a list of files which +# our clang plugin will allow to use `NS_NewNamedThread`. +# +# Files may be specified with any number of slash-separated path-elements; all +# provided path-elements must match. (Because we often move and/or symlink +# header files, this means headers will usually have no path-elements.) +# +# Note that this file contains a list of _files_, not _paths_. The clang plugin +# has no notion of $TOPSRCDIR. + +###### +# Release files + +# declaration and definition of `NS_NewNamedThread` +nsThreadUtils.h +xpcom/threads/nsThreadUtils.cpp + +# Thread-pools are permitted to make dynamically many threads, using dynamic +# thread names with explicit numbering. +xpcom/threads/nsThreadPool.cpp + +###### +# Test files + +# Tests for XPCOM threads themselves. +xpcom/tests/gtest/TestThreadManager.cpp +xpcom/tests/gtest/TestThreads.cpp +xpcom/tests/gtest/TestThreadUtils.cpp + +# Tests which use dynamic thread names. +xpcom/tests/gtest/TestHandleWatcher.cpp + +###### +# Unsorted release files +# +# Files below this point are grandfathered in. Please do not add new files to +# this list -- and please remove any that you can, whether by documenting and +# moving them or by confirming that they are no longer required. +dom/indexedDB/ActorsParent.cpp +dom/quota/ActorsParent.cpp +DecodePool.cpp +GeckoChildProcessHost.cpp +LazyIdleThread.cpp +LazyIdleThread.h +VRThread.cpp +mozStorageConnection.cpp +nr_socket_prsock.cpp + +###### +# Unsorted test files +# +# Files below this point are quasi-grandfathered in: these are test files which +# create new threads whose names were formerly in ThreadAllows.txt (without +# justification), and have been moved here (without justification). +dom/media/doctor/test/gtest/TestMultiWriterQueue.cpp +image/test/fuzzing/TestDecoders.cpp +image/test/gtest/TestDecodeToSurface.cpp +ipc/ipdl/test/gtest/IPDLUnitTest.cpp +security/sandbox/common/test/SandboxTestingThread.h +storage/test/gtest/test_interruptSynchronousConnection.cpp +storage/test/gtest/test_unlock_notify.cpp +toolkit/components/telemetry/geckoview/gtest/TestGeckoViewStreaming.cpp +toolkit/components/telemetry/tests/gtest/TestScalars.cpp +toolkit/components/url-classifier/tests/gtest/Common.cpp +tools/fuzzing/ipc/IPCFuzzController.cpp +tools/profiler/tests/gtest/GeckoProfiler.cpp +xpcom/tests/gtest/TestAtoms.cpp +xpcom/tests/gtest/TestAutoRefCnt.cpp +xpcom/tests/gtest/TestDelayedRunnable.cpp +xpcom/tests/gtest/TestLogging.cpp +xpcom/tests/gtest/TestPipes.cpp +xpcom/tests/gtest/TestRacingServiceManager.cpp +xpcom/tests/gtest/TestRWLock.cpp +xpcom/tests/gtest/TestThrottledEventQueue.cpp +xpcom/tests/gtest/TestTimers.cpp diff --git a/build/clang-plugin/TrivialCtorDtorChecker.cpp b/build/clang-plugin/TrivialCtorDtorChecker.cpp new file mode 100644 index 0000000000..59576a5b64 --- /dev/null +++ b/build/clang-plugin/TrivialCtorDtorChecker.cpp @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TrivialCtorDtorChecker.h" +#include "CustomMatchers.h" + +void TrivialCtorDtorChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher(cxxRecordDecl(hasTrivialCtorDtor()).bind("node"), + this); +} + +void TrivialCtorDtorChecker::check(const MatchFinder::MatchResult &Result) { + const char *Error = "class %0 must have trivial constructors and destructors"; + const CXXRecordDecl *Node = Result.Nodes.getNodeAs("node"); + + if (!Node->hasDefinition()) { + return; + } + + // We need to accept non-constexpr trivial constructors as well. This occurs + // when a struct contains pod members, which will not be initialized. As + // constexpr values are initialized, the constructor is non-constexpr. + bool BadCtor = !(Node->hasConstexprDefaultConstructor() || + Node->hasTrivialDefaultConstructor()); + bool BadDtor = !Node->hasTrivialDestructor(); + if (BadCtor || BadDtor) + diag(Node->getBeginLoc(), Error, DiagnosticIDs::Error) << Node; +} diff --git a/build/clang-plugin/TrivialCtorDtorChecker.h b/build/clang-plugin/TrivialCtorDtorChecker.h new file mode 100644 index 0000000000..6b44016781 --- /dev/null +++ b/build/clang-plugin/TrivialCtorDtorChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef TrivialCtorDtorChecker_h__ +#define TrivialCtorDtorChecker_h__ + +#include "plugin.h" + +class TrivialCtorDtorChecker : public BaseCheck { +public: + TrivialCtorDtorChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/TrivialDtorChecker.cpp b/build/clang-plugin/TrivialDtorChecker.cpp new file mode 100644 index 0000000000..ffcd2ae101 --- /dev/null +++ b/build/clang-plugin/TrivialDtorChecker.cpp @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TrivialDtorChecker.h" +#include "CustomMatchers.h" + +void TrivialDtorChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher(cxxRecordDecl(hasTrivialDtor()).bind("node"), this); +} + +void TrivialDtorChecker::check(const MatchFinder::MatchResult &Result) { + const char *Error = "class %0 must have a trivial destructor"; + const CXXRecordDecl *Node = Result.Nodes.getNodeAs("node"); + + if (!Node->hasDefinition()) { + return; + } + + bool BadDtor = !Node->hasTrivialDestructor(); + if (BadDtor) + diag(Node->getBeginLoc(), Error, DiagnosticIDs::Error) << Node; +} diff --git a/build/clang-plugin/TrivialDtorChecker.h b/build/clang-plugin/TrivialDtorChecker.h new file mode 100644 index 0000000000..dd0be727e6 --- /dev/null +++ b/build/clang-plugin/TrivialDtorChecker.h @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef TrivialDtorChecker_h__ +#define TrivialDtorChecker_h__ + +#include "plugin.h" + +class TrivialDtorChecker : public BaseCheck { +public: + TrivialDtorChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; +}; + +#endif diff --git a/build/clang-plugin/Utils.h b/build/clang-plugin/Utils.h new file mode 100644 index 0000000000..c25caf43ee --- /dev/null +++ b/build/clang-plugin/Utils.h @@ -0,0 +1,499 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef Utils_h__ +#define Utils_h__ + +#include "CustomAttributes.h" +#include "ThirdPartyPaths.h" +#include "ThreadAllows.h" +#include "plugin.h" + +#if CLANG_VERSION_FULL >= 1300 +// Starting with clang-13 some functions from StringRef have been renamed +#define compare_lower compare_insensitive +#endif + +inline StringRef getFilename(const SourceManager &SM, SourceLocation Loc) { + // We use the presumed location to handle #line directives and such, so the + // plugin is friendly to icecc / sccache users. + auto PL = SM.getPresumedLoc(Loc); + if (PL.isValid()) { + return StringRef(PL.getFilename()); + } + return SM.getFilename(Loc); +} + +// Check if the given expression contains an assignment expression. +// This can either take the form of a Binary Operator or a +// Overloaded Operator Call. +inline bool hasSideEffectAssignment(const Expr *Expression) { + if (auto OpCallExpr = dyn_cast_or_null(Expression)) { + auto BinOp = OpCallExpr->getOperator(); + if (BinOp == OO_Equal || (BinOp >= OO_PlusEqual && BinOp <= OO_PipeEqual)) { + return true; + } + } else if (auto BinOpExpr = dyn_cast_or_null(Expression)) { + if (BinOpExpr->isAssignmentOp()) { + return true; + } + } + + // Recurse to children. + for (const Stmt *SubStmt : Expression->children()) { + auto ChildExpr = dyn_cast_or_null(SubStmt); + if (ChildExpr && hasSideEffectAssignment(ChildExpr)) { + return true; + } + } + + return false; +} + +template +inline bool ASTIsInSystemHeader(const ASTContext &AC, const T &D) { + auto &SourceManager = AC.getSourceManager(); + auto ExpansionLoc = SourceManager.getExpansionLoc(D.getBeginLoc()); + if (ExpansionLoc.isInvalid()) { + return false; + } + return SourceManager.isInSystemHeader(ExpansionLoc); +} + +template inline StringRef getNameChecked(const T &D) { + return D->getIdentifier() ? D->getName() : ""; +} + +/// A cached data of whether classes are refcounted or not. +typedef DenseMap> + RefCountedMap; +extern RefCountedMap RefCountedClasses; + +inline bool classHasAddRefRelease(const CXXRecordDecl *D) { + const RefCountedMap::iterator &It = RefCountedClasses.find(D); + if (It != RefCountedClasses.end()) { + return It->second.second; + } + + bool SeenAddRef = false; + bool SeenRelease = false; + for (CXXRecordDecl::method_iterator Method = D->method_begin(); + Method != D->method_end(); ++Method) { + const auto &Name = getNameChecked(Method); + if (Name == "AddRef") { + SeenAddRef = true; + } else if (Name == "Release") { + SeenRelease = true; + } + } + RefCountedClasses[D] = std::make_pair(D, SeenAddRef && SeenRelease); + return SeenAddRef && SeenRelease; +} + +inline bool isClassRefCounted(QualType T); + +inline bool isClassRefCounted(const CXXRecordDecl *D) { + // Normalize so that D points to the definition if it exists. + if (!D->hasDefinition()) + return false; + D = D->getDefinition(); + // Base class: anyone with AddRef/Release is obviously a refcounted class. + if (classHasAddRefRelease(D)) + return true; + + // Look through all base cases to figure out if the parent is a refcounted + // class. + for (CXXRecordDecl::base_class_const_iterator Base = D->bases_begin(); + Base != D->bases_end(); ++Base) { + bool Super = isClassRefCounted(Base->getType()); + if (Super) { + return true; + } + } + + return false; +} + +inline bool isClassRefCounted(QualType T) { + while (const clang::ArrayType *ArrTy = T->getAsArrayTypeUnsafe()) + T = ArrTy->getElementType(); + CXXRecordDecl *Clazz = T->getAsCXXRecordDecl(); + return Clazz ? isClassRefCounted(Clazz) : false; +} + +inline const FieldDecl *getClassRefCntMember(const CXXRecordDecl *D) { + for (RecordDecl::field_iterator Field = D->field_begin(), E = D->field_end(); + Field != E; ++Field) { + if (getNameChecked(Field) == "mRefCnt") { + return *Field; + } + } + return 0; +} + +inline bool typeHasVTable(QualType T) { + while (const clang::ArrayType *ArrTy = T->getAsArrayTypeUnsafe()) + T = ArrTy->getElementType(); + CXXRecordDecl *Offender = T->getAsCXXRecordDecl(); + return Offender && Offender->hasDefinition() && Offender->isDynamicClass(); +} + +inline StringRef getDeclarationNamespace(const Decl *Declaration) { + const DeclContext *DC = + Declaration->getDeclContext()->getEnclosingNamespaceContext(); + const NamespaceDecl *ND = dyn_cast(DC); + if (!ND) { + return ""; + } + + while (const DeclContext *ParentDC = ND->getParent()) { + if (!isa(ParentDC)) { + break; + } + ND = cast(ParentDC); + } + + const auto &Name = ND->getName(); + return Name; +} + +inline bool isInIgnoredNamespaceForImplicitCtor(const Decl *Declaration) { + StringRef Name = getDeclarationNamespace(Declaration); + if (Name == "") { + return false; + } + + return Name == "std" || // standard C++ lib + Name == "__gnu_cxx" || // gnu C++ lib + Name == "boost" || // boost + Name == "webrtc" || // upstream webrtc + Name == "rtc" || // upstream webrtc 'base' package + Name.startswith("icu_") || // icu + Name == "google" || // protobuf + Name == "google_breakpad" || // breakpad + Name == "soundtouch" || // libsoundtouch + Name == "stagefright" || // libstagefright + Name == "MacFileUtilities" || // MacFileUtilities + Name == "dwarf2reader" || // dwarf2reader + Name == "arm_ex_to_module" || // arm_ex_to_module + Name == "testing" || // gtest + Name == "Json" || // jsoncpp + Name == "rlbox" || // rlbox + Name == "v8"; // irregexp +} + +inline bool isInIgnoredNamespaceForImplicitConversion(const Decl *Declaration) { + StringRef Name = getDeclarationNamespace(Declaration); + if (Name == "") { + return false; + } + + return Name == "std" || // standard C++ lib + Name == "__gnu_cxx" || // gnu C++ lib + Name == "google_breakpad" || // breakpad + Name == "webrtc" || // libwebrtc + Name == "testing" || // gtest + Name == "rlbox"; // rlbox +} + +inline bool isIgnoredPathForImplicitConversion(const Decl *Declaration) { + Declaration = Declaration->getCanonicalDecl(); + SourceLocation Loc = Declaration->getLocation(); + const SourceManager &SM = Declaration->getASTContext().getSourceManager(); + SmallString<1024> FileName = getFilename(SM, Loc); + llvm::sys::fs::make_absolute(FileName); + llvm::sys::path::reverse_iterator Begin = llvm::sys::path::rbegin(FileName), + End = llvm::sys::path::rend(FileName); + for (; Begin != End; ++Begin) { + if (Begin->compare_lower(StringRef("graphite2")) == 0) { + return true; + } + if (Begin->compare_lower(StringRef("chromium")) == 0) { + // Ignore security/sandbox/chromium but not ipc/chromium. + ++Begin; + return Begin != End && Begin->compare_lower(StringRef("sandbox")) == 0; + } + } + return false; +} + +inline bool isIgnoredPathForSprintfLiteral(const CallExpr *Call, + const SourceManager &SM) { + SourceLocation Loc = Call->getBeginLoc(); + SmallString<1024> FileName = getFilename(SM, Loc); + llvm::sys::fs::make_absolute(FileName); + llvm::sys::path::reverse_iterator Begin = llvm::sys::path::rbegin(FileName), + End = llvm::sys::path::rend(FileName); + for (; Begin != End; ++Begin) { + if (Begin->compare_lower(StringRef("angle")) == 0 || + Begin->compare_lower(StringRef("chromium")) == 0 || + Begin->compare_lower(StringRef("crashreporter")) == 0 || + Begin->compare_lower(StringRef("google-breakpad")) == 0 || + Begin->compare_lower(StringRef("gflags")) == 0 || + Begin->compare_lower(StringRef("harfbuzz")) == 0 || + Begin->compare_lower(StringRef("icu")) == 0 || + Begin->compare_lower(StringRef("jsoncpp")) == 0 || + Begin->compare_lower(StringRef("libstagefright")) == 0 || + Begin->compare_lower(StringRef("transport")) == 0 || + Begin->compare_lower(StringRef("protobuf")) == 0 || + Begin->compare_lower(StringRef("skia")) == 0 || + Begin->compare_lower(StringRef("sfntly")) == 0 || + // Gtest uses snprintf as GTEST_SNPRINTF_ with sizeof + Begin->compare_lower(StringRef("testing")) == 0) { + return true; + } + if (Begin->compare_lower(StringRef("webrtc")) == 0) { + // Ignore trunk/webrtc, but not media/webrtc + ++Begin; + return Begin != End && Begin->compare_lower(StringRef("trunk")) == 0; + } + } + return false; +} + +inline bool isInterestingDeclForImplicitConversion(const Decl *Declaration) { + return !isInIgnoredNamespaceForImplicitConversion(Declaration) && + !isIgnoredPathForImplicitConversion(Declaration); +} + +inline bool isIgnoredExprForMustUse(const Expr *E) { + if (const CXXOperatorCallExpr *OpCall = dyn_cast(E)) { + switch (OpCall->getOperator()) { + case OO_Equal: + case OO_PlusEqual: + case OO_MinusEqual: + case OO_StarEqual: + case OO_SlashEqual: + case OO_PercentEqual: + case OO_CaretEqual: + case OO_AmpEqual: + case OO_PipeEqual: + case OO_LessLessEqual: + case OO_GreaterGreaterEqual: + return true; + default: + return false; + } + } + + if (const BinaryOperator *Op = dyn_cast(E)) { + return Op->isAssignmentOp(); + } + + return false; +} + +inline bool typeIsRefPtr(QualType Q) { + CXXRecordDecl *D = Q->getAsCXXRecordDecl(); + if (!D || !D->getIdentifier()) { + return false; + } + + StringRef name = D->getName(); + if (name == "RefPtr" || name == "nsCOMPtr") { + return true; + } + return false; +} + +// The method defined in clang for ignoring implicit nodes doesn't work with +// some AST trees. To get around this, we define our own implementation of +// IgnoreTrivials. +inline const Stmt *MaybeSkipOneTrivial(const Stmt *s) { + if (!s) { + return nullptr; + } + if (auto *ewc = dyn_cast(s)) { + return ewc->getSubExpr(); + } + if (auto *mte = dyn_cast(s)) { + // With clang 10 and up `getTemporary` has been replaced with the more + // versatile `getSubExpr`. +#if CLANG_VERSION_FULL >= 1000 + return mte->getSubExpr(); +#else + return mte->GetTemporaryExpr(); +#endif + } + if (auto *bte = dyn_cast(s)) { + return bte->getSubExpr(); + } + if (auto *ce = dyn_cast(s)) { + s = ce->getSubExpr(); + } + if (auto *pe = dyn_cast(s)) { + s = pe->getSubExpr(); + } + // Not a trivial. + return s; +} + +inline const Stmt *IgnoreTrivials(const Stmt *s) { + while (true) { + const Stmt *newS = MaybeSkipOneTrivial(s); + if (newS == s) { + return newS; + } + s = newS; + } + + // Unreachable + return nullptr; +} + +inline const Expr *IgnoreTrivials(const Expr *e) { + return cast_or_null(IgnoreTrivials(static_cast(e))); +} + +// Returns the input if the input is not a trivial. +inline const Expr *MaybeSkipOneTrivial(const Expr *e) { + return cast_or_null(MaybeSkipOneTrivial(static_cast(e))); +} + +const FieldDecl *getBaseRefCntMember(QualType T); + +inline const FieldDecl *getBaseRefCntMember(const CXXRecordDecl *D) { + const FieldDecl *RefCntMember = getClassRefCntMember(D); + if (RefCntMember && isClassRefCounted(D)) { + return RefCntMember; + } + + for (CXXRecordDecl::base_class_const_iterator Base = D->bases_begin(), + E = D->bases_end(); + Base != E; ++Base) { + RefCntMember = getBaseRefCntMember(Base->getType()); + if (RefCntMember) { + return RefCntMember; + } + } + return 0; +} + +inline const FieldDecl *getBaseRefCntMember(QualType T) { + while (const clang::ArrayType *ArrTy = T->getAsArrayTypeUnsafe()) + T = ArrTy->getElementType(); + CXXRecordDecl *Clazz = T->getAsCXXRecordDecl(); + return Clazz ? getBaseRefCntMember(Clazz) : 0; +} + +inline bool isPlacementNew(const CXXNewExpr *Expression) { + // Regular new expressions aren't placement new + if (Expression->getNumPlacementArgs() == 0) + return false; + const FunctionDecl *Declaration = Expression->getOperatorNew(); + if (Declaration && hasCustomAttribute(Declaration)) { + return false; + } + return true; +} + +extern DenseMap InThirdPartyPathCache; + +inline bool inThirdPartyPath(SourceLocation Loc, const SourceManager &SM) { + StringRef OriginalFileName = getFilename(SM, Loc); + auto pair = InThirdPartyPathCache.find(OriginalFileName); + if (pair != InThirdPartyPathCache.end()) { + return pair->second; + } + + SmallString<1024> FileName = OriginalFileName; + llvm::sys::fs::make_absolute(FileName); + + for (uint32_t i = 0; i < MOZ_THIRD_PARTY_PATHS_COUNT; ++i) { + auto PathB = sys::path::begin(FileName); + auto PathE = sys::path::end(FileName); + + auto ThirdPartyB = sys::path::begin(MOZ_THIRD_PARTY_PATHS[i]); + auto ThirdPartyE = sys::path::end(MOZ_THIRD_PARTY_PATHS[i]); + + for (; PathB != PathE; ++PathB) { + // Perform an inner loop to compare path segments, checking if the current + // segment is the start of the current third party path. + auto IPathB = PathB; + auto IThirdPartyB = ThirdPartyB; + for (; IPathB != PathE && IThirdPartyB != ThirdPartyE; + ++IPathB, ++IThirdPartyB) { + if (IPathB->compare_lower(*IThirdPartyB) != 0) { + break; + } + } + + // We found a match! + if (IThirdPartyB == ThirdPartyE) { + InThirdPartyPathCache.insert(std::make_pair(OriginalFileName, true)); + return true; + } + } + } + + InThirdPartyPathCache.insert(std::make_pair(OriginalFileName, false)); + return false; +} + +inline bool inThirdPartyPath(const Decl *D, ASTContext *context) { + D = D->getCanonicalDecl(); + SourceLocation Loc = D->getLocation(); + const SourceManager &SM = context->getSourceManager(); + + return inThirdPartyPath(Loc, SM); +} + +inline CXXRecordDecl *getNonTemplateSpecializedCXXRecordDecl(QualType Q) { + auto *D = Q->getAsCXXRecordDecl(); + + if (!D) { + auto TemplateQ = Q->getAs(); + if (!TemplateQ) { + return nullptr; + } + + auto TemplateDecl = TemplateQ->getTemplateName().getAsTemplateDecl(); + if (!TemplateDecl) { + return nullptr; + } + + D = dyn_cast_or_null(TemplateDecl->getTemplatedDecl()); + if (!D) { + return nullptr; + } + } + + return D; +} + +inline bool inThirdPartyPath(const Decl *D) { + return inThirdPartyPath(D, &D->getASTContext()); +} + +inline bool inThirdPartyPath(const Stmt *S, ASTContext *context) { + SourceLocation Loc = S->getBeginLoc(); + const SourceManager &SM = context->getSourceManager(); + auto ExpansionLoc = SM.getExpansionLoc(Loc); + if (ExpansionLoc.isInvalid()) { + return inThirdPartyPath(Loc, SM); + } + return inThirdPartyPath(ExpansionLoc, SM); +} + +/// Polyfill for CXXOperatorCallExpr::isInfixBinaryOp() +inline bool isInfixBinaryOp(const CXXOperatorCallExpr *OpCall) { +#if CLANG_VERSION_FULL >= 400 + return OpCall->isInfixBinaryOp(); +#else + // Taken from clang source. + if (OpCall->getNumArgs() != 2) + return false; + + switch (OpCall->getOperator()) { + case OO_Call: + case OO_Subscript: + return false; + default: + return true; + } +#endif +} + +#undef compare_lower +#endif diff --git a/build/clang-plugin/VariableUsageHelpers.cpp b/build/clang-plugin/VariableUsageHelpers.cpp new file mode 100644 index 0000000000..abb9eb280f --- /dev/null +++ b/build/clang-plugin/VariableUsageHelpers.cpp @@ -0,0 +1,275 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "VariableUsageHelpers.h" +#include "Utils.h" + +std::vector getUsageAsRvalue(const ValueDecl *ValueDeclaration, + const FunctionDecl *FuncDecl) { + std::vector UsageStatements; + + // We check the function declaration has a body. + auto Body = FuncDecl->getBody(); + if (!Body) { + return std::vector(); + } + + // We build a Control Flow Graph (CFG) fron the body of the function + // declaration. + std::unique_ptr StatementCFG = CFG::buildCFG( + FuncDecl, Body, &FuncDecl->getASTContext(), CFG::BuildOptions()); + + // We iterate through all the CFGBlocks, which basically means that we go over + // all the possible branches of the code and therefore cover all statements. + for (auto &Block : *StatementCFG) { + // We iterate through all the statements of the block. + for (auto &BlockItem : *Block) { + auto CFGStatement = BlockItem.getAs(); + if (!CFGStatement) { + continue; + } + + // FIXME: Right now this function/if chain is very basic and only covers + // the cases we need for escapesFunction() + if (auto BinOp = dyn_cast(CFGStatement->getStmt())) { + // We only care about assignments. + if (BinOp->getOpcode() != BO_Assign) { + continue; + } + + // We want our declaration to be used on the right hand side of the + // assignment. + auto DeclRef = dyn_cast(IgnoreTrivials(BinOp->getRHS())); + if (!DeclRef) { + continue; + } + + if (DeclRef->getDecl() != ValueDeclaration) { + continue; + } + } else if (auto Return = dyn_cast(CFGStatement->getStmt())) { + // We want our declaration to be used as the expression of the return + // statement. + auto DeclRef = dyn_cast_or_null( + IgnoreTrivials(Return->getRetValue())); + if (!DeclRef) { + continue; + } + + if (DeclRef->getDecl() != ValueDeclaration) { + continue; + } + } else { + continue; + } + + // We didn't early-continue, so we add the statement to the list. + UsageStatements.push_back(CFGStatement->getStmt()); + } + } + + return UsageStatements; +} + +// We declare our EscapesFunctionError enum to be an error code enum. +namespace std { +template <> struct is_error_code_enum : true_type {}; +} // namespace std + +// We define the EscapesFunctionErrorCategory which contains the error messages +// corresponding to each enum variant. +namespace { +struct EscapesFunctionErrorCategory : std::error_category { + const char *name() const noexcept override; + std::string message(int ev) const override; +}; + +const char *EscapesFunctionErrorCategory::name() const noexcept { + return "escapes function"; +} + +std::string EscapesFunctionErrorCategory::message(int ev) const { + switch (static_cast(ev)) { + case EscapesFunctionError::ConstructorDeclNotFound: + return "constructor declaration not found"; + + case EscapesFunctionError::FunctionDeclNotFound: + return "function declaration not found"; + + case EscapesFunctionError::FunctionIsBuiltin: + return "function is builtin"; + + case EscapesFunctionError::FunctionIsVariadic: + return "function is variadic"; + + case EscapesFunctionError::ExprNotInCall: + return "expression is not in call"; + + case EscapesFunctionError::NoParamForArg: + return "no parameter for argument"; + + case EscapesFunctionError::ArgAndParamNotPointers: + return "argument and parameter are not pointers"; + } +} + +const EscapesFunctionErrorCategory TheEscapesFunctionErrorCategory{}; +} // namespace + +std::error_code make_error_code(EscapesFunctionError e) { + return {static_cast(e), TheEscapesFunctionErrorCategory}; +} + +ErrorOr> +escapesFunction(const Expr *Arg, const CXXConstructExpr *Construct) { + // We get the function declaration corresponding to the call. + auto CtorDecl = Construct->getConstructor(); + if (!CtorDecl) { + return EscapesFunctionError::ConstructorDeclNotFound; + } + + return escapesFunction(Arg, CtorDecl, Construct->getArgs(), + Construct->getNumArgs()); +} + +ErrorOr> +escapesFunction(const Expr *Arg, const CallExpr *Call) { + // We get the function declaration corresponding to the call. + auto FuncDecl = Call->getDirectCallee(); + if (!FuncDecl) { + return EscapesFunctionError::FunctionDeclNotFound; + } + + return escapesFunction(Arg, FuncDecl, Call->getArgs(), Call->getNumArgs()); +} + +ErrorOr> +escapesFunction(const Expr *Arg, const CXXOperatorCallExpr *OpCall) { + // We get the function declaration corresponding to the operator call. + auto FuncDecl = OpCall->getDirectCallee(); + if (!FuncDecl) { + return EscapesFunctionError::FunctionDeclNotFound; + } + + auto Args = OpCall->getArgs(); + auto NumArgs = OpCall->getNumArgs(); + // If this is an infix binary operator defined as a one-param method, we + // remove the first argument as it is inserted explicitly and creates a + // mismatch with the parameters of the method declaration. + if (isInfixBinaryOp(OpCall) && FuncDecl->getNumParams() == 1) { + Args++; + NumArgs--; + } + + return escapesFunction(Arg, FuncDecl, Args, NumArgs); +} + +ErrorOr> +escapesFunction(const Expr *Arg, const FunctionDecl *FuncDecl, + const Expr *const *Arguments, unsigned NumArgs) { + if (!NumArgs) { + return std::make_tuple((const Stmt *)nullptr, (const Decl *)nullptr); + } + + if (FuncDecl->getBuiltinID() != 0 || + ASTIsInSystemHeader(FuncDecl->getASTContext(), *FuncDecl)) { + return EscapesFunctionError::FunctionIsBuiltin; + } + + // FIXME: should probably be handled at some point, but it's too annoying + // for now. + if (FuncDecl->isVariadic()) { + return EscapesFunctionError::FunctionIsVariadic; + } + + // We find the argument number corresponding to the Arg expression. + unsigned ArgNum = 0; + for (unsigned i = 0; i < NumArgs; i++) { + if (IgnoreTrivials(Arg) == IgnoreTrivials(Arguments[i])) { + break; + } + ++ArgNum; + } + // If we don't find it, we early-return NoneType. + if (ArgNum >= NumArgs) { + return EscapesFunctionError::ExprNotInCall; + } + + // Now we get the associated parameter. + if (ArgNum >= FuncDecl->getNumParams()) { + return EscapesFunctionError::NoParamForArg; + } + auto Param = FuncDecl->getParamDecl(ArgNum); + + // We want both the argument and the parameter to be of pointer type. + // FIXME: this is enough for the DanglingOnTemporaryChecker, because the + // analysed methods only return pointers, but more cases should probably be + // handled when we want to use this function more broadly. + if ((!Arg->getType().getNonReferenceType()->isPointerType() && + Arg->getType().getNonReferenceType()->isBuiltinType()) || + (!Param->getType().getNonReferenceType()->isPointerType() && + Param->getType().getNonReferenceType()->isBuiltinType())) { + return EscapesFunctionError::ArgAndParamNotPointers; + } + + // We retrieve the usages of the parameter in the function. + auto Usages = getUsageAsRvalue(Param, FuncDecl); + + // For each usage, we check if it doesn't allow the parameter to escape the + // function scope. + for (auto Usage : Usages) { + // In the case of an assignment. + if (auto BinOp = dyn_cast(Usage)) { + // We retrieve the declaration the parameter is assigned to. + auto DeclRef = dyn_cast(BinOp->getLHS()); + if (!DeclRef) { + continue; + } + + if (auto ParamDeclaration = dyn_cast(DeclRef->getDecl())) { + // This is the case where the parameter escapes through another + // parameter. + + // FIXME: for now we only care about references because we only detect + // trivial LHS with just a DeclRefExpr, and not more complex cases like: + // void func(Type* param1, Type** param2) { + // *param2 = param1; + // } + // This should be fixed when we have better/more helper functions to + // help deal with this kind of lvalue expressions. + if (!ParamDeclaration->getType()->isReferenceType()) { + continue; + } + + return std::make_tuple(Usage, (const Decl *)ParamDeclaration); + } else if (auto VarDeclaration = dyn_cast(DeclRef->getDecl())) { + // This is the case where the parameter escapes through a global/static + // variable. + if (!VarDeclaration->hasGlobalStorage()) { + continue; + } + + return std::make_tuple(Usage, (const Decl *)VarDeclaration); + } else if (auto FieldDeclaration = + dyn_cast(DeclRef->getDecl())) { + // This is the case where the parameter escapes through a field. + + return std::make_tuple(Usage, (const Decl *)FieldDeclaration); + } + } else if (isa(Usage)) { + // This is the case where the parameter escapes through the return value + // of the function. + if (!FuncDecl->getReturnType()->isPointerType() && + !FuncDecl->getReturnType()->isReferenceType()) { + continue; + } + + return std::make_tuple(Usage, (const Decl *)FuncDecl); + } + } + + // No early-return, this means that we haven't found any case of funciton + // escaping and that therefore the parameter remains in the function scope. + return std::make_tuple((const Stmt *)nullptr, (const Decl *)nullptr); +} diff --git a/build/clang-plugin/VariableUsageHelpers.h b/build/clang-plugin/VariableUsageHelpers.h new file mode 100644 index 0000000000..d498857eea --- /dev/null +++ b/build/clang-plugin/VariableUsageHelpers.h @@ -0,0 +1,63 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef VariableUsageHelpers_h__ +#define VariableUsageHelpers_h__ + +#include "plugin.h" + +/// Returns a list of the statements where the given declaration is used as an +/// rvalue (within the provided function). +/// +/// WARNING: incomplete behaviour/implementation for general-purpose use outside +/// of escapesFunction(). This only detects very basic usages (see +/// implementation for more details). +std::vector getUsageAsRvalue(const ValueDecl *ValueDeclaration, + const FunctionDecl *FuncDecl); + +/// This is the error enumeration for escapesFunction(), describing all the +/// possible error cases. +enum class EscapesFunctionError { + ConstructorDeclNotFound = 1, + FunctionDeclNotFound, + FunctionIsBuiltin, + FunctionIsVariadic, + ExprNotInCall, + NoParamForArg, + ArgAndParamNotPointers +}; + +/// Required by the std::error_code system to convert our enum into a general +/// error code. +std::error_code make_error_code(EscapesFunctionError); + +/// Returns a (statement, decl) tuple if an argument from an argument list +/// escapes the function scope through globals/statics/other things. The +/// statement is where the value escapes the function, while the declaration +/// points to what it escapes through. If the argument doesn't escape the +/// function, the tuple will only contain nullptrs. +/// If the analysis runs into an unexpected error or into an unimplemented +/// configuration, it will return an error_code of type EscapesFunctionError +/// representing the precise issue. +/// +/// WARNING: incomplete behaviour/implementation for general-purpose use outside +/// of DanglingOnTemporaryChecker. This only covers a limited set of cases, +/// mainly in terms of arguments and parameter types. +ErrorOr> +escapesFunction(const Expr *Arg, const FunctionDecl *FuncDecl, + const Expr *const *Arguments, unsigned NumArgs); + +/// Helper function taking a call expression. +ErrorOr> +escapesFunction(const Expr *Arg, const CallExpr *Call); + +/// Helper function taking a construct expression. +ErrorOr> +escapesFunction(const Expr *Arg, const CXXConstructExpr *Construct); + +/// Helper function taking an operator call expression. +ErrorOr> +escapesFunction(const Expr *Arg, const CXXOperatorCallExpr *OpCall); + +#endif diff --git a/build/clang-plugin/alpha/AlphaChecks.inc b/build/clang-plugin/alpha/AlphaChecks.inc new file mode 100644 index 0000000000..4e0d050edd --- /dev/null +++ b/build/clang-plugin/alpha/AlphaChecks.inc @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// The list of checker classes that are compatible with clang-tidy and are considered +// to be in alpha stage development. + +// CHECK(AlphaChecker, "alpha-checker") +CHECK(NonStdMoveChecker, "non-std-move") +CHECK(TempRefPtrChecker, "performance-temp-refptr") diff --git a/build/clang-plugin/alpha/AlphaIncludes.inc b/build/clang-plugin/alpha/AlphaIncludes.inc new file mode 100644 index 0000000000..376c35b878 --- /dev/null +++ b/build/clang-plugin/alpha/AlphaIncludes.inc @@ -0,0 +1,2 @@ +#include "NonStdMoveChecker.h" +#include "TempRefPtrChecker.h" diff --git a/build/clang-plugin/alpha/NonStdMoveChecker.cpp b/build/clang-plugin/alpha/NonStdMoveChecker.cpp new file mode 100644 index 0000000000..e9ede00cea --- /dev/null +++ b/build/clang-plugin/alpha/NonStdMoveChecker.cpp @@ -0,0 +1,115 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NonStdMoveChecker.h" +#include "CustomMatchers.h" +#include "clang/Lex/Lexer.h" + +constexpr const char *kConstructExpr = "construct"; +constexpr const char *kOperatorCallExpr = "operator-call"; +constexpr const char *kSourceExpr = "source-expr"; +constexpr const char *kMaterializeExpr = "materialize-expr"; + +void NonStdMoveChecker::registerMatchers(MatchFinder *AstMatcher) { + + // Assignment through forget + AstMatcher->addMatcher( + cxxOperatorCallExpr( + hasOverloadedOperatorName("="), + hasAnyArgument(materializeTemporaryExpr( + has(cxxBindTemporaryExpr(has(cxxMemberCallExpr( + has(memberExpr(member(hasName("forget")))), + on(expr().bind(kSourceExpr))))))) + .bind(kMaterializeExpr))) + .bind(kOperatorCallExpr), + this); + + // Construction through forget + + AstMatcher->addMatcher( + cxxConstructExpr(has(materializeTemporaryExpr( + has(cxxBindTemporaryExpr(has(cxxMemberCallExpr( + has(memberExpr(member(hasName("forget")))), + on(expr().bind(kSourceExpr))))))) + .bind(kMaterializeExpr))) + .bind(kConstructExpr), + this); +} + +#if CLANG_VERSION_FULL >= 1600 +std::optional +#else +Optional +#endif +NonStdMoveChecker::makeFixItHint(const MatchFinder::MatchResult &Result, + const Expr *const TargetExpr) { + const auto *MaterializeExpr = Result.Nodes.getNodeAs(kMaterializeExpr); + + // TODO: In principle, we should check here if TargetExpr if + // assignable/constructible from std::move(SourceExpr). Not sure how to do + // this. Currently, we only filter out the case where the targetTypeTemplate + // is already_AddRefed, where this is known to fail. + + const auto *targetTypeTemplate = getNonTemplateSpecializedCXXRecordDecl( + TargetExpr->getType().getCanonicalType()); + const auto *sourceTypeTemplate = getNonTemplateSpecializedCXXRecordDecl( + MaterializeExpr->getType().getCanonicalType()); + + if (targetTypeTemplate && sourceTypeTemplate) { + // TODO is there a better way to check this than by name? otherwise, the + // names probably are necessarily unique in the scope + if (targetTypeTemplate->getName() == sourceTypeTemplate->getName() && + targetTypeTemplate->getName() == "already_AddRefed") { + return {}; + } + } + + const auto *SourceExpr = Result.Nodes.getNodeAs(kSourceExpr); + + const auto sourceText = Lexer::getSourceText( + CharSourceRange::getTokenRange(SourceExpr->getSourceRange()), + Result.Context->getSourceManager(), Result.Context->getLangOpts()); + + return FixItHint::CreateReplacement(MaterializeExpr->getSourceRange(), + ("std::move(" + sourceText + ")").str()); +} + +void NonStdMoveChecker::check(const MatchFinder::MatchResult &Result) { + // TODO: Include source and target type name in messages. + + const auto *OCE = + Result.Nodes.getNodeAs(kOperatorCallExpr); + + if (OCE) { + const auto *refPtrDecl = + dyn_cast(OCE->getCalleeDecl()->getDeclContext()); + + const auto XFixItHint = makeFixItHint(Result, OCE); + // TODO: produce diagnostic but no FixItHint in this case? + if (XFixItHint) { + diag(OCE->getBeginLoc(), "non-standard move assignment to %0 obscures " + "move, use std::move instead") + << refPtrDecl << *XFixItHint; + } + } + + const auto *CoE = Result.Nodes.getNodeAs(kConstructExpr); + + if (CoE) { + const auto *refPtrDecl = + dyn_cast(CoE->getConstructor()->getDeclContext()); + + const auto XFixItHint = makeFixItHint(Result, CoE); + // TODO: produce diagnostic but no FixItHint in this case? + if (XFixItHint) { + diag(CoE->getBeginLoc(), "non-standard move construction of %0 obscures " + "move, use std::move instead") + << refPtrDecl << *XFixItHint; + } + } + + // TODO: What about swap calls immediately after default-construction? These + // can also be replaced by move-construction, but this may require + // control-flow analysis. +} diff --git a/build/clang-plugin/alpha/NonStdMoveChecker.h b/build/clang-plugin/alpha/NonStdMoveChecker.h new file mode 100644 index 0000000000..bb0565cdf0 --- /dev/null +++ b/build/clang-plugin/alpha/NonStdMoveChecker.h @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NonStdMoveChecker_h__ +#define NonStdMoveChecker_h__ + +#include "plugin.h" + +class NonStdMoveChecker final : public BaseCheck { +public: + NonStdMoveChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; + +private: + CompilerInstance *CI; + + static +#if CLANG_VERSION_FULL >= 1600 + std::optional +#else + Optional +#endif + makeFixItHint(const MatchFinder::MatchResult &Result, const Expr *TargetExpr); +}; + +#endif diff --git a/build/clang-plugin/alpha/TempRefPtrChecker.cpp b/build/clang-plugin/alpha/TempRefPtrChecker.cpp new file mode 100644 index 0000000000..0a4d078368 --- /dev/null +++ b/build/clang-plugin/alpha/TempRefPtrChecker.cpp @@ -0,0 +1,57 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TempRefPtrChecker.h" +#include "CustomMatchers.h" + +constexpr const char *kCallExpr = "call-expr"; +constexpr const char *kOperatorCallExpr = "operator-call"; + +void TempRefPtrChecker::registerMatchers(MatchFinder *AstMatcher) { + AstMatcher->addMatcher( + cxxOperatorCallExpr( + hasOverloadedOperatorName("->"), + hasAnyArgument(implicitCastExpr( + hasSourceExpression(materializeTemporaryExpr(anyOf( + hasDescendant(callExpr().bind(kCallExpr)), anything()))))), + callee(hasDeclContext(classTemplateSpecializationDecl( + isSmartPtrToRefCountedDecl(), + // ignore any calls on temporary RefPtr>, + // since these typically need to be locally ref-counted, + // e.g. in Then chains where the promise might be resolved + // concurrently + unless(hasTemplateArgument( + 0, refersToType(hasDeclaration( + cxxRecordDecl(hasName("mozilla::MozPromise")))))))))) + .bind(kOperatorCallExpr), + this); +} + +void TempRefPtrChecker::check(const MatchFinder::MatchResult &Result) { + const auto *OCE = + Result.Nodes.getNodeAs(kOperatorCallExpr); + + const auto *refPtrDecl = + dyn_cast(OCE->getCalleeDecl()->getDeclContext()); + + diag(OCE->getOperatorLoc(), + "performance issue: temporary %0 is only dereferenced here once which " + "involves short-lived AddRef/Release calls") + << refPtrDecl; + + const auto *InnerCE = Result.Nodes.getNodeAs(kCallExpr); + if (InnerCE) { + const auto functionName = + InnerCE->getCalleeDecl()->getAsFunction()->getQualifiedNameAsString(); + + if (functionName != "mozilla::MakeRefPtr") { + diag( + OCE->getOperatorLoc(), + "consider changing function %0 to return a raw reference instead (be " + "sure that the pointee is held alive by someone else though!)", + DiagnosticIDs::Note) + << functionName; + } + } +} diff --git a/build/clang-plugin/alpha/TempRefPtrChecker.h b/build/clang-plugin/alpha/TempRefPtrChecker.h new file mode 100644 index 0000000000..ebed50c3a0 --- /dev/null +++ b/build/clang-plugin/alpha/TempRefPtrChecker.h @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef TempRefPtrChecker_h__ +#define TempRefPtrChecker_h__ + +#include "plugin.h" + +class TempRefPtrChecker final : public BaseCheck { +public: + TempRefPtrChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder *AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; + +private: + CompilerInstance *CI; +}; + +#endif diff --git a/build/clang-plugin/alpha/sources.mozbuild b/build/clang-plugin/alpha/sources.mozbuild new file mode 100644 index 0000000000..03ed90d3c1 --- /dev/null +++ b/build/clang-plugin/alpha/sources.mozbuild @@ -0,0 +1,10 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +HOST_SOURCES += [ + "NonStdMoveChecker.cpp", + "TempRefPtrChecker.cpp", +] diff --git a/build/clang-plugin/alpha/tests/TestNonStdMove.cpp b/build/clang-plugin/alpha/tests/TestNonStdMove.cpp new file mode 100644 index 0000000000..379f9655dd --- /dev/null +++ b/build/clang-plugin/alpha/tests/TestNonStdMove.cpp @@ -0,0 +1,125 @@ +#include + +// we can't include nsCOMPtr.h here, so let's redefine a basic version +template +struct nsCOMPtr { + nsCOMPtr() = default; + + template + MOZ_IMPLICIT nsCOMPtr(already_AddRefed&& aSrc); + + template + nsCOMPtr& operator=(already_AddRefed&& aSrc); +}; + + +using namespace mozilla; + +struct RefCountedBase { + void AddRef(); + void Release(); + + void method_test(); +}; + +struct RefCountedDerived : RefCountedBase {}; + +struct RefCountedBaseHolder { + RefPtr GetRefCountedBase() const { + return mRefCountedBase; + } + +private: + RefPtr mRefCountedBase = MakeRefPtr(); +}; + + +void test_assign_same_type() { + RefPtr a = MakeRefPtr(); + RefPtr b; + + b = a.forget(); // expected-warning {{non-standard move assignment}} +} + +void test_assign_implicit_cast() { + RefPtr a = MakeRefPtr(); + RefPtr b; + + b = a.forget(); // expected-warning {{non-standard move assignment}} +} + +void test_assign_different_template() { + RefPtr a = MakeRefPtr(); + nsCOMPtr b; + + b = a.forget(); // expected-warning {{non-standard move assignment}} +} + +void test_construct_different_template() { + RefPtr a = MakeRefPtr(); + nsCOMPtr b = a.forget(); // expected-warning {{non-standard move construction}} +} + +void test_assign_already_addrefed() { + RefPtr a = MakeRefPtr(); + already_AddRefed b; + + b = a.forget(); +} + +void test_construct_already_addrefed() { + RefPtr a = MakeRefPtr(); + already_AddRefed b = a.forget(); +} + +void test_construct_same_type() { + RefPtr a = MakeRefPtr(); + RefPtr b = a.forget(); // expected-warning {{non-standard move construction}} +} + +void test_construct_implicit_cast() { + RefPtr a = MakeRefPtr(); + RefPtr b = a.forget(); // expected-warning {{non-standard move construction}} +} + +void test_construct_brace_same_type() { + RefPtr a = MakeRefPtr(); + auto b = RefPtr{a.forget()}; // expected-warning {{non-standard move construction}} +} + +void test_construct_brace_implicit_cast() { + RefPtr a = MakeRefPtr(); + auto b = RefPtr{a.forget()}; // expected-warning {{non-standard move construction}} +} + +void test_construct_function_style_same_type() { + RefPtr a = MakeRefPtr(); + auto b = RefPtr(a.forget()); // expected-warning {{non-standard move construction}} +} + +void test_construct_function_style_implicit_cast() { + RefPtr a = MakeRefPtr(); + auto b = RefPtr(a.forget()); // expected-warning {{non-standard move construction}} +} + +void test_construct_result_type() { + RefPtr a = MakeRefPtr(); + already_AddRefed b = a.forget(); +} + +void test_construct_implicitly_cast_result_type() { + RefPtr a = MakeRefPtr(); + already_AddRefed b = a.forget(); +} + +void foo(already_AddRefed&& aArg); + +void test_call_with_result_type() { + RefPtr a = MakeRefPtr(); + foo(a.forget()); +} + +void test_call_with_implicitly_cast_result_type() { + RefPtr a = MakeRefPtr(); + foo(a.forget()); +} diff --git a/build/clang-plugin/alpha/tests/TestTempRefPtr.cpp b/build/clang-plugin/alpha/tests/TestTempRefPtr.cpp new file mode 100644 index 0000000000..51f756b8e6 --- /dev/null +++ b/build/clang-plugin/alpha/tests/TestTempRefPtr.cpp @@ -0,0 +1,52 @@ +#include + +using namespace mozilla; + +struct RefCountedBase { + void AddRef(); + void Release(); + + void method_test(); +}; + +struct RefCountedBaseHolder { + RefPtr GetRefCountedBase() const { + return mRefCountedBase; + } + +private: + RefPtr mRefCountedBase = MakeRefPtr(); +}; + + +void test_arrow_temporary_new_refptr_function_style_cast() { + RefPtr(new RefCountedBase())->method_test(); // expected-warning {{performance issue: temporary 'RefPtr' is only dereferenced here once which involves short-lived AddRef/Release calls}} +} + +void test_arrow_temporary_new_refptr_brace() { + RefPtr{new RefCountedBase()}->method_test(); // expected-warning {{performance issue: temporary 'RefPtr' is only dereferenced here once which involves short-lived AddRef/Release calls}} +} + +void test_arrow_temporary_new_c_style_cast() { + ((RefPtr)(new RefCountedBase()))->method_test(); // expected-warning {{performance issue: temporary 'RefPtr' is only dereferenced here once which involves short-lived AddRef/Release calls}} +} + +void test_arrow_temporary_new_static_cast() { + static_cast>(new RefCountedBase())->method_test(); // expected-warning {{performance issue: temporary 'RefPtr' is only dereferenced here once which involves short-lived AddRef/Release calls}} +} + +void test_arrow_temporary_new_refptr_makerefptr() { + MakeRefPtr()->method_test(); // expected-warning {{performance issue: temporary 'RefPtr' is only dereferenced here once which involves short-lived AddRef/Release calls}} +} + +void test_arrow_temporary_get_refptr_from_member_function() { + const RefCountedBaseHolder holder; + holder.GetRefCountedBase()->method_test(); // expected-warning {{performance issue: temporary 'RefPtr' is only dereferenced here once which involves short-lived AddRef/Release calls}} expected-note {{consider changing function RefCountedBaseHolder::GetRefCountedBase to return a raw reference instead}} +} + +void test_ref(RefCountedBase &aRefCountedBase); + +void test_star_temporary_new_refptr_function_style_cast() { + // TODO: Should we warn about operator* as well? + test_ref(*RefPtr(new RefCountedBase())); +} diff --git a/build/clang-plugin/alpha/tests/sources.mozbuild b/build/clang-plugin/alpha/tests/sources.mozbuild new file mode 100644 index 0000000000..6268746232 --- /dev/null +++ b/build/clang-plugin/alpha/tests/sources.mozbuild @@ -0,0 +1,10 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SOURCES += [ + "TestNonStdMove.cpp", + "TestTempRefPtr.cpp", +] diff --git a/build/clang-plugin/external/CustomAttributes.inc b/build/clang-plugin/external/CustomAttributes.inc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/build/clang-plugin/external/ExternalChecks.inc b/build/clang-plugin/external/ExternalChecks.inc new file mode 100644 index 0000000000..d5f0b0334c --- /dev/null +++ b/build/clang-plugin/external/ExternalChecks.inc @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Placeholder file to be overwritten with external checks during build +// The list of checker classes that are compatible with clang-tidy-external. + +// CHECK(ExternalChecker, "external-checker") diff --git a/build/clang-plugin/external/ExternalIncludes.inc b/build/clang-plugin/external/ExternalIncludes.inc new file mode 100644 index 0000000000..9fda16de8a --- /dev/null +++ b/build/clang-plugin/external/ExternalIncludes.inc @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Placeholder file to be overwritten with external checks during build +// The list of #include directives necessary for the checker classes that +// are compatible with clang-tidy-external. + +// #include "ExternalChecker.h" diff --git a/build/clang-plugin/external/sources.mozbuild b/build/clang-plugin/external/sources.mozbuild new file mode 100644 index 0000000000..01daf87080 --- /dev/null +++ b/build/clang-plugin/external/sources.mozbuild @@ -0,0 +1,10 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Placeholder file to be overwritten with external checks during build +HOST_SOURCES += [ + # 'ExternalChecker.cpp', +] diff --git a/build/clang-plugin/external/tests/sources.mozbuild b/build/clang-plugin/external/tests/sources.mozbuild new file mode 100644 index 0000000000..1f3b4a61c9 --- /dev/null +++ b/build/clang-plugin/external/tests/sources.mozbuild @@ -0,0 +1,10 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Placeholder file to be overwritten with external checks during build +SOURCES += [ + # 'ExternalTest.cpp', +] diff --git a/build/clang-plugin/import_mozilla_checks.py b/build/clang-plugin/import_mozilla_checks.py new file mode 100755 index 0000000000..d573dafcf1 --- /dev/null +++ b/build/clang-plugin/import_mozilla_checks.py @@ -0,0 +1,177 @@ +#!/usr/bin/python3 +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import errno +import glob +import os +import shutil + +import ThirdPartyPaths +import ThreadAllows + + +def copy_dir_contents(src, dest): + for f in glob.glob("%s/*" % src): + try: + destname = "%s/%s" % (dest, os.path.basename(f)) + if os.path.isdir(f): + shutil.copytree(f, destname) + else: + shutil.copy2(f, destname) + except OSError as e: + if e.errno == errno.ENOTDIR: + shutil.copy2(f, destname) + elif e.errno == errno.EEXIST: + if os.path.isdir(f): + copy_dir_contents(f, destname) + else: + os.remove(destname) + shutil.copy2(f, destname) + else: + raise Exception("Directory not copied. Error: %s" % e) + + +def write_cmake(module_path, import_options): + names = [" " + os.path.basename(f) for f in glob.glob("%s/*.cpp" % module_path)] + + if import_options["external"]: + names += [ + " " + os.path.join("external", os.path.basename(f)) + for f in glob.glob("%s/external/*.cpp" % (module_path)) + ] + + if import_options["alpha"]: + names += [ + " " + os.path.join("alpha", os.path.basename(f)) + for f in glob.glob("%s/alpha/*.cpp" % (module_path)) + ] + + with open(os.path.join(module_path, "CMakeLists.txt"), "w") as f: + f.write( + """set(LLVM_LINK_COMPONENTS support) + +add_definitions( -DCLANG_TIDY ) + +add_clang_library(clangTidyMozillaModule + ThirdPartyPaths.cpp +%(names)s + + LINK_LIBS + clangTidy + clangTidyReadabilityModule + clangTidyUtils + clangTidyMPIModule + ) + +clang_target_link_libraries(clangTidyMozillaModule + PRIVATE + clangAST + clangASTMatchers + clangBasic + clangLex + )""" + % {"names": "\n".join(names)} + ) + + +def add_moz_module(cmake_path): + with open(cmake_path, "r") as f: + lines = f.readlines() + f.close() + + try: + idx = lines.index("set(ALL_CLANG_TIDY_CHECKS\n") + lines.insert(idx + 1, " clangTidyMozillaModule\n") + + with open(cmake_path, "w") as f: + for line in lines: + f.write(line) + except ValueError: + raise Exception("Unable to find ALL_CLANG_TIDY_CHECKS in {}".format(cmake_path)) + + +def write_third_party_paths(mozilla_path, module_path): + tpp_txt = os.path.join(mozilla_path, "../../tools/rewriting/ThirdPartyPaths.txt") + generated_txt = os.path.join(mozilla_path, "../../tools/rewriting/Generated.txt") + with open(os.path.join(module_path, "ThirdPartyPaths.cpp"), "w") as f: + ThirdPartyPaths.generate(f, tpp_txt, generated_txt) + + +def generate_thread_allows(mozilla_path, module_path): + names = os.path.join(mozilla_path, "../../build/clang-plugin/ThreadAllows.txt") + files = os.path.join(mozilla_path, "../../build/clang-plugin/ThreadFileAllows.txt") + with open(os.path.join(module_path, "ThreadAllows.h"), "w") as f: + f.write( + ThreadAllows.generate_allows(allowed_names=[names], allowed_files=[files]) + ) + + +def do_import(mozilla_path, clang_tidy_path, import_options): + module = "mozilla" + module_path = os.path.join(clang_tidy_path, module) + try: + os.makedirs(module_path) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + copy_dir_contents(mozilla_path, module_path) + write_third_party_paths(mozilla_path, module_path) + generate_thread_allows(mozilla_path, module_path) + write_cmake(module_path, import_options) + add_moz_module(os.path.join(module_path, "..", "CMakeLists.txt")) + with open(os.path.join(module_path, "..", "CMakeLists.txt"), "a") as f: + f.write("add_subdirectory(%s)\n" % module) + # A better place for this would be in `ClangTidyForceLinker.h` but `ClangTidyMain.cpp` + # is also OK. + with open(os.path.join(module_path, "..", "tool", "ClangTidyMain.cpp"), "a") as f: + f.write( + """ +// This anchor is used to force the linker to link the MozillaModule. +extern volatile int MozillaModuleAnchorSource; +static int LLVM_ATTRIBUTE_UNUSED MozillaModuleAnchorDestination = + MozillaModuleAnchorSource; +""" + ) + + +def main(): + import argparse + + parser = argparse.ArgumentParser( + usage="import_mozilla_checks.py [option]", + description="Imports the Mozilla static analysis checks into a clang-tidy source tree.", + ) + parser.add_argument( + "mozilla_path", help="Full path to mozilla-central/build/clang-plugin" + ) + parser.add_argument( + "clang_tidy_path", help="Full path to llvm-project/clang-tools-extra/clang-tidy" + ) + parser.add_argument( + "--import-alpha", + help="Enable import of in-tree alpha checks", + action="store_true", + ) + parser.add_argument( + "--import-external", + help="Enable import of in-tree external checks", + action="store_true", + ) + args = parser.parse_args() + + if not os.path.isdir(args.mozilla_path): + print("Invalid path to mozilla clang plugin") + + if not os.path.isdir(args.clang_tidy_path): + print("Invalid path to clang-tidy source directory") + + import_options = {"alpha": args.import_alpha, "external": args.import_external} + + do_import(args.mozilla_path, args.clang_tidy_path, import_options) + + +if __name__ == "__main__": + main() diff --git a/build/clang-plugin/moz.build b/build/clang-plugin/moz.build new file mode 100644 index 0000000000..c9c2c520db --- /dev/null +++ b/build/clang-plugin/moz.build @@ -0,0 +1,129 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +HostSharedLibrary("clang-plugin") + +HOST_SOURCES += ["!ThirdPartyPaths.cpp"] + +HOST_SOURCES += [ + "ArithmeticArgChecker.cpp", + "AssertAssignmentChecker.cpp", + "CanRunScriptChecker.cpp", + "CustomAttributes.cpp", + "CustomTypeAnnotation.cpp", + "DanglingOnTemporaryChecker.cpp", + "DiagnosticsMatcher.cpp", + "ExplicitImplicitChecker.cpp", + "ExplicitOperatorBoolChecker.cpp", + "JSHandleRootedTypedefChecker.cpp", + "KnownLiveChecker.cpp", + "KungFuDeathGripChecker.cpp", + "MozCheckAction.cpp", + "MustOverrideChecker.cpp", + "MustReturnFromCallerChecker.cpp", + "NaNExprChecker.cpp", + "NeedsNoVTableTypeChecker.cpp", + "NoAddRefReleaseOnReturnChecker.cpp", + "NoAutoTypeChecker.cpp", + "NoDuplicateRefCntMemberChecker.cpp", + "NoExplicitMoveConstructorChecker.cpp", + "NoNewThreadsChecker.cpp", + "NonMemMovableMemberChecker.cpp", + "NonMemMovableTemplateArgChecker.cpp", + "NonParamInsideFunctionDeclChecker.cpp", + "NonTrivialTypeInFfiChecker.cpp", + "NoPrincipalGetURI.cpp", + "NoUsingNamespaceMozillaJavaChecker.cpp", + "OverrideBaseCallChecker.cpp", + "OverrideBaseCallUsageChecker.cpp", + "ParamTraitsEnumChecker.cpp", + "RefCountedCopyConstructorChecker.cpp", + "RefCountedInsideLambdaChecker.cpp", + "RefCountedThisInsideConstructorChecker.cpp", + "ScopeChecker.cpp", + "SprintfLiteralChecker.cpp", + "TrivialCtorDtorChecker.cpp", + "TrivialDtorChecker.cpp", + "VariableUsageHelpers.cpp", +] + +# Ideally, we wouldn't have compile-time choices wrt checks. bug 1617153. +if CONFIG["OS_ARCH"] == "WINNT": + HOST_DEFINES["TARGET_IS_WINDOWS"] = True + HOST_SOURCES += [ + "FopenUsageChecker.cpp", + "LoadLibraryUsageChecker.cpp", + ] + +if CONFIG["ENABLE_MOZSEARCH_PLUGIN"]: + HOST_SOURCES += [ + "mozsearch-plugin/BindingOperations.cpp", + "mozsearch-plugin/FileOperations.cpp", + "mozsearch-plugin/from-clangd/HeuristicResolver.cpp", + "mozsearch-plugin/MozsearchIndexer.cpp", + "mozsearch-plugin/StringOperations.cpp", + ] + +GeneratedFile( + "ThirdPartyPaths.cpp", + script="ThirdPartyPaths.py", + entry_point="generate", + inputs=[ + "/tools/rewriting/ThirdPartyPaths.txt", + "/tools/rewriting/Generated.txt", + ], +) + +GeneratedFile( + "ThreadAllows.h", + script="ThreadAllows.py", + entry_point="generate_file", + inputs=[ + "/build/clang-plugin/ThreadAllows.txt", + "/build/clang-plugin/ThreadFileAllows.txt", + ], +) + +HOST_COMPILE_FLAGS["STL"] = [] +HOST_COMPILE_FLAGS["VISIBILITY"] = [] + +# libc++ is required to build plugins against clang on OS X. +if CONFIG["HOST_OS_ARCH"] == "Darwin": + HOST_CXXFLAGS += ["-stdlib=libc++"] + +# As of clang 8, llvm-config doesn't output the flags used to build clang +# itself, so we don't end up with -fPIC as a side effect. llvm.org/PR8220 +if CONFIG["HOST_OS_ARCH"] != "WINNT": + HOST_CXXFLAGS += ["-fPIC"] + +DIRS += [ + "tests", +] + +include("external/sources.mozbuild") + +if CONFIG["ENABLE_CLANG_PLUGIN_ALPHA"]: + HOST_DEFINES["MOZ_CLANG_PLUGIN_ALPHA"] = "1" + include("alpha/sources.mozbuild") + +# In the current moz.build world, we need to override essentially every +# variable to limit ourselves to what we need to build the clang plugin. +if CONFIG["HOST_OS_ARCH"] == "WINNT": + extra_cxxflags = ["-GR-", "-EHsc"] + # Clang 14 headers enforce a requirement upon Visual Studio 2019 headers, + # for support of newer C++ versions, which is necessary for clang itself, + # but as of writing, it's not necessary for the plugin code, so enable + # the escape hatch, at least until we generally upgrade to VS 2019. + HOST_DEFINES["LLVM_FORCE_USE_OLD_TOOLCHAIN"] = True +else: + extra_cxxflags = ["-fno-rtti", "-fno-exceptions"] + +if CONFIG["LLVM_CXXFLAGS"]: + HOST_COMPILE_FLAGS["HOST_CXXFLAGS"] = CONFIG["LLVM_CXXFLAGS"] + extra_cxxflags + +# Avoid -DDEBUG=1 on the command line, which conflicts with a #define +# DEBUG(...) in llvm headers. +DEFINES["DEBUG"] = False diff --git a/build/clang-plugin/mozsearch-plugin/BindingOperations.cpp b/build/clang-plugin/mozsearch-plugin/BindingOperations.cpp new file mode 100644 index 0000000000..79f7f3aebf --- /dev/null +++ b/build/clang-plugin/mozsearch-plugin/BindingOperations.cpp @@ -0,0 +1,792 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BindingOperations.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cpp_lib_optional +#include +template using optional = std::optional; +#else +#include +template using optional = clang::Optional; +#endif + +using namespace clang; + +namespace { + +template +bool hasReverseQualifiedName(InputIt first, InputIt last, const NamedDecl &tag) +{ + const NamedDecl *currentDecl = &tag; + InputIt currentName; + for (currentName = first; currentName != last; currentName++) { + if (!currentDecl || !currentDecl->getIdentifier() || currentDecl->getName() != *currentName) + return false; + + currentDecl = dyn_cast(currentDecl->getDeclContext()); + } + if (currentName != last) + return false; + + if (currentDecl != nullptr) + return false; + + return true; +} + +bool isMozillaJniObjectBase(const CXXRecordDecl &klass) +{ + const auto qualifiedName = std::array{"mozilla", "jni", "ObjectBase"}; + return hasReverseQualifiedName(qualifiedName.crbegin(), qualifiedName.crend(), klass); +} + +bool isMozillaJniNativeImpl(const CXXRecordDecl &klass) +{ + const auto qualifiedName = std::array{"mozilla", "jni", "NativeImpl"}; + return hasReverseQualifiedName(qualifiedName.crbegin(), qualifiedName.crend(), klass); +} + +const NamedDecl *fieldNamed(StringRef name, const RecordDecl &strukt) +{ + for (const auto *decl : strukt.decls()) { + const auto *namedDecl = dyn_cast(decl); + if (!namedDecl) + continue; + + if (!namedDecl->getIdentifier() || namedDecl->getName() != name) + continue; + + return namedDecl; + } + + return {}; +} + +optional nameFieldValue(const RecordDecl &strukt) +{ + const auto *nameField = dyn_cast_or_null(fieldNamed("name", strukt)); + if (!nameField) + return {}; + + const auto *def = nameField->getDefinition(); + if (!def) + return {}; + + const auto *name = dyn_cast_or_null(def->getInit()); + if (!name) + return {}; + + return name->getString(); +} + +struct AbstractBinding { + // Subset of tools/analysis/BindingSlotLang + enum class Lang { + Cpp, + Jvm, + }; + static constexpr size_t LangLength = 2; + static constexpr std::array langNames = { + "cpp", + "jvm", + }; + + static optional langFromString(StringRef langName) + { + const auto it = std::find(langNames.begin(), langNames.end(), langName); + if (it == langNames.end()) + return {}; + + return Lang(it - langNames.begin()); + } + static StringRef stringFromLang(Lang lang) + { + return langNames[size_t(lang)]; + } + + // Subset of tools/analysis/BindingSlotKind + enum class Kind { + Class, + Method, + Getter, + Setter, + Const, + }; + static constexpr size_t KindLength = 5; + static constexpr std::array kindNames = { + "class", + "method", + "getter", + "setter", + "const", + }; + + static optional kindFromString(StringRef kindName) + { + const auto it = std::find(kindNames.begin(), kindNames.end(), kindName); + if (it == kindNames.end()) + return {}; + + return Kind(it - kindNames.begin()); + } + static StringRef stringFromKind(Kind kind) + { + return kindNames[size_t(kind)]; + } + + Lang lang; + Kind kind; + StringRef symbol; +}; +constexpr size_t AbstractBinding::KindLength; +constexpr std::array AbstractBinding::kindNames; +constexpr size_t AbstractBinding::LangLength; +constexpr std::array AbstractBinding::langNames; + +struct BindingTo : public AbstractBinding { + BindingTo(AbstractBinding b) : AbstractBinding(std::move(b)) {} + static constexpr StringRef ANNOTATION = "binding_to"; +}; +constexpr StringRef BindingTo::ANNOTATION; + +struct BoundAs : public AbstractBinding { + BoundAs(AbstractBinding b) : AbstractBinding(std::move(b)) {} + static constexpr StringRef ANNOTATION = "bound_as"; +}; +constexpr StringRef BoundAs::ANNOTATION; + +template +void setBindingAttr(ASTContext &C, Decl &decl, B binding) +{ + // recent LLVM: CreateImplicit then setDelayedArgs + Expr *langExpr = StringLiteral::Create(C, AbstractBinding::stringFromLang(binding.lang), StringLiteral::UTF8, false, {}, {}); + Expr *kindExpr = StringLiteral::Create(C, AbstractBinding::stringFromKind(binding.kind), StringLiteral::UTF8, false, {}, {}); + Expr *symbolExpr = StringLiteral::Create(C, binding.symbol, StringLiteral::UTF8, false, {}, {}); + auto **args = new (C, 16) Expr *[3]{langExpr, kindExpr, symbolExpr}; + auto *attr = AnnotateAttr::CreateImplicit(C, B::ANNOTATION, args, 3); + decl.addAttr(attr); +} + +optional readBinding(const AnnotateAttr &attr) +{ + if (attr.args_size() != 3) + return {}; + + const auto *langExpr = attr.args().begin()[0]; + const auto *kindExpr = attr.args().begin()[1]; + const auto *symbolExpr = attr.args().begin()[2]; + if (!langExpr || !kindExpr || !symbolExpr) + return {}; + + const auto *langName = dyn_cast(langExpr->IgnoreUnlessSpelledInSource()); + const auto *kindName = dyn_cast(kindExpr->IgnoreUnlessSpelledInSource()); + const auto *symbol = dyn_cast(symbolExpr->IgnoreUnlessSpelledInSource()); + if (!langName || !kindName || !symbol) + return {}; + + const auto lang = AbstractBinding::langFromString(langName->getString()); + const auto kind = AbstractBinding::kindFromString(kindName->getString()); + + if (!lang || !kind) + return {}; + + return AbstractBinding { + .lang = *lang, + .kind = *kind, + .symbol = symbol->getString(), + }; +} + +optional getBindingTo(const Decl &decl) +{ + for (const auto *attr : decl.specific_attrs()) { + if (attr->getAnnotation() != BindingTo::ANNOTATION) + continue; + + const auto binding = readBinding(*attr); + if (!binding) + continue; + + return BindingTo{*binding}; + } + return {}; +} + +// C++23: turn into generator +std::vector getBoundAs(const Decl &decl) +{ + std::vector found; + + for (const auto *attr : decl.specific_attrs()) { + if (attr->getAnnotation() != BoundAs::ANNOTATION) + continue; + + const auto binding = readBinding(*attr); + if (!binding) + continue; + + found.push_back(BoundAs{*binding}); + } + + return found; +} + +class FindCallCall : private RecursiveASTVisitor +{ +public: + struct Result { + using Kind = AbstractBinding::Kind; + + Kind kind; + StringRef name; + }; + + static optional search(Stmt *statement) + { + FindCallCall finder; + finder.TraverseStmt(statement); + return finder.result; + } + +private: + optional result; + + friend RecursiveASTVisitor; + + optional tryParseCallCall(CallExpr *callExpr){ + const auto *callee = dyn_cast_or_null(callExpr->getDirectCallee()); + if (!callee) + return {}; + + if (!callee->getIdentifier()) + return {}; + + const auto action = callee->getIdentifier()->getName(); + + if (action != "Call" && action != "Get" && action != "Set") + return {}; + + const auto *parentClass = dyn_cast_or_null(callee->getParent()); + + if (!parentClass) + return {}; + + const auto *parentTemplate = parentClass->getTemplateInstantiationPattern(); + + if (!parentTemplate || !parentTemplate->getIdentifier()) + return {}; + + const auto parentName = parentTemplate->getIdentifier()->getName(); + + AbstractBinding::Kind kind; + if (action == "Call") { + if (parentName == "Constructor" || parentName == "Method") { + kind = AbstractBinding::Kind::Method; + } else { + return {}; + } + } else if (parentName == "Field") { + if (action == "Get") { + kind = AbstractBinding::Kind::Getter; + } else if (action == "Set") { + kind = AbstractBinding::Kind::Setter; + } else { + return {}; + } + } else { + return {}; + } + + const auto *templateArg = parentClass->getTemplateArgs().get(0).getAsType()->getAsRecordDecl(); + + if (!templateArg) + return {}; + + const auto name = nameFieldValue(*templateArg); + if (!name) + return {}; + + return Result { + .kind = kind, + .name = *name, + }; + + return {}; + } + bool VisitCallExpr(CallExpr *callExpr) + { + return !(result = tryParseCallCall(callExpr)); + } +}; + +constexpr StringRef JVM_SCIP_SYMBOL_PREFIX = "S_jvm_"; + +std::string javaScipSymbol(StringRef prefix, StringRef name, AbstractBinding::Kind kind) +{ + auto symbol = (prefix + name).str(); + + switch (kind) { + case AbstractBinding::Kind::Class: + std::replace(symbol.begin(), symbol.end(), '$', '#'); + symbol += "#"; + break; + case AbstractBinding::Kind::Method: + symbol += "()."; + break; + case AbstractBinding::Kind::Const: + case AbstractBinding::Kind::Getter: + case AbstractBinding::Kind::Setter: + symbol += "."; + break; + } + + return symbol; +} + +void addSlotOwnerAttribute(llvm::json::OStream &J, const Decl &decl) +{ + if (const auto bindingTo = getBindingTo(decl)) { + J.attributeBegin("slotOwner"); + J.objectBegin(); + J.attribute("slotKind", AbstractBinding::stringFromKind(bindingTo->kind)); + J.attribute("slotLang", "cpp"); + J.attribute("ownerLang", AbstractBinding::stringFromLang(bindingTo->lang)); + J.attribute("sym", bindingTo->symbol); + J.objectEnd(); + J.attributeEnd(); + } +} +void addBindingSlotsAttribute(llvm::json::OStream &J, const Decl &decl) +{ + const auto allBoundAs = getBoundAs(decl); + if (!allBoundAs.empty()) { + J.attributeBegin("bindingSlots"); + J.arrayBegin(); + for (const auto boundAs : allBoundAs) { + J.objectBegin(); + J.attribute("slotKind", AbstractBinding::stringFromKind(boundAs.kind)); + J.attribute("slotLang", AbstractBinding::stringFromLang(boundAs.lang)); + J.attribute("ownerLang", "cpp"); + J.attribute("sym", boundAs.symbol); + J.objectEnd(); + } + J.arrayEnd(); + J.attributeEnd(); + } +} + +// The mangling scheme is documented at https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html +// The main takeaways are: +// - _0xxxx is the utf16 code unit xxxx +// - _1 is _ +// - _2 is ; +// - _3 is [ +// - __ is the separator between function name and overload specification +// - _ is otherwise the separator between packages/classes/methods +// +// This method takes a StringRef & and mutates it and can be called twice on a Jnicall function name to get +// first the demangled name +// second the demangled overload specification +// But we don't use the later for now because we have no way to map that to how SCIP resolves overloads. +optional demangleJnicallPart(StringRef &remainder) +{ + std::string demangled; + + std::mbstate_t ps = {}; + + while (!remainder.empty()) { + switch (remainder[0]) { + case '0': { + remainder = remainder.drop_front(1); + + uint16_t codeUnit; + const auto ok = remainder.substr(1, 4).getAsInteger(16, codeUnit); + remainder = remainder.drop_front(4); + + if (!ok) // failed reading xxxx as hexadecimal from _0xxxx + return {}; + + std::array codePoint; + const auto mbLen = std::c16rtomb(codePoint.data(), codeUnit, &ps); + + if (mbLen == -1) // failed converting utf16 to utf8 + return {}; + + demangled += StringRef(codePoint.begin(), mbLen); + break; + } + case '1': + remainder = remainder.drop_front(1); + ps = {}; + demangled += '_'; + break; + case '2': + remainder = remainder.drop_front(1); + ps = {}; + demangled += ';'; + break; + case '3': + remainder = remainder.drop_front(1); + ps = {}; + demangled += '['; + break; + case '_': + remainder = remainder.drop_front(1); + ps = {}; + if (remainder.empty()) // the string ends with _ + return {}; + + switch (remainder[0]) { + case '0': + case '1': + case '2': + case '3': + demangled += '.'; + break; + default: + // either: + // * the string began with _[^0-3], which is not supposed to happen; or + // * we reached __[^0-3] meaning we finished the first part of the name and remainder holds the overload specification + return demangled; + } + default: + ps = {}; + demangled += '.'; + break; + } + StringRef token; + std::tie(token, remainder) = remainder.split('_'); + demangled += token; + } + + return demangled; +} + +optional scipSymbolFromJnicallFunctionName(StringRef functionName) +{ + if (!functionName.consume_front("Java_")) + return {}; + + const auto demangledName = demangleJnicallPart(functionName); + + if (!demangledName || demangledName->empty()) + return {}; + + // demangleJavaName returns something like .some.package.Class$InnerClass.method + // - prepend S_jvm_ + // - remove the leading dot + // - replace the last dot with a # + // - replace the other dots with / + // - replace $ with # + // - add the ([+overloadNumber]). suffix + auto symbol = JVM_SCIP_SYMBOL_PREFIX.str(); + symbol += demangledName->substr(1); + const auto lastDot = symbol.rfind('.'); + if (lastDot != std::string::npos) + symbol[lastDot] = '#'; + std::replace(symbol.begin(), symbol.end(), '.', '/'); + std::replace(symbol.begin(), symbol.end(), '$', '#'); + + // Keep track of how many times we have seen this method, to build the ([+overloadNumber]). suffix. + // This assumes this function is called on C function definitions in the same order the matching overloads are declared in Java. + static std::unordered_map jnicallFunctions; + auto &overloadNumber = jnicallFunctions[symbol]; + + symbol += '('; + if (overloadNumber) { + symbol += '+'; + symbol += overloadNumber; + overloadNumber++; + } + symbol += ")."; + + return symbol; +}; + +} // anonymous namespace + +// class [wrapper] : public mozilla::jni::ObjectBase<[wrapper]> +// { +// static constexpr char name[] = "[nameFieldValue]"; +// } +void findBindingToJavaClass(ASTContext &C, CXXRecordDecl &klass) +{ + for (const auto &baseSpecifier : klass.bases()) { + const auto *base = baseSpecifier.getType()->getAsCXXRecordDecl(); + if (!base) + continue; + + if (!isMozillaJniObjectBase(*base)) + continue; + + const auto name = nameFieldValue(klass); + if (!name) + continue; + + const auto symbol = javaScipSymbol(JVM_SCIP_SYMBOL_PREFIX, *name, BindingTo::Kind::Class); + const auto binding = BindingTo {{ + .lang = BindingTo::Lang::Jvm, + .kind = BindingTo::Kind::Class, + .symbol = symbol, + }}; + + setBindingAttr(C, klass, binding); + return; + } +} + +// When a Java method is marked as native, the JRE looks by default for a function +// named Java_[__]. +void findBindingToJavaFunction(ASTContext &C, FunctionDecl &function) +{ + const auto *identifier = function.getIdentifier(); + if (!identifier) + return; + + const auto name = identifier->getName(); + const auto symbol = scipSymbolFromJnicallFunctionName(name); + if (!symbol) + return; + + const auto binding = BoundAs {{ + .lang = BindingTo::Lang::Jvm, + .kind = BindingTo::Kind::Method, + .symbol = *symbol, + }}; + + setBindingAttr(C, function, binding); +} + +// class [parent] +// { +// struct [methodStruct] { +// static constexpr char name[] = "[methodNameFieldValue]"; +// } +// [method] +// { +// ... +// mozilla::jni::{Method,Constructor,Field}<[methodStruct]>::{Call,Get,Set}(...) +// ... +// } +// } +void findBindingToJavaMember(ASTContext &C, CXXMethodDecl &method) +{ + const auto *parent = method.getParent(); + if (!parent) + return; + const auto classBinding = getBindingTo(*parent); + if (!classBinding) + return; + + auto *body = method.getBody(); + if (!body) + return; + + const auto found = FindCallCall::search(body); + if (!found) + return; + + const auto symbol = javaScipSymbol(classBinding->symbol, found->name, found->kind); + const auto binding = BindingTo {{ + .lang = BindingTo::Lang::Jvm, + .kind = found->kind, + .symbol = symbol, + }}; + + setBindingAttr(C, method, binding); +} + +// class [parent] +// { +// struct [methodStruct] { +// static constexpr char name[] = "[methodNameFieldValue]"; +// } +// [method] +// { +// ... +// mozilla::jni::{Method,Constructor,Field}<[methodStruct]>::{Call,Get,Set}(...) +// ... +// } +// } +void findBindingToJavaConstant(ASTContext &C, VarDecl &field) +{ + const auto *parent = dyn_cast_or_null(field.getDeclContext()); + if (!parent) + return; + + const auto classBinding = getBindingTo(*parent); + if (!classBinding) + return; + + const auto symbol = javaScipSymbol(classBinding->symbol, field.getName(), BindingTo::Kind::Const); + const auto binding = BindingTo {{ + .lang = BindingTo::Lang::Jvm, + .kind = BindingTo::Kind::Const, + .symbol = symbol, + }}; + + setBindingAttr(C, field, binding); +} + +// class [klass] : public [wrapper]::Natives<[klass]> {...} +// class [wrapper] : public mozilla::jni::ObjectBase<[wrapper]> +// { +// static constexpr char name[] = "[nameFieldValue]"; +// +// struct [methodStruct] { +// static constexpr char name[] = "[methodNameFieldValue]"; +// } +// +// template +// class [wrapper]::Natives : public mozilla::jni::NativeImpl<[wrapper], T> { +// static const JNINativeMethod methods[] = { +// mozilla::jni::MakeNativeMethod<[wrapper]::[methodStruct]>( +// mozilla::jni::NativeStub<[wrapper]::[methodStruct], Impl> +// ::template Wrap<&Impl::[method]>), +// } +// } +// } +void findBoundAsJavaClasses(ASTContext &C, CXXRecordDecl &klass) +{ + for (const auto &baseSpecifier : klass.bases()) { + const auto *base = baseSpecifier.getType()->getAsCXXRecordDecl(); + if (!base) + continue; + + for (const auto &baseBaseSpecifier : base->bases()) { + const auto *baseBase = dyn_cast_or_null(baseBaseSpecifier.getType()->getAsCXXRecordDecl()); + if (!baseBase) + continue; + + if (!isMozillaJniNativeImpl(*baseBase)) + continue; + + const auto *wrapper = baseBase->getTemplateArgs().get(0).getAsType()->getAsCXXRecordDecl(); + + if (!wrapper) + continue; + + const auto name = nameFieldValue(*wrapper); + if (!name) + continue; + + const auto javaClassSymbol = javaScipSymbol(JVM_SCIP_SYMBOL_PREFIX, *name, BoundAs::Kind::Class); + const auto classBinding = BoundAs {{ + .lang = BoundAs::Lang::Jvm, + .kind = BoundAs::Kind::Class, + .symbol = javaClassSymbol, + }}; + setBindingAttr(C, klass, classBinding); + + const auto *methodsDecl = dyn_cast_or_null(fieldNamed("methods", *base)); + if (!methodsDecl) + continue; + + const auto *methodsDef = methodsDecl->getDefinition(); + if (!methodsDef) + continue; + + const auto *inits = dyn_cast_or_null(methodsDef->getInit()); + if (!inits) + continue; + + std::set alreadyBound; + + for (const auto *init : inits->inits()) { + const auto *call = dyn_cast(init->IgnoreUnlessSpelledInSource()); + if (!call) + continue; + + const auto *funcDecl = call->getDirectCallee(); + if (!funcDecl) + continue; + + const auto *templateArgs = funcDecl->getTemplateSpecializationArgs(); + if (!templateArgs) + continue; + + const auto *strukt = dyn_cast_or_null(templateArgs->get(0).getAsType()->getAsRecordDecl()); + if (!strukt) + continue; + + const auto *wrapperRef = dyn_cast_or_null(call->getArg(0)->IgnoreUnlessSpelledInSource()); + if (!wrapperRef) + continue; + + const auto *boundRef = dyn_cast_or_null(wrapperRef->template_arguments().front().getArgument().getAsExpr()); + if (!boundRef) + continue; + + auto addToBound = [&](CXXMethodDecl &boundDecl, uint overloadNum) { + const auto methodName = nameFieldValue(*strukt); + if (!methodName) + return; + + auto javaMethodSymbol = javaClassSymbol; + javaMethodSymbol += *methodName; + javaMethodSymbol += '('; + if (overloadNum > 0) { + javaMethodSymbol += '+'; + javaMethodSymbol += std::to_string(overloadNum); + } + javaMethodSymbol += ")."; + + const auto binding = BoundAs {{ + .lang = BoundAs::Lang::Jvm, + .kind = BoundAs::Kind::Method, + .symbol = javaMethodSymbol, + }}; + setBindingAttr(C, boundDecl, binding); + }; + + if (auto *bound = dyn_cast_or_null(boundRef->getSubExpr())) { + auto *method = dyn_cast_or_null(bound->getDecl()); + if (!method) + continue; + addToBound(*method, 0); + } else if (const auto *bound = dyn_cast_or_null(boundRef->getSubExpr())) { + // XXX This is hackish + // In case of overloads it's not obvious which one we should use + // this expects the declaration order between C++ and Java to match + auto declarations = std::vector(bound->decls_begin(), bound->decls_end()); + auto byLocation = [](Decl *a, Decl *b){ return a->getLocation() < b->getLocation(); }; + std::sort(declarations.begin(), declarations.end(), byLocation); + + uint i = 0; + for (auto *decl : declarations) { + auto *method = dyn_cast(decl); + if (!method) + continue; + if (alreadyBound.find(method) == alreadyBound.end()) { + addToBound(*method, i); + alreadyBound.insert(method); + break; + } + i++; + } + } + } + } + } +} + +void emitBindingAttributes(llvm::json::OStream &J, const Decl &decl) +{ + addSlotOwnerAttribute(J, decl); + addBindingSlotsAttribute(J, decl); +} diff --git a/build/clang-plugin/mozsearch-plugin/BindingOperations.h b/build/clang-plugin/mozsearch-plugin/BindingOperations.h new file mode 100644 index 0000000000..259594c5c3 --- /dev/null +++ b/build/clang-plugin/mozsearch-plugin/BindingOperations.h @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include +#include +#include + +void findBindingToJavaClass(clang::ASTContext &C, clang::CXXRecordDecl &klass); +void findBoundAsJavaClasses(clang::ASTContext &C, clang::CXXRecordDecl &klass); +void findBindingToJavaFunction(clang::ASTContext &C, clang::FunctionDecl &function); +void findBindingToJavaMember(clang::ASTContext &C, clang::CXXMethodDecl &method); +void findBindingToJavaConstant(clang::ASTContext &C, clang::VarDecl &field); + +void emitBindingAttributes(llvm::json::OStream &json, const clang::Decl &decl); diff --git a/build/clang-plugin/mozsearch-plugin/FileOperations.cpp b/build/clang-plugin/mozsearch-plugin/FileOperations.cpp new file mode 100644 index 0000000000..9307f4989d --- /dev/null +++ b/build/clang-plugin/mozsearch-plugin/FileOperations.cpp @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FileOperations.h" + +#include +#include + +#if defined(_WIN32) || defined(_WIN64) +#include +#include +#include +#include "StringOperations.h" +#else +#include +#include +#include +#endif + +#include +#include +#include + +// Make sure that all directories on path exist, excluding the final element of +// the path. +void ensurePath(std::string Path) { + size_t Pos = 0; + if (Path[0] == PATHSEP_CHAR) { + Pos++; + } + + while ((Pos = Path.find(PATHSEP_CHAR, Pos)) != std::string::npos) { + std::string Portion = Path.substr(0, Pos); + if (!Portion.empty()) { +#if defined(_WIN32) || defined(_WIN64) + int Err = _mkdir(Portion.c_str()); +#else + int Err = mkdir(Portion.c_str(), 0775); +#endif + if (Err == -1 && errno != EEXIST) { + perror("mkdir failed"); + exit(1); + } + } + + Pos++; + } +} + +#if defined(_WIN32) || defined(_WIN64) +AutoLockFile::AutoLockFile(const std::string &SrcFile, const std::string &DstFile) { + this->Filename = DstFile; + std::string Hash = hash(SrcFile); + std::string MutexName = std::string("Local\\searchfox-") + Hash; + std::wstring WideMutexName; + WideMutexName.assign(MutexName.begin(), MutexName.end()); + Handle = CreateMutex(nullptr, false, WideMutexName.c_str()); + if (Handle == NULL) { + return; + } + + if (WaitForSingleObject(Handle, INFINITE) != WAIT_OBJECT_0) { + return; + } +} + +AutoLockFile::~AutoLockFile() { + ReleaseMutex(Handle); + CloseHandle(Handle); +} + +bool AutoLockFile::success() { + return Handle != NULL; +} + +FILE *AutoLockFile::openTmp() { + int TmpDescriptor = _open((Filename + ".tmp").c_str(), _O_WRONLY | _O_APPEND | _O_CREAT | _O_BINARY, 0666); + return _fdopen(TmpDescriptor, "ab"); +} + +bool AutoLockFile::moveTmp() { + if (_unlink(Filename.c_str()) == -1) { + if (errno != ENOENT) { + return false; + } + } + return rename((Filename + ".tmp").c_str(), Filename.c_str()) == 0; +} + +std::string getAbsolutePath(const std::string &Filename) { + char Full[_MAX_PATH]; + if (!_fullpath(Full, Filename.c_str(), _MAX_PATH)) { + return std::string(""); + } + return std::string(Full); +} +#else +AutoLockFile::AutoLockFile(const std::string &SrcFile, const std::string &DstFile) { + this->Filename = DstFile; + FileDescriptor = open(SrcFile.c_str(), O_RDONLY); + if (FileDescriptor == -1) { + return; + } + + do { + int rv = flock(FileDescriptor, LOCK_EX); + if (rv == 0) { + break; + } + } while (true); +} + +AutoLockFile::~AutoLockFile() { close(FileDescriptor); } + +bool AutoLockFile::success() { return FileDescriptor != -1; } + +FILE* AutoLockFile::openTmp() { + int TmpDescriptor = open((Filename + ".tmp").c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666); + return fdopen(TmpDescriptor, "ab"); +} + +bool AutoLockFile::moveTmp() { + if (unlink(Filename.c_str()) == -1) { + if (errno != ENOENT) { + return false; + } + } + return rename((Filename + ".tmp").c_str(), Filename.c_str()) == 0; +} + +std::string getAbsolutePath(const std::string &Filename) { + char Full[4096]; + if (!realpath(Filename.c_str(), Full)) { + return std::string(""); + } + return std::string(Full); +} +#endif diff --git a/build/clang-plugin/mozsearch-plugin/FileOperations.h b/build/clang-plugin/mozsearch-plugin/FileOperations.h new file mode 100644 index 0000000000..90764484da --- /dev/null +++ b/build/clang-plugin/mozsearch-plugin/FileOperations.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef FileOperations_h +#define FileOperations_h + +#include +#include + +#if defined(_WIN32) || defined(_WIN64) +#include +#define PATHSEP_CHAR '\\' +#define PATHSEP_STRING "\\" +#else +#define PATHSEP_CHAR '/' +#define PATHSEP_STRING "/" +#endif + +// Make sure that all directories on path exist, excluding the final element of +// the path. +void ensurePath(std::string Path); + +std::string getAbsolutePath(const std::string &Filename); + +// Used to synchronize access when writing to an analysis file, so that +// concurrently running clang instances don't clobber each other's data. +// On Windows, we use a named mutex. On POSIX platforms, we use flock on the +// source files. flock is advisory locking, and doesn't interfere with clang's +// own opening of the source files (i.e. to interfere, clang would have to be +// using flock itself, which it does not). +struct AutoLockFile { + // Absolute path to the analysis file + std::string Filename; + +#if defined(_WIN32) || defined(_WIN64) + // Handle for the named Mutex + HANDLE Handle = NULL; +#else + // fd for the *source* file that corresponds to the analysis file. We use + // the source file because it doesn't change while the analysis file gets + // repeatedly replaced by a new version written to a separate tmp file. + // This fd is used when using flock to synchronize access. + int FileDescriptor = -1; +#endif + + // SrcFile should be the absolute path to the source code file, and DstFile + // the absolute path to the corresponding analysis file. This constructor + // will block until exclusive access has been obtained. + AutoLockFile(const std::string &SrcFile, const std::string &DstFile); + ~AutoLockFile(); + + // Check after constructing to ensure the mutex was properly set up. + bool success(); + + // There used to be an `openFile` method here but we switched to directly + // using a std::ifstream for the input file in able to take advantage of its + // support for variable length lines (as opposed to fgets which takes a fixed + // size buffer). + + // Open a new tmp file for writing the new analysis data to. Caller is + // responsible for fclose'ing it. + FILE *openTmp(); + // Replace the existing analysis file with the new "tmp" one that has the new + // data. Returns false on error. + bool moveTmp(); +}; + +#endif diff --git a/build/clang-plugin/mozsearch-plugin/MozsearchIndexer.cpp b/build/clang-plugin/mozsearch-plugin/MozsearchIndexer.cpp new file mode 100644 index 0000000000..f6958384a8 --- /dev/null +++ b/build/clang-plugin/mozsearch-plugin/MozsearchIndexer.cpp @@ -0,0 +1,2436 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "clang/AST/AST.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/Mangle.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Version.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendPluginRegistry.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/JSON.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "BindingOperations.h" +#include "FileOperations.h" +#include "StringOperations.h" +#include "from-clangd/HeuristicResolver.h" + +#if CLANG_VERSION_MAJOR < 8 +// Starting with Clang 8.0 some basic functions have been renamed +#define getBeginLoc getLocStart +#define getEndLoc getLocEnd +#endif +// We want std::make_unique, but that's only available in c++14. In versions +// prior to that, we need to fall back to llvm's make_unique. It's also the +// case that we expect clang 10 to build with c++14 and clang 9 and earlier to +// build with c++11, at least as suggested by the llvm-config --cxxflags on +// non-windows platforms. mozilla-central seems to build with -std=c++17 on +// windows so we need to make this decision based on __cplusplus instead of +// the CLANG_VERSION_MAJOR. +#if __cplusplus < 201402L +using llvm::make_unique; +#else +using std::make_unique; +#endif + +using namespace clang; + +const std::string GENERATED("__GENERATED__" PATHSEP_STRING); + +// Absolute path to directory containing source code. +std::string Srcdir; + +// Absolute path to objdir (including generated code). +std::string Objdir; + +// Absolute path where analysis JSON output will be stored. +std::string Outdir; + +enum class FileType { + // The file was either in the source tree nor objdir. It might be a system + // include, for example. + Unknown, + // A file from the source tree. + Source, + // A file from the objdir. + Generated, +}; + +// Takes an absolute path to a file, and returns the type of file it is. If +// it's a Source or Generated file, the provided inout path argument is modified +// in-place so that it is relative to the source dir or objdir, respectively. +FileType relativizePath(std::string& path) { + if (path.compare(0, Objdir.length(), Objdir) == 0) { + path.replace(0, Objdir.length(), GENERATED); + return FileType::Generated; + } + // Empty filenames can get turned into Srcdir when they are resolved as + // absolute paths, so we should exclude files that are exactly equal to + // Srcdir or anything outside Srcdir. + if (path.length() > Srcdir.length() && path.compare(0, Srcdir.length(), Srcdir) == 0) { + // Remove the trailing `/' as well. + path.erase(0, Srcdir.length() + 1); + return FileType::Source; + } + return FileType::Unknown; +} + +#if !defined(_WIN32) && !defined(_WIN64) +#include + +static double time() { + struct timeval Tv; + gettimeofday(&Tv, nullptr); + return double(Tv.tv_sec) + double(Tv.tv_usec) / 1000000.; +} +#endif + +// Return true if |input| is a valid C++ identifier. We don't want to generate +// analysis information for operators, string literals, etc. by accident since +// it trips up consumers of the data. +static bool isValidIdentifier(std::string Input) { + for (char C : Input) { + if (!(isalpha(C) || isdigit(C) || C == '_')) { + return false; + } + } + return true; +} + +struct RAIITracer { + RAIITracer(const char *log) : mLog(log) { + printf("<%s>\n", mLog); + } + + ~RAIITracer() { + printf("\n", mLog); + } + + const char* mLog; +}; + +#define TRACEFUNC RAIITracer tracer(__FUNCTION__); + +class IndexConsumer; + +// For each C++ file seen by the analysis (.cpp or .h), we track a +// FileInfo. This object tracks whether the file is "interesting" (i.e., whether +// it's in the source dir or the objdir). We also store the analysis output +// here. +struct FileInfo { + FileInfo(std::string &Rname) : Realname(Rname) { + switch (relativizePath(Realname)) { + case FileType::Generated: + Interesting = true; + Generated = true; + break; + case FileType::Source: + Interesting = true; + Generated = false; + break; + case FileType::Unknown: + Interesting = false; + Generated = false; + break; + } + } + std::string Realname; + std::vector Output; + bool Interesting; + bool Generated; +}; + +class IndexConsumer; + +class PreprocessorHook : public PPCallbacks { + IndexConsumer *Indexer; + +public: + PreprocessorHook(IndexConsumer *C) : Indexer(C) {} + + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) override; + + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FileNameRange, +#if CLANG_VERSION_MAJOR >= 16 + OptionalFileEntryRef File, +#elif CLANG_VERSION_MAJOR >= 15 + Optional File, +#else + const FileEntry *File, +#endif + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported, + SrcMgr::CharacteristicKind FileType) override; + + virtual void MacroDefined(const Token &Tok, + const MacroDirective *Md) override; + + virtual void MacroExpands(const Token &Tok, const MacroDefinition &Md, + SourceRange Range, const MacroArgs *Ma) override; + virtual void MacroUndefined(const Token &Tok, const MacroDefinition &Md, + const MacroDirective *Undef) override; + virtual void Defined(const Token &Tok, const MacroDefinition &Md, + SourceRange Range) override; + virtual void Ifdef(SourceLocation Loc, const Token &Tok, + const MacroDefinition &Md) override; + virtual void Ifndef(SourceLocation Loc, const Token &Tok, + const MacroDefinition &Md) override; +}; + +class IndexConsumer : public ASTConsumer, + public RecursiveASTVisitor, + public DiagnosticConsumer { +private: + CompilerInstance &CI; + SourceManager &SM; + LangOptions &LO; + std::map> FileMap; + MangleContext *CurMangleContext; + ASTContext *AstContext; + std::unique_ptr Resolver; + + typedef RecursiveASTVisitor Super; + + // Tracks the set of declarations that the current expression/statement is + // nested inside of. + struct AutoSetContext { + AutoSetContext(IndexConsumer *Self, NamedDecl *Context, bool VisitImplicit = false) + : Self(Self), Prev(Self->CurDeclContext), Decl(Context) { + this->VisitImplicit = VisitImplicit || (Prev ? Prev->VisitImplicit : false); + Self->CurDeclContext = this; + } + + ~AutoSetContext() { Self->CurDeclContext = Prev; } + + IndexConsumer *Self; + AutoSetContext *Prev; + NamedDecl *Decl; + bool VisitImplicit; + }; + AutoSetContext *CurDeclContext; + + FileInfo *getFileInfo(SourceLocation Loc) { + FileID Id = SM.getFileID(Loc); + + std::map>::iterator It; + It = FileMap.find(Id); + if (It == FileMap.end()) { + // We haven't seen this file before. We need to make the FileInfo + // structure information ourselves + std::string Filename = std::string(SM.getFilename(Loc)); + std::string Absolute; + // If Loc is a macro id rather than a file id, it Filename might be + // empty. Also for some types of file locations that are clang-internal + // like "" it can return an empty Filename. In these cases we + // want to leave Absolute as empty. + if (!Filename.empty()) { + Absolute = getAbsolutePath(Filename); + if (Absolute.empty()) { + Absolute = Filename; + } + } + std::unique_ptr Info = make_unique(Absolute); + It = FileMap.insert(std::make_pair(Id, std::move(Info))).first; + } + return It->second.get(); + } + + // Helpers for processing declarations + // Should we ignore this location? + bool isInterestingLocation(SourceLocation Loc) { + if (Loc.isInvalid()) { + return false; + } + + return getFileInfo(Loc)->Interesting; + } + + // Convert location to "line:column" or "line:column-column" given length. + // In resulting string rep, line is 1-based and zero-padded to 5 digits, while + // column is 0-based and unpadded. + std::string locationToString(SourceLocation Loc, size_t Length = 0) { + std::pair Pair = SM.getDecomposedLoc(Loc); + + bool IsInvalid; + unsigned Line = SM.getLineNumber(Pair.first, Pair.second, &IsInvalid); + if (IsInvalid) { + return ""; + } + unsigned Column = SM.getColumnNumber(Pair.first, Pair.second, &IsInvalid); + if (IsInvalid) { + return ""; + } + + if (Length) { + return stringFormat("%05d:%d-%d", Line, Column - 1, Column - 1 + Length); + } else { + return stringFormat("%05d:%d", Line, Column - 1); + } + } + + // Convert SourceRange to "line-line". + // In the resulting string rep, line is 1-based. + std::string lineRangeToString(SourceRange Range) { + std::pair Begin = SM.getDecomposedLoc(Range.getBegin()); + std::pair End = SM.getDecomposedLoc(Range.getEnd()); + + bool IsInvalid; + unsigned Line1 = SM.getLineNumber(Begin.first, Begin.second, &IsInvalid); + if (IsInvalid) { + return ""; + } + unsigned Line2 = SM.getLineNumber(End.first, End.second, &IsInvalid); + if (IsInvalid) { + return ""; + } + + return stringFormat("%d-%d", Line1, Line2); + } + + // Convert SourceRange to "line:column-line:column". + // In the resulting string rep, line is 1-based, column is 0-based. + std::string fullRangeToString(SourceRange Range) { + std::pair Begin = SM.getDecomposedLoc(Range.getBegin()); + std::pair End = SM.getDecomposedLoc(Range.getEnd()); + + bool IsInvalid; + unsigned Line1 = SM.getLineNumber(Begin.first, Begin.second, &IsInvalid); + if (IsInvalid) { + return ""; + } + unsigned Column1 = SM.getColumnNumber(Begin.first, Begin.second, &IsInvalid); + if (IsInvalid) { + return ""; + } + unsigned Line2 = SM.getLineNumber(End.first, End.second, &IsInvalid); + if (IsInvalid) { + return ""; + } + unsigned Column2 = SM.getColumnNumber(End.first, End.second, &IsInvalid); + if (IsInvalid) { + return ""; + } + + return stringFormat("%d:%d-%d:%d", Line1, Column1 - 1, Line2, Column2 - 1); + } + + // Returns the qualified name of `d` without considering template parameters. + std::string getQualifiedName(const NamedDecl *D) { + const DeclContext *Ctx = D->getDeclContext(); + if (Ctx->isFunctionOrMethod()) { + return D->getQualifiedNameAsString(); + } + + std::vector Contexts; + + // Collect contexts. + while (Ctx && isa(Ctx)) { + Contexts.push_back(Ctx); + Ctx = Ctx->getParent(); + } + + std::string Result; + + std::reverse(Contexts.begin(), Contexts.end()); + + for (const DeclContext *DC : Contexts) { + if (const auto *Spec = dyn_cast(DC)) { + Result += Spec->getNameAsString(); + + if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization) { + std::string Backing; + llvm::raw_string_ostream Stream(Backing); + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + printTemplateArgumentList( + Stream, TemplateArgs.asArray(), PrintingPolicy(CI.getLangOpts())); + Result += Stream.str(); + } + } else if (const auto *Nd = dyn_cast(DC)) { + if (Nd->isAnonymousNamespace() || Nd->isInline()) { + continue; + } + Result += Nd->getNameAsString(); + } else if (const auto *Rd = dyn_cast(DC)) { + if (!Rd->getIdentifier()) { + Result += "(anonymous)"; + } else { + Result += Rd->getNameAsString(); + } + } else if (const auto *Fd = dyn_cast(DC)) { + Result += Fd->getNameAsString(); + } else if (const auto *Ed = dyn_cast(DC)) { + // C++ [dcl.enum]p10: Each enum-name and each unscoped + // enumerator is declared in the scope that immediately contains + // the enum-specifier. Each scoped enumerator is declared in the + // scope of the enumeration. + if (Ed->isScoped() || Ed->getIdentifier()) + Result += Ed->getNameAsString(); + else + continue; + } else { + Result += cast(DC)->getNameAsString(); + } + Result += "::"; + } + + if (D->getDeclName()) + Result += D->getNameAsString(); + else + Result += "(anonymous)"; + + return Result; + } + + std::string mangleLocation(SourceLocation Loc, + std::string Backup = std::string()) { + FileInfo *F = getFileInfo(Loc); + std::string Filename = F->Realname; + if (Filename.length() == 0 && Backup.length() != 0) { + return Backup; + } + if (F->Generated) { + // Since generated files may be different on different platforms, + // we need to include a platform-specific thing in the hash. Otherwise + // we can end up with hash collisions where different symbols from + // different platforms map to the same thing. + char* Platform = getenv("MOZSEARCH_PLATFORM"); + Filename = std::string(Platform ? Platform : "") + std::string("@") + Filename; + } + return hash(Filename + std::string("@") + locationToString(Loc)); + } + + bool isAcceptableSymbolChar(char c) { + return isalpha(c) || isdigit(c) || c == '_' || c == '/'; + } + + std::string mangleFile(std::string Filename, FileType Type) { + // "Mangle" the file path, such that: + // 1. The majority of paths will still be mostly human-readable. + // 2. The sanitization algorithm doesn't produce collisions where two + // different unsanitized paths can result in the same sanitized paths. + // 3. The produced symbol doesn't cause problems with downstream consumers. + // In order to accomplish this, we keep alphanumeric chars, underscores, + // and slashes, and replace everything else with an "@xx" hex encoding. + // The majority of path characters are letters and slashes which don't get + // encoded, so that satisfies (1). Since "@" characters in the unsanitized + // path get encoded, there should be no "@" characters in the sanitized path + // that got preserved from the unsanitized input, so that should satisfy (2). + // And (3) was done by trial-and-error. Note in particular the dot (.) + // character needs to be encoded, or the symbol-search feature of mozsearch + // doesn't work correctly, as all dot characters in the symbol query get + // replaced by #. + for (size_t i = 0; i < Filename.length(); i++) { + char c = Filename[i]; + if (isAcceptableSymbolChar(c)) { + continue; + } + char hex[4]; + sprintf(hex, "@%02X", ((int)c) & 0xFF); + Filename.replace(i, 1, hex); + i += 2; + } + + if (Type == FileType::Generated) { + // Since generated files may be different on different platforms, + // we need to include a platform-specific thing in the hash. Otherwise + // we can end up with hash collisions where different symbols from + // different platforms map to the same thing. + char* Platform = getenv("MOZSEARCH_PLATFORM"); + Filename = std::string(Platform ? Platform : "") + std::string("@") + Filename; + } + return Filename; + } + + std::string mangleQualifiedName(std::string Name) { + std::replace(Name.begin(), Name.end(), ' ', '_'); + return Name; + } + + std::string getMangledName(clang::MangleContext *Ctx, + const clang::NamedDecl *Decl) { + if (isa(Decl) && cast(Decl)->isExternC()) { + return cast(Decl)->getNameAsString(); + } + + if (isa(Decl) || isa(Decl)) { + const DeclContext *DC = Decl->getDeclContext(); + if (isa(DC) || isa(DC) || + isa(DC) || + // isa(DC) || + isa(DC)) { + llvm::SmallVector Output; + llvm::raw_svector_ostream Out(Output); +#if CLANG_VERSION_MAJOR >= 11 + // This code changed upstream in version 11: + // https://github.com/llvm/llvm-project/commit/29e1a16be8216066d1ed733a763a749aed13ff47 + GlobalDecl GD; + if (const CXXConstructorDecl *D = dyn_cast(Decl)) { + GD = GlobalDecl(D, Ctor_Complete); + } else if (const CXXDestructorDecl *D = + dyn_cast(Decl)) { + GD = GlobalDecl(D, Dtor_Complete); + } else { + GD = GlobalDecl(Decl); + } + Ctx->mangleName(GD, Out); +#else + if (const CXXConstructorDecl *D = dyn_cast(Decl)) { + Ctx->mangleCXXCtor(D, CXXCtorType::Ctor_Complete, Out); + } else if (const CXXDestructorDecl *D = + dyn_cast(Decl)) { + Ctx->mangleCXXDtor(D, CXXDtorType::Dtor_Complete, Out); + } else { + Ctx->mangleName(Decl, Out); + } +#endif + return Out.str().str(); + } else { + return std::string("V_") + mangleLocation(Decl->getLocation()) + + std::string("_") + hash(std::string(Decl->getName())); + } + } else if (isa(Decl) || isa(Decl)) { + if (!Decl->getIdentifier()) { + // Anonymous. + return std::string("T_") + mangleLocation(Decl->getLocation()); + } + + return std::string("T_") + mangleQualifiedName(getQualifiedName(Decl)); + } else if (isa(Decl)) { + if (!Decl->getIdentifier()) { + // Anonymous. + return std::string("TA_") + mangleLocation(Decl->getLocation()); + } + + return std::string("TA_") + mangleQualifiedName(getQualifiedName(Decl)); + } else if (isa(Decl) || isa(Decl)) { + if (!Decl->getIdentifier()) { + // Anonymous. + return std::string("NS_") + mangleLocation(Decl->getLocation()); + } + + return std::string("NS_") + mangleQualifiedName(getQualifiedName(Decl)); + } else if (const ObjCIvarDecl *D2 = dyn_cast(Decl)) { + const ObjCInterfaceDecl *Iface = D2->getContainingInterface(); + return std::string("F_<") + getMangledName(Ctx, Iface) + ">_" + + D2->getNameAsString(); + } else if (const FieldDecl *D2 = dyn_cast(Decl)) { + const RecordDecl *Record = D2->getParent(); + return std::string("F_<") + getMangledName(Ctx, Record) + ">_" + + D2->getNameAsString(); + } else if (const EnumConstantDecl *D2 = dyn_cast(Decl)) { + const DeclContext *DC = Decl->getDeclContext(); + if (const NamedDecl *Named = dyn_cast(DC)) { + return std::string("E_<") + getMangledName(Ctx, Named) + ">_" + + D2->getNameAsString(); + } + } + + assert(false); + return std::string(""); + } + + void debugLocation(SourceLocation Loc) { + std::string S = locationToString(Loc); + StringRef Filename = SM.getFilename(Loc); + printf("--> %s %s\n", std::string(Filename).c_str(), S.c_str()); + } + + void debugRange(SourceRange Range) { + printf("Range\n"); + debugLocation(Range.getBegin()); + debugLocation(Range.getEnd()); + } + +public: + IndexConsumer(CompilerInstance &CI) + : CI(CI), SM(CI.getSourceManager()), LO(CI.getLangOpts()), CurMangleContext(nullptr), + AstContext(nullptr), CurDeclContext(nullptr), TemplateStack(nullptr) { + CI.getPreprocessor().addPPCallbacks( + make_unique(this)); + } + + virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + return new IndexConsumer(CI); + } + +#if !defined(_WIN32) && !defined(_WIN64) + struct AutoTime { + AutoTime(double *Counter) : Counter(Counter), Start(time()) {} + ~AutoTime() { + if (Start) { + *Counter += time() - Start; + } + } + void stop() { + *Counter += time() - Start; + Start = 0; + } + double *Counter; + double Start; + }; +#endif + + // All we need is to follow the final declaration. + virtual void HandleTranslationUnit(ASTContext &Ctx) { + CurMangleContext = + clang::ItaniumMangleContext::create(Ctx, CI.getDiagnostics()); + + AstContext = &Ctx; + Resolver = std::make_unique(Ctx); + TraverseDecl(Ctx.getTranslationUnitDecl()); + + // Emit the JSON data for all files now. + std::map>::iterator It; + for (It = FileMap.begin(); It != FileMap.end(); It++) { + if (!It->second->Interesting) { + continue; + } + + FileInfo &Info = *It->second; + + std::string Filename = Outdir + Info.Realname; + std::string SrcFilename = Info.Generated + ? Objdir + Info.Realname.substr(GENERATED.length()) + : Srcdir + PATHSEP_STRING + Info.Realname; + + ensurePath(Filename); + + // We lock the output file in case some other clang process is trying to + // write to it at the same time. + AutoLockFile Lock(SrcFilename, Filename); + + if (!Lock.success()) { + fprintf(stderr, "Unable to lock file %s\n", Filename.c_str()); + exit(1); + } + + // Merge our results with the existing lines from the output file. + // This ensures that header files that are included multiple times + // in different ways are analyzed completely. + std::ifstream Fin(Filename.c_str(), std::ios::in | std::ios::binary); + FILE *OutFp = Lock.openTmp(); + if (!OutFp) { + fprintf(stderr, "Unable to open tmp out file for %s\n", Filename.c_str()); + exit(1); + } + + // Sort our new results and get an iterator to them + std::sort(Info.Output.begin(), Info.Output.end()); + std::vector::const_iterator NewLinesIter = Info.Output.begin(); + std::string LastNewWritten; + + // Loop over the existing (sorted) lines in the analysis output file. + // (The good() check also handles the case where Fin did not exist when we + // went to open it.) + while(Fin.good()) { + std::string OldLine; + std::getline(Fin, OldLine); + // Skip blank lines. + if (OldLine.length() == 0) { + continue; + } + // We need to put the newlines back that getline() eats. + OldLine.push_back('\n'); + + // Write any results from Info.Output that are lexicographically + // smaller than OldLine (read from the existing file), but make sure + // to skip duplicates. Keep advancing NewLinesIter until we reach an + // entry that is lexicographically greater than OldLine. + for (; NewLinesIter != Info.Output.end(); NewLinesIter++) { + if (*NewLinesIter > OldLine) { + break; + } + if (*NewLinesIter == OldLine) { + continue; + } + if (*NewLinesIter == LastNewWritten) { + // dedupe the new entries being written + continue; + } + if (fwrite(NewLinesIter->c_str(), NewLinesIter->length(), 1, OutFp) != 1) { + fprintf(stderr, "Unable to write %zu bytes[1] to tmp output file for %s\n", + NewLinesIter->length(), Filename.c_str()); + exit(1); + } + LastNewWritten = *NewLinesIter; + } + + // Write the entry read from the existing file. + if (fwrite(OldLine.c_str(), OldLine.length(), 1, OutFp) != 1) { + fprintf(stderr, "Unable to write %zu bytes[2] to tmp output file for %s\n", + OldLine.length(), Filename.c_str()); + exit(1); + } + } + + // We finished reading from Fin + Fin.close(); + + // Finish iterating our new results, discarding duplicates + for (; NewLinesIter != Info.Output.end(); NewLinesIter++) { + if (*NewLinesIter == LastNewWritten) { + continue; + } + if (fwrite(NewLinesIter->c_str(), NewLinesIter->length(), 1, OutFp) != 1) { + fprintf(stderr, "Unable to write %zu bytes[3] to tmp output file for %s\n", + NewLinesIter->length(), Filename.c_str()); + exit(1); + } + LastNewWritten = *NewLinesIter; + } + + // Done writing all the things, close it and replace the old output file + // with the new one. + fclose(OutFp); + if (!Lock.moveTmp()) { + fprintf(stderr, "Unable to move tmp output file into place for %s (err %d)\n", Filename.c_str(), errno); + exit(1); + } + } + } + + // Unfortunately, we have to override all these methods in order to track the + // context we're inside. + + bool TraverseEnumDecl(EnumDecl *D) { + AutoSetContext Asc(this, D); + return Super::TraverseEnumDecl(D); + } + bool TraverseRecordDecl(RecordDecl *D) { + AutoSetContext Asc(this, D); + return Super::TraverseRecordDecl(D); + } + bool TraverseCXXRecordDecl(CXXRecordDecl *D) { + AutoSetContext Asc(this, D); + return Super::TraverseCXXRecordDecl(D); + } + bool TraverseFunctionDecl(FunctionDecl *D) { + AutoSetContext Asc(this, D); + const FunctionDecl *Def; + // (See the larger AutoTemplateContext comment for more information.) If a + // method on a templated class is declared out-of-line, we need to analyze + // the definition inside the scope of the template or else we won't properly + // handle member access on the templated type. + if (TemplateStack && D->isDefined(Def) && Def && D != Def) { + TraverseFunctionDecl(const_cast(Def)); + } + return Super::TraverseFunctionDecl(D); + } + bool TraverseCXXMethodDecl(CXXMethodDecl *D) { + AutoSetContext Asc(this, D); + const FunctionDecl *Def; + // See TraverseFunctionDecl. + if (TemplateStack && D->isDefined(Def) && Def && D != Def) { + TraverseFunctionDecl(const_cast(Def)); + } + return Super::TraverseCXXMethodDecl(D); + } + bool TraverseCXXConstructorDecl(CXXConstructorDecl *D) { + AutoSetContext Asc(this, D, /*VisitImplicit=*/true); + const FunctionDecl *Def; + // See TraverseFunctionDecl. + if (TemplateStack && D->isDefined(Def) && Def && D != Def) { + TraverseFunctionDecl(const_cast(Def)); + } + return Super::TraverseCXXConstructorDecl(D); + } + bool TraverseCXXConversionDecl(CXXConversionDecl *D) { + AutoSetContext Asc(this, D); + const FunctionDecl *Def; + // See TraverseFunctionDecl. + if (TemplateStack && D->isDefined(Def) && Def && D != Def) { + TraverseFunctionDecl(const_cast(Def)); + } + return Super::TraverseCXXConversionDecl(D); + } + bool TraverseCXXDestructorDecl(CXXDestructorDecl *D) { + AutoSetContext Asc(this, D); + const FunctionDecl *Def; + // See TraverseFunctionDecl. + if (TemplateStack && D->isDefined(Def) && Def && D != Def) { + TraverseFunctionDecl(const_cast(Def)); + } + return Super::TraverseCXXDestructorDecl(D); + } + + // Used to keep track of the context in which a token appears. + struct Context { + // Ultimately this becomes the "context" JSON property. + std::string Name; + + // Ultimately this becomes the "contextsym" JSON property. + std::string Symbol; + + Context() {} + Context(std::string Name, std::string Symbol) + : Name(Name), Symbol(Symbol) {} + }; + + Context translateContext(NamedDecl *D) { + const FunctionDecl *F = dyn_cast(D); + if (F && F->isTemplateInstantiation()) { + D = F->getTemplateInstantiationPattern(); + } + + return Context(D->getQualifiedNameAsString(), getMangledName(CurMangleContext, D)); + } + + Context getContext(SourceLocation Loc) { + if (SM.isMacroBodyExpansion(Loc)) { + // If we're inside a macro definition, we don't return any context. It + // will probably not be what the user expects if we do. + return Context(); + } + + if (CurDeclContext) { + return translateContext(CurDeclContext->Decl); + } + return Context(); + } + + // Similar to GetContext(SourceLocation), but it skips the declaration passed + // in. This is useful if we want the context of a declaration that's already + // on the stack. + Context getContext(Decl *D) { + if (SM.isMacroBodyExpansion(D->getLocation())) { + // If we're inside a macro definition, we don't return any context. It + // will probably not be what the user expects if we do. + return Context(); + } + + AutoSetContext *Ctxt = CurDeclContext; + while (Ctxt) { + if (Ctxt->Decl != D) { + return translateContext(Ctxt->Decl); + } + Ctxt = Ctxt->Prev; + } + return Context(); + } + + // Analyzing template code is tricky. Suppose we have this code: + // + // template + // bool Foo(T* ptr) { return T::StaticMethod(ptr); } + // + // If we analyze the body of Foo without knowing the type T, then we will not + // be able to generate any information for StaticMethod. However, analyzing + // Foo for every possible instantiation is inefficient and it also generates + // too much data in some cases. For example, the following code would generate + // one definition of Baz for every instantiation, which is undesirable: + // + // template + // class Bar { struct Baz { ... }; }; + // + // To solve this problem, we analyze templates only once. We do so in a + // GatherDependent mode where we look for "dependent scoped member + // expressions" (i.e., things like StaticMethod). We keep track of the + // locations of these expressions. If we find one or more of them, we analyze + // the template for each instantiation, in an AnalyzeDependent mode. This mode + // ignores all source locations except for the ones where we found dependent + // scoped member expressions before. For these locations, we generate a + // separate JSON result for each instantiation. + // + // We inherit our parent's mode if it is exists. This is because if our + // parent is in analyze mode, it means we've already lived a full life in + // gather mode and we must not restart in gather mode or we'll cause the + // indexer to visit EVERY identifier, which is way too much data. + struct AutoTemplateContext { + AutoTemplateContext(IndexConsumer *Self) + : Self(Self) + , CurMode(Self->TemplateStack ? Self->TemplateStack->CurMode : Mode::GatherDependent) + , Parent(Self->TemplateStack) { + Self->TemplateStack = this; + } + + ~AutoTemplateContext() { Self->TemplateStack = Parent; } + + // We traverse templates in two modes: + enum class Mode { + // Gather mode does not traverse into specializations. It looks for + // locations where it would help to have more info from template + // specializations. + GatherDependent, + + // Analyze mode traverses into template specializations and records + // information about token locations saved in gather mode. + AnalyzeDependent, + }; + + // We found a dependent scoped member expression! Keep track of it for + // later. + void visitDependent(SourceLocation Loc) { + if (CurMode == Mode::AnalyzeDependent) { + return; + } + + DependentLocations.insert(Loc.getRawEncoding()); + if (Parent) { + Parent->visitDependent(Loc); + } + } + + bool inGatherMode() { + return CurMode == Mode::GatherDependent; + } + + // Do we need to perform the extra AnalyzeDependent passes (one per + // instantiation)? + bool needsAnalysis() const { + if (!DependentLocations.empty()) { + return true; + } + if (Parent) { + return Parent->needsAnalysis(); + } + return false; + } + + void switchMode() { CurMode = Mode::AnalyzeDependent; } + + // Do we want to analyze each template instantiation separately? + bool shouldVisitTemplateInstantiations() const { + if (CurMode == Mode::AnalyzeDependent) { + return true; + } + if (Parent) { + return Parent->shouldVisitTemplateInstantiations(); + } + return false; + } + + // For a given expression/statement, should we emit JSON data for it? + bool shouldVisit(SourceLocation Loc) { + if (CurMode == Mode::GatherDependent) { + return true; + } + if (DependentLocations.find(Loc.getRawEncoding()) != + DependentLocations.end()) { + return true; + } + if (Parent) { + return Parent->shouldVisit(Loc); + } + return false; + } + + private: + IndexConsumer *Self; + Mode CurMode; + std::unordered_set DependentLocations; + AutoTemplateContext *Parent; + }; + + AutoTemplateContext *TemplateStack; + + bool shouldVisitTemplateInstantiations() const { + if (TemplateStack) { + return TemplateStack->shouldVisitTemplateInstantiations(); + } + return false; + } + + bool shouldVisitImplicitCode() const { + return CurDeclContext && CurDeclContext->VisitImplicit; + } + + bool TraverseClassTemplateDecl(ClassTemplateDecl *D) { + AutoTemplateContext Atc(this); + Super::TraverseClassTemplateDecl(D); + + if (!Atc.needsAnalysis()) { + return true; + } + + Atc.switchMode(); + + if (D != D->getCanonicalDecl()) { + return true; + } + + for (auto *Spec : D->specializations()) { + for (auto *Rd : Spec->redecls()) { + // We don't want to visit injected-class-names in this traversal. + if (cast(Rd)->isInjectedClassName()) + continue; + + TraverseDecl(Rd); + } + } + + return true; + } + + bool TraverseFunctionTemplateDecl(FunctionTemplateDecl *D) { + AutoTemplateContext Atc(this); + if (Atc.inGatherMode()) { + Super::TraverseFunctionTemplateDecl(D); + } + + if (!Atc.needsAnalysis()) { + return true; + } + + Atc.switchMode(); + + if (D != D->getCanonicalDecl()) { + return true; + } + + for (auto *Spec : D->specializations()) { + for (auto *Rd : Spec->redecls()) { + TraverseDecl(Rd); + } + } + + return true; + } + + bool shouldVisit(SourceLocation Loc) { + if (TemplateStack) { + return TemplateStack->shouldVisit(Loc); + } + return true; + } + + enum { + // Flag to omit the identifier from being cross-referenced across files. + // This is usually desired for local variables. + NoCrossref = 1 << 0, + // Flag to indicate the token with analysis data is not an identifier. Indicates + // we want to skip the check that tries to ensure a sane identifier token. + NotIdentifierToken = 1 << 1, + // This indicates that the end of the provided SourceRange is valid and + // should be respected. If this flag is not set, the visitIdentifier + // function should use only the start of the SourceRange and auto-detect + // the end based on whatever token is found at the start. + LocRangeEndValid = 1 << 2 + }; + + void emitStructuredInfo(SourceLocation Loc, const RecordDecl *decl) { + std::string json_str; + llvm::raw_string_ostream ros(json_str); + llvm::json::OStream J(ros); + // Start the top-level object. + J.objectBegin(); + + unsigned StartOffset = SM.getFileOffset(Loc); + unsigned EndOffset = + StartOffset + Lexer::MeasureTokenLength(Loc, SM, CI.getLangOpts()); + J.attribute("loc", locationToString(Loc, EndOffset - StartOffset)); + J.attribute("structured", 1); + J.attribute("pretty", getQualifiedName(decl)); + J.attribute("sym", getMangledName(CurMangleContext, decl)); + + J.attribute("kind", TypeWithKeyword::getTagTypeKindName(decl->getTagKind())); + + const ASTContext &C = *AstContext; + const ASTRecordLayout &Layout = C.getASTRecordLayout(decl); + + J.attribute("sizeBytes", Layout.getSize().getQuantity()); + + emitBindingAttributes(J, *decl); + + auto cxxDecl = dyn_cast(decl); + + if (cxxDecl) { + J.attributeBegin("supers"); + J.arrayBegin(); + for (const CXXBaseSpecifier &Base : cxxDecl->bases()) { + const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); + + J.objectBegin(); + + J.attribute("sym", getMangledName(CurMangleContext, BaseDecl)); + + J.attributeBegin("props"); + J.arrayBegin(); + if (Base.isVirtual()) { + J.value("virtual"); + } + J.arrayEnd(); + J.attributeEnd(); + + J.objectEnd(); + } + J.arrayEnd(); + J.attributeEnd(); + + J.attributeBegin("methods"); + J.arrayBegin(); + for (const CXXMethodDecl *MethodDecl : cxxDecl->methods()) { + J.objectBegin(); + + J.attribute("pretty", getQualifiedName(MethodDecl)); + J.attribute("sym", getMangledName(CurMangleContext, MethodDecl)); + + // TODO: Better figure out what to do for non-isUserProvided methods + // which means there's potentially semantic data that doesn't correspond + // to a source location in the source. Should we be emitting + // structured info for those when we're processing the class here? + + J.attributeBegin("props"); + J.arrayBegin(); + if (MethodDecl->isStatic()) { + J.value("static"); + } + if (MethodDecl->isInstance()) { + J.value("instance"); + } + if (MethodDecl->isVirtual()) { + J.value("virtual"); + } + if (MethodDecl->isUserProvided()) { + J.value("user"); + } + if (MethodDecl->isDefaulted()) { + J.value("defaulted"); + } + if (MethodDecl->isDeleted()) { + J.value("deleted"); + } + if (MethodDecl->isConstexpr()) { + J.value("constexpr"); + } + J.arrayEnd(); + J.attributeEnd(); + + J.objectEnd(); + } + J.arrayEnd(); + J.attributeEnd(); + } + + J.attributeBegin("fields"); + J.arrayBegin(); + uint64_t iField = 0; + for (RecordDecl::field_iterator It = decl->field_begin(), + End = decl->field_end(); It != End; ++It, ++iField) { + const FieldDecl &Field = **It; + uint64_t localOffsetBits = Layout.getFieldOffset(iField); + CharUnits localOffsetBytes = C.toCharUnitsFromBits(localOffsetBits); + + J.objectBegin(); + J.attribute("pretty", getQualifiedName(&Field)); + J.attribute("sym", getMangledName(CurMangleContext, &Field)); + QualType FieldType = Field.getType(); + QualType CanonicalFieldType = FieldType.getCanonicalType(); + J.attribute("type", CanonicalFieldType.getAsString()); + const TagDecl *tagDecl = CanonicalFieldType->getAsTagDecl(); + if (!tagDecl) { + // Try again piercing any pointers/references involved. Note that our + // typesym semantics are dubious-ish and right now crossref just does + // some parsing of "type" itself until we improve this rep. + CanonicalFieldType = CanonicalFieldType->getPointeeType(); + if (!CanonicalFieldType.isNull()) { + tagDecl = CanonicalFieldType->getAsTagDecl(); + } + } + if (tagDecl) { + J.attribute("typesym", getMangledName(CurMangleContext, tagDecl)); + } + J.attribute("offsetBytes", localOffsetBytes.getQuantity()); + if (Field.isBitField()) { + J.attributeBegin("bitPositions"); + J.objectBegin(); + + J.attribute("begin", unsigned(localOffsetBits - C.toBits(localOffsetBytes))); + J.attribute("width", Field.getBitWidthValue(C)); + + J.objectEnd(); + J.attributeEnd(); + } else { + // Try and get the field as a record itself so we can know its size, but + // we don't actually want to recurse into it. + if (auto FieldRec = Field.getType()->getAs()) { + auto const &FieldLayout = C.getASTRecordLayout(FieldRec->getDecl()); + J.attribute("sizeBytes", FieldLayout.getSize().getQuantity()); + } else { + // We were unable to get it as a record, which suggests it's a normal + // type, in which case let's just ask for the type size. (Maybe this + // would also work for the above case too?) + uint64_t typeSizeBits = C.getTypeSize(Field.getType()); + CharUnits typeSizeBytes = C.toCharUnitsFromBits(typeSizeBits); + J.attribute("sizeBytes", typeSizeBytes.getQuantity()); + } + } + J.objectEnd(); + } + J.arrayEnd(); + J.attributeEnd(); + + // End the top-level object. + J.objectEnd(); + + FileInfo *F = getFileInfo(Loc); + // we want a newline. + ros << '\n'; + F->Output.push_back(std::move(ros.str())); + } + + void emitStructuredInfo(SourceLocation Loc, const FunctionDecl *decl) { + std::string json_str; + llvm::raw_string_ostream ros(json_str); + llvm::json::OStream J(ros); + // Start the top-level object. + J.objectBegin(); + + unsigned StartOffset = SM.getFileOffset(Loc); + unsigned EndOffset = + StartOffset + Lexer::MeasureTokenLength(Loc, SM, CI.getLangOpts()); + J.attribute("loc", locationToString(Loc, EndOffset - StartOffset)); + J.attribute("structured", 1); + J.attribute("pretty", getQualifiedName(decl)); + J.attribute("sym", getMangledName(CurMangleContext, decl)); + + emitBindingAttributes(J, *decl); + + J.attributeBegin("args"); + J.arrayBegin(); + + for (auto param : decl->parameters()) { + J.objectBegin(); + + J.attribute("name", param->getName()); + QualType ArgType = param->getOriginalType(); + J.attribute("type", ArgType.getAsString()); + + QualType CanonicalArgType = ArgType.getCanonicalType(); + const TagDecl *canonDecl = CanonicalArgType->getAsTagDecl(); + if (!canonDecl) { + // Try again piercing any pointers/references involved. Note that our + // typesym semantics are dubious-ish and right now crossref just does + // some parsing of "type" itself until we improve this rep. + CanonicalArgType = CanonicalArgType->getPointeeType(); + if (!CanonicalArgType.isNull()) { + canonDecl = CanonicalArgType->getAsTagDecl(); + } + } + if (canonDecl) { + J.attribute("typesym", getMangledName(CurMangleContext, canonDecl)); + } + + J.objectEnd(); + } + + J.arrayEnd(); + J.attributeEnd(); + + + auto cxxDecl = dyn_cast(decl); + + if (cxxDecl) { + J.attribute("kind", "method"); + if (auto parentDecl = cxxDecl->getParent()) { + J.attribute("parentsym", getMangledName(CurMangleContext, parentDecl)); + } + + J.attributeBegin("overrides"); + J.arrayBegin(); + for (const CXXMethodDecl *MethodDecl : cxxDecl->overridden_methods()) { + J.objectBegin(); + + // TODO: Make sure we're doing template traversals appropriately... + // findOverriddenMethods (now removed) liked to do: + // if (Decl->isTemplateInstantiation()) { + // Decl = dyn_cast(Decl->getTemplateInstantiationPattern()); + // } + // I think our pre-emptive dereferencing/avoidance of templates may + // protect us from this, but it needs more investigation. + + J.attribute("sym", getMangledName(CurMangleContext, MethodDecl)); + + J.objectEnd(); + } + J.arrayEnd(); + J.attributeEnd(); + + } else { + J.attribute("kind", "function"); + } + + // ## Props + J.attributeBegin("props"); + J.arrayBegin(); + // some of these are only possible on a CXXMethodDecl, but we want them all + // in the same array, so condition these first ones. + if (cxxDecl) { + if (cxxDecl->isStatic()) { + J.value("static"); + } + if (cxxDecl->isInstance()) { + J.value("instance"); + } + if (cxxDecl->isVirtual()) { + J.value("virtual"); + } + if (cxxDecl->isUserProvided()) { + J.value("user"); + } + } + if (decl->isDefaulted()) { + J.value("defaulted"); + } + if (decl->isDeleted()) { + J.value("deleted"); + } + if (decl->isConstexpr()) { + J.value("constexpr"); + } + J.arrayEnd(); + J.attributeEnd(); + + // End the top-level object. + J.objectEnd(); + + FileInfo *F = getFileInfo(Loc); + // we want a newline. + ros << '\n'; + F->Output.push_back(std::move(ros.str())); + } + + /** + * Emit structured info for a field. Right now the intent is for this to just + * be a pointer to its parent's structured info with this method entirely + * avoiding getting the ASTRecordLayout. + * + * TODO: Give more thought on where to locate the canonical info on fields and + * how to normalize their exposure over the web. We could relink the info + * both at cross-reference time and web-server lookup time. This is also + * called out in `analysis.md`. + */ + void emitStructuredInfo(SourceLocation Loc, const FieldDecl *decl) { + // XXX the call to decl::getParent will assert below for ObjCIvarDecl + // instances because their DecContext is not a RecordDecl. So just bail + // for now. + // TODO: better support ObjC. + if (const ObjCIvarDecl *D2 = dyn_cast(decl)) { + return; + } + + std::string json_str; + llvm::raw_string_ostream ros(json_str); + llvm::json::OStream J(ros); + // Start the top-level object. + J.objectBegin(); + + unsigned StartOffset = SM.getFileOffset(Loc); + unsigned EndOffset = + StartOffset + Lexer::MeasureTokenLength(Loc, SM, CI.getLangOpts()); + J.attribute("loc", locationToString(Loc, EndOffset - StartOffset)); + J.attribute("structured", 1); + J.attribute("pretty", getQualifiedName(decl)); + J.attribute("sym", getMangledName(CurMangleContext, decl)); + J.attribute("kind", "field"); + + if (auto parentDecl = decl->getParent()) { + J.attribute("parentsym", getMangledName(CurMangleContext, parentDecl)); + } + + // End the top-level object. + J.objectEnd(); + + FileInfo *F = getFileInfo(Loc); + // we want a newline. + ros << '\n'; + F->Output.push_back(std::move(ros.str())); + } + + /** + * Emit structured info for a variable if it is a static class member. + */ + void emitStructuredInfo(SourceLocation Loc, const VarDecl *decl) { + const auto *parentDecl = dyn_cast_or_null(decl->getDeclContext()); + + std::string json_str; + llvm::raw_string_ostream ros(json_str); + llvm::json::OStream J(ros); + // Start the top-level object. + J.objectBegin(); + + unsigned StartOffset = SM.getFileOffset(Loc); + unsigned EndOffset = + StartOffset + Lexer::MeasureTokenLength(Loc, SM, CI.getLangOpts()); + J.attribute("loc", locationToString(Loc, EndOffset - StartOffset)); + J.attribute("structured", 1); + J.attribute("pretty", getQualifiedName(decl)); + J.attribute("sym", getMangledName(CurMangleContext, decl)); + J.attribute("kind", "field"); + + if (parentDecl) { + J.attribute("parentsym", getMangledName(CurMangleContext, parentDecl)); + } + + emitBindingAttributes(J, *decl); + + // End the top-level object. + J.objectEnd(); + + FileInfo *F = getFileInfo(Loc); + // we want a newline. + ros << '\n'; + F->Output.push_back(std::move(ros.str())); + } + + // XXX Type annotating. + // QualType is the type class. It has helpers like TagDecl via getAsTagDecl. + // ValueDecl exposes a getType() method. + // + // Arguably it makes sense to only expose types that Searchfox has definitions + // for as first-class. Probably the way to go is like context/contextsym. + // We expose a "type" which is just a human-readable string which has no + // semantic purposes and is just a display string, plus then a "typesym" which + // we expose if we were able to map the type. + // + // Other meta-info: field offsets. Ancestor types. + + // This is the only function that emits analysis JSON data. It should be + // called for each identifier that corresponds to a symbol. + void visitIdentifier(const char *Kind, const char *SyntaxKind, + llvm::StringRef QualName, SourceRange LocRange, + std::string Symbol, + QualType MaybeType = QualType(), + Context TokenContext = Context(), int Flags = 0, + SourceRange PeekRange = SourceRange(), + SourceRange NestingRange = SourceRange(), + std::vector *ArgRanges = nullptr) { + SourceLocation Loc = LocRange.getBegin(); + if (!shouldVisit(Loc)) { + return; + } + + // Find the file positions corresponding to the token. + unsigned StartOffset = SM.getFileOffset(Loc); + unsigned EndOffset = (Flags & LocRangeEndValid) + ? SM.getFileOffset(LocRange.getEnd()) + : StartOffset + Lexer::MeasureTokenLength(Loc, SM, CI.getLangOpts()); + + std::string LocStr = locationToString(Loc, EndOffset - StartOffset); + std::string RangeStr = locationToString(Loc, EndOffset - StartOffset); + std::string PeekRangeStr; + + if (!(Flags & NotIdentifierToken)) { + // Get the token's characters so we can make sure it's a valid token. + const char *StartChars = SM.getCharacterData(Loc); + std::string Text(StartChars, EndOffset - StartOffset); + if (!isValidIdentifier(Text)) { + return; + } + } + + FileInfo *F = getFileInfo(Loc); + + if (!(Flags & NoCrossref)) { + std::string json_str; + llvm::raw_string_ostream ros(json_str); + llvm::json::OStream J(ros); + // Start the top-level object. + J.objectBegin(); + + J.attribute("loc", LocStr); + J.attribute("target", 1); + J.attribute("kind", Kind); + J.attribute("pretty", QualName.data()); + J.attribute("sym", Symbol); + if (!TokenContext.Name.empty()) { + J.attribute("context", TokenContext.Name); + } + if (!TokenContext.Symbol.empty()) { + J.attribute("contextsym", TokenContext.Symbol); + } + if (PeekRange.isValid()) { + PeekRangeStr = lineRangeToString(PeekRange); + if (!PeekRangeStr.empty()) { + J.attribute("peekRange", PeekRangeStr); + } + } + + if (ArgRanges) { + J.attributeBegin("argRanges"); + J.arrayBegin(); + + for (auto range : *ArgRanges) { + std::string ArgRangeStr = fullRangeToString(range); + if (!ArgRangeStr.empty()) { + J.value(ArgRangeStr); + } + } + + J.arrayEnd(); + J.attributeEnd(); + } + + // End the top-level object. + J.objectEnd(); + // we want a newline. + ros << '\n'; + F->Output.push_back(std::move(ros.str())); + } + + // Generate a single "source":1 for all the symbols. If we search from here, + // we want to union the results for every symbol in `symbols`. + std::string json_str; + llvm::raw_string_ostream ros(json_str); + llvm::json::OStream J(ros); + // Start the top-level object. + J.objectBegin(); + + J.attribute("loc", RangeStr); + J.attribute("source", 1); + + if (NestingRange.isValid()) { + std::string NestingRangeStr = fullRangeToString(NestingRange); + if (!NestingRangeStr.empty()) { + J.attribute("nestingRange", NestingRangeStr); + } + } + + std::string Syntax; + if (Flags & NoCrossref) { + J.attribute("syntax", ""); + } else { + Syntax = Kind; + Syntax.push_back(','); + Syntax.append(SyntaxKind); + J.attribute("syntax", Syntax); + } + + if (!MaybeType.isNull()) { + J.attribute("type", MaybeType.getAsString()); + QualType canonical = MaybeType.getCanonicalType(); + const TagDecl *decl = canonical->getAsTagDecl(); + if (!decl) { + // Try again piercing any pointers/references involved. Note that our + // typesym semantics are dubious-ish and right now crossref just does + // some parsing of "type" itself until we improve this rep. + canonical = canonical->getPointeeType(); + if (!canonical.isNull()) { + decl = canonical->getAsTagDecl(); + } + } + if (decl) { + std::string Mangled = getMangledName(CurMangleContext, decl); + J.attribute("typesym", Mangled); + } + } + + std::string Pretty(SyntaxKind); + Pretty.push_back(' '); + Pretty.append(QualName.data()); + J.attribute("pretty", Pretty); + + J.attribute("sym", Symbol); + + if (Flags & NoCrossref) { + J.attribute("no_crossref", 1); + } + + if (ArgRanges) { + J.attributeBegin("argRanges"); + J.arrayBegin(); + + for (auto range : *ArgRanges) { + std::string ArgRangeStr = fullRangeToString(range); + if (!ArgRangeStr.empty()) { + J.value(ArgRangeStr); + } + } + + J.arrayEnd(); + J.attributeEnd(); + } + + // End the top-level object. + J.objectEnd(); + + // we want a newline. + ros << '\n'; + F->Output.push_back(std::move(ros.str())); + } + + void normalizeLocation(SourceLocation *Loc) { + *Loc = SM.getSpellingLoc(*Loc); + } + + // For cases where the left-brace is not directly accessible from the AST, + // helper to use the lexer to find the brace. Make sure you're picking the + // start location appropriately! + SourceLocation findLeftBraceFromLoc(SourceLocation Loc) { + return Lexer::findLocationAfterToken(Loc, tok::l_brace, SM, LO, false); + } + + // If the provided statement is compound, return its range. + SourceRange getCompoundStmtRange(Stmt* D) { + if (!D) { + return SourceRange(); + } + + CompoundStmt *D2 = dyn_cast(D); + if (D2) { + return D2->getSourceRange(); + } + + return SourceRange(); + } + + SourceRange getFunctionPeekRange(FunctionDecl* D) { + // We always start at the start of the function decl, which may include the + // return type on a separate line. + SourceLocation Start = D->getBeginLoc(); + + // By default, we end at the line containing the function's name. + SourceLocation End = D->getLocation(); + + std::pair FuncLoc = SM.getDecomposedLoc(End); + + // But if there are parameters, we want to include those as well. + for (ParmVarDecl* Param : D->parameters()) { + std::pair ParamLoc = SM.getDecomposedLoc(Param->getLocation()); + + // It's possible there are macros involved or something. We don't include + // the parameters in that case. + if (ParamLoc.first == FuncLoc.first) { + // Assume parameters are in order, so we always take the last one. + End = Param->getEndLoc(); + } + } + + return SourceRange(Start, End); + } + + SourceRange getTagPeekRange(TagDecl* D) { + SourceLocation Start = D->getBeginLoc(); + + // By default, we end at the line containing the name. + SourceLocation End = D->getLocation(); + + std::pair FuncLoc = SM.getDecomposedLoc(End); + + if (CXXRecordDecl* D2 = dyn_cast(D)) { + // But if there are parameters, we want to include those as well. + for (CXXBaseSpecifier& Base : D2->bases()) { + std::pair Loc = SM.getDecomposedLoc(Base.getEndLoc()); + + // It's possible there are macros involved or something. We don't include + // the parameters in that case. + if (Loc.first == FuncLoc.first) { + // Assume parameters are in order, so we always take the last one. + End = Base.getEndLoc(); + } + } + } + + return SourceRange(Start, End); + } + + SourceRange getCommentRange(NamedDecl* D) { + const RawComment* RC = + AstContext->getRawCommentForDeclNoCache(D); + if (!RC) { + return SourceRange(); + } + + return RC->getSourceRange(); + } + + // Sanity checks that all ranges are in the same file, returning the first if + // they're in different files. Unions the ranges based on which is first. + SourceRange combineRanges(SourceRange Range1, SourceRange Range2) { + if (Range1.isInvalid()) { + return Range2; + } + if (Range2.isInvalid()) { + return Range1; + } + + std::pair Begin1 = SM.getDecomposedLoc(Range1.getBegin()); + std::pair End1 = SM.getDecomposedLoc(Range1.getEnd()); + std::pair Begin2 = SM.getDecomposedLoc(Range2.getBegin()); + std::pair End2 = SM.getDecomposedLoc(Range2.getEnd()); + + if (End1.first != Begin2.first) { + // Something weird is probably happening with the preprocessor. Just + // return the first range. + return Range1; + } + + // See which range comes first. + if (Begin1.second <= End2.second) { + return SourceRange(Range1.getBegin(), Range2.getEnd()); + } else { + return SourceRange(Range2.getBegin(), Range1.getEnd()); + } + } + + // Given a location and a range, returns the range if: + // - The location and the range live in the same file. + // - The range is well ordered (end is not before begin). + // Returns an empty range otherwise. + SourceRange validateRange(SourceLocation Loc, SourceRange Range) { + std::pair Decomposed = SM.getDecomposedLoc(Loc); + std::pair Begin = SM.getDecomposedLoc(Range.getBegin()); + std::pair End = SM.getDecomposedLoc(Range.getEnd()); + + if (Begin.first != Decomposed.first || End.first != Decomposed.first) { + return SourceRange(); + } + + if (Begin.second >= End.second) { + return SourceRange(); + } + + return Range; + } + + bool VisitNamedDecl(NamedDecl *D) { + SourceLocation Loc = D->getLocation(); + + // If the token is from a macro expansion and the expansion location + // is interesting, use that instead as it tends to be more useful. + SourceLocation expandedLoc = Loc; + if (SM.isMacroBodyExpansion(Loc)) { + Loc = SM.getFileLoc(Loc); + } + + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return true; + } + + if (isa(D) && !D->getDeclName().getAsIdentifierInfo()) { + // Unnamed parameter in function proto. + return true; + } + + int Flags = 0; + const char *Kind = "def"; + const char *PrettyKind = "?"; + bool wasTemplate = false; + SourceRange PeekRange(D->getBeginLoc(), D->getEndLoc()); + // The nesting range identifies the left brace and right brace, which + // heavily depends on the AST node type. + SourceRange NestingRange; + QualType qtype = QualType(); + if (FunctionDecl *D2 = dyn_cast(D)) { + if (D2->isTemplateInstantiation()) { + wasTemplate = true; + D = D2->getTemplateInstantiationPattern(); + } + // We treat pure virtual declarations as definitions. + Kind = (D2->isThisDeclarationADefinition() || D2->isPure()) ? "def" : "decl"; + PrettyKind = "function"; + PeekRange = getFunctionPeekRange(D2); + + // Only emit the nesting range if: + // - This is a definition AND + // - This isn't a template instantiation. Function templates' + // instantiations can end up as a definition with a Loc at their point + // of declaration but with the CompoundStmt of the template's + // point of definition. This really messes up the nesting range logic. + // At the time of writing this, the test repo's `big_header.h`'s + // `WhatsYourVector_impl::forwardDeclaredTemplateThingInlinedBelow` as + // instantiated by `big_cpp.cpp` triggers this phenomenon. + // + // Note: As covered elsewhere, template processing is tricky and it's + // conceivable that we may change traversal patterns in the future, + // mooting this guard. + if (D2->isThisDeclarationADefinition() && + !D2->isTemplateInstantiation()) { + // The CompoundStmt range is the brace range. + NestingRange = getCompoundStmtRange(D2->getBody()); + } + } else if (TagDecl *D2 = dyn_cast(D)) { + Kind = D2->isThisDeclarationADefinition() ? "def" : "forward"; + PrettyKind = "type"; + + if (D2->isThisDeclarationADefinition() && D2->getDefinition() == D2) { + PeekRange = getTagPeekRange(D2); + NestingRange = D2->getBraceRange(); + } else { + PeekRange = SourceRange(); + } + } else if (TypedefNameDecl *D2 = dyn_cast(D)) { + Kind = "alias"; + PrettyKind = "type"; + PeekRange = SourceRange(Loc, Loc); + qtype = D2->getUnderlyingType(); + } else if (VarDecl *D2 = dyn_cast(D)) { + if (D2->isLocalVarDeclOrParm()) { + Flags = NoCrossref; + } + + Kind = D2->isThisDeclarationADefinition() == VarDecl::DeclarationOnly + ? "decl" + : "def"; + PrettyKind = "variable"; + } else if (isa(D) || isa(D)) { + Kind = "def"; + PrettyKind = "namespace"; + PeekRange = SourceRange(Loc, Loc); + NamespaceDecl *D2 = dyn_cast(D); + if (D2) { + // There's no exposure of the left brace so we have to find it. + NestingRange = SourceRange( + findLeftBraceFromLoc(D2->isAnonymousNamespace() ? D2->getBeginLoc() : Loc), + D2->getRBraceLoc()); + } + } else if (isa(D)) { + Kind = "def"; + PrettyKind = "field"; + } else if (isa(D)) { + Kind = "def"; + PrettyKind = "enum constant"; + } else { + return true; + } + + if (ValueDecl *D2 = dyn_cast(D)) { + qtype = D2->getType(); + } + + SourceRange CommentRange = getCommentRange(D); + PeekRange = combineRanges(PeekRange, CommentRange); + PeekRange = validateRange(Loc, PeekRange); + NestingRange = validateRange(Loc, NestingRange); + + std::string Symbol = getMangledName(CurMangleContext, D); + + // In the case of destructors, Loc might point to the ~ character. In that + // case we want to skip to the name of the class. However, Loc might also + // point to other places that generate destructors, such as the use site of + // a macro that expands to generate a destructor, or a lambda (apparently + // clang 8 creates a destructor declaration for at least some lambdas). In + // the former case we'll use the macro use site as the location, and in the + // latter we'll just drop the declaration. + if (isa(D)) { + PrettyKind = "destructor"; + const char *P = SM.getCharacterData(Loc); + if (*P == '~') { + // Advance Loc to the class name + P++; + + unsigned Skipped = 1; + while (*P == ' ' || *P == '\t' || *P == '\r' || *P == '\n') { + P++; + Skipped++; + } + + Loc = Loc.getLocWithOffset(Skipped); + } else { + // See if the destructor is coming from a macro expansion + P = SM.getCharacterData(expandedLoc); + if (*P != '~') { + // It's not + return true; + } + // It is, so just use Loc as-is + } + } + + visitIdentifier(Kind, PrettyKind, getQualifiedName(D), SourceRange(Loc), Symbol, + qtype, + getContext(D), Flags, PeekRange, NestingRange); + + // In-progress structured info emission. + if (RecordDecl *D2 = dyn_cast(D)) { + if (D2->isThisDeclarationADefinition() && + // XXX getASTRecordLayout doesn't work for dependent types, so we + // avoid calling into emitStructuredInfo for now if there's a + // dependent type or if we're in any kind of template context. This + // should be re-evaluated once this is working for normal classes and + // we can better evaluate what is useful. + !D2->isDependentType() && + !TemplateStack) { + if (auto *D3 = dyn_cast(D2)) { + findBindingToJavaClass(*AstContext, *D3); + findBoundAsJavaClasses(*AstContext, *D3); + } + emitStructuredInfo(Loc, D2); + } + } + if (FunctionDecl *D2 = dyn_cast(D)) { + if ((D2->isThisDeclarationADefinition() || D2->isPure()) && + // a clause at the top should have generalized and set wasTemplate so + // it shouldn't be the case that isTemplateInstantiation() is true. + !D2->isTemplateInstantiation() && + !wasTemplate && + !D2->isFunctionTemplateSpecialization() && + !TemplateStack) { + if (auto *D3 = dyn_cast(D2)) { + findBindingToJavaMember(*AstContext, *D3); + } else { + findBindingToJavaFunction(*AstContext, *D2); + } + emitStructuredInfo(Loc, D2); + } + } + if (FieldDecl *D2 = dyn_cast(D)) { + if (!D2->isTemplated() && + !TemplateStack) { + emitStructuredInfo(Loc, D2); + } + } + if (VarDecl *D2 = dyn_cast(D)) { + if (!D2->isTemplated() && + !TemplateStack && + isa(D2->getDeclContext())) { + findBindingToJavaConstant(*AstContext, *D2); + emitStructuredInfo(Loc, D2); + } + } + + return true; + } + + bool VisitCXXConstructExpr(CXXConstructExpr *E) { + SourceLocation Loc = E->getBeginLoc(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return true; + } + + FunctionDecl *Ctor = E->getConstructor(); + if (Ctor->isTemplateInstantiation()) { + Ctor = Ctor->getTemplateInstantiationPattern(); + } + std::string Mangled = getMangledName(CurMangleContext, Ctor); + + // FIXME: Need to do something different for list initialization. + + visitIdentifier("use", "constructor", getQualifiedName(Ctor), Loc, Mangled, + QualType(), getContext(Loc)); + + return true; + } + + bool VisitCallExpr(CallExpr *E) { + Decl *Callee = E->getCalleeDecl(); + if (!Callee || !FunctionDecl::classof(Callee)) { + return true; + } + + const NamedDecl *NamedCallee = dyn_cast(Callee); + + SourceLocation Loc; + + const FunctionDecl *F = dyn_cast(NamedCallee); + if (F->isTemplateInstantiation()) { + NamedCallee = F->getTemplateInstantiationPattern(); + } + + std::string Mangled = getMangledName(CurMangleContext, NamedCallee); + int Flags = 0; + + Expr *CalleeExpr = E->getCallee()->IgnoreParenImpCasts(); + + if (CXXOperatorCallExpr::classof(E)) { + // Just take the first token. + CXXOperatorCallExpr *Op = dyn_cast(E); + Loc = Op->getOperatorLoc(); + Flags |= NotIdentifierToken; + } else if (MemberExpr::classof(CalleeExpr)) { + MemberExpr *Member = dyn_cast(CalleeExpr); + Loc = Member->getMemberLoc(); + } else if (DeclRefExpr::classof(CalleeExpr)) { + // We handle this in VisitDeclRefExpr. + return true; + } else { + return true; + } + + normalizeLocation(&Loc); + + if (!isInterestingLocation(Loc)) { + return true; + } + + std::vector argRanges; + for (auto argExpr : E->arguments()) { + argRanges.push_back(argExpr->getSourceRange()); + } + + visitIdentifier("use", "function", getQualifiedName(NamedCallee), Loc, Mangled, + E->getCallReturnType(*AstContext), getContext(Loc), Flags, + SourceRange(), SourceRange(), &argRanges); + + return true; + } + + bool VisitTagTypeLoc(TagTypeLoc L) { + SourceLocation Loc = L.getBeginLoc(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return true; + } + + TagDecl *Decl = L.getDecl(); + std::string Mangled = getMangledName(CurMangleContext, Decl); + visitIdentifier("use", "type", getQualifiedName(Decl), Loc, Mangled, + L.getType(), getContext(Loc)); + return true; + } + + bool VisitTypedefTypeLoc(TypedefTypeLoc L) { + SourceLocation Loc = L.getBeginLoc(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return true; + } + + NamedDecl *Decl = L.getTypedefNameDecl(); + std::string Mangled = getMangledName(CurMangleContext, Decl); + visitIdentifier("use", "type", getQualifiedName(Decl), Loc, Mangled, + L.getType(), getContext(Loc)); + return true; + } + + bool VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc L) { + SourceLocation Loc = L.getBeginLoc(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return true; + } + + NamedDecl *Decl = L.getDecl(); + std::string Mangled = getMangledName(CurMangleContext, Decl); + visitIdentifier("use", "type", getQualifiedName(Decl), Loc, Mangled, + L.getType(), getContext(Loc)); + return true; + } + + bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc L) { + SourceLocation Loc = L.getBeginLoc(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return true; + } + + TemplateDecl *Td = L.getTypePtr()->getTemplateName().getAsTemplateDecl(); + if (ClassTemplateDecl *D = dyn_cast(Td)) { + NamedDecl *Decl = D->getTemplatedDecl(); + std::string Mangled = getMangledName(CurMangleContext, Decl); + visitIdentifier("use", "type", getQualifiedName(Decl), Loc, Mangled, + QualType(), getContext(Loc)); + } else if (TypeAliasTemplateDecl *D = dyn_cast(Td)) { + NamedDecl *Decl = D->getTemplatedDecl(); + std::string Mangled = getMangledName(CurMangleContext, Decl); + visitIdentifier("use", "type", getQualifiedName(Decl), Loc, Mangled, + QualType(), getContext(Loc)); + } + + return true; + } + + bool VisitDependentNameTypeLoc(DependentNameTypeLoc L) { + SourceLocation Loc = L.getNameLoc(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return true; + } + + for (const NamedDecl *D : + Resolver->resolveDependentNameType(L.getTypePtr())) { + visitHeuristicResult(Loc, D); + } + return true; + } + + bool VisitDeclRefExpr(DeclRefExpr *E) { + SourceLocation Loc = E->getExprLoc(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return true; + } + + if (E->hasQualifier()) { + Loc = E->getNameInfo().getLoc(); + normalizeLocation(&Loc); + } + + NamedDecl *Decl = E->getDecl(); + if (const VarDecl *D2 = dyn_cast(Decl)) { + int Flags = 0; + if (D2->isLocalVarDeclOrParm()) { + Flags = NoCrossref; + } + std::string Mangled = getMangledName(CurMangleContext, Decl); + visitIdentifier("use", "variable", getQualifiedName(Decl), Loc, Mangled, + D2->getType(), getContext(Loc), Flags); + } else if (isa(Decl)) { + const FunctionDecl *F = dyn_cast(Decl); + if (F->isTemplateInstantiation()) { + Decl = F->getTemplateInstantiationPattern(); + } + + std::string Mangled = getMangledName(CurMangleContext, Decl); + visitIdentifier("use", "function", getQualifiedName(Decl), Loc, Mangled, + E->getType(), getContext(Loc)); + } else if (isa(Decl)) { + std::string Mangled = getMangledName(CurMangleContext, Decl); + visitIdentifier("use", "enum", getQualifiedName(Decl), Loc, Mangled, + E->getType(), getContext(Loc)); + } + + return true; + } + + bool VisitCXXConstructorDecl(CXXConstructorDecl *D) { + if (!isInterestingLocation(D->getLocation())) { + return true; + } + + for (CXXConstructorDecl::init_const_iterator It = D->init_begin(); + It != D->init_end(); ++It) { + const CXXCtorInitializer *Ci = *It; + if (!Ci->getMember() || !Ci->isWritten()) { + continue; + } + + SourceLocation Loc = Ci->getMemberLocation(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + continue; + } + + FieldDecl *Member = Ci->getMember(); + std::string Mangled = getMangledName(CurMangleContext, Member); + visitIdentifier("use", "field", getQualifiedName(Member), Loc, Mangled, + Member->getType(), getContext(D)); + } + + return true; + } + + bool VisitMemberExpr(MemberExpr *E) { + SourceLocation Loc = E->getExprLoc(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return true; + } + + ValueDecl *Decl = E->getMemberDecl(); + if (FieldDecl *Field = dyn_cast(Decl)) { + std::string Mangled = getMangledName(CurMangleContext, Field); + visitIdentifier("use", "field", getQualifiedName(Field), Loc, Mangled, + Field->getType(), getContext(Loc)); + } + return true; + } + + // Helper function for producing heuristic results for usages in dependent + // code. These should be distinguished from concrete results (obtained for + // dependent code using the AutoTemplateContext machinery) once bug 1833552 is + // fixed. + // We don't expect this method to be intentionally called multiple times for + // a given (Loc, NamedDecl) pair because our callers should be mutually + // exclusive AST node types. However, it's fine if this method is called + // multiple time for a given pair because we explicitly de-duplicate records + // with an identical string representation (which is a good reason to have + // this helper, as it ensures identical representations). + void visitHeuristicResult(SourceLocation Loc, const NamedDecl *ND) { + if (const TemplateDecl *TD = dyn_cast(ND)) { + ND = TD->getTemplatedDecl(); + } + QualType MaybeType; + const char *SyntaxKind = nullptr; + if (const FunctionDecl *F = dyn_cast(ND)) { + MaybeType = F->getType(); + SyntaxKind = "function"; + } else if (const FieldDecl *F = dyn_cast(ND)) { + MaybeType = F->getType(); + SyntaxKind = "field"; + } else if (const EnumConstantDecl *E = dyn_cast(ND)) { + MaybeType = E->getType(); + SyntaxKind = "enum"; + } else if (const TypedefNameDecl *T = dyn_cast(ND)) { + MaybeType = T->getUnderlyingType(); + SyntaxKind = "type"; + } + if (SyntaxKind) { + std::string Mangled = getMangledName(CurMangleContext, ND); + visitIdentifier("use", SyntaxKind, getQualifiedName(ND), Loc, Mangled, + MaybeType, getContext(Loc)); + } + } + + bool VisitOverloadExpr(OverloadExpr *E) { + SourceLocation Loc = E->getExprLoc(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return true; + } + + for (auto *Candidate : E->decls()) { + visitHeuristicResult(Loc, Candidate); + } + return true; + } + + bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) { + SourceLocation Loc = E->getMemberLoc(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return true; + } + + // If possible, provide a heuristic result without instantiation. + for (const NamedDecl *D : Resolver->resolveMemberExpr(E)) { + visitHeuristicResult(Loc, D); + } + + // Also record this location so that if we have instantiations, we can + // gather more accurate results from them. + if (TemplateStack) { + TemplateStack->visitDependent(Loc); + } + return true; + } + + bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { + SourceLocation Loc = E->getLocation(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return true; + } + + for (const NamedDecl *D : Resolver->resolveDeclRefExpr(E)) { + visitHeuristicResult(Loc, D); + } + return true; + } + + void enterSourceFile(SourceLocation Loc) { + normalizeLocation(&Loc); + FileInfo* newFile = getFileInfo(Loc); + if (!newFile->Interesting) { + return; + } + FileType type = newFile->Generated ? FileType::Generated : FileType::Source; + std::string symbol = + std::string("FILE_") + mangleFile(newFile->Realname, type); + + // We use an explicit zero-length source range at the start of the file. If we + // don't set the LocRangeEndValid flag, the visitIdentifier code will use the + // entire first token, which could be e.g. a long multiline-comment. + visitIdentifier("def", "file", newFile->Realname, SourceRange(Loc), + symbol, QualType(), Context(), + NotIdentifierToken | LocRangeEndValid); + } + + void inclusionDirective(SourceRange FileNameRange, const FileEntry* File) { + std::string includedFile(File->tryGetRealPathName()); + FileType type = relativizePath(includedFile); + if (type == FileType::Unknown) { + return; + } + std::string symbol = + std::string("FILE_") + mangleFile(includedFile, type); + + visitIdentifier("use", "file", includedFile, FileNameRange, symbol, + QualType(), Context(), + NotIdentifierToken | LocRangeEndValid); + } + + void macroDefined(const Token &Tok, const MacroDirective *Macro) { + if (Macro->getMacroInfo()->isBuiltinMacro()) { + return; + } + SourceLocation Loc = Tok.getLocation(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return; + } + + IdentifierInfo *Ident = Tok.getIdentifierInfo(); + if (Ident) { + std::string Mangled = + std::string("M_") + mangleLocation(Loc, std::string(Ident->getName())); + visitIdentifier("def", "macro", Ident->getName(), Loc, Mangled); + } + } + + void macroUsed(const Token &Tok, const MacroInfo *Macro) { + if (!Macro) { + return; + } + if (Macro->isBuiltinMacro()) { + return; + } + SourceLocation Loc = Tok.getLocation(); + normalizeLocation(&Loc); + if (!isInterestingLocation(Loc)) { + return; + } + + IdentifierInfo *Ident = Tok.getIdentifierInfo(); + if (Ident) { + std::string Mangled = + std::string("M_") + + mangleLocation(Macro->getDefinitionLoc(), std::string(Ident->getName())); + visitIdentifier("use", "macro", Ident->getName(), Loc, Mangled); + } + } +}; + +void PreprocessorHook::FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID = FileID()) { + switch (Reason) { + case PPCallbacks::RenameFile: + case PPCallbacks::SystemHeaderPragma: + // Don't care about these, since we want the actual on-disk filenames + break; + case PPCallbacks::EnterFile: + Indexer->enterSourceFile(Loc); + break; + case PPCallbacks::ExitFile: + // Don't care about exiting files + break; + } +} + +void PreprocessorHook::InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FileNameRange, +#if CLANG_VERSION_MAJOR >= 16 + OptionalFileEntryRef File, +#elif CLANG_VERSION_MAJOR >= 15 + Optional File, +#else + const FileEntry *File, +#endif + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported, + SrcMgr::CharacteristicKind FileType) { +#if CLANG_VERSION_MAJOR >= 15 + if (!File) { + return; + } + Indexer->inclusionDirective(FileNameRange.getAsRange(), &File->getFileEntry()); +#else + Indexer->inclusionDirective(FileNameRange.getAsRange(), File); +#endif +} + +void PreprocessorHook::MacroDefined(const Token &Tok, + const MacroDirective *Md) { + Indexer->macroDefined(Tok, Md); +} + +void PreprocessorHook::MacroExpands(const Token &Tok, const MacroDefinition &Md, + SourceRange Range, const MacroArgs *Ma) { + Indexer->macroUsed(Tok, Md.getMacroInfo()); +} + +void PreprocessorHook::MacroUndefined(const Token &Tok, + const MacroDefinition &Md, + const MacroDirective *Undef) +{ + Indexer->macroUsed(Tok, Md.getMacroInfo()); +} + +void PreprocessorHook::Defined(const Token &Tok, const MacroDefinition &Md, + SourceRange Range) { + Indexer->macroUsed(Tok, Md.getMacroInfo()); +} + +void PreprocessorHook::Ifdef(SourceLocation Loc, const Token &Tok, + const MacroDefinition &Md) { + Indexer->macroUsed(Tok, Md.getMacroInfo()); +} + +void PreprocessorHook::Ifndef(SourceLocation Loc, const Token &Tok, + const MacroDefinition &Md) { + Indexer->macroUsed(Tok, Md.getMacroInfo()); +} + +class IndexAction : public PluginASTAction { +protected: + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef F) { + return make_unique(CI); + } + + bool ParseArgs(const CompilerInstance &CI, + const std::vector &Args) { + if (Args.size() != 3) { + DiagnosticsEngine &D = CI.getDiagnostics(); + unsigned DiagID = D.getCustomDiagID( + DiagnosticsEngine::Error, + "Need arguments for the source, output, and object directories"); + D.Report(DiagID); + return false; + } + + // Load our directories + Srcdir = getAbsolutePath(Args[0]); + if (Srcdir.empty()) { + DiagnosticsEngine &D = CI.getDiagnostics(); + unsigned DiagID = D.getCustomDiagID( + DiagnosticsEngine::Error, "Source directory '%0' does not exist"); + D.Report(DiagID) << Args[0]; + return false; + } + + ensurePath(Args[1] + PATHSEP_STRING); + Outdir = getAbsolutePath(Args[1]); + Outdir += PATHSEP_STRING; + + Objdir = getAbsolutePath(Args[2]); + if (Objdir.empty()) { + DiagnosticsEngine &D = CI.getDiagnostics(); + unsigned DiagID = D.getCustomDiagID(DiagnosticsEngine::Error, + "Objdir '%0' does not exist"); + D.Report(DiagID) << Args[2]; + return false; + } + Objdir += PATHSEP_STRING; + + printf("MOZSEARCH: %s %s %s\n", Srcdir.c_str(), Outdir.c_str(), + Objdir.c_str()); + + return true; + } + + void printHelp(llvm::raw_ostream &Ros) { + Ros << "Help for mozsearch plugin goes here\n"; + } +}; + +static FrontendPluginRegistry::Add + Y("mozsearch-index", "create the mozsearch index database"); diff --git a/build/clang-plugin/mozsearch-plugin/README b/build/clang-plugin/mozsearch-plugin/README new file mode 100644 index 0000000000..d948e9aca3 --- /dev/null +++ b/build/clang-plugin/mozsearch-plugin/README @@ -0,0 +1,12 @@ +This clang plugin code generates a JSON file for each compiler input +file. The JSON file contains information about the C++ symbols that +are referenced by the input file. The data is eventually consumed by +Searchfox. See https://github.com/mozsearch/mozsearch for more +information. + +This plugin is enabled with the --enable-clang-plugin and +--enable-mozsearch-plugin mozconfig options. The output of the plugin +is stored in $OBJDIR/mozsearch_index. + +This code is not a checker, unlike other parts of the Mozilla clang +plugin. It cannot be used with clang-tidy. diff --git a/build/clang-plugin/mozsearch-plugin/StringOperations.cpp b/build/clang-plugin/mozsearch-plugin/StringOperations.cpp new file mode 100644 index 0000000000..a2e60e42c6 --- /dev/null +++ b/build/clang-plugin/mozsearch-plugin/StringOperations.cpp @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "StringOperations.h" + +static unsigned long djbHash(const char *Str) { + unsigned long Hash = 5381; + + for (const char *P = Str; *P; P++) { + // Hash * 33 + c + Hash = ((Hash << 5) + Hash) + *P; + } + + return Hash; +} + +// This doesn't actually return a hex string of |hash|, but it +// does... something. It doesn't really matter what. +static void hashToString(unsigned long Hash, char *Buffer) { + const char Table[] = {"0123456789abcdef"}; + char *P = Buffer; + while (Hash) { + *P = Table[Hash & 0xf]; + Hash >>= 4; + P++; + } + + *P = 0; +} + +std::string hash(const std::string &Str) { + static char HashStr[41]; + unsigned long H = djbHash(Str.c_str()); + hashToString(H, HashStr); + return std::string(HashStr); +} + +std::string toString(int N) { + return stringFormat("%d", N); +} diff --git a/build/clang-plugin/mozsearch-plugin/StringOperations.h b/build/clang-plugin/mozsearch-plugin/StringOperations.h new file mode 100644 index 0000000000..4aa5b31962 --- /dev/null +++ b/build/clang-plugin/mozsearch-plugin/StringOperations.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef StringOperations_h +#define StringOperations_h + +#include +#include +#include + +std::string hash(const std::string &Str); + +template +inline std::string stringFormat(const std::string &Format, Args... ArgList) { + size_t Len = snprintf(nullptr, 0, Format.c_str(), ArgList...); + std::unique_ptr Buf(new char[Len + 1]); + snprintf(Buf.get(), Len + 1, Format.c_str(), ArgList...); + return std::string(Buf.get(), Buf.get() + Len); +} + +std::string toString(int N); + +#endif diff --git a/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.cpp b/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.cpp new file mode 100644 index 0000000000..719094dbf2 --- /dev/null +++ b/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.cpp @@ -0,0 +1,349 @@ +//===--- HeuristicResolver.cpp ---------------------------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "HeuristicResolver.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/Type.h" + +namespace clang { +namespace clangd { + +// Convenience lambdas for use as the 'Filter' parameter of +// HeuristicResolver::resolveDependentMember(). +const auto NoFilter = [](const NamedDecl *D) { return true; }; +const auto NonStaticFilter = [](const NamedDecl *D) { + return D->isCXXInstanceMember(); +}; +const auto StaticFilter = [](const NamedDecl *D) { + return !D->isCXXInstanceMember(); +}; +const auto ValueFilter = [](const NamedDecl *D) { return isa(D); }; +const auto TypeFilter = [](const NamedDecl *D) { return isa(D); }; +const auto TemplateFilter = [](const NamedDecl *D) { + return isa(D); +}; + +namespace { + +const Type *resolveDeclsToType(const std::vector &Decls, + ASTContext &Ctx) { + if (Decls.size() != 1) // Names an overload set -- just bail. + return nullptr; + if (const auto *TD = dyn_cast(Decls[0])) { + return Ctx.getTypeDeclType(TD).getTypePtr(); + } + if (const auto *VD = dyn_cast(Decls[0])) { + return VD->getType().getTypePtrOrNull(); + } + return nullptr; +} + +} // namespace + +// Helper function for HeuristicResolver::resolveDependentMember() +// which takes a possibly-dependent type `T` and heuristically +// resolves it to a CXXRecordDecl in which we can try name lookup. +CXXRecordDecl *HeuristicResolver::resolveTypeToRecordDecl(const Type *T) const { + assert(T); + + // Unwrap type sugar such as type aliases. + T = T->getCanonicalTypeInternal().getTypePtr(); + + if (const auto *DNT = T->getAs()) { + T = resolveDeclsToType(resolveDependentNameType(DNT), Ctx); + if (!T) + return nullptr; + T = T->getCanonicalTypeInternal().getTypePtr(); + } + + if (const auto *RT = T->getAs()) + return dyn_cast(RT->getDecl()); + + if (const auto *ICNT = T->getAs()) + T = ICNT->getInjectedSpecializationType().getTypePtrOrNull(); + if (!T) + return nullptr; + + const auto *TST = T->getAs(); + if (!TST) + return nullptr; + + const ClassTemplateDecl *TD = dyn_cast_or_null( + TST->getTemplateName().getAsTemplateDecl()); + if (!TD) + return nullptr; + + return TD->getTemplatedDecl(); +} + +const Type *HeuristicResolver::getPointeeType(const Type *T) const { + if (!T) + return nullptr; + + if (T->isPointerType()) + return T->castAs()->getPointeeType().getTypePtrOrNull(); + + // Try to handle smart pointer types. + + // Look up operator-> in the primary template. If we find one, it's probably a + // smart pointer type. + auto ArrowOps = resolveDependentMember( + T, Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow), NonStaticFilter); + if (ArrowOps.empty()) + return nullptr; + + // Getting the return type of the found operator-> method decl isn't useful, + // because we discarded template arguments to perform lookup in the primary + // template scope, so the return type would just have the form U* where U is a + // template parameter type. + // Instead, just handle the common case where the smart pointer type has the + // form of SmartPtr, and assume X is the pointee type. + auto *TST = T->getAs(); + if (!TST) + return nullptr; + if (TST->template_arguments().size() == 0) + return nullptr; + const TemplateArgument &FirstArg = TST->template_arguments()[0]; + if (FirstArg.getKind() != TemplateArgument::Type) + return nullptr; + return FirstArg.getAsType().getTypePtrOrNull(); +} + +std::vector HeuristicResolver::resolveMemberExpr( + const CXXDependentScopeMemberExpr *ME) const { + // If the expression has a qualifier, first try resolving the member + // inside the qualifier's type. + // Note that we cannot use a NonStaticFilter in either case, for a couple + // of reasons: + // 1. It's valid to access a static member using instance member syntax, + // e.g. `instance.static_member`. + // 2. We can sometimes get a CXXDependentScopeMemberExpr for static + // member syntax too, e.g. if `X::static_member` occurs inside + // an instance method, it's represented as a CXXDependentScopeMemberExpr + // with `this` as the base expression as `X` as the qualifier + // (which could be valid if `X` names a base class after instantiation). + if (NestedNameSpecifier *NNS = ME->getQualifier()) { + if (const Type *QualifierType = resolveNestedNameSpecifierToType(NNS)) { + auto Decls = + resolveDependentMember(QualifierType, ME->getMember(), NoFilter); + if (!Decls.empty()) + return Decls; + } + } + + // If that didn't yield any results, try resolving the member inside + // the expression's base type. + const Type *BaseType = ME->getBaseType().getTypePtrOrNull(); + if (ME->isArrow()) { + BaseType = getPointeeType(BaseType); + } + if (!BaseType) + return {}; + if (const auto *BT = BaseType->getAs()) { + // If BaseType is the type of a dependent expression, it's just + // represented as BuiltinType::Dependent which gives us no information. We + // can get further by analyzing the dependent expression. + Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase(); + if (Base && BT->getKind() == BuiltinType::Dependent) { + BaseType = resolveExprToType(Base); + } + } + return resolveDependentMember(BaseType, ME->getMember(), NoFilter); +} + +std::vector HeuristicResolver::resolveDeclRefExpr( + const DependentScopeDeclRefExpr *RE) const { + return resolveDependentMember(RE->getQualifier()->getAsType(), + RE->getDeclName(), StaticFilter); +} + +std::vector +HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const { + const auto *CalleeType = resolveExprToType(CE->getCallee()); + if (!CalleeType) + return {}; + if (const auto *FnTypePtr = CalleeType->getAs()) + CalleeType = FnTypePtr->getPointeeType().getTypePtr(); + if (const FunctionType *FnType = CalleeType->getAs()) { + if (const auto *D = + resolveTypeToRecordDecl(FnType->getReturnType().getTypePtr())) { + return {D}; + } + } + return {}; +} + +std::vector +HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const { + if (const auto *ND = dyn_cast_or_null(CE->getCalleeDecl())) { + return {ND}; + } + + return resolveExprToDecls(CE->getCallee()); +} + +std::vector HeuristicResolver::resolveUsingValueDecl( + const UnresolvedUsingValueDecl *UUVD) const { + return resolveDependentMember(UUVD->getQualifier()->getAsType(), + UUVD->getNameInfo().getName(), ValueFilter); +} + +std::vector HeuristicResolver::resolveDependentNameType( + const DependentNameType *DNT) const { + return resolveDependentMember( + resolveNestedNameSpecifierToType(DNT->getQualifier()), + DNT->getIdentifier(), TypeFilter); +} + +std::vector +HeuristicResolver::resolveTemplateSpecializationType( + const DependentTemplateSpecializationType *DTST) const { + return resolveDependentMember( + resolveNestedNameSpecifierToType(DTST->getQualifier()), + DTST->getIdentifier(), TemplateFilter); +} + +std::vector +HeuristicResolver::resolveExprToDecls(const Expr *E) const { + if (const auto *ME = dyn_cast(E)) { + return resolveMemberExpr(ME); + } + if (const auto *RE = dyn_cast(E)) { + return resolveDeclRefExpr(RE); + } + if (const auto *OE = dyn_cast(E)) { + return {OE->decls_begin(), OE->decls_end()}; + } + if (const auto *CE = dyn_cast(E)) { + return resolveTypeOfCallExpr(CE); + } + if (const auto *ME = dyn_cast(E)) + return {ME->getMemberDecl()}; + + return {}; +} + +const Type *HeuristicResolver::resolveExprToType(const Expr *E) const { + std::vector Decls = resolveExprToDecls(E); + if (!Decls.empty()) + return resolveDeclsToType(Decls, Ctx); + + return E->getType().getTypePtr(); +} + +const Type *HeuristicResolver::resolveNestedNameSpecifierToType( + const NestedNameSpecifier *NNS) const { + if (!NNS) + return nullptr; + + // The purpose of this function is to handle the dependent (Kind == + // Identifier) case, but we need to recurse on the prefix because + // that may be dependent as well, so for convenience handle + // the TypeSpec cases too. + switch (NNS->getKind()) { + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + return NNS->getAsType(); + case NestedNameSpecifier::Identifier: { + return resolveDeclsToType( + resolveDependentMember( + resolveNestedNameSpecifierToType(NNS->getPrefix()), + NNS->getAsIdentifier(), TypeFilter), + Ctx); + } + default: + break; + } + return nullptr; +} + +namespace { + +bool isOrdinaryMember(const NamedDecl *ND) { + return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag | + Decl::IDNS_Member); +} + +bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path, + DeclarationName Name) { + Path.Decls = RD->lookup(Name).begin(); + for (DeclContext::lookup_iterator I = Path.Decls, E = I.end(); I != E; ++I) + if (isOrdinaryMember(*I)) + return true; + + return false; +} + +} // namespace + +bool HeuristicResolver::findOrdinaryMemberInDependentClasses( + const CXXBaseSpecifier *Specifier, CXXBasePath &Path, + DeclarationName Name) const { + CXXRecordDecl *RD = + resolveTypeToRecordDecl(Specifier->getType().getTypePtr()); + if (!RD) + return false; + return findOrdinaryMember(RD, Path, Name); +} + +std::vector HeuristicResolver::lookupDependentName( + CXXRecordDecl *RD, DeclarationName Name, + llvm::function_ref Filter) const { + std::vector Results; + + // Lookup in the class. + bool AnyOrdinaryMembers = false; + for (const NamedDecl *ND : RD->lookup(Name)) { + if (isOrdinaryMember(ND)) + AnyOrdinaryMembers = true; + if (Filter(ND)) + Results.push_back(ND); + } + if (AnyOrdinaryMembers) + return Results; + + // Perform lookup into our base classes. + CXXBasePaths Paths; + Paths.setOrigin(RD); + if (!RD->lookupInBases( + [&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { + return findOrdinaryMemberInDependentClasses(Specifier, Path, Name); + }, + Paths, /*LookupInDependent=*/true)) + return Results; + for (DeclContext::lookup_iterator I = Paths.front().Decls, E = I.end(); + I != E; ++I) { + if (isOrdinaryMember(*I) && Filter(*I)) + Results.push_back(*I); + } + return Results; +} + +std::vector HeuristicResolver::resolveDependentMember( + const Type *T, DeclarationName Name, + llvm::function_ref Filter) const { + if (!T) + return {}; + if (auto *ET = T->getAs()) { + auto Result = ET->getDecl()->lookup(Name); + return {Result.begin(), Result.end()}; + } + if (auto *RD = resolveTypeToRecordDecl(T)) { + if (!RD->hasDefinition()) + return {}; + RD = RD->getDefinition(); + return lookupDependentName(RD, Name, Filter); + } + return {}; +} + +} // namespace clangd +} // namespace clang diff --git a/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.h b/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.h new file mode 100644 index 0000000000..dc04123d37 --- /dev/null +++ b/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.h @@ -0,0 +1,122 @@ +//===--- HeuristicResolver.h - Resolution of dependent names -----*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEURISTICRESOLVER_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEURISTICRESOLVER_H + +#include "clang/AST/Decl.h" +#include + +namespace clang { + +class ASTContext; +class CallExpr; +class CXXBasePath; +class CXXDependentScopeMemberExpr; +class DeclarationName; +class DependentScopeDeclRefExpr; +class NamedDecl; +class Type; +class UnresolvedUsingValueDecl; + +namespace clangd { + +// This class heuristic resolution of declarations and types in template code. +// +// As a compiler, clang only needs to perform certain types of processing on +// template code (such as resolving dependent names to declarations, or +// resolving the type of a dependent expression) after instantiation. Indeed, +// C++ language features such as template specialization mean such resolution +// cannot be done accurately before instantiation +// +// However, template code is written and read in uninstantiated form, and clangd +// would like to provide editor features like go-to-definition in template code +// where possible. To this end, clangd attempts to resolve declarations and +// types in uninstantiated code by using heuristics, understanding that the +// results may not be fully accurate but that this is better than nothing. +// +// At this time, the heuristic used is a simple but effective one: assume that +// template instantiations are based on the primary template definition and not +// not a specialization. More advanced heuristics may be added in the future. +class HeuristicResolver { +public: + HeuristicResolver(ASTContext &Ctx) : Ctx(Ctx) {} + + // Try to heuristically resolve certain types of expressions, declarations, or + // types to one or more likely-referenced declarations. + std::vector + resolveMemberExpr(const CXXDependentScopeMemberExpr *ME) const; + std::vector + resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE) const; + std::vector + resolveTypeOfCallExpr(const CallExpr *CE) const; + std::vector + resolveCalleeOfCallExpr(const CallExpr *CE) const; + std::vector + resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD) const; + std::vector + resolveDependentNameType(const DependentNameType *DNT) const; + std::vector resolveTemplateSpecializationType( + const DependentTemplateSpecializationType *DTST) const; + + // Try to heuristically resolve a dependent nested name specifier + // to the type it likely denotes. Note that *dependent* name specifiers always + // denote types, not namespaces. + const Type * + resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS) const; + + // Given the type T of a dependent expression that appears of the LHS of a + // "->", heuristically find a corresponding pointee type in whose scope we + // could look up the name appearing on the RHS. + const Type *getPointeeType(const Type *T) const; + +private: + ASTContext &Ctx; + + // Given a tag-decl type and a member name, heuristically resolve the + // name to one or more declarations. + // The current heuristic is simply to look up the name in the primary + // template. This is a heuristic because the template could potentially + // have specializations that declare different members. + // Multiple declarations could be returned if the name is overloaded + // (e.g. an overloaded method in the primary template). + // This heuristic will give the desired answer in many cases, e.g. + // for a call to vector::size(). + std::vector resolveDependentMember( + const Type *T, DeclarationName Name, + llvm::function_ref Filter) const; + + // Try to heuristically resolve the type of a possibly-dependent expression + // `E`. + const Type *resolveExprToType(const Expr *E) const; + std::vector resolveExprToDecls(const Expr *E) const; + + // Helper function for HeuristicResolver::resolveDependentMember() + // which takes a possibly-dependent type `T` and heuristically + // resolves it to a CXXRecordDecl in which we can try name lookup. + CXXRecordDecl *resolveTypeToRecordDecl(const Type *T) const; + + // This is a reimplementation of CXXRecordDecl::lookupDependentName() + // so that the implementation can call into other HeuristicResolver helpers. + // FIXME: Once HeuristicResolver is upstreamed to the clang libraries + // (https://github.com/clangd/clangd/discussions/1662), + // CXXRecordDecl::lookupDepenedentName() can be removed, and its call sites + // can be modified to benefit from the more comprehensive heuristics offered + // by HeuristicResolver instead. + std::vector lookupDependentName( + CXXRecordDecl *RD, DeclarationName Name, + llvm::function_ref Filter) const; + bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + DeclarationName Name) const; +}; + +} // namespace clangd +} // namespace clang + +#endif diff --git a/build/clang-plugin/mozsearch-plugin/from-clangd/README.md b/build/clang-plugin/mozsearch-plugin/from-clangd/README.md new file mode 100644 index 0000000000..9f39dab231 --- /dev/null +++ b/build/clang-plugin/mozsearch-plugin/from-clangd/README.md @@ -0,0 +1,10 @@ +The facilities in this subdirectory are copied over from clangd +(https://clangd.llvm.org/). + +The files here are currently copies of the following upstream files: +https://github.com/llvm/llvm-project/blob/2bcbcbefcd0f7432f99cc07bb47d1e1ecb579a3f/clang-tools-extra/clangd/HeuristicResolver.h +https://github.com/llvm/llvm-project/blob/2bcbcbefcd0f7432f99cc07bb47d1e1ecb579a3f/clang-tools-extra/clangd/HeuristicResolver.cpp + +If, in the future, these facilities are moved from clangd to +to libclangTooling and exposed in the clang API headers, we can +switch to consuming them from there directly. diff --git a/build/clang-plugin/plugin.h b/build/clang-plugin/plugin.h new file mode 100644 index 0000000000..15e7560455 --- /dev/null +++ b/build/clang-plugin/plugin.h @@ -0,0 +1,57 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef plugin_h__ +#define plugin_h__ + +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Analysis/CFG.h" +#include "clang/Basic/Version.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include +#include + +#define CLANG_VERSION_FULL (CLANG_VERSION_MAJOR * 100 + CLANG_VERSION_MINOR) + +using namespace llvm; +using namespace clang; +using namespace clang::ast_matchers; + +#if CLANG_VERSION_FULL >= 306 +typedef std::unique_ptr ASTConsumerPtr; +#else +typedef ASTConsumer *ASTConsumerPtr; +#endif + +#if CLANG_VERSION_FULL < 800 +// Starting with Clang 8.0 some basic functions have been renamed +#define getBeginLoc getLocStart +#define getEndLoc getLocEnd +#endif + +// In order to support running our checks using clang-tidy, we implement a +// source compatible base check class called BaseCheck, and we use the +// preprocessor to decide which base class to pick. +#ifdef CLANG_TIDY +#if CLANG_VERSION_FULL >= 900 +#include "../ClangTidyCheck.h" +#else +#include "../ClangTidy.h" +#endif +typedef clang::tidy::ClangTidyCheck BaseCheck; +typedef clang::tidy::ClangTidyContext ContextType; +#else +#include "BaseCheck.h" +#endif + +#endif // plugin_h__ diff --git a/build/clang-plugin/tests/Makefile.in b/build/clang-plugin/tests/Makefile.in new file mode 100644 index 0000000000..318c9a0261 --- /dev/null +++ b/build/clang-plugin/tests/Makefile.in @@ -0,0 +1,19 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include $(topsrcdir)/config/rules.mk + +$(OBJS): $(CLANG_PLUGIN) + +# Because building the objects doesn't actually build anything, create +# a stamp file to avoid re-running the tests unless the test files or +# the plugin changed. And since no objects are created, and not having +# the files around makes the rule always, we create dummy files here too. +tests-ok: $(OBJS) $(CSRCS) $(CPPSRCS) $(CLANG_PLUGIN) + touch $@ $(OBJS) + +target-objects: tests-ok + +# Don't actually build a library, since we don't actually build objects. +$(LIBRARY): EXPAND_LIBS_GEN=true diff --git a/build/clang-plugin/tests/NonParameterTestCases.h b/build/clang-plugin/tests/NonParameterTestCases.h new file mode 100644 index 0000000000..d38a14d944 --- /dev/null +++ b/build/clang-plugin/tests/NonParameterTestCases.h @@ -0,0 +1,61 @@ +MAYBE_STATIC void raw(Param x) {} + +MAYBE_STATIC void raw(NonParam x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(NonParamUnion x) {} //expected-error {{Type 'NonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(NonParamClass x) {} //expected-error {{Type 'NonParamClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(NonParamEnum x) {} //expected-error {{Type 'NonParamEnum' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(NonParamEnumClass x) {} //expected-error {{Type 'NonParamEnumClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(HasNonParamStruct x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(HasNonParamUnion x) {} //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(HasNonParamStructUnion x) {} //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + +MAYBE_STATIC void const_(const NonParam x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const NonParamUnion x) {} //expected-error {{Type 'NonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const NonParamClass x) {} //expected-error {{Type 'NonParamClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const NonParamEnum x) {} //expected-error {{Type 'NonParamEnum' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const NonParamEnumClass x) {} //expected-error {{Type 'NonParamEnumClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const HasNonParamStruct x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const HasNonParamUnion x) {} //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const HasNonParamStructUnion x) {} //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + +MAYBE_STATIC void array(NonParam x[]) {} +MAYBE_STATIC void array(NonParamUnion x[]) {} +MAYBE_STATIC void array(NonParamClass x[]) {} +MAYBE_STATIC void array(NonParamEnum x[]) {} +MAYBE_STATIC void array(NonParamEnumClass x[]) {} +MAYBE_STATIC void array(HasNonParamStruct x[]) {} +MAYBE_STATIC void array(HasNonParamUnion x[]) {} +MAYBE_STATIC void array(HasNonParamStructUnion x[]) {} + +MAYBE_STATIC void ptr(NonParam* x) {} +MAYBE_STATIC void ptr(NonParamUnion* x) {} +MAYBE_STATIC void ptr(NonParamClass* x) {} +MAYBE_STATIC void ptr(NonParamEnum* x) {} +MAYBE_STATIC void ptr(NonParamEnumClass* x) {} +MAYBE_STATIC void ptr(HasNonParamStruct* x) {} +MAYBE_STATIC void ptr(HasNonParamUnion* x) {} +MAYBE_STATIC void ptr(HasNonParamStructUnion* x) {} + +MAYBE_STATIC void ref(NonParam& x) {} +MAYBE_STATIC void ref(NonParamUnion& x) {} +MAYBE_STATIC void ref(NonParamClass& x) {} +MAYBE_STATIC void ref(NonParamEnum& x) {} +MAYBE_STATIC void ref(NonParamEnumClass& x) {} +MAYBE_STATIC void ref(HasNonParamStruct& x) {} +MAYBE_STATIC void ref(HasNonParamUnion& x) {} +MAYBE_STATIC void ref(HasNonParamStructUnion& x) {} + +MAYBE_STATIC void constRef(const NonParam& x) {} +MAYBE_STATIC void constRef(const NonParamUnion& x) {} +MAYBE_STATIC void constRef(const NonParamClass& x) {} +MAYBE_STATIC void constRef(const NonParamEnum& x) {} +MAYBE_STATIC void constRef(const NonParamEnumClass& x) {} +MAYBE_STATIC void constRef(const HasNonParamStruct& x) {} +MAYBE_STATIC void constRef(const HasNonParamUnion& x) {} +MAYBE_STATIC void constRef(const HasNonParamStructUnion& x) {} + +MAYBE_STATIC inline void inlineRaw(NonParam x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC inline void inlineRaw(NonParamUnion x) {} //expected-error {{Type 'NonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC inline void inlineRaw(NonParamClass x) {} //expected-error {{Type 'NonParamClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC inline void inlineRaw(NonParamEnum x) {} //expected-error {{Type 'NonParamEnum' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC inline void inlineRaw(NonParamEnumClass x) {} //expected-error {{Type 'NonParamEnumClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} diff --git a/build/clang-plugin/tests/TestAssertWithAssignment.cpp b/build/clang-plugin/tests/TestAssertWithAssignment.cpp new file mode 100644 index 0000000000..f0f049e4a3 --- /dev/null +++ b/build/clang-plugin/tests/TestAssertWithAssignment.cpp @@ -0,0 +1,68 @@ +#include "mozilla/MacroArgs.h" + +static __attribute__((always_inline)) bool MOZ_AssertAssignmentTest(bool expr) { + return expr; +} + +#define MOZ_UNLIKELY(x) (__builtin_expect(!!(x), 0)) +#define MOZ_CRASH() do { } while(0) +#define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) MOZ_AssertAssignmentTest(!!(expr)) + +#define MOZ_ASSERT_HELPER1(expr) \ + do { \ + if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ + MOZ_CRASH();\ + } \ + } while(0) \ + +/* Now the two-argument form. */ +#define MOZ_ASSERT_HELPER2(expr, explain) \ + do { \ + if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ + MOZ_CRASH();\ + } \ + } while(0) \ + +#define MOZ_RELEASE_ASSERT_GLUE(a, b) a b +#define MOZ_RELEASE_ASSERT(...) \ + MOZ_RELEASE_ASSERT_GLUE( \ + MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \ + (__VA_ARGS__)) + +#define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__) + +void FunctionTest(int p) { + MOZ_ASSERT(p = 1); // expected-error {{Forbidden assignment in assert expression}} +} + +void FunctionTest2(int p) { + MOZ_ASSERT(((p = 1))); // expected-error {{Forbidden assignment in assert expression}} +} + +void FunctionTest3(int p) { + MOZ_ASSERT(p != 3); +} + +class TestOverloading { + int value; +public: + explicit TestOverloading(int _val) : value(_val) {} + // different operators + explicit operator bool() const { return true; } + TestOverloading& operator=(const int _val) { value = _val; return *this; } + + int& GetInt() {return value;} +}; + +void TestOverloadingFunc() { + TestOverloading p(2); + int f; + + MOZ_ASSERT(p); + MOZ_ASSERT(p = 3); // expected-error {{Forbidden assignment in assert expression}} + MOZ_ASSERT(p, "p is not valid"); + MOZ_ASSERT(p = 3, "p different than 3"); // expected-error {{Forbidden assignment in assert expression}} + MOZ_ASSERT(p.GetInt() = 2); // expected-error {{Forbidden assignment in assert expression}} + MOZ_ASSERT(p.GetInt() == 2); + MOZ_ASSERT(p.GetInt() == 2, f = 3); +} diff --git a/build/clang-plugin/tests/TestBadImplicitConversionCtor.cpp b/build/clang-plugin/tests/TestBadImplicitConversionCtor.cpp new file mode 100644 index 0000000000..ca2472582e --- /dev/null +++ b/build/clang-plugin/tests/TestBadImplicitConversionCtor.cpp @@ -0,0 +1,50 @@ +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +struct Foo { + Foo(int); // expected-error {{bad implicit conversion constructor for 'Foo'}} expected-note {{consider adding the explicit keyword to the constructor}} + Foo(int, char=0); // expected-error {{bad implicit conversion constructor for 'Foo'}} expected-note {{consider adding the explicit keyword to the constructor}} + Foo(...); // expected-error {{bad implicit conversion constructor for 'Foo'}} expected-note {{consider adding the explicit keyword to the constructor}} + template + Foo(float); // expected-error {{bad implicit conversion constructor for 'Foo'}} expected-note {{consider adding the explicit keyword to the constructor}} + Foo(int, unsigned); + Foo(Foo&); + Foo(const Foo&); + Foo(volatile Foo&); + Foo(const volatile Foo&); + Foo(Foo&&); + Foo(const Foo&&); + Foo(volatile Foo&&); + Foo(const volatile Foo&&); +}; + +struct Bar { + explicit Bar(int); + explicit Bar(int, char=0); + explicit Bar(...); +}; + +struct Baz { + MOZ_IMPLICIT Baz(int); + MOZ_IMPLICIT Baz(int, char=0); + MOZ_IMPLICIT Baz(...); +}; + +struct Barn { + Barn(int) = delete; + Barn(int, char=0) = delete; + Barn(...) = delete; +}; + +struct Abstract { + Abstract(int); + Abstract(int, char=0); + Abstract(...); + virtual void f() = 0; +}; + +template +struct Template { + Template(int); // expected-error {{bad implicit conversion constructor for 'Template'}} expected-note {{consider adding the explicit keyword to the constructor}} + template + Template(float); // expected-error {{bad implicit conversion constructor for 'Template'}} expected-note {{consider adding the explicit keyword to the constructor}} +}; diff --git a/build/clang-plugin/tests/TestCanRunScript.cpp b/build/clang-plugin/tests/TestCanRunScript.cpp new file mode 100644 index 0000000000..28795a31bf --- /dev/null +++ b/build/clang-plugin/tests/TestCanRunScript.cpp @@ -0,0 +1,881 @@ +#include +#include + +#define MOZ_CAN_RUN_SCRIPT __attribute__((annotate("moz_can_run_script"))) +#define MOZ_CAN_RUN_SCRIPT_BOUNDARY __attribute__((annotate("moz_can_run_script_boundary"))) + +MOZ_CAN_RUN_SCRIPT void test() { + +} + +void test_parent() { // expected-note {{caller function declared here}} + test(); // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT can only be called from functions also marked as MOZ_CAN_RUN_SCRIPT}} +} + +MOZ_CAN_RUN_SCRIPT void test_parent2() { + test(); +} + +struct RefCountedBase; +MOZ_CAN_RUN_SCRIPT void test2(RefCountedBase* param) { + +} + +struct RefCountedBase { + void AddRef(); + void Release(); + + MOZ_CAN_RUN_SCRIPT void method_test() { + test(); + } + + MOZ_CAN_RUN_SCRIPT void method_test2() { + test2(this); + } + + virtual void method_test3() { // expected-note {{caller function declared here}} + test(); // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT can only be called from functions also marked as MOZ_CAN_RUN_SCRIPT}} + } + + MOZ_CAN_RUN_SCRIPT void method_test4() { + method_test(); + } + + MOZ_CAN_RUN_SCRIPT void method_test5() { + this->method_test(); + } +}; + +MOZ_CAN_RUN_SCRIPT void testLambda() { + auto doIt = []() MOZ_CAN_RUN_SCRIPT { + test(); + }; + + auto doItWrong = []() { // expected-note {{caller function declared here}} + test(); // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT can only be called from functions also marked as MOZ_CAN_RUN_SCRIPT}} + }; + + doIt(); + doItWrong(); +} + +void test2_parent() { // expected-note {{caller function declared here}} + test2(new RefCountedBase); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'new RefCountedBase' is neither.}} \ + // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT can only be called from functions also marked as MOZ_CAN_RUN_SCRIPT}} +} + +MOZ_CAN_RUN_SCRIPT void test2_parent2() { + test2(new RefCountedBase); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'new RefCountedBase' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test2_parent3(RefCountedBase* param) { + test2(param); + + RefCountedBase*& paramRef = param; + test2(paramRef); +} + +MOZ_CAN_RUN_SCRIPT void test2_parent4() { + RefPtr refptr = new RefCountedBase; + test2(refptr); + RefPtr& refptrRef = refptr; + test2(refptrRef); + const RefPtr& refptrConstRef = refptr; + test2(refptrConstRef); + + RefPtr refptrOther = refptr; + RefPtr& refptrRef2 = refptr ? refptr : refptrOther; + test2(refptrRef2); + + RefPtr* refPtrInHeap = new RefPtr; + RefPtr& refptrRefUnsafe1 = *refPtrInHeap; + test2(refptrRefUnsafe1); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe1' is neither.}} + + RefPtr& refptrRefUnsafe2 = refPtrInHeap ? *refPtrInHeap : refptr; + test2(refptrRefUnsafe2); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe2' is neither.}} + + RefPtr& refptrRefUnsafe3 = refPtrInHeap ? refptr : *refPtrInHeap; + test2(refptrRefUnsafe3); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe3' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test2_parent5() { + test2(MOZ_KnownLive(new RefCountedBase)); +} + +MOZ_CAN_RUN_SCRIPT void test2_parent6() { + RefPtr refptr = new RefCountedBase; + refptr->method_test(); + refptr->method_test2(); + RefPtr& refptrRef = refptr; + refptrRef->method_test(); + refptrRef->method_test2(); + + RefPtr refptrOther = refptr; + RefPtr& refptrRef2 = refptr ? refptr : refptrOther; + refptrRef2->method_test(); + refptrRef2->method_test2(); + + RefPtr* refPtrInHeap = new RefPtr; + RefPtr& refptrRefUnsafe1 = *refPtrInHeap; + refptrRefUnsafe1->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe1->' is neither.}} + refptrRefUnsafe1->method_test2(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe1->' is neither.}} + + RefPtr& refptrRefUnsafe2 = refPtrInHeap ? *refPtrInHeap : refptr; + refptrRefUnsafe2->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe2->' is neither.}} + refptrRefUnsafe2->method_test2(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe2->' is neither.}} + + RefPtr& refptrRefUnsafe3 = refPtrInHeap ? refptr : *refPtrInHeap; + refptrRefUnsafe3->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe3->' is neither.}} + refptrRefUnsafe3->method_test2(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe3->' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test2_parent7() { + RefCountedBase* t = new RefCountedBase; + t->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 't' is neither.}} + t->method_test2(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 't' is neither.}} + + RefCountedBase*& tRef = t; + tRef->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'tRef' is neither.}} + tRef->method_test2(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'tRef' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test2_parent8() { + test2(nullptr); +} + +MOZ_CAN_RUN_SCRIPT void test3(int* param) {} + +MOZ_CAN_RUN_SCRIPT void test3_parent() { + test3(new int); +} + +struct RefCountedChild : public RefCountedBase { + virtual void method_test3() override; // expected-note {{overridden function declared here}} expected-note {{overridden function declared here}} expected-note {{caller function declared here}} +}; + +void RefCountedChild::method_test3() { + test(); // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT can only be called from functions also marked as MOZ_CAN_RUN_SCRIPT}} +} + +struct RefCountedSubChild : public RefCountedChild { + MOZ_CAN_RUN_SCRIPT void method_test3() override; // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT cannot override functions that are not marked MOZ_CAN_RUN_SCRIPT}} +}; + +void RefCountedSubChild::method_test3() { // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT cannot override functions that are not marked MOZ_CAN_RUN_SCRIPT}} + test(); +} + +MOZ_CAN_RUN_SCRIPT void test4() { + RefPtr refptr1 = new RefCountedChild; + refptr1->method_test3(); + + RefPtr refptr2 = new RefCountedSubChild; + refptr2->method_test3(); + + RefPtr refptr3 = new RefCountedSubChild; + refptr3->method_test3(); + + RefPtr refptr4 = new RefCountedSubChild; + refptr4->method_test3(); +} + +MOZ_CAN_RUN_SCRIPT_BOUNDARY void test5() { + RefPtr refptr1 = new RefCountedChild; + refptr1->method_test3(); + + RefPtr refptr2 = new RefCountedSubChild; + refptr2->method_test3(); + + RefPtr refptr3 = new RefCountedSubChild; + refptr3->method_test3(); + + RefPtr refptr4 = new RefCountedSubChild; + refptr4->method_test3(); +} + +// We should be able to call test5 from a non-can_run_script function. +void test5_b() { + test5(); +} + +MOZ_CAN_RUN_SCRIPT void test6() { + void* x = new RefCountedBase(); + test2((RefCountedBase*)x); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'x' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_ref(const RefCountedBase&) { + +} + +MOZ_CAN_RUN_SCRIPT void test_ref_1() { + RefCountedBase* t = new RefCountedBase; + test_ref(*t); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*t' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_ref_2() { + RefCountedBase* t = new RefCountedBase; + (*t).method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*t' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_ref_3() { + RefCountedBase* t = new RefCountedBase; + auto& ref = *t; + test_ref(ref); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'ref' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_ref_4() { + RefCountedBase* t = new RefCountedBase; + auto& ref = *t; + ref.method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'ref' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_ref_5() { + RefPtr t = new RefCountedBase; + test_ref(*t); +} + +MOZ_CAN_RUN_SCRIPT void test_ref_6() { + RefPtr t = new RefCountedBase; + (*t).method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ref_7() { + RefPtr t = new RefCountedBase; + auto& ref = *t; + MOZ_KnownLive(ref).method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ref_8() { + RefPtr t = new RefCountedBase; + auto& ref = *t; + test_ref(MOZ_KnownLive(ref)); +} + +MOZ_CAN_RUN_SCRIPT void test_ref_9() { + void* x = new RefCountedBase(); + test_ref(*(RefCountedBase*)x); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*(RefCountedBase*)x' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_maybe() { + mozilla::Maybe unsafe; + unsafe.emplace(new RefCountedBase); + (*unsafe)->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*unsafe' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_maybe_2() { + // FIXME(bz): This should not generate an error! + mozilla::Maybe> safe; + safe.emplace(new RefCountedBase); + (*safe)->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '(*safe){{(->)?}}' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_helper_1(RefCountedBase* arg = nullptr) { +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_1() { + test_defaults_helper_1(); +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_2() { + RefCountedBase* t = new RefCountedBase; + test_defaults_helper_1(t); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 't' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_3() { + RefPtr t = new RefCountedBase; + test_defaults_helper_1(t); +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_helper_2(RefCountedBase* arg = new RefCountedBase()) { // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'new RefCountedBase()' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_4() { + test_defaults_helper_2(); +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_5() { + RefCountedBase* t = new RefCountedBase; + test_defaults_helper_2(t); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 't' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_6() { + RefPtr t = new RefCountedBase; + test_defaults_helper_2(t); +} + +MOZ_CAN_RUN_SCRIPT void test_arg_deref_helper(RefCountedBase&) { +} + +MOZ_CAN_RUN_SCRIPT void test_arg_deref(RefCountedBase* arg) { + test_arg_deref_helper(*arg); +} + +struct RefCountedDerefTester : public RefCountedBase { + MOZ_CAN_RUN_SCRIPT void foo() { + test_arg_deref_helper(*this); + } +}; + +struct DisallowMemberArgs { + RefPtr mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + mRefCounted->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mRefCounted{{(->)?}}' is neither.}} + + RefPtr& unsafeMemberRef = mRefCounted; + unsafeMemberRef->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'unsafeMemberRef{{(->)?}}' is neither.}} + + RefPtr safeRefCounted = mRefCounted; + RefPtr& maybeUnsafeMemberRef1 = mRefCounted ? mRefCounted : safeRefCounted; + maybeUnsafeMemberRef1->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef1{{(->)?}}' is neither.}} + RefPtr& maybeUnsafeMemberRef2 = safeRefCounted ? safeRefCounted : mRefCounted; + maybeUnsafeMemberRef2->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef2{{(->)?}}' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mRefCounted); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mRefCounted' is neither.}} + + RefPtr& unsafeMemberRef = mRefCounted; + test2(unsafeMemberRef); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'unsafeMemberRef' is neither.}} + + RefPtr safeRefCounted = mRefCounted; + RefPtr& maybeUnsafeMemberRef1 = mRefCounted ? mRefCounted : safeRefCounted; + test2(maybeUnsafeMemberRef1); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef1' is neither.}} + RefPtr& maybeUnsafeMemberRef2 = safeRefCounted ? safeRefCounted : mRefCounted; + test2(maybeUnsafeMemberRef2); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef2' is neither.}} + } +}; + +struct DisallowMemberArgsWithGet { + RefPtr mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + mRefCounted.get()->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mRefCounted.get()' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mRefCounted.get()); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mRefCounted.get()' is neither.}} + } +}; + +struct AllowKnownLiveMemberArgs { + RefPtr mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + MOZ_KnownLive(mRefCounted)->method_test(); + + RefPtr& unsafeMemberRef = mRefCounted; + MOZ_KnownLive(unsafeMemberRef)->method_test(); + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(MOZ_KnownLive(mRefCounted)); + + RefPtr& unsafeMemberRef = mRefCounted; + test2(MOZ_KnownLive(unsafeMemberRef)); + } +}; + +struct WeakPtrReturner : public RefCountedBase { + RefCountedBase* getWeakPtr() { return new RefCountedBase(); } +}; + +struct DisallowMemberCallsOnRandomKnownLive { + RefPtr mWeakPtrReturner1; + WeakPtrReturner* mWeakPtrReturner2; + + MOZ_CAN_RUN_SCRIPT void test_refptr_method() { + MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()' is neither.}} + } + + MOZ_CAN_RUN_SCRIPT void test_refptr_function() { + test2(MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()' is neither.}} + } + + MOZ_CAN_RUN_SCRIPT void test_raw_method() { + MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()' is neither.}} + } + + MOZ_CAN_RUN_SCRIPT void test_raw_function() { + test2(MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()' is neither.}} + } +}; + +struct AllowConstMemberArgs { + const RefPtr mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + mRefCounted->method_test(); + + const RefPtr& safeMemberRef1 = mRefCounted; + safeMemberRef1->method_test(); + + const RefPtr safeRefCounted = new RefCountedBase; + const RefPtr& safeMemberRef2 = safeRefCounted ? safeRefCounted : mRefCounted; + safeMemberRef2->method_test(); + const RefPtr& safeMemberRef3 = mRefCounted ? mRefCounted : safeRefCounted; + safeMemberRef3->method_test(); + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mRefCounted); + + const RefPtr& safeMemberRef1 = mRefCounted; + test2(safeMemberRef1); + + const RefPtr safeRefCounted = new RefCountedBase; + const RefPtr& safeMemberRef2 = safeRefCounted ? safeRefCounted : mRefCounted; + test2(safeMemberRef2); + const RefPtr& safeMemberRef3 = mRefCounted ? mRefCounted : safeRefCounted; + test2(safeMemberRef3); + } +}; + +struct AllowConstMemberArgsWithExplicitThis { + const RefPtr mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + this->mRefCounted->method_test(); + + const RefPtr& safeMemberRef1 = this->mRefCounted; + safeMemberRef1->method_test(); + + const RefPtr safeRefCounted = new RefCountedBase; + const RefPtr& safeMemberRef2 = safeRefCounted ? safeRefCounted : this->mRefCounted; + safeMemberRef2->method_test(); + const RefPtr& safeMemberRef3 = this->mRefCounted ? this->mRefCounted : safeRefCounted; + safeMemberRef3->method_test(); + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(this->mRefCounted); + + const RefPtr& safeMemberRef1 = this->mRefCounted; + test2(safeMemberRef1); + + const RefPtr safeRefCounted = new RefCountedBase; + const RefPtr& safeMemberRef2 = safeRefCounted ? safeRefCounted : this->mRefCounted; + test2(safeMemberRef2); + const RefPtr& safeMemberRef3 = this->mRefCounted ? this->mRefCounted : safeRefCounted; + test2(safeMemberRef3); + } +}; + +struct DisallowConstMemberArgsOfMembers { + RefPtr mMember; + MOZ_CAN_RUN_SCRIPT void foo() { + mMember->mRefCounted->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mMember->mRefCounted{{(->)?}}' is neither.}} + + const RefPtr& unsafeMemberRef = mMember->mRefCounted; + unsafeMemberRef->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'unsafeMemberRef{{(->)?}}' is neither.}} + + const RefPtr safeRefCounted = new RefCountedBase; + const RefPtr& maybeUnsafeMemberRef1 = safeRefCounted ? safeRefCounted : mMember->mRefCounted; + maybeUnsafeMemberRef1->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef1{{(->)?}}' is neither.}} + const RefPtr& maybeUnsafeMemberRef2 = mMember->mRefCounted ? mMember->mRefCounted : safeRefCounted; + maybeUnsafeMemberRef2->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef2{{(->)?}}' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mMember->mRefCounted); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mMember->mRefCounted' is neither.}} + + const RefPtr& unsafeMemberRef = mMember->mRefCounted; + test2(unsafeMemberRef); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'unsafeMemberRef' is neither.}} + + const RefPtr safeRefCounted = new RefCountedBase; + const RefPtr& maybeUnsafeMemberRef1 = safeRefCounted ? safeRefCounted : mMember->mRefCounted; + test2(maybeUnsafeMemberRef1); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef1' is neither.}} + const RefPtr& maybeUnsafeMemberRef2 = mMember->mRefCounted ? mMember->mRefCounted : safeRefCounted; + test2(maybeUnsafeMemberRef2); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef2' is neither.}} + } +}; + +struct DisallowConstNonRefPtrMemberArgs { + RefCountedBase* const mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + mRefCounted->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mRefCounted' is neither.}} + + RefCountedBase* const& unsafeMemberRefCounted = mRefCounted; + unsafeMemberRefCounted->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'unsafeMemberRefCounted' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mRefCounted); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mRefCounted' is neither.}} + + RefCountedBase* const& unsafeMemberRefCounted = mRefCounted; + test2(unsafeMemberRefCounted); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'unsafeMemberRefCounted' is neither.}} + } +}; + +MOZ_CAN_RUN_SCRIPT void test_temporary_1() { +#ifdef MOZ_CLANG_PLUGIN_ALPHA + RefPtr(new RefCountedBase())->method_test(); // expected-warning {{performance issue: temporary 'RefPtr' is only dereferenced here once which involves short-lived AddRef/Release calls}} +#else + RefPtr(new RefCountedBase())->method_test(); +#endif +} + +MOZ_CAN_RUN_SCRIPT void test_temporary_2() { + test_ref(*RefPtr(new RefCountedBase())); +} + +struct WeakSmartPtr { + RefCountedBase* member; + + explicit WeakSmartPtr(RefCountedBase* arg) : member(arg) {} + + RefCountedBase* operator->() const { + return member; + } + + RefCountedBase& operator*() const { + return *member; + } + + operator RefCountedBase*() const { + return member; + } +}; + +MOZ_CAN_RUN_SCRIPT void test_temporary_3() { + WeakSmartPtr(new RefCountedBase())->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'WeakSmartPtr(new RefCountedBase()){{(->)?}}' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_temporary_4() { + test_ref(*WeakSmartPtr(new RefCountedBase())); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*WeakSmartPtr(new RefCountedBase())' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_temporary_5() { + test2(WeakSmartPtr(new RefCountedBase())); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'WeakSmartPtr(new RefCountedBase())' is neither.}} +} + + +template +struct TArray { + TArray() { + mArray[0] = new RefCountedBase(); + } + T& operator[](unsigned int index) { return mArray[index]; } + T mArray[1]; +}; + +struct DisallowRawTArrayElement { + TArray mArray; + MOZ_CAN_RUN_SCRIPT void foo() { + mArray[0]->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mArray[0]' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mArray[0]); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mArray[0]' is neither.}} + } +}; + +struct DisallowRefPtrTArrayElement { + TArray> mArray; + MOZ_CAN_RUN_SCRIPT void foo() { + mArray[0]->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mArray[0]{{(->)?}}' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mArray[0]); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mArray[0]' is neither.}} + } +}; + +struct AllowConstexprMembers { + static constexpr RefCountedBase* mRefCounted = nullptr; + static constexpr RefCountedBase* mRefCounted2 = nullptr; + MOZ_CAN_RUN_SCRIPT void foo() { + mRefCounted->method_test(); + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mRefCounted); + } + MOZ_CAN_RUN_SCRIPT void baz() { + test_ref(*mRefCounted); + } +}; + +MOZ_CAN_RUN_SCRIPT void test_constexpr_1() { + AllowConstexprMembers::mRefCounted->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_constexpr_2() { + test2(AllowConstexprMembers::mRefCounted); +} + +MOZ_CAN_RUN_SCRIPT void test_constexpr_3() { + test_ref(*AllowConstexprMembers::mRefCounted); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_1(RefCountedBase* arg1, RefCountedBase* arg2) { + (arg1 ? arg1 : arg2)->method_test(); + RefCountedBase*& safeArg = arg1 ? arg1 : arg2; + safeArg->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_2(RefCountedBase* arg1, RefCountedBase* arg2) { + test2(arg1 ? arg1 : arg2); + RefCountedBase*& safeArg = arg1 ? arg1 : arg2; + test2(safeArg); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_3(RefCountedBase* arg1, RefCountedBase& arg2) { + (arg1 ? *arg1 : arg2).method_test(); + RefCountedBase& safeArg = arg1 ? *arg1 : arg2; + safeArg.method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_4(RefCountedBase* arg1, RefCountedBase& arg2) { + test_ref(arg1 ? *arg1 : arg2); + RefCountedBase& safeArg = arg1 ? *arg1 : arg2; + test_ref(safeArg); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_5(RefCountedBase* arg) { + RefPtr local = new RefCountedBase(); + (arg ? arg : local.get())->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_6(RefCountedBase* arg) { + RefPtr local = new RefCountedBase(); + test2(arg ? arg : local.get()); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_7(RefCountedBase* arg) { + RefPtr local = new RefCountedBase(); + (arg ? *arg : *local).method_test(); + RefCountedBase& safeArgOrLocal = arg ? *arg : *local; + safeArgOrLocal.method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_8(RefCountedBase* arg) { + RefPtr local = new RefCountedBase(); + test_ref(arg ? *arg : *local); + RefCountedBase& safeArgOrLocal = arg ? *arg : *local; + test_ref(safeArgOrLocal); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_9(RefCountedBase* arg) { + (arg ? arg : AllowConstexprMembers::mRefCounted)->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_10(RefCountedBase* arg) { + test2(arg ? arg : AllowConstexprMembers::mRefCounted); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_11(RefCountedBase* arg) { + (arg ? *arg : *AllowConstexprMembers::mRefCounted).method_test(); + RefCountedBase& safeArgOrMember = arg ? *arg : *AllowConstexprMembers::mRefCounted; + safeArgOrMember.method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_12(RefCountedBase* arg) { + test_ref(arg ? *arg : *AllowConstexprMembers::mRefCounted); + RefCountedBase& safeArgOrMember = arg ? *arg : *AllowConstexprMembers::mRefCounted; + test_ref(safeArgOrMember); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_13(RefCountedBase* arg1, RefCountedBase& arg2) { + (arg1 ? arg1 : &arg2)->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_44(RefCountedBase* arg1, RefCountedBase& arg2) { + test2(arg1 ? arg1 : &arg2); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_13(bool arg) { + (arg ? + AllowConstexprMembers::mRefCounted : + AllowConstexprMembers::mRefCounted2)->method_test(); + RefCountedBase* const& safeConstexprMember = arg ? AllowConstexprMembers::mRefCounted : AllowConstexprMembers::mRefCounted2; + safeConstexprMember->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_14(bool arg) { + test2(arg ? + AllowConstexprMembers::mRefCounted : + AllowConstexprMembers::mRefCounted2); + RefCountedBase* const& safeConstexprMember = arg ? AllowConstexprMembers::mRefCounted : AllowConstexprMembers::mRefCounted2; + test2(safeConstexprMember); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_15(bool arg) { + (arg ? + *AllowConstexprMembers::mRefCounted : + *AllowConstexprMembers::mRefCounted2).method_test(); + RefCountedBase& safeConstexprMember = arg ? *AllowConstexprMembers::mRefCounted : *AllowConstexprMembers::mRefCounted2; + safeConstexprMember.method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_16(bool arg) { + test_ref(arg ? + *AllowConstexprMembers::mRefCounted : + *AllowConstexprMembers::mRefCounted2); + RefCountedBase& safeConstexprMember = arg ? *AllowConstexprMembers::mRefCounted : *AllowConstexprMembers::mRefCounted2; + test_ref(safeConstexprMember); +} + +MOZ_CAN_RUN_SCRIPT void test_pointer_to_ref_1(RefCountedBase& arg) { + (&arg)->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_pointer_to_ref_2(RefCountedBase& arg) { + test2(&arg); +} + +struct DisallowMemberArgsViaReferenceAlias { + RefPtr mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + RefPtr& bogus = mRefCounted; + bogus->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'bogus{{(->)?}}' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + RefPtr& bogus = mRefCounted; + test2(bogus); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'bogus' is neither.}} + } +}; + +struct DisallowMemberArgsViaReferenceAlias2 { + RefPtr mRefCountedArr[2]; + MOZ_CAN_RUN_SCRIPT void foo1() { + for (RefPtr& item : mRefCountedArr) { + item->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'item{{(->)?}}' is neither.}} + } + } + MOZ_CAN_RUN_SCRIPT void foo2() { + for (auto& item : mRefCountedArr) { + item->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'item{{(->)?}}' is neither.}} + } + } + MOZ_CAN_RUN_SCRIPT void foo3() { + for (RefPtr item : mRefCountedArr) { + item->method_test(); + } + } + MOZ_CAN_RUN_SCRIPT void foo4() { + for (auto item : mRefCountedArr) { + item->method_test(); + } + } + MOZ_CAN_RUN_SCRIPT void bar1() { + for (RefPtr& item : mRefCountedArr) { + test2(item); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'item' is neither.}} + } + } + MOZ_CAN_RUN_SCRIPT void bar2() { + for (auto& item : mRefCountedArr) { + test2(item); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'item' is neither.}} + } + } + MOZ_CAN_RUN_SCRIPT void bar3() { + for (RefPtr item : mRefCountedArr) { + test2(item); + } + } + MOZ_CAN_RUN_SCRIPT void bar4() { + for (auto item : mRefCountedArr) { + test2(item); + } + } +}; + +struct AllowMozKnownLiveMember { +public: + MOZ_KNOWN_LIVE RefCountedBase* mWhatever; + MOZ_KNOWN_LIVE RefPtr mRefCountedWhatever; + MOZ_CAN_RUN_SCRIPT void fooPtr(RefCountedBase* aWhatever) {} + MOZ_CAN_RUN_SCRIPT void fooRef(RefCountedBase& aWhatever) {} + MOZ_CAN_RUN_SCRIPT void bar() { + fooPtr(mWhatever); + fooRef(*mWhatever); + fooPtr(mRefCountedWhatever); + fooRef(*mRefCountedWhatever); + + RefCountedBase*& whateverRef = mWhatever; + fooPtr(whateverRef); + fooRef(*whateverRef); + RefPtr& refCountedWhateverRef = mRefCountedWhatever; + fooPtr(refCountedWhateverRef); + fooRef(*refCountedWhateverRef); + } +}; + +struct AllowMozKnownLiveMemberParent : AllowMozKnownLiveMember { + MOZ_CAN_RUN_SCRIPT void baz() { + fooPtr(mWhatever); + fooRef(*mWhatever); + fooPtr(mRefCountedWhatever); + fooRef(*mRefCountedWhatever); + + RefCountedBase*& whateverRef = mWhatever; + fooPtr(whateverRef); + fooRef(*whateverRef); + RefPtr& refCountedWhateverRef = mRefCountedWhatever; + fooPtr(refCountedWhateverRef); + fooRef(*refCountedWhateverRef); + } +}; + +struct AllowMozKnownLiveParamMember { +public: + MOZ_CAN_RUN_SCRIPT void foo(AllowMozKnownLiveMember& aAllow) { + aAllow.fooPtr(aAllow.mWhatever); + aAllow.fooRef(*aAllow.mWhatever); + aAllow.fooPtr(aAllow.mRefCountedWhatever); + aAllow.fooRef(*aAllow.mRefCountedWhatever); + + RefCountedBase*& whateverRef = aAllow.mWhatever; + aAllow.fooPtr(whateverRef); + aAllow.fooRef(*whateverRef); + RefPtr& refCountedWhateverRef = aAllow.mRefCountedWhatever; + aAllow.fooPtr(refCountedWhateverRef); + aAllow.fooRef(*refCountedWhateverRef); + } + MOZ_CAN_RUN_SCRIPT void bar(AllowMozKnownLiveMemberParent& aAllowParent) { + aAllowParent.fooPtr(aAllowParent.mWhatever); + aAllowParent.fooRef(*aAllowParent.mWhatever); + aAllowParent.fooPtr(aAllowParent.mRefCountedWhatever); + aAllowParent.fooRef(*aAllowParent.mRefCountedWhatever); + + RefCountedBase*& whateverRef = aAllowParent.mWhatever; + aAllowParent.fooPtr(whateverRef); + aAllowParent.fooRef(*whateverRef); + RefPtr& refCountedWhateverRef = aAllowParent.mRefCountedWhatever; + aAllowParent.fooPtr(refCountedWhateverRef); + aAllowParent.fooRef(*refCountedWhateverRef); + } +}; + +MOZ_CAN_RUN_SCRIPT void AllowMozKnownLiveMemberInAutoStorage() { + AllowMozKnownLiveMember inStack; + AllowMozKnownLiveMember* inHeap = new AllowMozKnownLiveMember(); + inStack.fooPtr(inStack.mWhatever); + inStack.fooRef(*inStack.mWhatever); + inStack.fooPtr(inStack.mRefCountedWhatever); + inStack.fooRef(*inStack.mRefCountedWhatever); + RefCountedBase*& whateverRefInStack = inStack.mWhatever; + inStack.fooPtr(whateverRefInStack); + inStack.fooRef(*whateverRefInStack); + RefPtr& refCountedWhateverRefInStack = inStack.mRefCountedWhatever; + inStack.fooPtr(refCountedWhateverRefInStack); + inStack.fooRef(*refCountedWhateverRefInStack); + + inStack.fooPtr(inHeap->mWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'inHeap->mWhatever' is neither.}} + inStack.fooRef(*inHeap->mWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*inHeap->mWhatever' is neither.}} + inStack.fooPtr(inHeap->mRefCountedWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'inHeap->mRefCountedWhatever' is neither.}} + inStack.fooRef(*inHeap->mRefCountedWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*inHeap->mRefCountedWhatever' is neither.}} + RefCountedBase*& whateverRefInHeap = inHeap->mWhatever; + inStack.fooPtr(whateverRefInHeap); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'whateverRefInHeap' is neither.}} + inStack.fooRef(*whateverRefInHeap); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*whateverRefInHeap' is neither.}} + RefPtr& refCountedWhateverRefInHeap = inHeap->mRefCountedWhatever; + inStack.fooPtr(refCountedWhateverRefInHeap); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refCountedWhateverRefInHeap' is neither.}} + inStack.fooRef(*refCountedWhateverRefInHeap); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*refCountedWhateverRefInHeap' is neither.}} +} + +struct DisallowMozKnownLiveMemberNotFromKnownLive { + AllowMozKnownLiveMember* mMember; + MOZ_CAN_RUN_SCRIPT void fooPtr(RefCountedBase* aWhatever) {} + MOZ_CAN_RUN_SCRIPT void fooRef(RefCountedBase& aWhatever) {} + MOZ_CAN_RUN_SCRIPT void bar() { + fooPtr(mMember->mWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mMember->mWhatever' is neither.}} + fooRef(*mMember->mWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*mMember->mWhatever' is neither.}} + fooPtr(mMember->mRefCountedWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mMember->mRefCountedWhatever' is neither.}} + fooRef(*mMember->mRefCountedWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*mMember->mRefCountedWhatever' is neither.}} + RefCountedBase*& whateverRef = mMember->mWhatever; + fooPtr(whateverRef); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'whateverRef' is neither.}} + fooRef(*whateverRef); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*whateverRef' is neither.}} + RefPtr& refCountedWhateverRef = mMember->mRefCountedWhatever; + fooPtr(refCountedWhateverRef); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refCountedWhateverRef' is neither.}} + fooRef(*refCountedWhateverRef); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*refCountedWhateverRef' is neither.}} + } +}; + +void IncorrectlyUnmarkedEarlyDeclaration(); // expected-note {{The first declaration exists here}} + +MOZ_CAN_RUN_SCRIPT void IncorrectlyUnmarkedEarlyDeclaration() {}; // expected-error {{MOZ_CAN_RUN_SCRIPT must be put in front of the declaration, not the definition}} diff --git a/build/clang-plugin/tests/TestCustomHeap.cpp b/build/clang-plugin/tests/TestCustomHeap.cpp new file mode 100644 index 0000000000..c1e82f2fa7 --- /dev/null +++ b/build/clang-plugin/tests/TestCustomHeap.cpp @@ -0,0 +1,29 @@ +#define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class"))) +#ifndef MOZ_HEAP_ALLOCATOR +#define MOZ_HEAP_ALLOCATOR \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((annotate("moz_heap_allocator"))) \ + _Pragma("GCC diagnostic pop") +#endif + +#include +#include + +struct MOZ_NONHEAP_CLASS X { +}; + +void *operator new(size_t x, int qual) MOZ_HEAP_ALLOCATOR { + return ::operator new(x); +} + +template +T *customAlloc() MOZ_HEAP_ALLOCATOR { + T *arg = static_cast(malloc(sizeof(T))); + return new (arg) T(); +} + +void misuseX() { + X *foo = customAlloc(); // expected-error {{variable of type 'X' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + X *foo2 = new (100) X(); // expected-error {{variable of type 'X' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} +} diff --git a/build/clang-plugin/tests/TestDanglingOnTemporary.cpp b/build/clang-plugin/tests/TestDanglingOnTemporary.cpp new file mode 100644 index 0000000000..62a7755ece --- /dev/null +++ b/build/clang-plugin/tests/TestDanglingOnTemporary.cpp @@ -0,0 +1,45 @@ +#define MOZ_NO_DANGLING_ON_TEMPORARIES \ + __attribute__((annotate("moz_no_dangling_on_temporaries"))) + +class AnnotateConflict { + MOZ_NO_DANGLING_ON_TEMPORARIES int *get() && { return nullptr; } // expected-error {{methods annotated with MOZ_NO_DANGLING_ON_TEMPORARIES cannot be && ref-qualified}} + MOZ_NO_DANGLING_ON_TEMPORARIES int test() { return 0; } // expected-error {{methods annotated with MOZ_NO_DANGLING_ON_TEMPORARIES must return a pointer}} +}; + +class NS_ConvertUTF8toUTF16 { +public: + MOZ_NO_DANGLING_ON_TEMPORARIES int *get() { return nullptr; } + operator int*() + { + return get(); // This should be ignored because the call is implcitly on this + } +}; + +NS_ConvertUTF8toUTF16 TemporaryFunction() { return NS_ConvertUTF8toUTF16(); } + +void UndefinedFunction(int* test); + +void NoEscapeFunction(int *test) {} + +int *glob; // expected-note {{through the variable declared here}} +void EscapeFunction1(int *test) { glob = test; } // expected-note {{the raw pointer escapes the function scope here}} + +void EscapeFunction2(int *test, int *&escape) { escape = test; } // expected-note {{the raw pointer escapes the function scope here}} \ + expected-note {{through the parameter declared here}} + +int *EscapeFunction3(int *test) { return test; } // expected-note {{the raw pointer escapes the function scope here}} \ + expected-note {{through the return value of the function declared here}} + +int main() { + int *test = TemporaryFunction().get(); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}} + int *test2 = NS_ConvertUTF8toUTF16().get(); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}} + + UndefinedFunction(NS_ConvertUTF8toUTF16().get()); + + NoEscapeFunction(TemporaryFunction().get()); + EscapeFunction1(TemporaryFunction().get()); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}} + + int *escape; + EscapeFunction2(TemporaryFunction().get(), escape); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}} + int *escape2 = EscapeFunction3(TemporaryFunction().get()); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}} +} diff --git a/build/clang-plugin/tests/TestExplicitOperatorBool.cpp b/build/clang-plugin/tests/TestExplicitOperatorBool.cpp new file mode 100644 index 0000000000..bc4b43a7d0 --- /dev/null +++ b/build/clang-plugin/tests/TestExplicitOperatorBool.cpp @@ -0,0 +1,11 @@ +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +struct Bad { + operator bool(); // expected-error {{bad implicit conversion operator for 'Bad'}} expected-note {{consider adding the explicit keyword to 'operator bool'}} +}; +struct Good { + explicit operator bool(); +}; +struct Okay { + MOZ_IMPLICIT operator bool(); +}; diff --git a/build/clang-plugin/tests/TestFopenUsage.cpp b/build/clang-plugin/tests/TestFopenUsage.cpp new file mode 100644 index 0000000000..19a89f88c9 --- /dev/null +++ b/build/clang-plugin/tests/TestFopenUsage.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include + +void func_fopen() { + FILE *f1 = fopen("dummy.txt", "rt"); // expected-warning {{Usage of ASCII file functions (here fopen) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + FILE *f2; + fopen_s(&f2, "dummy.txt", "rt"); // expected-warning {{Usage of ASCII file functions (here fopen_s) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + + int fh1 = _open("dummy.txt", _O_RDONLY); // expected-warning {{Usage of ASCII file functions (here _open) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + int fh2 = open("dummy.txt", _O_RDONLY); // expected-warning {{Usage of ASCII file functions (here open) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + int fh3 = _sopen("dummy.txt", _O_RDONLY, _SH_DENYRW); // expected-warning {{Usage of ASCII file functions (here _sopen) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + int fd4; + errno_t err = _sopen_s(&fd4, "dummy.txt", _O_RDONLY, _SH_DENYRW, 0); // expected-warning {{Usage of ASCII file functions (here _sopen_s) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + + std::fstream fs1; + fs1.open("dummy.txt"); // expected-warning {{Usage of ASCII file functions (here open) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + std::ifstream ifs1; + ifs1.open("dummy.txt"); // expected-warning {{Usage of ASCII file functions (here open) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + std::ofstream ofs1; + ofs1.open("dummy.txt"); // expected-warning {{Usage of ASCII file functions (here open) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} +#ifdef _MSC_VER + std::fstream fs2; + fs2.open(L"dummy.txt"); + std::ifstream ifs2; + ifs2.open(L"dummy.txt"); + std::ofstream ofs2; + ofs2.open(L"dummy.txt"); +#endif + + LPOFSTRUCT buffer; + HFILE hFile1 = OpenFile("dummy.txt", buffer, OF_READ); // expected-warning {{Usage of ASCII file functions (here OpenFile) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + +#ifndef UNICODE + // CreateFile is just an alias of CreateFileA + LPCSTR buffer2; + HANDLE hFile2 = CreateFile(buffer2, GENERIC_WRITE, 0, NULL, CREATE_NEW, // expected-warning {{Usage of ASCII file functions (here CreateFileA) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + FILE_ATTRIBUTE_NORMAL, NULL); +#else + // CreateFile is just an alias of CreateFileW and should not be matched + LPCWSTR buffer2; + HANDLE hFile2 = CreateFile(buffer2, GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); +#endif + LPCSTR buffer3; + HANDLE hFile3 = CreateFileA(buffer3, GENERIC_WRITE, 0, NULL, CREATE_NEW, // expected-warning {{Usage of ASCII file functions (here CreateFileA) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + FILE_ATTRIBUTE_NORMAL, NULL); +} diff --git a/build/clang-plugin/tests/TestGlobalClass.cpp b/build/clang-plugin/tests/TestGlobalClass.cpp new file mode 100644 index 0000000000..7ce9c8d463 --- /dev/null +++ b/build/clang-plugin/tests/TestGlobalClass.cpp @@ -0,0 +1,52 @@ +#define MOZ_GLOBAL_CLASS __attribute__((annotate("moz_global_class"))) +#include + +struct MOZ_GLOBAL_CLASS Global { + int i; + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template +struct MOZ_GLOBAL_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void misuseGlobalClass(int len) { + Global notValid; // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated in an automatic variable}} + Global alsoNotValid[2]; // expected-error-re {{variable of type 'Global{{ ?}}[2]' only valid as global}} expected-note-re {{'Global{{ ?}}[2]' is a global type because it is an array of global type 'Global'}} expected-note {{value incorrectly allocated in an automatic variable}} + static Global valid; + static Global alsoValid[2]; + + gobble(¬Valid); + gobble(&valid); + gobble(&alsoValid[0]); + + gobble(new Global); // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated on the heap}} + gobble(new Global[10]); // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass); // expected-error {{variable of type 'TemplateClass' only valid as global}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &valid : new Global); // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated on the heap}} + + char buffer[sizeof(Global)]; + gobble(new (buffer) Global); +} + +Global valid; +struct RandomClass { + Global nonstaticMember; // expected-note {{'RandomClass' is a global type because member 'nonstaticMember' is a global type 'Global'}} + static Global staticMember; +}; +struct MOZ_GLOBAL_CLASS RandomGlobalClass { + Global nonstaticMember; + static Global staticMember; +}; + +struct BadInherit : Global {}; // expected-note {{'BadInherit' is a global type because it inherits from a global type 'Global'}} +struct MOZ_GLOBAL_CLASS GoodInherit : Global {}; + +void misuseGlobalClassEvenMore(int len) { + BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid as global}} expected-note {{value incorrectly allocated in an automatic variable}} + RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid as global}} expected-note {{value incorrectly allocated in an automatic variable}} +} diff --git a/build/clang-plugin/tests/TestHeapClass.cpp b/build/clang-plugin/tests/TestHeapClass.cpp new file mode 100644 index 0000000000..0cdd939250 --- /dev/null +++ b/build/clang-plugin/tests/TestHeapClass.cpp @@ -0,0 +1,64 @@ +#define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class"))) +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +#include + +struct MOZ_HEAP_CLASS Heap { + int i; + Heap() {} + MOZ_IMPLICIT Heap(int a) {} + Heap(int a, int b) {} + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template +struct MOZ_HEAP_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void gobbleref(const Heap&) { } + +void misuseHeapClass(int len) { + Heap invalid; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} + Heap alsoInvalid[2]; // expected-error-re {{variable of type 'Heap{{ ?}}[2]' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} expected-note-re {{'Heap{{ ?}}[2]' is a heap type because it is an array of heap type 'Heap'}} + static Heap invalidStatic; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} + static Heap alsoInvalidStatic[2]; // expected-error-re {{variable of type 'Heap{{ ?}}[2]' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} expected-note-re {{'Heap{{ ?}}[2]' is a heap type because it is an array of heap type 'Heap'}} + + gobble(&invalid); + gobble(&invalidStatic); + gobble(&alsoInvalid[0]); + + gobbleref(Heap()); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(Heap(10, 20)); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(Heap(10)); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(10); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}} + + gobble(new Heap); + gobble(new Heap[10]); + gobble(new TemplateClass); + gobble(len <= 5 ? &invalid : new Heap); + + char buffer[sizeof(Heap)]; + gobble(new (buffer) Heap); +} + +Heap invalidStatic; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} +struct RandomClass { + Heap nonstaticMember; // expected-note {{'RandomClass' is a heap type because member 'nonstaticMember' is a heap type 'Heap'}} + static Heap staticMember; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} +}; +struct MOZ_HEAP_CLASS RandomHeapClass { + Heap nonstaticMember; + static Heap staticMember; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} +}; + +struct BadInherit : Heap {}; // expected-note {{'BadInherit' is a heap type because it inherits from a heap type 'Heap'}} +struct MOZ_HEAP_CLASS GoodInherit : Heap {}; + +void useStuffWrongly() { + BadInherit i; // expected-error {{variable of type 'BadInherit' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} + RandomClass r; // expected-error {{variable of type 'RandomClass' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} +} diff --git a/build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp b/build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp new file mode 100644 index 0000000000..0c04c3b2bd --- /dev/null +++ b/build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp @@ -0,0 +1,46 @@ +#define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \ + __attribute__((annotate("moz_inherit_type_annotations_from_template_args"))) +#define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) +#define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable"))) +#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type"))) + +class Normal {}; +class MOZ_STACK_CLASS Stack {}; +class IndirectStack : Stack {}; // expected-note {{'IndirectStack' is a stack type because it inherits from a stack type 'Stack'}} +class ContainsStack { Stack m; }; // expected-note {{'ContainsStack' is a stack type because member 'm' is a stack type 'Stack'}} +class MOZ_NON_MEMMOVABLE Pointery {}; +class IndirectPointery : Pointery {}; // expected-note {{'IndirectPointery' is a non-memmove()able type because it inherits from a non-memmove()able type 'Pointery'}} +class ContainsPointery { Pointery m; }; // expected-note {{'ContainsPointery' is a non-memmove()able type because member 'm' is a non-memmove()able type 'Pointery'}} + +template +class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Template {}; // expected-note-re 5 {{'Template<{{.*}}>' is a stack type because it has a template argument stack type '{{.*}}'}} expected-note-re 5 {{'Template<{{.*}}>' is a non-memmove()able type because it has a template argument non-memmove()able type '{{.*}}'}} +class IndirectTemplate : Template {}; // expected-note {{'IndirectTemplate' is a stack type because it inherits from a stack type 'Template'}} +class ContainsTemplate { Template m; }; // expected-note {{'ContainsTemplate' is a stack type because member 'm' is a stack type 'Template'}} + +static Template a; // expected-error {{variable of type 'Template' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +static Template b; // expected-error {{variable of type 'Template' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +static Template c; // expected-error {{variable of type 'Template' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +static IndirectTemplate d; // expected-error {{variable of type 'IndirectTemplate' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +static ContainsTemplate e; // expected-error {{variable of type 'ContainsTemplate' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +static Template f; + +template +class MOZ_NEEDS_MEMMOVABLE_TYPE Mover { // expected-error-re 8 {{Cannot instantiate 'Mover<{{.*}}>' with non-memmovable template argument '{{.*}}'}} + char mForceInstantiation[sizeof(T)]; +}; +class IndirectTemplatePointery : Template {}; // expected-note {{'IndirectTemplatePointery' is a non-memmove()able type because it inherits from a non-memmove()able type 'Template'}} +class ContainsTemplatePointery { Template m; }; // expected-note {{'ContainsTemplatePointery' is a non-memmove()able type because member 'm' is a non-memmove()able type 'Template'}} + +static Mover> n; // expected-note-re {{instantiation of 'Mover{{ ?}}>' requested here}} +static Mover> o; // expected-note-re {{instantiation of 'Mover{{ ?}}>' requested here}} +static Mover> p; // expected-note-re {{instantiation of 'Mover{{ ?}}>' requested here}} +static Mover q; // expected-note {{instantiation of 'Mover' requested here}} +static Mover r; // expected-note {{instantiation of 'Mover' requested here}} +static Mover> s; + +template +class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS ManyTs {}; // expected-note-re 3 {{'ManyTs<{{.*}}>' is a non-memmove()able type because it has a template argument non-memmove()able type '{{.*}}'}} + +static Mover> t; // expected-note-re {{instantiation of 'Mover{{ ?}}>' requested here}} +static Mover> u; // expected-note-re {{instantiation of 'Mover{{ ?}}>' requested here}} +static Mover> v; // expected-note-re {{instantiation of 'Mover{{ ?}}>' requested here}} diff --git a/build/clang-plugin/tests/TestJSHandleRootedTypedef.cpp b/build/clang-plugin/tests/TestJSHandleRootedTypedef.cpp new file mode 100644 index 0000000000..a0489e09ef --- /dev/null +++ b/build/clang-plugin/tests/TestJSHandleRootedTypedef.cpp @@ -0,0 +1,168 @@ +#include "js/TypeDecls.h" +#include "js/Value.h" +#include "js/GCVector.h" +#include "js/Id.h" + +class Foo { + void HandleFunction(JS::HandleFunction){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleId(JS::HandleId){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleObject(JS::HandleObject){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleScript(JS::HandleScript){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleString(JS::HandleString){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleSymbol(JS::HandleSymbol){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleBigInt(JS::HandleBigInt){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleValue(JS::HandleValue){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleValueVector(JS::HandleValueVector){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleObjectVector(JS::HandleObjectVector){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleIdVector(JS::HandleIdVector){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + void MutableHandleFunction(JS::MutableHandleFunction){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleId(JS::MutableHandleId){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleObject(JS::MutableHandleObject){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleScript(JS::MutableHandleScript){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleString(JS::MutableHandleString){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleSymbol(JS::MutableHandleSymbol){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleBigInt(JS::MutableHandleBigInt){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleValue(JS::MutableHandleValue){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleValueVector(JS::MutableHandleValueVector){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleObjectVector(JS::MutableHandleObjectVector){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleIdVector(JS::MutableHandleIdVector){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + // Examples of preferred forms + void FullHandleFunction(JS::Handle){}; + void FullHandleId(JS::Handle){}; + void FullHandleObject(JS::Handle){}; + void FullHandleScript(JS::Handle){}; + void FullHandleString(JS::Handle){}; + void FullHandleSymbol(JS::Handle){}; + void FullHandleBigInt(JS::Handle){}; + void FullHandleValue(JS::Handle){}; + void FullHandleValueVector(JS::Handle>){}; + void FullHandleObjectVector(JS::Handle>){}; + void FullHandleIdVector(JS::HandleVector){}; + void FullHandleValueVectorShorter(JS::HandleVector){}; + void FullHandleObjectVectorShorter(JS::HandleVector){}; + void FullHandleIdVectorShorter(JS::HandleVector){}; + + void FullMutableHandleFunction(JS::MutableHandle){}; + void FullMutableHandleId(JS::MutableHandle){}; + void FullMutableHandleObject(JS::MutableHandle){}; + void FullMutableHandleScript(JS::MutableHandle){}; + void FullMutableHandleString(JS::MutableHandle){}; + void FullMutableHandleSymbol(JS::MutableHandle){}; + void FullMutableHandleBigInt(JS::MutableHandle){}; + void FullMutableHandleValue(JS::MutableHandle){}; + void FullMutableHandleValueVector(JS::MutableHandle>){}; + void FullMutableHandleObjectVector(JS::MutableHandle>){}; + void FullMutableHandleIdVector(JS::MutableHandle>){}; + void FullMutableHandleValueVectorShorter(JS::MutableHandleVector){}; + void FullMutableHandleObjectVectorShorter(JS::MutableHandleVector){}; + void FullMutableHandleIdVectorShorter(JS::MutableHandleVector){}; +}; + +static void Bar(JSContext *aCx) { + JS::RootedObject RootedObject(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedFunction RootedFunction(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedScript RootedScript(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedString RootedString(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedSymbol RootedSymbol(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedBigInt RootedBigInt(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedId RootedId(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedValue RootedValue(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + JS::RootedValueVector RootedValueVector(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedObjectVector RootedObjectVector(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedIdVector RootedIdVector(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + JS::PersistentRootedFunction PersistentRootedFunction(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedId PersistentRootedId(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedObject PersistentRootedObject(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedScript PersistentRootedScript(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedString PersistentRootedString(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedSymbol PersistentRootedSymbol(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedBigInt PersistentRootedBigInt(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedValue PersistentRootedValue(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + JS::PersistentRootedIdVector PersistentRootedIdVector(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedObjectVector PersistentRootedObjectVector(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + JS::HandleFunction HandleFunction(RootedFunction); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleId HandleId(RootedId); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleObject HandleObject(RootedObject); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleScript HandleScript(RootedScript); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleString HandleString(RootedString); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleSymbol HandleSymbol(RootedSymbol); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleBigInt HandleBigInt(RootedBigInt); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleValue HandleValue(RootedValue); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleValueVector HandleValueVector(RootedValueVector); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleObjectVector HandleObjectVector(RootedObjectVector); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleIdVector HandleIdVector(RootedIdVector); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + JS::MutableHandleFunction MutableHandleFunction(&RootedFunction); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleId MutableHandleId(&RootedId); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleObject MutableHandleObject(&RootedObject); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleScript MutableHandleScript(&RootedScript); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleString MutableHandleString(&RootedString); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleSymbol MutableHandleSymbol(&RootedSymbol); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleBigInt MutableHandleBigInt(&RootedBigInt); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleValue MutableHandleValue(&RootedValue); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleValueVector MutableHandleValueVector(&RootedValueVector); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleObjectVector MutableHandleObjectVector(&RootedObjectVector); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleIdVector MutableHandleIdVector(&RootedIdVector); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + // Examples of preferred forms + JS::Rooted FullRootedObject(aCx); + JS::Rooted FullRootedFunction(aCx); + JS::Rooted FullRootedScript(aCx); + JS::Rooted FullRootedString(aCx); + JS::Rooted FullRootedSymbol(aCx); + JS::Rooted FullRootedBigInt(aCx); + JS::Rooted FullRootedId(aCx); + JS::Rooted FullRootedValue(aCx); + + JS::RootedVector FullRootedValueVector(aCx); + JS::RootedVector FullRootedObjectVector(aCx); + JS::RootedVector FullRootedIdVector(aCx); + + JS::PersistentRooted FullPersistentRootedFunction(aCx); + JS::PersistentRooted FullPersistentRootedId(aCx); + JS::PersistentRooted FullPersistentRootedObject(aCx); + JS::PersistentRooted FullPersistentRootedScript(aCx); + JS::PersistentRooted FullPersistentRootedString(aCx); + JS::PersistentRooted FullPersistentRootedSymbol(aCx); + JS::PersistentRooted FullPersistentRootedBigInt(aCx); + JS::PersistentRooted FullPersistentRootedValue(aCx); + + JS::PersistentRootedVector FullPersistentRootedIdVector(aCx); + JS::PersistentRootedVector FullPersistentRootedObjectVector(aCx); + + JS::Handle FullHandleFunction(FullRootedFunction); + JS::Handle FullHandleId(FullRootedId); + JS::Handle FullHandleObject(FullRootedObject); + JS::Handle FullHandleScript(FullRootedScript); + JS::Handle FullHandleString(FullRootedString); + JS::Handle FullHandleSymbol(FullRootedSymbol); + JS::Handle FullHandleBigInt(FullRootedBigInt); + JS::Handle FullHandleValue(FullRootedValue); + JS::Handle> FullHandleValueVector(FullRootedValueVector); + JS::Handle> FullHandleObjectVector(FullRootedObjectVector); + JS::Handle> FullHandleIdVector(FullRootedIdVector); + JS::HandleVector FullHandleValueVectorShorter(FullRootedValueVector); + JS::HandleVector FullHandleObjectVectorShorter(FullRootedObjectVector); + JS::HandleVector FullHandleIdVectorShorter(FullRootedIdVector); + + JS::MutableHandle FullMutableHandleFunction(&FullRootedFunction); + JS::MutableHandle FullMutableHandleId(&FullRootedId); + JS::MutableHandle FullMutableHandleObject(&FullRootedObject); + JS::MutableHandle FullMutableHandleScript(&FullRootedScript); + JS::MutableHandle FullMutableHandleString(&FullRootedString); + JS::MutableHandle FullMutableHandleSymbol(&FullRootedSymbol); + JS::MutableHandle FullMutableHandleBigInt(&FullRootedBigInt); + JS::MutableHandle FullMutableHandleValue(&FullRootedValue); + JS::MutableHandle> FullMutableHandleValueVector(&FullRootedValueVector); + JS::MutableHandle> FullMutableHandleObjectVector(&FullRootedObjectVector); + JS::MutableHandle> FullMutableHandleIdVector(&FullRootedIdVector); + JS::MutableHandleVector FullMutableHandleValueVectorShorter(&FullRootedValueVector); + JS::MutableHandleVector FullMutableHandleObjectVectorShorter(&FullRootedObjectVector); + JS::MutableHandleVector FullMutableHandleIdVectorShorter(&FullRootedIdVector); +} diff --git a/build/clang-plugin/tests/TestKnownLive.cpp b/build/clang-plugin/tests/TestKnownLive.cpp new file mode 100644 index 0000000000..8d01160d1d --- /dev/null +++ b/build/clang-plugin/tests/TestKnownLive.cpp @@ -0,0 +1,33 @@ +#include + +#define MOZ_KNOWN_LIVE __attribute__((annotate("moz_known_live"))) + +class Foo { + // dummy refcounting +public: + uint32_t AddRef() { return 0; } + uint32_t Release() { return 0; } + +private: + ~Foo() = default; +}; + +class Bar { + MOZ_KNOWN_LIVE RefPtr mFoo; + Bar() : mFoo(new Foo()) {} + ~Bar() { mFoo = nullptr; } + + void Baz() { + mFoo = nullptr; // expected-error {{MOZ_KNOWN_LIVE members can only be modified by constructors and destructors}} + } +}; + +class Bar2 { + MOZ_KNOWN_LIVE Foo *mFoo; + Bar2() : mFoo(new Foo()) {} + ~Bar2() { mFoo = nullptr; } + + void Baz() { + mFoo = nullptr; // expected-error {{MOZ_KNOWN_LIVE members can only be modified by constructors and destructors}} + } +}; diff --git a/build/clang-plugin/tests/TestKungFuDeathGrip.cpp b/build/clang-plugin/tests/TestKungFuDeathGrip.cpp new file mode 100644 index 0000000000..0218015807 --- /dev/null +++ b/build/clang-plugin/tests/TestKungFuDeathGrip.cpp @@ -0,0 +1,142 @@ +#include + +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +template +class already_AddRefed { +public: + already_AddRefed(); + T* mPtr; +}; + +template +class RefPtr { +public: + RefPtr(); + MOZ_IMPLICIT RefPtr(T* aIn); + MOZ_IMPLICIT RefPtr(already_AddRefed aIn); + + RefPtr(const RefPtr& aOther) = default; + RefPtr& operator=(const RefPtr&) = default; + + // We must define non-defaulted move operations as in the real RefPtr to make + // the type non-trivially-copyable. + RefPtr(RefPtr&&); + RefPtr& operator=(RefPtr&&); + + void swap(RefPtr& aOther); + + ~RefPtr(); + T* mPtr; +}; + +template +class nsCOMPtr { +public: + nsCOMPtr(); + MOZ_IMPLICIT nsCOMPtr(T* aIn); + MOZ_IMPLICIT nsCOMPtr(already_AddRefed aIn); + ~nsCOMPtr(); + T* mPtr; +}; + +class Type { +public: + static nsCOMPtr someStaticCOMPtr; + + void f(nsCOMPtr ignoredArgument, Type *param) { + nsCOMPtr never_referenced; + nsCOMPtr kfdg_t1(this); + nsCOMPtr kfdg_t2 = this; + nsCOMPtr kfdg_t3 = (this); + + nsCOMPtr kfdg_m1(p); // expected-error {{Unused "kungFuDeathGrip" 'nsCOMPtr' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m1', or explicitly pass 'kfdg_m1' to `mozilla::Unused`}} + nsCOMPtr kfdg_m2 = p; // expected-error {{Unused "kungFuDeathGrip" 'nsCOMPtr' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m2', or explicitly pass 'kfdg_m2' to `mozilla::Unused`}} + nsCOMPtr kfdg_m3(p); + kfdg_m3.mPtr->f(nullptr, nullptr); + nsCOMPtr kfdg_m4 = p; + kfdg_m4.mPtr->f(nullptr, nullptr); + + nsCOMPtr kfdg_a1((already_AddRefed())); + nsCOMPtr kfdg_a2 = already_AddRefed(); + + nsCOMPtr kfdg_p1(param); + nsCOMPtr kfdg_p2 = param; + + + RefPtr never_referenced2; + RefPtr kfdg_t4(this); + RefPtr kfdg_t5 = this; + RefPtr kfdg_t6 = (this); + + RefPtr kfdg_m5(p); // expected-error {{Unused "kungFuDeathGrip" 'RefPtr' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m5', or explicitly pass 'kfdg_m5' to `mozilla::Unused`}} + RefPtr kfdg_m6 = p; // expected-error {{Unused "kungFuDeathGrip" 'RefPtr' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m6', or explicitly pass 'kfdg_m6' to `mozilla::Unused`}} + RefPtr kfdg_m7(p); + kfdg_m7.mPtr->f(nullptr, nullptr); + RefPtr kfdg_m8 = p; + kfdg_m8.mPtr->f(nullptr, nullptr); + + RefPtr kfdg_a3((already_AddRefed())); + RefPtr kfdg_a4 = already_AddRefed(); + + RefPtr kfdg_p3(param); + RefPtr kfdg_p4 = param; + } + + Type *p; +}; + +struct Type2 { + void f() { + mWeakRef->f(nullptr, nullptr); + } + + void g() { + RefPtr kfdg; + kfdg.swap(mStrongRef); + f(); + } + + void h() { + RefPtr kfdg = std::move(mStrongRef); + f(); + } + + RefPtr mStrongRef; + Type* mWeakRef; +}; + +void f(nsCOMPtr ignoredArgument, Type *param) { + nsCOMPtr never_referenced; + Type t; + // Type *p = nullptr; + nsCOMPtr kfdg_m1(t.p); // expected-error {{Unused "kungFuDeathGrip" 'nsCOMPtr' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m1', or explicitly pass 'kfdg_m1' to `mozilla::Unused`}} + nsCOMPtr kfdg_m2 = t.p; // expected-error {{Unused "kungFuDeathGrip" 'nsCOMPtr' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m2', or explicitly pass 'kfdg_m2' to `mozilla::Unused`}} + nsCOMPtr kfdg_m3(t.p); + kfdg_m3.mPtr->f(nullptr, nullptr); + nsCOMPtr kfdg_m4 = t.p; + kfdg_m4.mPtr->f(nullptr, nullptr); + + nsCOMPtr kfdg_a1((already_AddRefed())); + nsCOMPtr kfdg_a2 = already_AddRefed(); + + nsCOMPtr kfdg_p1(param); + nsCOMPtr kfdg_p2 = param; + + + RefPtr never_referenced2; + RefPtr kfdg_m5(t.p); // expected-error {{Unused "kungFuDeathGrip" 'RefPtr' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m5', or explicitly pass 'kfdg_m5' to `mozilla::Unused`}} + RefPtr kfdg_m6 = t.p; // expected-error {{Unused "kungFuDeathGrip" 'RefPtr' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m6', or explicitly pass 'kfdg_m6' to `mozilla::Unused`}} + RefPtr kfdg_m7(t.p); + kfdg_m7.mPtr->f(nullptr, nullptr); + RefPtr kfdg_m8 = t.p; + kfdg_m8.mPtr->f(nullptr, nullptr); + + RefPtr kfdg_a3((already_AddRefed())); + RefPtr kfdg_a4 = already_AddRefed(); + + RefPtr kfdg_p3(param); + RefPtr kfdg_p4 = param; +} + +nsCOMPtr Type::someStaticCOMPtr(nullptr); diff --git a/build/clang-plugin/tests/TestLoadLibraryUsage.cpp b/build/clang-plugin/tests/TestLoadLibraryUsage.cpp new file mode 100644 index 0000000000..319c9d6b2a --- /dev/null +++ b/build/clang-plugin/tests/TestLoadLibraryUsage.cpp @@ -0,0 +1,20 @@ +#include +#include "prlink.h" + +void Func() { + auto h1 = PR_LoadLibrary(nullptr); // expected-error {{Usage of ASCII file functions (such as PR_LoadLibrary) is forbidden.}} + auto h2 = PR_LoadLibrary("C:\\Some\\Path"); + auto h3 = LoadLibraryA(nullptr); // expected-error {{Usage of ASCII file functions (such as LoadLibraryA) is forbidden.}} + auto h4 = LoadLibraryA("C:\\Some\\Path"); + auto h5 = LoadLibraryExA(nullptr, nullptr, 0); // expected-error {{Usage of ASCII file functions (such as LoadLibraryExA) is forbidden.}} + auto h6 = LoadLibraryExA("C:\\Some\\Path", nullptr, 0); + +#ifndef UNICODE + // LoadLibrary is a defnine for LoadLibraryA + auto h7 = LoadLibrary(nullptr); // expected-error {{Usage of ASCII file functions (such as LoadLibraryA) is forbidden.}} + auto h8 = LoadLibrary("C:\\Some\\Path"); + // LoadLibraryEx is a define for LoadLibraryExA + auto h9 = LoadLibraryEx(nullptr, nullptr, 0); // expected-error {{Usage of ASCII file functions (such as LoadLibraryExA) is forbidden.}} + auto h10 = LoadLibraryEx("C:\\Some\\Path", nullptr, 0); +#endif +} diff --git a/build/clang-plugin/tests/TestMultipleAnnotations.cpp b/build/clang-plugin/tests/TestMultipleAnnotations.cpp new file mode 100644 index 0000000000..034367a58e --- /dev/null +++ b/build/clang-plugin/tests/TestMultipleAnnotations.cpp @@ -0,0 +1,19 @@ +#define MOZ_NON_TEMPORARY_CLASS __attribute__((annotate("moz_non_temporary_class"))) +#define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) + +class MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS TestClass {}; + +TestClass foo; // expected-error {{variable of type 'TestClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} + +TestClass f() +{ + TestClass bar; + return bar; +} + +void gobbleref(const TestClass&) { } + +void g() +{ + gobbleref(f()); // expected-error {{variable of type 'TestClass' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} +} diff --git a/build/clang-plugin/tests/TestMustOverride.cpp b/build/clang-plugin/tests/TestMustOverride.cpp new file mode 100644 index 0000000000..8e053f6c23 --- /dev/null +++ b/build/clang-plugin/tests/TestMustOverride.cpp @@ -0,0 +1,63 @@ +#define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) +// Ignore warnings not related to static analysis here +#pragma GCC diagnostic ignored "-Woverloaded-virtual" + +struct S { + virtual void f() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + virtual void g() MOZ_MUST_OVERRIDE; + virtual void h() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} +}; +struct C : S { // expected-error {{'C' must override 'f'}} expected-error {{'C' must override 'h'}} + virtual void g() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + virtual void h(int); + void q() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} +}; +struct D : C { // expected-error {{'D' must override 'g'}} expected-error {{'D' must override 'q'}} + virtual void f(); +}; + +struct Base { + virtual void VirtMethod() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + void NonVirtMethod() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + static void StaticMethod() MOZ_MUST_OVERRIDE; +}; + +struct DoesNotPropagate : Base { + virtual void VirtMethod(); + void NonVirtMethod(); + static void StaticMethod(); +}; + +struct Final : DoesNotPropagate { }; + +struct Propagates : Base { + virtual void VirtMethod() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + void NonVirtMethod() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + static void StaticMethod() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} +}; + +struct FailsFinal : Propagates { }; // expected-error {{'FailsFinal' must override 'VirtMethod'}} expected-error {{'FailsFinal' must override 'NonVirtMethod'}} expected-error {{'FailsFinal' must override 'StaticMethod'}} + +struct WrongOverload : Base { // expected-error {{'WrongOverload' must override 'VirtMethod'}} expected-error {{'WrongOverload' must override 'NonVirtMethod'}} + virtual void VirtMethod() const; + void NonVirtMethod(int param); + static void StaticMethod(); +}; + +namespace A { namespace B { namespace C { + struct Param {}; + struct Base { + void f(Param p) MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + }; +}}} + +struct Param {}; + +struct Derived : A::B::C::Base { + typedef A::B::C::Param Typedef; + void f(Typedef t); +}; + +struct BadDerived : A::B::C::Base { // expected-error {{'BadDerived' must override 'f'}} + void f(Param p); +}; diff --git a/build/clang-plugin/tests/TestMustReturnFromCaller.cpp b/build/clang-plugin/tests/TestMustReturnFromCaller.cpp new file mode 100644 index 0000000000..c935be3cf8 --- /dev/null +++ b/build/clang-plugin/tests/TestMustReturnFromCaller.cpp @@ -0,0 +1,270 @@ +#include +#include + +#define MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG __attribute__((annotate("moz_must_return_from_caller_if_this_is_arg"))) +#define MOZ_MAY_CALL_AFTER_MUST_RETURN __attribute__((annotate("moz_may_call_after_must_return"))) + +struct Thrower { + void MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG Throw() {} +}; + +void DoAnythingElse(); +int MakeAnInt(); +int MOZ_MAY_CALL_AFTER_MUST_RETURN SafeMakeInt(); +bool Condition(); + +// It might be nicer to #include "mozilla/ScopeExit.h" and use that here -- but +// doing so also will #define the two attribute-macros defined above, running a +// risk of redefinition errors. Just stick to the normal clang-plugin test +// style and use as little external code as possible. + +template +class ScopeExit { + Func exitFunction; + bool callOnDestruction; +public: + explicit ScopeExit(Func&& func) + : exitFunction(std::move(func)) + , callOnDestruction(true) + {} + + ~ScopeExit() { + if (callOnDestruction) { + exitFunction(); + } + } + + void release() { callOnDestruction = false; } +}; + +template +ScopeExit +MakeScopeExit(ExitFunction&& func) +{ + return ScopeExit(std::move(func)); +} + +class Foo { +public: + __attribute__((annotate("moz_implicit"))) Foo(std::nullptr_t); + Foo(); +}; + +void a1(Thrower& thrower) { + thrower.Throw(); +} + +int a2(Thrower& thrower) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + return MakeAnInt(); +} + +int a3(Thrower& thrower) { + // RAII operations happening after a must-immediately-return are fine. + auto atExit = MakeScopeExit([] { DoAnythingElse(); }); + thrower.Throw(); + return 5; +} + +int a4(Thrower& thrower) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + return Condition() ? MakeAnInt() : MakeAnInt(); +} + +void a5(Thrower& thrower) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + DoAnythingElse(); +} + +int a6(Thrower& thrower) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + DoAnythingElse(); + return MakeAnInt(); +} + +int a7(Thrower& thrower) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + DoAnythingElse(); + return Condition() ? MakeAnInt() : MakeAnInt(); +} + +int a8(Thrower& thrower) { + thrower.Throw(); + return SafeMakeInt(); +} + +int a9(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return SafeMakeInt(); +} + +int a10(Thrower& thrower) { + auto atExit = MakeScopeExit([] { DoAnythingElse(); }); + + if (Condition()) { + thrower.Throw(); + return SafeMakeInt(); + } + + atExit.release(); + DoAnythingElse(); + return 5; +} + +void b1(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } +} + +int b2(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + } + return MakeAnInt(); +} + +int b3(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return 5; +} + +// Explicit test in orer to also verify the `UnaryOperator` node in the `CFG` +int b3a(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return -1; +} + +float b3b(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return 1.0f; +} + +bool b3c(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return false; +} + +int b4(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + } + return Condition() ? MakeAnInt() : MakeAnInt(); +} + +void b5(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + } + DoAnythingElse(); +} + +void b6(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + DoAnythingElse(); + } +} + +void b7(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + return; + } + DoAnythingElse(); +} + +void b8(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + DoAnythingElse(); + return; + } + DoAnythingElse(); +} + +void b9(Thrower& thrower) { + while (Condition()) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + } +} + +void b10(Thrower& thrower) { + while (Condition()) { + thrower.Throw(); + return; + } +} + +void b11(Thrower& thrower) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + if (Condition()) { + return; + } else { + return; + } +} + +void b12(Thrower& thrower) { + switch (MakeAnInt()) { + case 1: + break; + default: + thrower.Throw(); + return; + } +} + +void b13(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return; +} + +Foo b14(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + return nullptr; + } + return nullptr; +} + +Foo b15(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return nullptr; +} + +Foo b16(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return Foo(); +} + +void c1() { + Thrower thrower; + thrower.Throw(); + DoAnythingElse(); // Should be allowed, since our thrower is not an arg +} + +class TestRet { + TestRet *b13(Thrower &thrower) { + if (Condition()) { + thrower.Throw(); + } + return this; + } +}; diff --git a/build/clang-plugin/tests/TestNANTestingExpr.cpp b/build/clang-plugin/tests/TestNANTestingExpr.cpp new file mode 100644 index 0000000000..9aac46d036 --- /dev/null +++ b/build/clang-plugin/tests/TestNANTestingExpr.cpp @@ -0,0 +1,24 @@ +#line 1 "tests/SkScalar.h" +// This checks that the whitelist accounts for #line directives and such. If you +// remove SkScalar from the whitelist, please change the filename here instead +// of adding expected diagnostics. +inline int headerSays(double x) { + return x != x; +} +#line 9 "TestNANTestingExpr.cpp" +void test(bool x); +void foo() { + float f, f2; + typedef double mydouble; + mydouble d; + double d2; + test(f == f); // expected-error{{comparing a floating point value to itself for NaN checking can lead to incorrect results}} expected-note{{consider using std::isnan instead}} + test(d == d); // expected-error{{comparing a floating point value to itself for NaN checking can lead to incorrect results}} expected-note{{consider using std::isnan instead}} + test(f != f); // expected-error{{comparing a floating point value to itself for NaN checking can lead to incorrect results}} expected-note{{consider using std::isnan instead}} + test(d != d); // expected-error{{comparing a floating point value to itself for NaN checking can lead to incorrect results}} expected-note{{consider using std::isnan instead}} + test(f != d); + test(d == (d - f)); + test(f == f2); + test(d == d2); + test(d + 1 == d); +} diff --git a/build/clang-plugin/tests/TestNANTestingExprC.c b/build/clang-plugin/tests/TestNANTestingExprC.c new file mode 100644 index 0000000000..ab2fead22a --- /dev/null +++ b/build/clang-plugin/tests/TestNANTestingExprC.c @@ -0,0 +1,17 @@ +/* expected-no-diagnostics */ +void test(int x); +void foo() { + float f, f2; + typedef double mydouble; + mydouble d; + double d2; + test(f == f); + test(d == d); + test(f != f); + test(d != d); + test(f != d); + test(d == (d - f)); + test(f == f2); + test(d == d2); + test(d + 1 == d); +} diff --git a/build/clang-plugin/tests/TestNeedsNoVTableType.cpp b/build/clang-plugin/tests/TestNeedsNoVTableType.cpp new file mode 100644 index 0000000000..9b7c405d80 --- /dev/null +++ b/build/clang-plugin/tests/TestNeedsNoVTableType.cpp @@ -0,0 +1,94 @@ +#define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type"))) + +template +struct MOZ_NEEDS_NO_VTABLE_TYPE PickyConsumer { // expected-error {{'PickyConsumer' cannot be instantiated because 'B' has a VTable}} expected-error {{'PickyConsumer' cannot be instantiated because 'E' has a VTable}} expected-error {{'PickyConsumer' cannot be instantiated because 'F' has a VTable}} expected-error {{'PickyConsumer' cannot be instantiated because 'G' has a VTable}} + T *m; +}; + +template +struct MOZ_NEEDS_NO_VTABLE_TYPE PickyConsumer_A { // expected-error {{'PickyConsumer_A' cannot be instantiated because 'B' has a VTable}} expected-error {{'PickyConsumer_A' cannot be instantiated because 'E' has a VTable}} expected-error {{'PickyConsumer_A' cannot be instantiated because 'F' has a VTable}} expected-error {{'PickyConsumer_A' cannot be instantiated because 'G' has a VTable}} + T *m; +}; +template +struct PickyConsumerWrapper { + PickyConsumer_A m; // expected-note {{bad instantiation of 'PickyConsumer_A' requested here}} expected-note {{bad instantiation of 'PickyConsumer_A' requested here}} expected-note {{bad instantiation of 'PickyConsumer_A' requested here}} expected-note {{bad instantiation of 'PickyConsumer_A' requested here}} +}; + +template +struct MOZ_NEEDS_NO_VTABLE_TYPE PickyConsumer_B { // expected-error {{'PickyConsumer_B' cannot be instantiated because 'B' has a VTable}} expected-error {{'PickyConsumer_B' cannot be instantiated because 'E' has a VTable}} expected-error {{'PickyConsumer_B' cannot be instantiated because 'F' has a VTable}} expected-error {{'PickyConsumer_B' cannot be instantiated because 'G' has a VTable}} + T *m; +}; +template +struct PickyConsumerSubclass : PickyConsumer_B {}; // expected-note {{bad instantiation of 'PickyConsumer_B' requested here}} expected-note {{bad instantiation of 'PickyConsumer_B' requested here}} expected-note {{bad instantiation of 'PickyConsumer_B' requested here}} expected-note {{bad instantiation of 'PickyConsumer_B' requested here}} + +template +struct NonPickyConsumer { + T *m; +}; + +struct A {}; +struct B : virtual A {}; +struct C : A {}; +struct D { + void d(); +}; +struct E { + virtual void e(); +}; +struct F : E { + void e() final; +}; +struct G { + virtual void e() = 0; +}; + +void f() { + { + PickyConsumer a1; + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } + + { + PickyConsumer a1; // expected-note {{bad instantiation of 'PickyConsumer' requested here}} + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } + + { + PickyConsumer a1; + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } + + { + PickyConsumer a1; + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } + + { + PickyConsumer a1; // expected-note {{bad instantiation of 'PickyConsumer' requested here}} + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } + + { + PickyConsumer a1; // expected-note {{bad instantiation of 'PickyConsumer' requested here}} + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } + + { + PickyConsumer a1; // expected-note {{bad instantiation of 'PickyConsumer' requested here}} + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } +} diff --git a/build/clang-plugin/tests/TestNoAddRefReleaseOnReturn.cpp b/build/clang-plugin/tests/TestNoAddRefReleaseOnReturn.cpp new file mode 100644 index 0000000000..5db514f7ab --- /dev/null +++ b/build/clang-plugin/tests/TestNoAddRefReleaseOnReturn.cpp @@ -0,0 +1,110 @@ +#define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return"))) + +struct Test { + void AddRef(); + void Release(); + void foo(); +}; + +struct TestD : Test {}; + +struct S { + Test* f() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + Test& g() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + Test h() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +}; + +struct SD { + TestD* f() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + TestD& g() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + TestD h() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +}; + +template +struct X { + T* f() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + T& g() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + T h() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +}; + +template +struct SP { + T* operator->() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +}; + +Test* f() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +Test& g() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +Test h() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + +TestD* fd() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +TestD& gd() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +TestD hd() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + +void test() { + S s; + s.f()->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'S::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + s.f()->Release(); // expected-error{{'Release' must not be called on the return value of 'S::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + s.f()->foo(); + s.g().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'S::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + s.g().Release(); // expected-error{{'Release' must not be called on the return value of 'S::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + s.g().foo(); + s.h().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'S::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + s.h().Release(); // expected-error{{'Release' must not be called on the return value of 'S::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + s.h().foo(); + SD sd; + sd.f()->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'SD::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sd.f()->Release(); // expected-error{{'Release' must not be called on the return value of 'SD::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sd.f()->foo(); + sd.g().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'SD::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sd.g().Release(); // expected-error{{'Release' must not be called on the return value of 'SD::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sd.g().foo(); + sd.h().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'SD::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sd.h().Release(); // expected-error{{'Release' must not be called on the return value of 'SD::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sd.h().foo(); + X x; + x.f()->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'X::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + x.f()->Release(); // expected-error{{'Release' must not be called on the return value of 'X::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + x.f()->foo(); + x.g().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'X::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + x.g().Release(); // expected-error{{'Release' must not be called on the return value of 'X::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + x.g().foo(); + x.h().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'X::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + x.h().Release(); // expected-error{{'Release' must not be called on the return value of 'X::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + x.h().foo(); + X xd; + xd.f()->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'X::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + xd.f()->Release(); // expected-error{{'Release' must not be called on the return value of 'X::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + xd.f()->foo(); + xd.g().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'X::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + xd.g().Release(); // expected-error{{'Release' must not be called on the return value of 'X::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + xd.g().foo(); + xd.h().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'X::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + xd.h().Release(); // expected-error{{'Release' must not be called on the return value of 'X::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + xd.h().foo(); + SP sp; + sp->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'SP::operator->' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sp->Release(); // expected-error{{'Release' must not be called on the return value of 'SP::operator->' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sp->foo(); + SP spd; + spd->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'SP::operator->' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + spd->Release(); // expected-error{{'Release' must not be called on the return value of 'SP::operator->' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + spd->foo(); + f()->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + f()->Release(); // expected-error{{'Release' must not be called on the return value of 'f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + f()->foo(); + g().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + g().Release(); // expected-error{{'Release' must not be called on the return value of 'g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + g().foo(); + h().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + h().Release(); // expected-error{{'Release' must not be called on the return value of 'h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + h().foo(); + fd()->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'fd' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + fd()->Release(); // expected-error{{'Release' must not be called on the return value of 'fd' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + fd()->foo(); + gd().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'gd' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + gd().Release(); // expected-error{{'Release' must not be called on the return value of 'gd' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + gd().foo(); + hd().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'hd' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + hd().Release(); // expected-error{{'Release' must not be called on the return value of 'hd' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + hd().foo(); +} diff --git a/build/clang-plugin/tests/TestNoArithmeticExprInArgument.cpp b/build/clang-plugin/tests/TestNoArithmeticExprInArgument.cpp new file mode 100644 index 0000000000..d147b17012 --- /dev/null +++ b/build/clang-plugin/tests/TestNoArithmeticExprInArgument.cpp @@ -0,0 +1,32 @@ +#define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg"))) + +struct X { + explicit X(int) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT; + void baz(int) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT; +}; + +int operator+(int, X); +int operator+(X, int); +int operator++(X); + +void badArithmeticsInArgs() { + int a = 1; + typedef int myint; + myint b = 2; + X goodObj1(a); + goodObj1.baz(b); + X badObj1(a + b); // expected-error{{cannot pass an arithmetic expression of built-in types to 'X'}} + X badObj2 = X(a ? 0 : ++a); // expected-error{{cannot pass an arithmetic expression of built-in types to 'X'}} + X badObj3(~a); // expected-error{{cannot pass an arithmetic expression of built-in types to 'X'}} + badObj1.baz(a - 1 - b); // expected-error{{cannot pass an arithmetic expression of built-in types to 'baz'}} + badObj1.baz(++a); // expected-error{{cannot pass an arithmetic expression of built-in types to 'baz'}} + badObj1.baz(a++); // expected-error{{cannot pass an arithmetic expression of built-in types to 'baz'}} + badObj1.baz(a || b); + badObj1.baz(a + goodObj1); + badObj1.baz(goodObj1 + a); + badObj1.baz(++goodObj1); + badObj1.baz(-1); + badObj1.baz(-1.0); + badObj1.baz(1 + 2); + badObj1.baz(1 << (sizeof(int)/2)); +} diff --git a/build/clang-plugin/tests/TestNoAutoType.cpp b/build/clang-plugin/tests/TestNoAutoType.cpp new file mode 100644 index 0000000000..6c6e65f243 --- /dev/null +++ b/build/clang-plugin/tests/TestNoAutoType.cpp @@ -0,0 +1,41 @@ +#define MOZ_NON_AUTOABLE __attribute__((annotate("moz_non_autoable"))) + +template +struct MOZ_NON_AUTOABLE ExplicitTypeTemplate {}; +struct MOZ_NON_AUTOABLE ExplicitType {}; +struct NonExplicitType {}; + +void f() { + { + ExplicitType a; + auto b = a; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitType'}} expected-note {{Please write out this type explicitly}} + auto &br = a; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitType &'}} expected-note {{Please write out this type explicitly}} + const auto &brc = a; // expected-error {{Cannot use auto to declare a variable of type 'const ExplicitType &'}} expected-note {{Please write out this type explicitly}} + auto *bp = &a; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitType *'}} expected-note {{Please write out this type explicitly}} + const auto *bpc = &a; // expected-error {{Cannot use auto to declare a variable of type 'const ExplicitType *'}} expected-note {{Please write out this type explicitly}} + } + + { + ExplicitTypeTemplate a; + auto b = a; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitTypeTemplate'}} expected-note {{Please write out this type explicitly}} + auto &br = a; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitTypeTemplate &'}} expected-note {{Please write out this type explicitly}} + const auto &brc = a; // expected-error {{Cannot use auto to declare a variable of type 'const ExplicitTypeTemplate &'}} expected-note {{Please write out this type explicitly}} + auto *bp = &a; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitTypeTemplate *'}} expected-note {{Please write out this type explicitly}} + const auto *bpc = &a; // expected-error {{Cannot use auto to declare a variable of type 'const ExplicitTypeTemplate *'}} expected-note {{Please write out this type explicitly}} + } + + { + NonExplicitType c; + auto d = c; + auto &dr = c; + const auto &drc = c; + auto *dp = &c; + const auto *dpc = &c; + } +} + +ExplicitType A; +auto B = A; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitType'}} expected-note {{Please write out this type explicitly}} + +NonExplicitType C; +auto D = C; diff --git a/build/clang-plugin/tests/TestNoDuplicateRefCntMember.cpp b/build/clang-plugin/tests/TestNoDuplicateRefCntMember.cpp new file mode 100644 index 0000000000..ff68e4fc7c --- /dev/null +++ b/build/clang-plugin/tests/TestNoDuplicateRefCntMember.cpp @@ -0,0 +1,49 @@ +class C1 {}; + +class RC1 { +public: + virtual void AddRef(); + virtual void Release(); + +private: + int mRefCnt; // expected-note 2 {{Superclass 'RC1' also has an mRefCnt member}} expected-note 3 {{Superclass 'RC1' has an mRefCnt member}} +}; + +class RC2 : public RC1 { // expected-error {{Refcounted record 'RC2' has multiple mRefCnt members}} +public: + virtual void AddRef(); + virtual void Release(); + +private: + int mRefCnt; // expected-note {{Consider using the _INHERITED macros for AddRef and Release here}} +}; + +class C2 : public RC1 {}; + +class RC3 : public RC1 {}; + +class RC4 : public RC3, public C2 {}; // expected-error {{Refcounted record 'RC4' has multiple superclasses with mRefCnt members}} + +class RC5 : public RC1 {}; + +class RC6 : public C1, public RC5 { // expected-error {{Refcounted record 'RC6' has multiple mRefCnt members}} +public: + virtual void AddRef(); + virtual void Release(); + +private: + int mRefCnt; // expected-note {{Consider using the _INHERITED macros for AddRef and Release here}} +}; + +class Predecl; + +class OtherRC { +public: + virtual void AddRef(); + virtual void Release(); + +private: + int mRefCnt; // expected-note {{Superclass 'OtherRC' has an mRefCnt member}} +}; + +class MultRCSuper : public RC1, public OtherRC {}; // expected-error {{Refcounted record 'MultRCSuper' has multiple superclasses with mRefCnt members}} diff --git a/build/clang-plugin/tests/TestNoExplicitMoveConstructor.cpp b/build/clang-plugin/tests/TestNoExplicitMoveConstructor.cpp new file mode 100644 index 0000000000..5aea6b1a7f --- /dev/null +++ b/build/clang-plugin/tests/TestNoExplicitMoveConstructor.cpp @@ -0,0 +1,25 @@ +class Foo { + Foo(Foo&& f); +}; + +class Bar { + explicit Bar(Bar&& f); // expected-error {{Move constructors may not be marked explicit}} +}; + +class Baz { + template + explicit Baz(T&& f) {}; +}; + +class Quxx { + Quxx(); + Quxx(Quxx& q) = delete; + template + explicit Quxx(T&& f) {}; +}; + +void f() { + // Move a quxx into a quxx! (This speciailizes Quxx's constructor to look like + // a move constructor - to make sure it doesn't trigger) + Quxx(Quxx()); +} diff --git a/build/clang-plugin/tests/TestNoNewThreadsChecker.cpp b/build/clang-plugin/tests/TestNoNewThreadsChecker.cpp new file mode 100644 index 0000000000..c10277c1c4 --- /dev/null +++ b/build/clang-plugin/tests/TestNoNewThreadsChecker.cpp @@ -0,0 +1,9 @@ +// Dummy NS_NewNamedThread. +void NS_NewNamedThread(const char *aName) {} + +void func_threads() { + // Test to see if the checker recognizes a bad name, and if it recognizes a + // name from the ThreadAllows.txt. + NS_NewNamedThread("A bad name"); // expected-error {{Thread name not recognized. Please use the background thread pool.}} expected-note {{NS_NewNamedThread has been deprecated in favor of background task dispatch via NS_DispatchBackgroundTask and NS_CreateBackgroundTaskQueue. If you must create a new ad-hoc thread, have your thread name added to ThreadAllows.txt.}} + NS_NewNamedThread("Checker Test"); +} diff --git a/build/clang-plugin/tests/TestNoPrincipalGetUri.cpp b/build/clang-plugin/tests/TestNoPrincipalGetUri.cpp new file mode 100644 index 0000000000..c94a2add8a --- /dev/null +++ b/build/clang-plugin/tests/TestNoPrincipalGetUri.cpp @@ -0,0 +1,31 @@ +class nsIPrincipal { +public: + void GetURI(int foo){}; +}; + +class SomePrincipal : public nsIPrincipal { +public: + void GetURI(int foo) {} +}; + +class NullPrincipal : public SomePrincipal {}; + +class SomeURI { +public: + void GetURI(int foo) {} +}; + +void f() { + nsIPrincipal *a = new SomePrincipal(); + a->GetURI(0); // expected-error {{Principal->GetURI is deprecated and will be removed soon. Please consider using the new helper functions of nsIPrincipal}} + + ::nsIPrincipal *b = new NullPrincipal(); + b->GetURI(0); // expected-error {{Principal->GetURI is deprecated and will be removed soon. Please consider using the new helper functions of nsIPrincipal}} + + SomeURI *c = new SomeURI(); + c->GetURI(0); + + SomePrincipal *d = new SomePrincipal(); + d->GetURI(0); + +} diff --git a/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp b/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp new file mode 100644 index 0000000000..aedc5af096 --- /dev/null +++ b/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp @@ -0,0 +1,682 @@ +#include + +#include +#define MOZ_STRONG_REF +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +// Ensure that warnings about returning stack addresses of local variables are +// errors, so our `expected-error` annotations below work correctly. +#pragma GCC diagnostic error "-Wreturn-stack-address" + +struct RefCountedBase { + void AddRef(); + void Release(); +}; + +template +struct SmartPtr { + SmartPtr(); + MOZ_IMPLICIT SmartPtr(T*); + T* MOZ_STRONG_REF t; + T* operator->() const; +}; + +struct R : RefCountedBase { + void method(); +private: + void privateMethod(); +}; + +void take(...); +void foo() { + R* ptr; + SmartPtr sp; + take([&](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + take([&](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + take([&](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + take([&](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); + take([=](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + take([=](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + take([=](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + take([=](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); + take([ptr](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + take([sp](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + take([ptr](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + take([sp](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); + take([&ptr](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + take([&sp](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + take([&ptr](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + take([&sp](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); +} + +void b() { + R* ptr; + SmartPtr sp; + std::function([&](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + std::function)>([&](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + std::function([&](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + std::function)>([&](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); + std::function([=](R* argptr) { + R* localptr; + ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + argptr->method(); + localptr->method(); + }); + std::function)>([=](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + std::function([=](R* argptr) { + R* localptr; + take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + take(argptr); + take(localptr); + }); + std::function)>([=](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); + std::function([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + std::function)>([sp](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + std::function([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + std::function)>([sp](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); + std::function([&ptr](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + std::function)>([&sp](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + std::function([&ptr](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + std::function)>([&sp](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); +} + +// These tests would check c++14 deduced return types, if they were supported in +// our codebase. They are being kept here for convenience in the future if we do +// add support for c++14 deduced return types +#if 0 +auto d1() { + R* ptr; + SmartPtr sp; + return ([&](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); +} +auto d2() { + R* ptr; + SmartPtr sp; + return ([&](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); +} +auto d3() { + R* ptr; + SmartPtr sp; + return ([&](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); +} +auto d4() { + R* ptr; + SmartPtr sp; + return ([&](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); +} +auto d5() { + R* ptr; + SmartPtr sp; + return ([=](R* argptr) { + R* localptr; + ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + argptr->method(); + localptr->method(); + }); +} +auto d6() { + R* ptr; + SmartPtr sp; + return ([=](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); +} +auto d8() { + R* ptr; + SmartPtr sp; + return ([=](R* argptr) { + R* localptr; + take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + take(argptr); + take(localptr); + }); +} +auto d9() { + R* ptr; + SmartPtr sp; + return ([=](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); +} +auto d10() { + R* ptr; + SmartPtr sp; + return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); +} +auto d11() { + R* ptr; + SmartPtr sp; + return ([sp](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); +} +auto d12() { + R* ptr; + SmartPtr sp; + return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); +} +auto d13() { + R* ptr; + SmartPtr sp; + return ([sp](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); +} +auto d14() { + R* ptr; + SmartPtr sp; + return ([&ptr](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); +} +auto d15() { + R* ptr; + SmartPtr sp; + return ([&sp](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); +} +auto d16() { + R* ptr; + SmartPtr sp; + return ([&ptr](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); +} +auto d17() { + R* ptr; + SmartPtr sp; + return ([&sp](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); +} +#endif + +void e() { + auto e1 = []() { + R* ptr; + SmartPtr sp; + return ([&](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} + R* localptr; +#if __clang_major__ >= 12 + ptr->method(); // expected-note{{implicitly captured by reference due to use here}} +#else + ptr->method(); +#endif + argptr->method(); + localptr->method(); + }); + }; + auto e2 = []() { + R* ptr; + SmartPtr sp; + return ([&](SmartPtr argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} + SmartPtr localsp; +#if __clang_major__ >= 12 + sp->method(); // expected-note{{implicitly captured by reference due to use here}} +#else + sp->method(); +#endif + argsp->method(); + localsp->method(); + }); + }; + auto e3 = []() { + R* ptr; + SmartPtr sp; + return ([&](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} + R* localptr; +#if __clang_major__ >= 12 + take(ptr); // expected-note{{implicitly captured by reference due to use here}} +#else + take(ptr); +#endif + take(argptr); + take(localptr); + }); + }; + auto e4 = []() { + R* ptr; + SmartPtr sp; + return ([&](SmartPtr argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} + SmartPtr localsp; +#if __clang_major__ >= 12 + take(sp); // expected-note{{implicitly captured by reference due to use here}} +#else + take(sp); +#endif + take(argsp); + take(localsp); + }); + }; + auto e5 = []() { + R* ptr; + SmartPtr sp; + return ([=](R* argptr) { + R* localptr; + ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + argptr->method(); + localptr->method(); + }); + }; + auto e6 = []() { + R* ptr; + SmartPtr sp; + return ([=](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + }; + auto e8 = []() { + R* ptr; + SmartPtr sp; + return ([=](R* argptr) { + R* localptr; + take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + take(argptr); + take(localptr); + }); + }; + auto e9 = []() { + R* ptr; + SmartPtr sp; + return ([=](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); + }; + auto e10 = []() { + R* ptr; + SmartPtr sp; + return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + }; + auto e11 = []() { + R* ptr; + SmartPtr sp; + return ([sp](SmartPtr argsp) { + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + }; + auto e12 = []() { + R* ptr; + SmartPtr sp; + return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + }; + auto e13 = []() { + R* ptr; + SmartPtr sp; + return ([sp](SmartPtr argsp) { + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); + }; + auto e14 = []() { + R* ptr; + SmartPtr sp; +#if __clang_major__ >= 12 + return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} expected-note{{captured by reference here}} + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); +#else + return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); +#endif + }; + auto e15 = []() { + R* ptr; + SmartPtr sp; +#if __clang_major__ >= 12 + return ([&sp](SmartPtr argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} expected-note{{captured by reference here}} + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); +#else + return ([&sp](SmartPtr argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} + SmartPtr localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); +#endif + }; + auto e16 = []() { + R* ptr; + SmartPtr sp; +#if __clang_major__ >= 12 + return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} expected-note{{captured by reference here}} + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); +#else + return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); +#endif + }; + auto e17 = []() { + R* ptr; + SmartPtr sp; +#if __clang_major__ >= 12 + return ([&sp](SmartPtr argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} expected-note{{captured by reference here}} + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); +#else + return ([&sp](SmartPtr argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} + SmartPtr localsp; + take(sp); + take(argsp); + take(localsp); + }); +#endif + }; +} + +void +R::privateMethod() { + SmartPtr self = this; + std::function([&]() { + self->method(); + }); + std::function([&]() { + self->privateMethod(); + }); + std::function([&]() { + this->method(); + }); + std::function([&]() { + this->privateMethod(); + }); + std::function([=]() { + self->method(); + }); + std::function([=]() { + self->privateMethod(); + }); + std::function([=]() { + this->method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function([=]() { + this->privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function([self]() { + self->method(); + }); + std::function([self]() { + self->privateMethod(); + }); + std::function([this]() { + this->method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function([this]() { + this->privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function([this]() { + method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function([this]() { + privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function([=]() { + method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function([=]() { + privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function([&]() { + method(); + }); + std::function([&]() { + privateMethod(); + }); + + std::function( + [instance = MOZ_KnownLive(this)]() { instance->privateMethod(); }); + + // It should be OK to go through `this` if we have captured a reference to it. + std::function([this, self]() { + this->method(); + this->privateMethod(); + method(); + privateMethod(); + }); +} diff --git a/build/clang-plugin/tests/TestNoUsingNamespaceMozillaJava.cpp b/build/clang-plugin/tests/TestNoUsingNamespaceMozillaJava.cpp new file mode 100644 index 0000000000..70cfbe1827 --- /dev/null +++ b/build/clang-plugin/tests/TestNoUsingNamespaceMozillaJava.cpp @@ -0,0 +1,29 @@ +namespace mozilla { +namespace java { +namespace sdk { +} // namespace sdk + +namespace future { +} // namespace future +} // namespace java +} // namespace mozilla + +namespace mozilla { + using namespace java; // expected-error{{using namespace mozilla::java is forbidden}} + using namespace java::future; // expected-error{{using namespace mozilla::java::future is forbidden}} +} + +using namespace mozilla::java::sdk; // expected-error{{using namespace mozilla::java::sdk is forbidden}} + +namespace shouldPass { + namespace java { + } + + using namespace java; +} + +using namespace shouldPass::java; + + +void test() { +} diff --git a/build/clang-plugin/tests/TestNonHeapClass.cpp b/build/clang-plugin/tests/TestNonHeapClass.cpp new file mode 100644 index 0000000000..26fe6404e0 --- /dev/null +++ b/build/clang-plugin/tests/TestNonHeapClass.cpp @@ -0,0 +1,62 @@ +#define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class"))) +#define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) +#include + +struct MOZ_NONHEAP_CLASS NonHeap { + int i; + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template +struct MOZ_NONHEAP_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void misuseNonHeapClass(int len) { + NonHeap valid; + NonHeap alsoValid[2]; + static NonHeap validStatic; + static NonHeap alsoValidStatic[2]; + + gobble(&valid); + gobble(&validStatic); + gobble(&alsoValid[0]); + + gobble(new NonHeap); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + gobble(new NonHeap[10]); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass); // expected-error {{variable of type 'TemplateClass' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &valid : new NonHeap); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + + char buffer[sizeof(NonHeap)]; + gobble(new (buffer) NonHeap); +} + +NonHeap validStatic; +struct RandomClass { + NonHeap nonstaticMember; // expected-note {{'RandomClass' is a non-heap type because member 'nonstaticMember' is a non-heap type 'NonHeap'}} + static NonHeap staticMember; +}; +struct MOZ_NONHEAP_CLASS RandomNonHeapClass { + NonHeap nonstaticMember; + static NonHeap staticMember; +}; + +struct BadInherit : NonHeap {}; // expected-note {{'BadInherit' is a non-heap type because it inherits from a non-heap type 'NonHeap'}} +struct MOZ_NONHEAP_CLASS GoodInherit : NonHeap {}; + +void useStuffWrongly() { + gobble(new BadInherit); // expected-error {{variable of type 'BadInherit' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + gobble(new RandomClass); // expected-error {{variable of type 'RandomClass' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} +} + +// Stack class overrides non-heap typees. +struct MOZ_STACK_CLASS StackClass {}; +struct MOZ_NONHEAP_CLASS InferredStackClass : GoodInherit { + NonHeap nonstaticMember; + StackClass stackClass; // expected-note {{'InferredStackClass' is a stack type because member 'stackClass' is a stack type 'StackClass'}} +}; + +InferredStackClass global; // expected-error {{variable of type 'InferredStackClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} diff --git a/build/clang-plugin/tests/TestNonMemMovable.cpp b/build/clang-plugin/tests/TestNonMemMovable.cpp new file mode 100644 index 0000000000..dfbb5a6c65 --- /dev/null +++ b/build/clang-plugin/tests/TestNonMemMovable.cpp @@ -0,0 +1,830 @@ +#define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable"))) +#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type"))) +#define MOZ_NEEDS_MEMMOVABLE_MEMBERS __attribute__((annotate("moz_needs_memmovable_members"))) + +/* + These are a bunch of structs with variable levels of memmovability. + They will be used as template parameters to the various NeedyTemplates +*/ +struct MOZ_NON_MEMMOVABLE NonMovable {}; +struct Movable {}; + +// Subclasses +struct S_NonMovable : NonMovable {}; // expected-note 51 {{'S_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'NonMovable'}} +struct S_Movable : Movable {}; + +// Members +struct W_NonMovable { + NonMovable m; // expected-note 34 {{'W_NonMovable' is a non-memmove()able type because member 'm' is a non-memmove()able type 'NonMovable'}} +}; +struct W_Movable { + Movable m; +}; + +// Wrapped Subclasses +struct WS_NonMovable { + S_NonMovable m; // expected-note 34 {{'WS_NonMovable' is a non-memmove()able type because member 'm' is a non-memmove()able type 'S_NonMovable'}} +}; +struct WS_Movable { + S_Movable m; +}; + +// Combinations of the above +struct SW_NonMovable : W_NonMovable {}; // expected-note 17 {{'SW_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'W_NonMovable'}} +struct SW_Movable : W_Movable {}; + +struct SWS_NonMovable : WS_NonMovable {}; // expected-note 17 {{'SWS_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'WS_NonMovable'}} +struct SWS_Movable : WS_Movable {}; + +// Basic templated wrapper +template +struct Template_Inline { + T m; // expected-note-re 56 {{'Template_Inline<{{.*}}>' is a non-memmove()able type because member 'm' is a non-memmove()able type '{{.*}}'}} +}; + +template +struct Template_Ref { + T* m; +}; + +template +struct Template_Unused {}; + +template +struct MOZ_NON_MEMMOVABLE Template_NonMovable {}; + +/* + These tests take the following form: + DECLARATIONS => Declarations of the templates which are either marked with MOZ_NEEDS_MEMMOVABLE_TYPE + or which instantiate a MOZ_NEEDS_MEMMOVABLE_TYPE through some mechanism. + BAD N => Instantiations of the wrapper template with each of the non-memmovable types. + The prefix S_ means subclass, W_ means wrapped. Each of these rows should produce an error + on the NeedyTemplate in question, and a note at the instantiation location of that template. + Unfortunately, on every case more complicated than bad1, the instantiation location is + within another template. Thus, the notes are expected on the template in question which + actually instantiates the MOZ_NEEDS_MEMMOVABLE_TYPE template. + GOOD N => Instantiations of the wrapper template with each of the memmovable types. + This is meant as a sanity check to ensure that we don't reject valid instantiations of + templates. + + + Note 1: Each set uses it's own types to ensure that they don't re-use each-other's template specializations. + If they did, then some of the error messages would not be emitted (as error messages are emitted for template + specializations, rather than for variable declarations) + + Note 2: Every instance of NeedyTemplate contains a member of type T. This is to ensure that T is actually + instantiated (if T is a template) by clang. If T isn't instantiated, then we can't actually tell if it is + NON_MEMMOVABLE. (This is OK in practice, as you cannot memmove a type which you don't know the size of). + + Note 3: There are a set of tests for specializations of NeedyTemplate at the bottom. For each set of tests, + these tests contribute two expected errors to the templates. +*/ + +// +// 1 - Unwrapped MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate1 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate1<{{.*}}>' with non-memmovable template argument '{{.*}}'}} + +void bad1() { + NeedyTemplate1 a1; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 a2; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 a3; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 a4; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 a5; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 a6; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + + NeedyTemplate1 > b1; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > b2; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > b3; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > b4; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > b5; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > b6; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + + NeedyTemplate1 > c1; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c2; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c3; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c4; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c5; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c6; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c7; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c8; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c9; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c10; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c11; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c12; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} +} + +void good1() { + NeedyTemplate1 a1; + NeedyTemplate1 a2; + NeedyTemplate1 a3; + NeedyTemplate1 a4; + NeedyTemplate1 a5; + NeedyTemplate1 a6; + + NeedyTemplate1 > b1; + NeedyTemplate1 > b2; + NeedyTemplate1 > b3; + NeedyTemplate1 > b4; + NeedyTemplate1 > b5; + NeedyTemplate1 > b6; + + NeedyTemplate1 > c1; + NeedyTemplate1 > c2; + NeedyTemplate1 > c3; + NeedyTemplate1 > c4; + NeedyTemplate1 > c5; + NeedyTemplate1 > c6; + NeedyTemplate1 > c7; + NeedyTemplate1 > c8; + NeedyTemplate1 > c9; + NeedyTemplate1 > c10; + NeedyTemplate1 > c11; + NeedyTemplate1 > c12; + + NeedyTemplate1 > d1; + NeedyTemplate1 > d2; + NeedyTemplate1 > d3; + NeedyTemplate1 > d4; + NeedyTemplate1 > d5; + NeedyTemplate1 > d6; + NeedyTemplate1 > d7; + NeedyTemplate1 > d8; + NeedyTemplate1 > d9; + NeedyTemplate1 > d10; + NeedyTemplate1 > d11; + NeedyTemplate1 > d12; +} + +// +// 2 - Subclassed MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate2 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate2<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template +struct S_NeedyTemplate2 : NeedyTemplate2 {}; // expected-note-re 26 {{instantiation of 'NeedyTemplate2<{{.*}}>' requested here}} + +void bad2() { + S_NeedyTemplate2 a1; + S_NeedyTemplate2 a2; + S_NeedyTemplate2 a3; + S_NeedyTemplate2 a4; + S_NeedyTemplate2 a5; + S_NeedyTemplate2 a6; + + S_NeedyTemplate2 > b1; + S_NeedyTemplate2 > b2; + S_NeedyTemplate2 > b3; + S_NeedyTemplate2 > b4; + S_NeedyTemplate2 > b5; + S_NeedyTemplate2 > b6; + + S_NeedyTemplate2 > c1; + S_NeedyTemplate2 > c2; + S_NeedyTemplate2 > c3; + S_NeedyTemplate2 > c4; + S_NeedyTemplate2 > c5; + S_NeedyTemplate2 > c6; + S_NeedyTemplate2 > c7; + S_NeedyTemplate2 > c8; + S_NeedyTemplate2 > c9; + S_NeedyTemplate2 > c10; + S_NeedyTemplate2 > c11; + S_NeedyTemplate2 > c12; +} + +void good2() { + S_NeedyTemplate2 a1; + S_NeedyTemplate2 a2; + S_NeedyTemplate2 a3; + S_NeedyTemplate2 a4; + S_NeedyTemplate2 a5; + S_NeedyTemplate2 a6; + + S_NeedyTemplate2 > b1; + S_NeedyTemplate2 > b2; + S_NeedyTemplate2 > b3; + S_NeedyTemplate2 > b4; + S_NeedyTemplate2 > b5; + S_NeedyTemplate2 > b6; + + S_NeedyTemplate2 > c1; + S_NeedyTemplate2 > c2; + S_NeedyTemplate2 > c3; + S_NeedyTemplate2 > c4; + S_NeedyTemplate2 > c5; + S_NeedyTemplate2 > c6; + S_NeedyTemplate2 > c7; + S_NeedyTemplate2 > c8; + S_NeedyTemplate2 > c9; + S_NeedyTemplate2 > c10; + S_NeedyTemplate2 > c11; + S_NeedyTemplate2 > c12; + + S_NeedyTemplate2 > d1; + S_NeedyTemplate2 > d2; + S_NeedyTemplate2 > d3; + S_NeedyTemplate2 > d4; + S_NeedyTemplate2 > d5; + S_NeedyTemplate2 > d6; + S_NeedyTemplate2 > d7; + S_NeedyTemplate2 > d8; + S_NeedyTemplate2 > d9; + S_NeedyTemplate2 > d10; + S_NeedyTemplate2 > d11; + S_NeedyTemplate2 > d12; +} + +// +// 3 - Wrapped MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate3 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate3<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template +struct W_NeedyTemplate3 { + NeedyTemplate3 m; // expected-note-re 26 {{instantiation of 'NeedyTemplate3<{{.*}}>' requested here}} +}; +void bad3() { + W_NeedyTemplate3 a1; + W_NeedyTemplate3 a2; + W_NeedyTemplate3 a3; + W_NeedyTemplate3 a4; + W_NeedyTemplate3 a5; + W_NeedyTemplate3 a6; + + W_NeedyTemplate3 > b1; + W_NeedyTemplate3 > b2; + W_NeedyTemplate3 > b3; + W_NeedyTemplate3 > b4; + W_NeedyTemplate3 > b5; + W_NeedyTemplate3 > b6; + + W_NeedyTemplate3 > c1; + W_NeedyTemplate3 > c2; + W_NeedyTemplate3 > c3; + W_NeedyTemplate3 > c4; + W_NeedyTemplate3 > c5; + W_NeedyTemplate3 > c6; + W_NeedyTemplate3 > c7; + W_NeedyTemplate3 > c8; + W_NeedyTemplate3 > c9; + W_NeedyTemplate3 > c10; + W_NeedyTemplate3 > c11; + W_NeedyTemplate3 > c12; +} + +void good3() { + W_NeedyTemplate3 a1; + W_NeedyTemplate3 a2; + W_NeedyTemplate3 a3; + W_NeedyTemplate3 a4; + W_NeedyTemplate3 a5; + W_NeedyTemplate3 a6; + + W_NeedyTemplate3 > b1; + W_NeedyTemplate3 > b2; + W_NeedyTemplate3 > b3; + W_NeedyTemplate3 > b4; + W_NeedyTemplate3 > b5; + W_NeedyTemplate3 > b6; + + W_NeedyTemplate3 > c1; + W_NeedyTemplate3 > c2; + W_NeedyTemplate3 > c3; + W_NeedyTemplate3 > c4; + W_NeedyTemplate3 > c5; + W_NeedyTemplate3 > c6; + W_NeedyTemplate3 > c7; + W_NeedyTemplate3 > c8; + W_NeedyTemplate3 > c9; + W_NeedyTemplate3 > c10; + W_NeedyTemplate3 > c11; + W_NeedyTemplate3 > c12; + + W_NeedyTemplate3 > d1; + W_NeedyTemplate3 > d2; + W_NeedyTemplate3 > d3; + W_NeedyTemplate3 > d4; + W_NeedyTemplate3 > d5; + W_NeedyTemplate3 > d6; + W_NeedyTemplate3 > d7; + W_NeedyTemplate3 > d8; + W_NeedyTemplate3 > d9; + W_NeedyTemplate3 > d10; + W_NeedyTemplate3 > d11; + W_NeedyTemplate3 > d12; +} + +// +// 4 - Wrapped Subclassed MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate4 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate4<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template +struct S_NeedyTemplate4 : NeedyTemplate4 {}; // expected-note-re 26 {{instantiation of 'NeedyTemplate4<{{.*}}>' requested here}} +template +struct WS_NeedyTemplate4 { + S_NeedyTemplate4 m; +}; +void bad4() { + WS_NeedyTemplate4 a1; + WS_NeedyTemplate4 a2; + WS_NeedyTemplate4 a3; + WS_NeedyTemplate4 a4; + WS_NeedyTemplate4 a5; + WS_NeedyTemplate4 a6; + + WS_NeedyTemplate4 > b1; + WS_NeedyTemplate4 > b2; + WS_NeedyTemplate4 > b3; + WS_NeedyTemplate4 > b4; + WS_NeedyTemplate4 > b5; + WS_NeedyTemplate4 > b6; + + WS_NeedyTemplate4 > c1; + WS_NeedyTemplate4 > c2; + WS_NeedyTemplate4 > c3; + WS_NeedyTemplate4 > c4; + WS_NeedyTemplate4 > c5; + WS_NeedyTemplate4 > c6; + WS_NeedyTemplate4 > c7; + WS_NeedyTemplate4 > c8; + WS_NeedyTemplate4 > c9; + WS_NeedyTemplate4 > c10; + WS_NeedyTemplate4 > c11; + WS_NeedyTemplate4 > c12; +} + +void good4() { + WS_NeedyTemplate4 a1; + WS_NeedyTemplate4 a2; + WS_NeedyTemplate4 a3; + WS_NeedyTemplate4 a4; + WS_NeedyTemplate4 a5; + WS_NeedyTemplate4 a6; + + WS_NeedyTemplate4 > b1; + WS_NeedyTemplate4 > b2; + WS_NeedyTemplate4 > b3; + WS_NeedyTemplate4 > b4; + WS_NeedyTemplate4 > b5; + WS_NeedyTemplate4 > b6; + + WS_NeedyTemplate4 > c1; + WS_NeedyTemplate4 > c2; + WS_NeedyTemplate4 > c3; + WS_NeedyTemplate4 > c4; + WS_NeedyTemplate4 > c5; + WS_NeedyTemplate4 > c6; + WS_NeedyTemplate4 > c7; + WS_NeedyTemplate4 > c8; + WS_NeedyTemplate4 > c9; + WS_NeedyTemplate4 > c10; + WS_NeedyTemplate4 > c11; + WS_NeedyTemplate4 > c12; + + WS_NeedyTemplate4 > d1; + WS_NeedyTemplate4 > d2; + WS_NeedyTemplate4 > d3; + WS_NeedyTemplate4 > d4; + WS_NeedyTemplate4 > d5; + WS_NeedyTemplate4 > d6; + WS_NeedyTemplate4 > d7; + WS_NeedyTemplate4 > d8; + WS_NeedyTemplate4 > d9; + WS_NeedyTemplate4 > d10; + WS_NeedyTemplate4 > d11; + WS_NeedyTemplate4 > d12; +} + +// +// 5 - Subclassed Wrapped MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate5 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate5<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template +struct W_NeedyTemplate5 { + NeedyTemplate5 m; // expected-note-re 26 {{instantiation of 'NeedyTemplate5<{{.*}}>' requested here}} +}; +template +struct SW_NeedyTemplate5 : W_NeedyTemplate5 {}; +void bad5() { + SW_NeedyTemplate5 a1; + SW_NeedyTemplate5 a2; + SW_NeedyTemplate5 a3; + SW_NeedyTemplate5 a4; + SW_NeedyTemplate5 a5; + SW_NeedyTemplate5 a6; + + SW_NeedyTemplate5 > b1; + SW_NeedyTemplate5 > b2; + SW_NeedyTemplate5 > b3; + SW_NeedyTemplate5 > b4; + SW_NeedyTemplate5 > b5; + SW_NeedyTemplate5 > b6; + + SW_NeedyTemplate5 > c1; + SW_NeedyTemplate5 > c2; + SW_NeedyTemplate5 > c3; + SW_NeedyTemplate5 > c4; + SW_NeedyTemplate5 > c5; + SW_NeedyTemplate5 > c6; + SW_NeedyTemplate5 > c7; + SW_NeedyTemplate5 > c8; + SW_NeedyTemplate5 > c9; + SW_NeedyTemplate5 > c10; + SW_NeedyTemplate5 > c11; + SW_NeedyTemplate5 > c12; +} + +void good5() { + SW_NeedyTemplate5 a1; + SW_NeedyTemplate5 a2; + SW_NeedyTemplate5 a3; + SW_NeedyTemplate5 a4; + SW_NeedyTemplate5 a5; + SW_NeedyTemplate5 a6; + + SW_NeedyTemplate5 > b1; + SW_NeedyTemplate5 > b2; + SW_NeedyTemplate5 > b3; + SW_NeedyTemplate5 > b4; + SW_NeedyTemplate5 > b5; + SW_NeedyTemplate5 > b6; + + SW_NeedyTemplate5 > c1; + SW_NeedyTemplate5 > c2; + SW_NeedyTemplate5 > c3; + SW_NeedyTemplate5 > c4; + SW_NeedyTemplate5 > c5; + SW_NeedyTemplate5 > c6; + SW_NeedyTemplate5 > c7; + SW_NeedyTemplate5 > c8; + SW_NeedyTemplate5 > c9; + SW_NeedyTemplate5 > c10; + SW_NeedyTemplate5 > c11; + SW_NeedyTemplate5 > c12; + + SW_NeedyTemplate5 > d1; + SW_NeedyTemplate5 > d2; + SW_NeedyTemplate5 > d3; + SW_NeedyTemplate5 > d4; + SW_NeedyTemplate5 > d5; + SW_NeedyTemplate5 > d6; + SW_NeedyTemplate5 > d7; + SW_NeedyTemplate5 > d8; + SW_NeedyTemplate5 > d9; + SW_NeedyTemplate5 > d10; + SW_NeedyTemplate5 > d11; + SW_NeedyTemplate5 > d12; +} + +// +// 6 - MOZ_NEEDS_MEMMOVABLE_TYPE instantiated with default template argument +// +// Note: This has an extra error, because it also includes a test with the default template argument. +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate6 {T m;}; // expected-error-re 27 {{Cannot instantiate 'NeedyTemplate6<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template +struct W_NeedyTemplate6 { + NeedyTemplate6 m; // expected-note-re 27 {{instantiation of 'NeedyTemplate6<{{.*}}>' requested here}} +}; +template +struct SW_NeedyTemplate6 : W_NeedyTemplate6 {}; +// We create a different NonMovable type here, as NeedyTemplate6 will already be instantiated with NonMovable +struct MOZ_NON_MEMMOVABLE NonMovable2 {}; +template +struct Defaulted_SW_NeedyTemplate6 { + SW_NeedyTemplate6 m; +}; +void bad6() { + Defaulted_SW_NeedyTemplate6 a1; + Defaulted_SW_NeedyTemplate6 a2; + Defaulted_SW_NeedyTemplate6 a3; + Defaulted_SW_NeedyTemplate6 a4; + Defaulted_SW_NeedyTemplate6 a5; + Defaulted_SW_NeedyTemplate6 a6; + + Defaulted_SW_NeedyTemplate6 > b1; + Defaulted_SW_NeedyTemplate6 > b2; + Defaulted_SW_NeedyTemplate6 > b3; + Defaulted_SW_NeedyTemplate6 > b4; + Defaulted_SW_NeedyTemplate6 > b5; + Defaulted_SW_NeedyTemplate6 > b6; + + Defaulted_SW_NeedyTemplate6 > c1; + Defaulted_SW_NeedyTemplate6 > c2; + Defaulted_SW_NeedyTemplate6 > c3; + Defaulted_SW_NeedyTemplate6 > c4; + Defaulted_SW_NeedyTemplate6 > c5; + Defaulted_SW_NeedyTemplate6 > c6; + Defaulted_SW_NeedyTemplate6 > c7; + Defaulted_SW_NeedyTemplate6 > c8; + Defaulted_SW_NeedyTemplate6 > c9; + Defaulted_SW_NeedyTemplate6 > c10; + Defaulted_SW_NeedyTemplate6 > c11; + Defaulted_SW_NeedyTemplate6 > c12; + + Defaulted_SW_NeedyTemplate6<> c13; +} + +void good6() { + Defaulted_SW_NeedyTemplate6 a1; + Defaulted_SW_NeedyTemplate6 a2; + Defaulted_SW_NeedyTemplate6 a3; + Defaulted_SW_NeedyTemplate6 a4; + Defaulted_SW_NeedyTemplate6 a5; + Defaulted_SW_NeedyTemplate6 a6; + + Defaulted_SW_NeedyTemplate6 > b1; + Defaulted_SW_NeedyTemplate6 > b2; + Defaulted_SW_NeedyTemplate6 > b3; + Defaulted_SW_NeedyTemplate6 > b4; + Defaulted_SW_NeedyTemplate6 > b5; + Defaulted_SW_NeedyTemplate6 > b6; + + Defaulted_SW_NeedyTemplate6 > c1; + Defaulted_SW_NeedyTemplate6 > c2; + Defaulted_SW_NeedyTemplate6 > c3; + Defaulted_SW_NeedyTemplate6 > c4; + Defaulted_SW_NeedyTemplate6 > c5; + Defaulted_SW_NeedyTemplate6 > c6; + Defaulted_SW_NeedyTemplate6 > c7; + Defaulted_SW_NeedyTemplate6 > c8; + Defaulted_SW_NeedyTemplate6 > c9; + Defaulted_SW_NeedyTemplate6 > c10; + Defaulted_SW_NeedyTemplate6 > c11; + Defaulted_SW_NeedyTemplate6 > c12; + + Defaulted_SW_NeedyTemplate6 > d1; + Defaulted_SW_NeedyTemplate6 > d2; + Defaulted_SW_NeedyTemplate6 > d3; + Defaulted_SW_NeedyTemplate6 > d4; + Defaulted_SW_NeedyTemplate6 > d5; + Defaulted_SW_NeedyTemplate6 > d6; + Defaulted_SW_NeedyTemplate6 > d7; + Defaulted_SW_NeedyTemplate6 > d8; + Defaulted_SW_NeedyTemplate6 > d9; + Defaulted_SW_NeedyTemplate6 > d10; + Defaulted_SW_NeedyTemplate6 > d11; + Defaulted_SW_NeedyTemplate6 > d12; +} + +// +// 7 - MOZ_NEEDS_MEMMOVABLE_TYPE instantiated as default template argument +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate7 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate7<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template > +struct Defaulted_Templated_NeedyTemplate7 {Q m;}; // expected-note-re 26 {{instantiation of 'NeedyTemplate7<{{.*}}>' requested here}} +void bad7() { + Defaulted_Templated_NeedyTemplate7 a1; + Defaulted_Templated_NeedyTemplate7 a2; + Defaulted_Templated_NeedyTemplate7 a3; + Defaulted_Templated_NeedyTemplate7 a4; + Defaulted_Templated_NeedyTemplate7 a5; + Defaulted_Templated_NeedyTemplate7 a6; + + Defaulted_Templated_NeedyTemplate7 > b1; + Defaulted_Templated_NeedyTemplate7 > b2; + Defaulted_Templated_NeedyTemplate7 > b3; + Defaulted_Templated_NeedyTemplate7 > b4; + Defaulted_Templated_NeedyTemplate7 > b5; + Defaulted_Templated_NeedyTemplate7 > b6; + + Defaulted_Templated_NeedyTemplate7 > c1; + Defaulted_Templated_NeedyTemplate7 > c2; + Defaulted_Templated_NeedyTemplate7 > c3; + Defaulted_Templated_NeedyTemplate7 > c4; + Defaulted_Templated_NeedyTemplate7 > c5; + Defaulted_Templated_NeedyTemplate7 > c6; + Defaulted_Templated_NeedyTemplate7 > c7; + Defaulted_Templated_NeedyTemplate7 > c8; + Defaulted_Templated_NeedyTemplate7 > c9; + Defaulted_Templated_NeedyTemplate7 > c10; + Defaulted_Templated_NeedyTemplate7 > c11; + Defaulted_Templated_NeedyTemplate7 > c12; +} + +void good7() { + Defaulted_Templated_NeedyTemplate7 a1; + Defaulted_Templated_NeedyTemplate7 a2; + Defaulted_Templated_NeedyTemplate7 a3; + Defaulted_Templated_NeedyTemplate7 a4; + Defaulted_Templated_NeedyTemplate7 a5; + Defaulted_Templated_NeedyTemplate7 a6; + + Defaulted_Templated_NeedyTemplate7 > b1; + Defaulted_Templated_NeedyTemplate7 > b2; + Defaulted_Templated_NeedyTemplate7 > b3; + Defaulted_Templated_NeedyTemplate7 > b4; + Defaulted_Templated_NeedyTemplate7 > b5; + Defaulted_Templated_NeedyTemplate7 > b6; + + Defaulted_Templated_NeedyTemplate7 > c1; + Defaulted_Templated_NeedyTemplate7 > c2; + Defaulted_Templated_NeedyTemplate7 > c3; + Defaulted_Templated_NeedyTemplate7 > c4; + Defaulted_Templated_NeedyTemplate7 > c5; + Defaulted_Templated_NeedyTemplate7 > c6; + Defaulted_Templated_NeedyTemplate7 > c7; + Defaulted_Templated_NeedyTemplate7 > c8; + Defaulted_Templated_NeedyTemplate7 > c9; + Defaulted_Templated_NeedyTemplate7 > c10; + Defaulted_Templated_NeedyTemplate7 > c11; + Defaulted_Templated_NeedyTemplate7 > c12; + + Defaulted_Templated_NeedyTemplate7 > d1; + Defaulted_Templated_NeedyTemplate7 > d2; + Defaulted_Templated_NeedyTemplate7 > d3; + Defaulted_Templated_NeedyTemplate7 > d4; + Defaulted_Templated_NeedyTemplate7 > d5; + Defaulted_Templated_NeedyTemplate7 > d6; + Defaulted_Templated_NeedyTemplate7 > d7; + Defaulted_Templated_NeedyTemplate7 > d8; + Defaulted_Templated_NeedyTemplate7 > d9; + Defaulted_Templated_NeedyTemplate7 > d10; + Defaulted_Templated_NeedyTemplate7 > d11; + Defaulted_Templated_NeedyTemplate7 > d12; +} + +// +// 8 - Wrapped MOZ_NEEDS_MEMMOVABLE_TYPE instantiated as default template argument +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate8 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate8<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template > +struct Defaulted_Templated_NeedyTemplate8 {Q m;}; // expected-note-re 26 {{instantiation of 'NeedyTemplate8<{{.*}}>' requested here}} +template +struct W_Defaulted_Templated_NeedyTemplate8 { + Defaulted_Templated_NeedyTemplate8 m; +}; +void bad8() { + W_Defaulted_Templated_NeedyTemplate8 a1; + W_Defaulted_Templated_NeedyTemplate8 a2; + W_Defaulted_Templated_NeedyTemplate8 a3; + W_Defaulted_Templated_NeedyTemplate8 a4; + W_Defaulted_Templated_NeedyTemplate8 a5; + W_Defaulted_Templated_NeedyTemplate8 a6; + + W_Defaulted_Templated_NeedyTemplate8 > b1; + W_Defaulted_Templated_NeedyTemplate8 > b2; + W_Defaulted_Templated_NeedyTemplate8 > b3; + W_Defaulted_Templated_NeedyTemplate8 > b4; + W_Defaulted_Templated_NeedyTemplate8 > b5; + W_Defaulted_Templated_NeedyTemplate8 > b6; + + W_Defaulted_Templated_NeedyTemplate8 > c1; + W_Defaulted_Templated_NeedyTemplate8 > c2; + W_Defaulted_Templated_NeedyTemplate8 > c3; + W_Defaulted_Templated_NeedyTemplate8 > c4; + W_Defaulted_Templated_NeedyTemplate8 > c5; + W_Defaulted_Templated_NeedyTemplate8 > c6; + W_Defaulted_Templated_NeedyTemplate8 > c7; + W_Defaulted_Templated_NeedyTemplate8 > c8; + W_Defaulted_Templated_NeedyTemplate8 > c9; + W_Defaulted_Templated_NeedyTemplate8 > c10; + W_Defaulted_Templated_NeedyTemplate8 > c11; + W_Defaulted_Templated_NeedyTemplate8 > c12; +} + +void good8() { + W_Defaulted_Templated_NeedyTemplate8 a1; + W_Defaulted_Templated_NeedyTemplate8 a2; + W_Defaulted_Templated_NeedyTemplate8 a3; + W_Defaulted_Templated_NeedyTemplate8 a4; + W_Defaulted_Templated_NeedyTemplate8 a5; + W_Defaulted_Templated_NeedyTemplate8 a6; + + W_Defaulted_Templated_NeedyTemplate8 > b1; + W_Defaulted_Templated_NeedyTemplate8 > b2; + W_Defaulted_Templated_NeedyTemplate8 > b3; + W_Defaulted_Templated_NeedyTemplate8 > b4; + W_Defaulted_Templated_NeedyTemplate8 > b5; + W_Defaulted_Templated_NeedyTemplate8 > b6; + + W_Defaulted_Templated_NeedyTemplate8 > c1; + W_Defaulted_Templated_NeedyTemplate8 > c2; + W_Defaulted_Templated_NeedyTemplate8 > c3; + W_Defaulted_Templated_NeedyTemplate8 > c4; + W_Defaulted_Templated_NeedyTemplate8 > c5; + W_Defaulted_Templated_NeedyTemplate8 > c6; + W_Defaulted_Templated_NeedyTemplate8 > c7; + W_Defaulted_Templated_NeedyTemplate8 > c8; + W_Defaulted_Templated_NeedyTemplate8 > c9; + W_Defaulted_Templated_NeedyTemplate8 > c10; + W_Defaulted_Templated_NeedyTemplate8 > c11; + W_Defaulted_Templated_NeedyTemplate8 > c12; + + W_Defaulted_Templated_NeedyTemplate8 > d1; + W_Defaulted_Templated_NeedyTemplate8 > d2; + W_Defaulted_Templated_NeedyTemplate8 > d3; + W_Defaulted_Templated_NeedyTemplate8 > d4; + W_Defaulted_Templated_NeedyTemplate8 > d5; + W_Defaulted_Templated_NeedyTemplate8 > d6; + W_Defaulted_Templated_NeedyTemplate8 > d7; + W_Defaulted_Templated_NeedyTemplate8 > d8; + W_Defaulted_Templated_NeedyTemplate8 > d9; + W_Defaulted_Templated_NeedyTemplate8 > d10; + W_Defaulted_Templated_NeedyTemplate8 > d11; + W_Defaulted_Templated_NeedyTemplate8 > d12; +} + +/* + SpecializedNonMovable is a non-movable class which has an explicit specialization of NeedyTemplate + for it. Instantiations of NeedyTemplateN should be legal as the explicit + specialization isn't annotated with MOZ_NEEDS_MEMMOVABLE_TYPE. + + However, as it is MOZ_NON_MEMMOVABLE, derived classes and members shouldn't be able to be used to + instantiate NeedyTemplate. +*/ + +struct MOZ_NON_MEMMOVABLE SpecializedNonMovable {}; +struct S_SpecializedNonMovable : SpecializedNonMovable {}; // expected-note 8 {{'S_SpecializedNonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'SpecializedNonMovable'}} + +// Specialize all of the NeedyTemplates with SpecializedNonMovable. +template <> +struct NeedyTemplate1 {}; +template <> +struct NeedyTemplate2 {}; +template <> +struct NeedyTemplate3 {}; +template <> +struct NeedyTemplate4 {}; +template <> +struct NeedyTemplate5 {}; +template <> +struct NeedyTemplate6 {}; +template <> +struct NeedyTemplate7 {}; +template <> +struct NeedyTemplate8 {}; + +void specialization() { + /* + SpecializedNonMovable has a specialization for every variant of NeedyTemplate, + so these templates are valid, even though SpecializedNonMovable isn't + memmovable + */ + NeedyTemplate1 a1; + S_NeedyTemplate2 a2; + W_NeedyTemplate3 a3; + WS_NeedyTemplate4 a4; + SW_NeedyTemplate5 a5; + Defaulted_SW_NeedyTemplate6 a6; + Defaulted_Templated_NeedyTemplate7 a7; + W_Defaulted_Templated_NeedyTemplate8 a8; + + /* + These entries contain an element which is SpecializedNonMovable, and are non-movable + as there is no valid specialization, and their member is non-memmovable + */ + NeedyTemplate1 > b1; // expected-note-re {{instantiation of 'NeedyTemplate1{{ ?}}>' requested here}} + S_NeedyTemplate2 > b2; + W_NeedyTemplate3 > b3; + WS_NeedyTemplate4 > b4; + SW_NeedyTemplate5 > b5; + Defaulted_SW_NeedyTemplate6 > b6; + Defaulted_Templated_NeedyTemplate7 > b7; + W_Defaulted_Templated_NeedyTemplate8 > b8; + + /* + The subclass of SpecializedNonMovable, is also non-memmovable, + as there is no valid specialization. + */ + NeedyTemplate1 c1; // expected-note {{instantiation of 'NeedyTemplate1' requested here}} + S_NeedyTemplate2 c2; + W_NeedyTemplate3 c3; + WS_NeedyTemplate4 c4; + SW_NeedyTemplate5 c5; + Defaulted_SW_NeedyTemplate6 c6; + Defaulted_Templated_NeedyTemplate7 c7; + W_Defaulted_Templated_NeedyTemplate8 c8; +} + +class MOZ_NEEDS_MEMMOVABLE_MEMBERS NeedsMemMovableMembers { + Movable m1; + NonMovable m2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'm2' of type 'NonMovable'}} + S_Movable sm1; + S_NonMovable sm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'sm2' of type 'S_NonMovable'}} + W_Movable wm1; + W_NonMovable wm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'wm2' of type 'W_NonMovable'}} + SW_Movable swm1; + SW_NonMovable swm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'swm2' of type 'SW_NonMovable'}} + WS_Movable wsm1; + WS_NonMovable wsm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'wsm2' of type 'WS_NonMovable'}} + SWS_Movable swsm1; + SWS_NonMovable swsm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'swsm2' of type 'SWS_NonMovable'}} +}; + +class NeedsMemMovableMembersDerived : public NeedsMemMovableMembers {}; diff --git a/build/clang-plugin/tests/TestNonMemMovableStd.cpp b/build/clang-plugin/tests/TestNonMemMovableStd.cpp new file mode 100644 index 0000000000..b380d07186 --- /dev/null +++ b/build/clang-plugin/tests/TestNonMemMovableStd.cpp @@ -0,0 +1,70 @@ +#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type"))) + +template +class MOZ_NEEDS_MEMMOVABLE_TYPE Mover { T mForceInst; }; // expected-error-re 9 {{Cannot instantiate 'Mover<{{.*}}>' with non-memmovable template argument '{{.*}}'}} + +namespace std { +// In theory defining things in std:: like this invokes undefined +// behavior, but in practice it's good enough for this test case. +template class basic_string { // expected-note 2 {{'std::basic_string' is a non-memmove()able type because it is an stl-provided type not guaranteed to be memmove-able}} expected-note {{'std::string' (aka 'basic_string') is a non-memmove()able type because it is an stl-provided type not guaranteed to be memmove-able}} + public: + basic_string(); + basic_string(const basic_string&); + basic_string(basic_string&&); + basic_string& operator=(const basic_string&); + basic_string& operator=(basic_string&&); + ~basic_string(); +}; +typedef basic_string string; +template class pair { T mT; U mU; }; // expected-note-re 4 {{'std::pair' is a non-memmove()able type because it has a template argument non-memmove()able type '{{.*}}'}} + +struct has_nontrivial_dtor { // expected-note 2 {{'std::has_nontrivial_dtor' is a non-memmove()able type because it is an stl-provided type not guaranteed to be memmove-able}} + has_nontrivial_dtor() = default; + ~has_nontrivial_dtor(); +}; +struct has_nontrivial_copy { // expected-note 2 {{'std::has_nontrivial_copy' is a non-memmove()able type because it is an stl-provided type not guaranteed to be memmove-able}} + has_nontrivial_copy() = default; + has_nontrivial_copy(const has_nontrivial_copy&); + has_nontrivial_copy& operator=(const has_nontrivial_copy&); +}; +struct has_nontrivial_move { // expected-note 2 {{'std::has_nontrivial_move' is a non-memmove()able type because it is an stl-provided type not guaranteed to be memmove-able}} + has_nontrivial_move() = default; + has_nontrivial_move(const has_nontrivial_move&); + has_nontrivial_move& operator=(const has_nontrivial_move&); +}; +struct has_trivial_dtor { + has_trivial_dtor() = default; + ~has_trivial_dtor() = default; +}; +struct has_trivial_copy { + has_trivial_copy() = default; + has_trivial_copy(const has_trivial_copy&) = default; + has_trivial_copy& operator=(const has_trivial_copy&) = default; +}; +struct has_trivial_move { + has_trivial_move() = default; + has_trivial_move(const has_trivial_move&) = default; + has_trivial_move& operator=(const has_trivial_move&) = default; +}; +} + +class HasString { std::string m; }; // expected-note {{'HasString' is a non-memmove()able type because member 'm' is a non-memmove()able type 'std::string' (aka 'basic_string')}} + +static Mover bad; // expected-note-re {{instantiation of 'Mover{{ ?}}>' requested here}} +static Mover bad_mem; // expected-note {{instantiation of 'Mover' requested here}} +static Mover> good; +static Mover> not_good; // expected-note-re {{instantiation of 'Mover{{ ?}}>{{ ?}}>' requested here}} + +static Mover nontrivial_dtor; // expected-note {{instantiation of 'Mover' requested here}} +static Mover nontrivial_copy; // expected-note {{instantiation of 'Mover' requested here}} +static Mover nontrivial_move; // expected-note {{instantiation of 'Mover' requested here}} +static Mover trivial_dtor; +static Mover trivial_copy; +static Mover trivial_move; + +static Mover> pair_nontrivial_dtor; // expected-note {{instantiation of 'Mover>' requested here}} +static Mover> pair_nontrivial_copy; // expected-note {{instantiation of 'Mover>' requested here}} +static Mover> pair_nontrivial_move; // expected-note {{instantiation of 'Mover>' requested here}} +static Mover> pair_trivial_dtor; +static Mover> pair_trivial_copy; +static Mover> pair_trivial_move; diff --git a/build/clang-plugin/tests/TestNonMemMovableStdAtomic.cpp b/build/clang-plugin/tests/TestNonMemMovableStdAtomic.cpp new file mode 100644 index 0000000000..b8aef2eacd --- /dev/null +++ b/build/clang-plugin/tests/TestNonMemMovableStdAtomic.cpp @@ -0,0 +1,30 @@ +// expected-no-diagnostics + +#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type"))) + +template +class MOZ_NEEDS_MEMMOVABLE_TYPE Mover { T mForceInst; }; + +#include +#include +struct CustomType{}; +static struct { + Mover> m1; + Mover> m2; + Mover> m3; + Mover> m4; + Mover> m5; + Mover> m6; + Mover> m7; + Mover> m8; + Mover> m9; + Mover> m10; + Mover> m11; + Mover> m12; + Mover> m13; + Mover> m14; + Mover> m15; + Mover> m16; + Mover> m17; + Mover> m18; +} good; diff --git a/build/clang-plugin/tests/TestNonParameterChecker.cpp b/build/clang-plugin/tests/TestNonParameterChecker.cpp new file mode 100644 index 0000000000..291ef949f6 --- /dev/null +++ b/build/clang-plugin/tests/TestNonParameterChecker.cpp @@ -0,0 +1,187 @@ +#define MOZ_NON_PARAM __attribute__((annotate("moz_non_param"))) + +struct Param {}; +struct MOZ_NON_PARAM NonParam {}; +union MOZ_NON_PARAM NonParamUnion {}; +class MOZ_NON_PARAM NonParamClass {}; +enum MOZ_NON_PARAM NonParamEnum { X, Y, Z }; +enum class MOZ_NON_PARAM NonParamEnumClass { X, Y, Z }; + +struct HasNonParamStruct { NonParam x; int y; }; // expected-note 14 {{'HasNonParamStruct' is a non-param type because member 'x' is a non-param type 'NonParam'}} +union HasNonParamUnion { NonParam x; int y; }; // expected-note 18 {{'HasNonParamUnion' is a non-param type because member 'x' is a non-param type 'NonParam'}} +struct HasNonParamStructUnion { HasNonParamUnion z; }; // expected-note 9 {{'HasNonParamStructUnion' is a non-param type because member 'z' is a non-param type 'HasNonParamUnion'}} + +#define MAYBE_STATIC +#include "NonParameterTestCases.h" +#undef MAYBE_STATIC + +// Do not check typedef and using. +typedef void (*funcTypeParam)(Param x); +typedef void (*funcTypeNonParam)(NonParam x); + +using usingFuncTypeParam = void (*)(Param x); +using usingFuncTypeNonParam = void (*)(NonParam x); + +class class_ +{ + explicit class_(Param x) {} + explicit class_(NonParam x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + explicit class_(HasNonParamStruct x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + explicit class_(HasNonParamUnion x) {} //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + explicit class_(HasNonParamStructUnion x) {} //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + +#define MAYBE_STATIC +#include "NonParameterTestCases.h" +#undef MAYBE_STATIC +}; + +class classWithStatic +{ +#define MAYBE_STATIC static +#include "NonParameterTestCases.h" +#undef MAYBE_STATIC +}; + +template +class tmplClassForParam +{ +public: + void raw(T x) {} + void rawDefault(T x = T()) {} + void const_(const T x) {} + void ptr(T* x) {} + void ref(T& x) {} + void constRef(const T& x) {} + + void notCalled(T x) {} +}; + +template +class tmplClassForNonParam +{ +public: + void raw(T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + void rawDefault(T x = T()) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + void const_(const T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + void ptr(T* x) {} + void ref(T& x) {} + void constRef(const T& x) {} + + void notCalled(T x) {} +}; + +template +class tmplClassForHasNonParamStruct +{ +public: + void raw(T x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + void rawDefault(T x = T()) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + void const_(const T x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + void ptr(T* x) {} + void ref(T& x) {} + void constRef(const T& x) {} + + void notCalled(T x) {} +}; + +void testTemplateClass() +{ + tmplClassForParam paramClass; + Param param; + paramClass.raw(param); + paramClass.rawDefault(); + paramClass.const_(param); + paramClass.ptr(¶m); + paramClass.ref(param); + paramClass.constRef(param); + + tmplClassForNonParam nonParamClass; //expected-note 3 {{The bad argument was passed to 'tmplClassForNonParam' here}} + NonParam nonParam; + nonParamClass.raw(nonParam); + nonParamClass.rawDefault(); + nonParamClass.const_(nonParam); + nonParamClass.ptr(&nonParam); + nonParamClass.ref(nonParam); + nonParamClass.constRef(nonParam); + + tmplClassForHasNonParamStruct hasNonParamStructClass;//expected-note 3 {{The bad argument was passed to 'tmplClassForHasNonParamStruct' here}} + HasNonParamStruct hasNonParamStruct; + hasNonParamStructClass.raw(hasNonParamStruct); + hasNonParamStructClass.rawDefault(); + hasNonParamStructClass.const_(hasNonParamStruct); + hasNonParamStructClass.ptr(&hasNonParamStruct); + hasNonParamStructClass.ref(hasNonParamStruct); + hasNonParamStructClass.constRef(hasNonParamStruct); +} + +template +class NestedTemplateInner +{ +public: + void raw(T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +}; + +template +class nestedTemplateOuter +{ +public: + void constRef(const T& x) { + NestedTemplateInner inner; //expected-note {{The bad argument was passed to 'NestedTemplateInner' here}} + inner.raw(x); + } +}; + +void testNestedTemplateClass() +{ + nestedTemplateOuter outer; + NonParam nonParam; + outer.constRef(nonParam); // FIXME: this line needs note "The bad argument was passed to 'constRef' here" +} + +template +void tmplFuncForParam(T x) {} +template +void tmplFuncForNonParam(T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +template +void tmplFuncForNonParamImplicit(T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +template +void tmplFuncForHasNonParamStruct(T x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +template +void tmplFuncForHasNonParamStructImplicit(T x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + +void testTemplateFunc() +{ + Param param; + tmplFuncForParam(param); + + NonParam nonParam; + tmplFuncForNonParam(nonParam); // FIXME: this line needs note "The bad argument was passed to 'tmplFuncForNonParam' here" + tmplFuncForNonParamImplicit(nonParam); // FIXME: this line needs note "The bad argument was passed to 'tmplFuncForNonParamImplicit' here" + + HasNonParamStruct hasNonParamStruct; + tmplFuncForHasNonParamStruct(hasNonParamStruct); // FIXME: this line needs note "The bad argument was passed to 'tmplFuncForHasNonParamStruct' here" + tmplFuncForHasNonParamStructImplicit(hasNonParamStruct); // FIXME: this line needs note "The bad argument was passed to 'tmplFuncForHasNonParamStructImplicit' here" +} + +void testLambda() +{ + auto paramLambda = [](Param x) -> void {}; + auto nonParamLambda = [](NonParam x) -> void {}; //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + auto nonParamStructLambda = [](HasNonParamStruct x) -> void {}; //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + auto nonParamUnionLambda = [](HasNonParamUnion x) -> void {}; //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + auto nonParamStructUnionLambda = [](HasNonParamStructUnion x) -> void {}; //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + + (void)[](Param x) -> void {}; + (void)[](NonParam x) -> void {}; //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + (void)[](HasNonParamStruct x) -> void {}; //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + (void)[](HasNonParamUnion x) -> void {}; //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + (void)[](HasNonParamStructUnion x) -> void {}; //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +} + +struct alignas(16) AlignasStruct { char a; ~AlignasStruct(); }; // expected-note {{'AlignasStruct' is a non-param type because it has an explicit alignment of '16'}} +void takesAlignasStruct(AlignasStruct x) { } // expected-error {{Type 'AlignasStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +void takesAlignasStructByRef(const AlignasStruct& x) { } + +struct AlignasMember { alignas(16) char a; ~AlignasMember(); }; // expected-note {{'AlignasMember' is a non-param type because member 'a' has an explicit alignment of '16'}} +void takesAlignasMember(AlignasMember x) { } // expected-error {{Type 'AlignasMember' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +void takesAlignasMemberByRef(const AlignasMember& x) { } diff --git a/build/clang-plugin/tests/TestNonTemporaryClass.cpp b/build/clang-plugin/tests/TestNonTemporaryClass.cpp new file mode 100644 index 0000000000..682c8ad530 --- /dev/null +++ b/build/clang-plugin/tests/TestNonTemporaryClass.cpp @@ -0,0 +1,70 @@ +#define MOZ_NON_TEMPORARY_CLASS __attribute__((annotate("moz_non_temporary_class"))) +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +#include + +struct MOZ_NON_TEMPORARY_CLASS NonTemporary { + int i; + NonTemporary() {} + MOZ_IMPLICIT NonTemporary(int a) {} + NonTemporary(int a, int b) {} + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template +struct MOZ_NON_TEMPORARY_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void gobbleref(const NonTemporary&) { } + +template +void gobbleanyref(const T&) { } + +void misuseNonTemporaryClass(int len) { + NonTemporary invalid; + NonTemporary alsoInvalid[2]; + static NonTemporary invalidStatic; + static NonTemporary alsoInvalidStatic[2]; + + gobble(&invalid); + gobble(&invalidStatic); + gobble(&alsoInvalid[0]); + + gobbleref(NonTemporary()); // expected-error {{variable of type 'NonTemporary' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(NonTemporary(10, 20)); // expected-error {{variable of type 'NonTemporary' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(NonTemporary(10)); // expected-error {{variable of type 'NonTemporary' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(10); // expected-error {{variable of type 'NonTemporary' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} + gobbleanyref(TemplateClass()); // expected-error {{variable of type 'TemplateClass' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} + + gobble(new NonTemporary); + gobble(new NonTemporary[10]); + gobble(new TemplateClass); + gobble(len <= 5 ? &invalid : new NonTemporary); + + char buffer[sizeof(NonTemporary)]; + gobble(new (buffer) NonTemporary); +} + +void defaultArg(const NonTemporary& arg = NonTemporary()) { +} + +NonTemporary invalidStatic; +struct RandomClass { + NonTemporary nonstaticMember; // expected-note {{'RandomClass' is a non-temporary type because member 'nonstaticMember' is a non-temporary type 'NonTemporary'}} + static NonTemporary staticMember; +}; +struct MOZ_NON_TEMPORARY_CLASS RandomNonTemporaryClass { + NonTemporary nonstaticMember; + static NonTemporary staticMember; +}; + +struct BadInherit : NonTemporary {}; // expected-note {{'BadInherit' is a non-temporary type because it inherits from a non-temporary type 'NonTemporary'}} + +void useStuffWrongly() { + gobbleanyref(BadInherit()); // expected-error {{variable of type 'BadInherit' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} + gobbleanyref(RandomClass()); // expected-error {{variable of type 'RandomClass' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} +} diff --git a/build/clang-plugin/tests/TestNonTrivialTypeInFfi.cpp b/build/clang-plugin/tests/TestNonTrivialTypeInFfi.cpp new file mode 100644 index 0000000000..e491122b99 --- /dev/null +++ b/build/clang-plugin/tests/TestNonTrivialTypeInFfi.cpp @@ -0,0 +1,65 @@ +// clang warns for some of these on its own, but we're not testing that, plus +// some of them (TrivialT) is a false positive (clang doesn't realize the +// type is fully specialized below). +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wreturn-type-c-linkage" + +struct Opaque; +struct Trivial { + int foo; + char bar; + Opaque* baz; +}; + +template +struct TrivialT { + int foo; + char bar; + T* baz; +}; + +struct NonTrivial { + ~NonTrivial() { + } + + Opaque* ptr; +}; + +template +struct NonTrivialT { + ~NonTrivialT() { + delete ptr; + } + + T* ptr; +}; + +struct TransitivelyNonTrivial { + NonTrivial nontrivial; +}; + +extern "C" void Foo(); +extern "C" Trivial Foo1(); +extern "C" NonTrivial Foo2(); // expected-error {{Type 'NonTrivial' must not be used as return type of extern "C" function}} expected-note {{Please consider using a pointer or reference instead}} +extern "C" NonTrivialT Foo3(); // expected-error {{Type 'NonTrivialT' must not be used as return type of extern "C" function}} expected-note {{Please consider using a pointer or reference, or explicitly instantiating the template instead}} +extern "C" NonTrivialT Foo4(); // expected-error {{Type 'NonTrivialT' must not be used as return type of extern "C" function}} expected-note {{Please consider using a pointer or reference, or explicitly instantiating the template instead}} + +extern "C" NonTrivial* Foo5(); + +extern "C" TrivialT Foo6(); +extern "C" TrivialT Foo7(); // expected-error {{Type 'TrivialT' must not be used as return type of extern "C" function}} expected-note {{Please consider using a pointer or reference, or explicitly instantiating the template instead}} +extern "C" Trivial* Foo8(); + +extern "C" void Foo9(Trivial); +extern "C" void Foo10(NonTrivial); // expected-error {{Type 'NonTrivial' must not be used as parameter to extern "C" function}} expected-note {{Please consider using a pointer or reference instead}} +extern "C" void Foo11(NonTrivial*); +extern "C" void Foo12(NonTrivialT); // expected-error {{Type 'NonTrivialT' must not be used as parameter to extern "C" function}} expected-note {{Please consider using a pointer or reference, or explicitly instantiating the template instead}} +extern "C" void Foo13(TrivialT); +extern "C" void Foo14(TrivialT); // expected-error {{Type 'TrivialT' must not be used as parameter to extern "C" function}} expected-note {{Please consider using a pointer or reference, or explicitly instantiating the template instead}} + +extern "C" TransitivelyNonTrivial Foo15(); // expected-error {{Type 'TransitivelyNonTrivial' must not be used as return type of extern "C" function}} expected-note {{Please consider using a pointer or reference instead}} +extern "C" void Foo16(TransitivelyNonTrivial); // expected-error {{Type 'TransitivelyNonTrivial' must not be used as parameter to extern "C" function}} expected-note {{Please consider using a pointer or reference instead}} + +template struct TrivialT; + +#pragma GCC diagnostic pop diff --git a/build/clang-plugin/tests/TestOverrideBaseCall.cpp b/build/clang-plugin/tests/TestOverrideBaseCall.cpp new file mode 100644 index 0000000000..6fdaaad04e --- /dev/null +++ b/build/clang-plugin/tests/TestOverrideBaseCall.cpp @@ -0,0 +1,175 @@ +#define MOZ_REQUIRED_BASE_METHOD __attribute__((annotate("moz_required_base_method"))) + +class Base { +public: + virtual void fo() MOZ_REQUIRED_BASE_METHOD { + } + + virtual int foRet() MOZ_REQUIRED_BASE_METHOD { + return 0; + } +}; + +class BaseOne : public Base { +public: + virtual void fo() MOZ_REQUIRED_BASE_METHOD { + Base::fo(); + } +}; + +class BaseSecond : public Base { +public: + virtual void fo() MOZ_REQUIRED_BASE_METHOD { + Base::fo(); + } +}; + +class Deriv : public BaseOne, public BaseSecond { +public: + void func() { + } + + void fo() { + func(); + BaseSecond::fo(); + BaseOne::fo(); + } +}; + +class DerivSimple : public Base { +public: + void fo() { // expected-error {{Method Base::fo must be called in all overrides, but is not called in this override defined for class DerivSimple}} + } +}; + +class BaseVirtualOne : public virtual Base { +}; + +class BaseVirtualSecond: public virtual Base { +}; + +class DerivVirtual : public BaseVirtualOne, public BaseVirtualSecond { +public: + void fo() { + Base::fo(); + } +}; + +class DerivIf : public Base { +public: + void fo() { + if (true) { + Base::fo(); + } + } +}; + +class DerivIfElse : public Base { +public: + void fo() { + if (true) { + Base::fo(); + } else { + Base::fo(); + } + } +}; + +class DerivFor : public Base { +public: + void fo() { + for (int i = 0; i < 10; i++) { + Base::fo(); + } + } +}; + +class DerivDoWhile : public Base { +public: + void fo() { + do { + Base::fo(); + } while(false); + } +}; + +class DerivWhile : public Base { +public: + void fo() { + while (true) { + Base::fo(); + break; + } + } +}; + +class DerivAssignment : public Base { +public: + int foRet() { + return foRet(); + } +}; + +class BaseOperator { +private: + int value; +public: + BaseOperator() : value(0) { + } + virtual BaseOperator& operator++() MOZ_REQUIRED_BASE_METHOD { + value++; + return *this; + } +}; + +class DerivOperatorErr : public BaseOperator { +private: + int value; +public: + DerivOperatorErr() : value(0) { + } + DerivOperatorErr& operator++() { // expected-error {{Method BaseOperator::operator++ must be called in all overrides, but is not called in this override defined for class DerivOperatorErr}} + value++; + return *this; + } +}; + +class DerivOperator : public BaseOperator { +private: + int value; +public: + DerivOperator() : value(0) { + } + DerivOperator& operator++() { + BaseOperator::operator++(); + value++; + return *this; + } +}; + +class DerivPrime : public Base { +public: + void fo() { + Base::fo(); + } +}; + +class DerivSecondErr : public DerivPrime { +public: + void fo() { // expected-error {{Method Base::fo must be called in all overrides, but is not called in this override defined for class DerivSecondErr}} + } +}; + +class DerivSecond : public DerivPrime { +public: + void fo() { + Base::fo(); + } +}; + +class DerivSecondIndirect : public DerivPrime { +public: + void fo() { + DerivPrime::fo(); + } +}; diff --git a/build/clang-plugin/tests/TestOverrideBaseCallAnnotation.cpp b/build/clang-plugin/tests/TestOverrideBaseCallAnnotation.cpp new file mode 100644 index 0000000000..e268122c69 --- /dev/null +++ b/build/clang-plugin/tests/TestOverrideBaseCallAnnotation.cpp @@ -0,0 +1,47 @@ +#define MOZ_REQUIRED_BASE_METHOD __attribute__((annotate("moz_required_base_method"))) + +class Base { +public: + virtual void fo() MOZ_REQUIRED_BASE_METHOD { + } +}; + +class BaseNonVirtual { +public: + void fo() MOZ_REQUIRED_BASE_METHOD { // expected-error {{MOZ_REQUIRED_BASE_METHOD can be used only on virtual methods}} + } +}; + +class Deriv : public BaseNonVirtual { +public: + virtual void fo() MOZ_REQUIRED_BASE_METHOD { + } +}; + +class DerivVirtual : public Base { +public: + void fo() MOZ_REQUIRED_BASE_METHOD { + Base::fo(); + } +}; + +class BaseOperator { +public: + BaseOperator& operator++() MOZ_REQUIRED_BASE_METHOD { // expected-error {{MOZ_REQUIRED_BASE_METHOD can be used only on virtual methods}} + return *this; + } +}; + +class DerivOperator : public BaseOperator { +public: + virtual DerivOperator& operator++() { + return *this; + } +}; + +class DerivPrimeOperator : public DerivOperator { +public: + DerivPrimeOperator& operator++() { + return *this; + } +}; diff --git a/build/clang-plugin/tests/TestParamTraitsEnum.cpp b/build/clang-plugin/tests/TestParamTraitsEnum.cpp new file mode 100644 index 0000000000..a250250bfe --- /dev/null +++ b/build/clang-plugin/tests/TestParamTraitsEnum.cpp @@ -0,0 +1,94 @@ +typedef enum { + BadFirst, + BadSecond, + BadThird +} BadEnum; + +typedef enum { + NestedFirst, + NestedSecond +} NestedBadEnum; + +typedef enum { + GoodFirst, + GoodSecond, + GoodLast +} GoodEnum; + +enum RawEnum { + RawFirst, + RawLast +}; + +enum class ClassEnum { + ClassFirst, + ClassLast +}; + +template struct ParamTraits; + +// Simplified EnumSerializer etc. from IPCMessageUtils.h +template +struct EnumSerializer { + typedef E paramType; +}; + +template +class ContiguousEnumValidator +{}; + +template +struct ContiguousEnumSerializer + : EnumSerializer> +{}; + +// Typical ParamTraits implementation that should be avoided +template<> +struct ParamTraits // expected-error {{Custom ParamTraits implementation for an enum type}} expected-note {{Please use a helper class for example ContiguousEnumSerializer}} +{ + typedef ClassEnum paramType; +}; + +template<> +struct ParamTraits // expected-error {{Custom ParamTraits implementation for an enum type}} expected-note {{Please use a helper class for example ContiguousEnumSerializer}} +{ + typedef enum RawEnum paramType; +}; + +template<> +struct ParamTraits // expected-error {{Custom ParamTraits implementation for an enum type}} expected-note {{Please use a helper class for example ContiguousEnumSerializer}} +{ + typedef BadEnum paramType; +}; + +// Make sure the analysis catches nested typedefs +typedef NestedBadEnum NestedDefLevel1; +typedef NestedDefLevel1 NestedDefLevel2; + +template<> +struct ParamTraits // expected-error {{Custom ParamTraits implementation for an enum type}} expected-note {{Please use a helper class for example ContiguousEnumSerializer}} +{ + typedef NestedDefLevel2 paramType; +}; + +// Make sure a non enum typedef is not accidentally flagged +typedef int IntTypedef; + +template<> +struct ParamTraits +{ + typedef IntTypedef paramType; +}; + +// Make sure ParamTraits using helper classes are not flagged +template<> +struct ParamTraits +: public ContiguousEnumSerializer +{}; diff --git a/build/clang-plugin/tests/TestRefCountedCopyConstructor.cpp b/build/clang-plugin/tests/TestRefCountedCopyConstructor.cpp new file mode 100644 index 0000000000..d3bd73084c --- /dev/null +++ b/build/clang-plugin/tests/TestRefCountedCopyConstructor.cpp @@ -0,0 +1,25 @@ +// Implicit copy construct which is unused +class RC1 { + void AddRef(); + void Release(); + int mRefCnt; +}; + +// Explicit copy constructor which is used +class RC2 { +public: + RC2(); + RC2(const RC2&); +private: + void AddRef(); + void Release(); + int mRefCnt; +}; + +void f() { + RC1* r1 = new RC1(); + RC1* r1p = new RC1(*r1); // expected-error {{Invalid use of compiler-provided copy constructor on refcounted type}} expected-note {{The default copy constructor also copies the default mRefCnt property, leading to reference count imbalance issues. Please provide your own copy constructor which only copies the fields which need to be copied}} + + RC2* r2 = new RC2(); + RC2* r2p = new RC2(*r2); +} diff --git a/build/clang-plugin/tests/TestRefCountedThisInsideConstructor.cpp b/build/clang-plugin/tests/TestRefCountedThisInsideConstructor.cpp new file mode 100644 index 0000000000..a6684e3812 --- /dev/null +++ b/build/clang-plugin/tests/TestRefCountedThisInsideConstructor.cpp @@ -0,0 +1,76 @@ +#include + +#include + +struct RefCountedBase { + void AddRef(); + void Release(); +}; + +struct Bar; + +struct Foo : RefCountedBase { + void foo(); +}; + +struct Bar : RefCountedBase { + Bar() { + RefPtr self = this; // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + auto self2 = RefPtr(this); // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + auto self3 = RefPtr{this}; // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + RefPtr self4(this); // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + RefPtr self5{this}; // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + [self=RefPtr{this}]{}(); // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + refptr(RefPtr{this}); // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + refptr(this); // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + } + + explicit Bar(float f) { + // Does not match member expressions with `this` + RefPtr foo = this->mFoo; + foo->foo(); + auto foo2 = RefPtr(this->mFoo); + foo2->foo(); + auto foo3 = RefPtr{this->mFoo}; + foo3->foo(); + } + + explicit Bar(short i); + + explicit Bar(int i): mBar(this) {} // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + explicit Bar(int i, int i2): mBar(RefPtr(this)) {} // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + + void Init() { + // Does not match outside the constructor + RefPtr self = this; + auto self2 = RefPtr(this); + auto self3 = RefPtr{this}; + } + + void refptr(const RefPtr& aBar) {} + + RefPtr mFoo; + RefPtr mBar; +}; + +// Test case for non-inline constructor +Bar::Bar(short i) { + RefPtr self = this; // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + auto self2 = RefPtr(this); // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + auto self3 = RefPtr{this}; // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} +} + +// Same goes for any class with MOZ_IS_REFPTR (not including nsCOMPtr because SM +// doesn't have it) +template class MOZ_IS_REFPTR MyRefPtr { +public: + MOZ_IMPLICIT MyRefPtr(T *aPtr) : mPtr(aPtr) {} + T *mPtr; +}; + +class Baz : RefCountedBase { + Baz() { + MyRefPtr self = this; // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + (void)self; + } +}; diff --git a/build/clang-plugin/tests/TestSprintfLiteral.cpp b/build/clang-plugin/tests/TestSprintfLiteral.cpp new file mode 100644 index 0000000000..3c54ce004f --- /dev/null +++ b/build/clang-plugin/tests/TestSprintfLiteral.cpp @@ -0,0 +1,41 @@ +#include + +void bad() { + char x[100]; + snprintf(x, sizeof(x), "bar"); // expected-error {{Use SprintfLiteral instead of snprintf when writing into a character array.}} expected-note {{This will prevent passing in the wrong size to snprintf accidentally.}} + snprintf(x, 100, "bar"); // expected-error {{Use SprintfLiteral instead of snprintf when writing into a character array.}} expected-note {{This will prevent passing in the wrong size to snprintf accidentally.}} + const int hundred = 100; + snprintf(x, hundred, "bar"); // expected-error {{Use SprintfLiteral instead of snprintf when writing into a character array.}} expected-note {{This will prevent passing in the wrong size to snprintf accidentally.}} +} + +void ok() { + char x[100]; + int y; + snprintf(x, sizeof(y), "foo"); + + snprintf(x, 50, "foo"); + + int nothundred = 100; + nothundred = 99; + snprintf(x, nothundred, "foo"); +} + +void vargs_bad(va_list args) { + char x[100]; + vsnprintf(x, sizeof(x), "bar", args); // expected-error {{Use VsprintfLiteral instead of vsnprintf when writing into a character array.}} expected-note {{This will prevent passing in the wrong size to vsnprintf accidentally.}} + vsnprintf(x, 100, "bar", args); // expected-error {{Use VsprintfLiteral instead of vsnprintf when writing into a character array.}} expected-note {{This will prevent passing in the wrong size to vsnprintf accidentally.}} + const int hundred = 100; + vsnprintf(x, hundred, "bar", args); // expected-error {{Use VsprintfLiteral instead of vsnprintf when writing into a character array.}} expected-note {{This will prevent passing in the wrong size to vsnprintf accidentally.}} +} + +void vargs_good(va_list args) { + char x[100]; + int y; + vsnprintf(x, sizeof(y), "foo", args); + + vsnprintf(x, 50, "foo", args); + + int nothundred = 100; + nothundred = 99; + vsnprintf(x, nothundred, "foo", args); +} diff --git a/build/clang-plugin/tests/TestStackClass.cpp b/build/clang-plugin/tests/TestStackClass.cpp new file mode 100644 index 0000000000..3289abef1b --- /dev/null +++ b/build/clang-plugin/tests/TestStackClass.cpp @@ -0,0 +1,50 @@ +#define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) +#include + +struct MOZ_STACK_CLASS Stack { + int i; + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template +struct MOZ_STACK_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void misuseStackClass(int len) { + Stack valid; + Stack alsoValid[2]; + static Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} + static Stack alsoNotValid[2]; // expected-error-re {{variable of type 'Stack{{ ?}}[2]' only valid on the stack}} expected-note-re {{'Stack{{ ?}}[2]' is a stack type because it is an array of stack type 'Stack'}} expected-note {{value incorrectly allocated in a global variable}} + + gobble(&valid); + gobble(¬Valid); + gobble(&alsoValid[0]); + + gobble(new Stack); // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}} + gobble(new Stack[10]); // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass); // expected-error {{variable of type 'TemplateClass' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &valid : new Stack); // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}} + + char buffer[sizeof(Stack)]; + gobble(new (buffer) Stack); +} + +Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +struct RandomClass { + Stack nonstaticMember; // expected-note {{'RandomClass' is a stack type because member 'nonstaticMember' is a stack type 'Stack'}} + static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +}; +struct MOZ_STACK_CLASS RandomStackClass { + Stack nonstaticMember; + static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +}; + +struct BadInherit : Stack {}; // expected-note {{'BadInherit' is a stack type because it inherits from a stack type 'Stack'}} +struct MOZ_STACK_CLASS GoodInherit : Stack {}; + +BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} diff --git a/build/clang-plugin/tests/TestStaticLocalClass.cpp b/build/clang-plugin/tests/TestStaticLocalClass.cpp new file mode 100644 index 0000000000..c3b0d8645a --- /dev/null +++ b/build/clang-plugin/tests/TestStaticLocalClass.cpp @@ -0,0 +1,54 @@ +#define MOZ_STATIC_LOCAL_CLASS __attribute__((annotate("moz_static_local_class"))) +#include + +struct MOZ_STATIC_LOCAL_CLASS StaticLocal { + int i; + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template +struct MOZ_STATIC_LOCAL_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void misuseStaticLocalClass(int len) { + StaticLocal notValid; // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated in an automatic variable}} + StaticLocal alsoNotValid[2]; // expected-error-re {{variable of type 'StaticLocal{{ ?}}[2]' is only valid as a static local}} expected-note-re {{'StaticLocal{{ ?}}[2]' is a static-local type because it is an array of static-local type 'StaticLocal'}} expected-note {{value incorrectly allocated in an automatic variable}} + static StaticLocal valid; + static StaticLocal alsoValid[2]; + + gobble(¬Valid); + gobble(&valid); + gobble(&alsoValid[0]); + + gobble(new StaticLocal); // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated on the heap}} + gobble(new StaticLocal[10]); // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass); // expected-error {{variable of type 'TemplateClass' is only valid as a static local}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &valid : new StaticLocal); // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated on the heap}} + + char buffer[sizeof(StaticLocal)]; + gobble(new (buffer) StaticLocal); +} + +StaticLocal notValid; // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated in a global variable}} + +struct RandomClass { + StaticLocal nonstaticMember; // expected-note {{'RandomClass' is a static-local type because member 'nonstaticMember' is a static-local type 'StaticLocal'}} + static StaticLocal staticMember; // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated in a global variable}} +}; + +struct MOZ_STATIC_LOCAL_CLASS RandomStaticLocalClass { + StaticLocal nonstaticMember; + static StaticLocal staticMember; // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated in a global variable}} +}; + +struct BadInherit : StaticLocal {}; // expected-note {{'BadInherit' is a static-local type because it inherits from a static-local type 'StaticLocal'}} +struct MOZ_STATIC_LOCAL_CLASS GoodInherit : StaticLocal {}; + +void misuseStaticLocalClassEvenMore(int len) { + BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' is only valid as a static local}} expected-note {{value incorrectly allocated in an automatic variable}} + RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' is only valid as a static local}} expected-note {{value incorrectly allocated in an automatic variable}} +} diff --git a/build/clang-plugin/tests/TestTemporaryClass.cpp b/build/clang-plugin/tests/TestTemporaryClass.cpp new file mode 100644 index 0000000000..f00acf0d7a --- /dev/null +++ b/build/clang-plugin/tests/TestTemporaryClass.cpp @@ -0,0 +1,72 @@ +#define MOZ_TEMPORARY_CLASS __attribute__((annotate("moz_temporary_class"))) +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +#include + +struct MOZ_TEMPORARY_CLASS Temporary { + int i; + Temporary() {} + MOZ_IMPLICIT Temporary(int a) {} + Temporary(int a, int b) {} + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template +struct MOZ_TEMPORARY_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void gobbleref(const Temporary&) { } + +template +void gobbleanyref(const T&) { } + +void misuseNonTemporaryClass(int len) { + // All of these should error. + Temporary invalid; // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated in an automatic variable}} + Temporary alsoInvalid[2]; // expected-error-re {{variable of type 'Temporary{{ ?}}[2]' is only valid as a temporary}} expected-note {{value incorrectly allocated in an automatic variable}} expected-note-re {{'Temporary{{ ?}}[2]' is a temporary type because it is an array of temporary type 'Temporary'}} + static Temporary invalidStatic; // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated in a global variable}} + static Temporary alsoInvalidStatic[2]; // expected-error-re {{variable of type 'Temporary{{ ?}}[2]' is only valid as a temporary}} expected-note {{value incorrectly allocated in a global variable}} expected-note-re {{'Temporary{{ ?}}[2]' is a temporary type because it is an array of temporary type 'Temporary'}} + + gobble(&invalid); + gobble(&invalidStatic); + gobble(&alsoInvalid[0]); + + // All of these should be fine. + gobbleref(Temporary()); + gobbleref(Temporary(10, 20)); + gobbleref(Temporary(10)); + gobbleref(10); + gobbleanyref(TemplateClass()); + + // All of these should error. + gobble(new Temporary); // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated on the heap}} + gobble(new Temporary[10]); // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass); // expected-error {{variable of type 'TemplateClass' is only valid as a temporary}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &invalid : new Temporary); // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated on the heap}} + + // Placement new is odd, but okay. + char buffer[sizeof(Temporary)]; + gobble(new (buffer) Temporary); +} + +void defaultArg(const Temporary& arg = Temporary()) { // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated in an automatic variable}} +} + +// Can't be a global, this should error. +Temporary invalidStatic; // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated in a global variable}} + +struct RandomClass { + Temporary nonstaticMember; // This is okay if RandomClass is only used as a temporary. + static Temporary staticMember; // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated in a global variable}} +}; + +struct BadInherit : Temporary {}; + +void useStuffWrongly() { + gobbleanyref(BadInherit()); + gobbleanyref(RandomClass()); +} diff --git a/build/clang-plugin/tests/TestTrivialCtorDtor.cpp b/build/clang-plugin/tests/TestTrivialCtorDtor.cpp new file mode 100644 index 0000000000..a1038b6e63 --- /dev/null +++ b/build/clang-plugin/tests/TestTrivialCtorDtor.cpp @@ -0,0 +1,88 @@ +#define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor"))) + +struct MOZ_TRIVIAL_CTOR_DTOR EmptyClass{}; + +template +struct MOZ_TRIVIAL_CTOR_DTOR TemplateEmptyClass{}; + +struct MOZ_TRIVIAL_CTOR_DTOR NonEmptyClass { + void *m; +}; + +template +struct MOZ_TRIVIAL_CTOR_DTOR TemplateNonEmptyClass { + T* m; +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadUserDefinedCtor { // expected-error {{class 'BadUserDefinedCtor' must have trivial constructors and destructors}} + BadUserDefinedCtor() {} +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadUserDefinedDtor { // expected-error {{class 'BadUserDefinedDtor' must have trivial constructors and destructors}} + ~BadUserDefinedDtor() {} +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualDtor { // expected-error {{class 'BadVirtualDtor' must have trivial constructors and destructors}} + virtual ~BadVirtualDtor() {} +}; + +struct MOZ_TRIVIAL_CTOR_DTOR OkVirtualMember { + virtual void f(); +}; + +void foo(); +struct MOZ_TRIVIAL_CTOR_DTOR BadNonEmptyCtorDtor { // expected-error {{class 'BadNonEmptyCtorDtor' must have trivial constructors and destructors}} + BadNonEmptyCtorDtor() { foo(); } + ~BadNonEmptyCtorDtor() { foo(); } +}; + +struct NonTrivialCtor { + NonTrivialCtor() { foo(); } +}; + +struct NonTrivialDtor { + ~NonTrivialDtor() { foo(); } +}; + +struct VirtualMember { + virtual void f(); +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialCtorInBase : NonTrivialCtor { // expected-error {{class 'BadNonTrivialCtorInBase' must have trivial constructors and destructors}} +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialDtorInBase : NonTrivialDtor { // expected-error {{class 'BadNonTrivialDtorInBase' must have trivial constructors and destructors}} +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialCtorInMember { // expected-error {{class 'BadNonTrivialCtorInMember' must have trivial constructors and destructors}} + NonTrivialCtor m; +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialDtorInMember { // expected-error {{class 'BadNonTrivialDtorInMember' must have trivial constructors and destructors}} + NonTrivialDtor m; +}; + +struct MOZ_TRIVIAL_CTOR_DTOR OkVirtualMemberInMember { + VirtualMember m; +}; + +struct MOZ_TRIVIAL_CTOR_DTOR OkConstExprConstructor { + constexpr OkConstExprConstructor() {} +}; + +struct MOZ_TRIVIAL_CTOR_DTOR OkConstExprConstructorInMember { + OkConstExprConstructor m; +}; + +#if __cplusplus >= 202002L +struct +#else +// XXX: This error is unfortunate, but is unlikely to come up in real code. +// In this situation, it should be possible to define a constexpr constructor +// which explicitly initializes the members. +struct // expected-error {{class 'BadUnfortunateError' must have trivial constructors and destructors}} +#endif +MOZ_TRIVIAL_CTOR_DTOR BadUnfortunateError { + OkConstExprConstructor m; + void *n; +}; diff --git a/build/clang-plugin/tests/TestTrivialDtor.cpp b/build/clang-plugin/tests/TestTrivialDtor.cpp new file mode 100644 index 0000000000..f86d41b238 --- /dev/null +++ b/build/clang-plugin/tests/TestTrivialDtor.cpp @@ -0,0 +1,52 @@ +#define MOZ_TRIVIAL_DTOR __attribute__((annotate("moz_trivial_dtor"))) + +struct MOZ_TRIVIAL_DTOR EmptyClass{}; + +template +struct MOZ_TRIVIAL_DTOR TemplateEmptyClass{}; + +struct MOZ_TRIVIAL_DTOR NonEmptyClass { + void *m; +}; + +template +struct MOZ_TRIVIAL_DTOR TemplateNonEmptyClass { + T* m; +}; + +struct MOZ_TRIVIAL_DTOR BadUserDefinedDtor { // expected-error {{class 'BadUserDefinedDtor' must have a trivial destructor}} + ~BadUserDefinedDtor() {} +}; + +struct MOZ_TRIVIAL_DTOR BadVirtualDtor { // expected-error {{class 'BadVirtualDtor' must have a trivial destructor}} + virtual ~BadVirtualDtor() {} +}; + +struct MOZ_TRIVIAL_DTOR OkVirtualMember { + virtual void f(); +}; + +void foo(); +struct MOZ_TRIVIAL_DTOR BadNonEmptyCtorDtor { // expected-error {{class 'BadNonEmptyCtorDtor' must have a trivial destructor}} + BadNonEmptyCtorDtor() { foo(); } + ~BadNonEmptyCtorDtor() { foo(); } +}; + +struct NonTrivialDtor { + ~NonTrivialDtor() { foo(); } +}; + +struct VirtualMember { + virtual void f(); +}; + +struct MOZ_TRIVIAL_DTOR BadNonTrivialDtorInBase : NonTrivialDtor { // expected-error {{class 'BadNonTrivialDtorInBase' must have a trivial destructor}} +}; + +struct MOZ_TRIVIAL_DTOR BadNonTrivialDtorInMember { // expected-error {{class 'BadNonTrivialDtorInMember' must have a trivial destructor}} + NonTrivialDtor m; +}; + +struct MOZ_TRIVIAL_DTOR OkVirtualMemberInMember { + VirtualMember m; +}; diff --git a/build/clang-plugin/tests/moz.build b/build/clang-plugin/tests/moz.build new file mode 100644 index 0000000000..45f416be44 --- /dev/null +++ b/build/clang-plugin/tests/moz.build @@ -0,0 +1,101 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# dummy library name to avoid skipping building the sources here. +Library("clang-plugin-tests") + +SOURCES += [ + "TestAssertWithAssignment.cpp", + "TestBadImplicitConversionCtor.cpp", + "TestCanRunScript.cpp", + "TestCustomHeap.cpp", + "TestDanglingOnTemporary.cpp", + "TestExplicitOperatorBool.cpp", + "TestGlobalClass.cpp", + "TestHeapClass.cpp", + "TestInheritTypeAnnotationsFromTemplateArgs.cpp", + "TestJSHandleRootedTypedef.cpp", + "TestKnownLive.cpp", + "TestKungFuDeathGrip.cpp", + "TestMultipleAnnotations.cpp", + "TestMustOverride.cpp", + "TestMustReturnFromCaller.cpp", + "TestNANTestingExpr.cpp", + "TestNANTestingExprC.c", + "TestNeedsNoVTableType.cpp", + "TestNoAddRefReleaseOnReturn.cpp", + "TestNoArithmeticExprInArgument.cpp", + "TestNoAutoType.cpp", + "TestNoDuplicateRefCntMember.cpp", + "TestNoExplicitMoveConstructor.cpp", + "TestNoNewThreadsChecker.cpp", + "TestNonHeapClass.cpp", + "TestNonMemMovable.cpp", + "TestNonMemMovableStd.cpp", + "TestNonMemMovableStdAtomic.cpp", + "TestNonParameterChecker.cpp", + "TestNonTemporaryClass.cpp", + "TestNonTrivialTypeInFfi.cpp", + "TestNoPrincipalGetUri.cpp", + "TestNoRefcountedInsideLambdas.cpp", + "TestNoUsingNamespaceMozillaJava.cpp", + "TestOverrideBaseCall.cpp", + "TestOverrideBaseCallAnnotation.cpp", + "TestParamTraitsEnum.cpp", + "TestRefCountedCopyConstructor.cpp", + "TestRefCountedThisInsideConstructor.cpp", + "TestSprintfLiteral.cpp", + "TestStackClass.cpp", + "TestStaticLocalClass.cpp", + "TestTemporaryClass.cpp", + "TestTrivialCtorDtor.cpp", + "TestTrivialDtor.cpp", +] + +if CONFIG["OS_ARCH"] == "WINNT": + SOURCES += [ + "TestFopenUsage.cpp", + "TestLoadLibraryUsage.cpp", + ] + +include("../external/tests/sources.mozbuild") + +if CONFIG["ENABLE_CLANG_PLUGIN_ALPHA"]: + DEFINES["MOZ_CLANG_PLUGIN_ALPHA"] = "1" + include("../alpha/tests/sources.mozbuild") + +DisableStlWrapping() +NoVisibilityFlags() + +# Build without any warning flags, and with clang verify flag for a +# syntax-only build (no codegen), without a limit on the number of errors. +COMPILE_FLAGS["OS_CXXFLAGS"] = [ + f for f in COMPILE_FLAGS.get("OS_CXXFLAGS", []) if not f.startswith("-W") +] + [ + "-fsyntax-only", + "-Xclang", + "-verify", + "-ferror-limit=0", + "-Wno-invalid-noreturn", + # For SpiderMonkey headers in TestJSHandleRootedTypedef.cpp + "-Wno-attributes", + "-Wno-invalid-offsetof", +] +COMPILE_FLAGS["OS_CFLAGS"] = [ + f for f in COMPILE_FLAGS.get("OS_CFLAGS", []) if not f.startswith("-W") +] + [ + "-fsyntax-only", + "-Xclang", + "-verify", + "-ferror-limit=0", + "-Xclang", + "-std=c11", + "-Wno-invalid-noreturn", +] + +# Don't reflect WARNINGS_CFLAGS into CFLAGS, as the warnings flags should be +# as specified in OS_CFLAGS above. +DisableCompilerWarnings() diff --git a/build/compare-mozconfig/compare-mozconfigs.py b/build/compare-mozconfig/compare-mozconfigs.py new file mode 100644 index 0000000000..210fd0568e --- /dev/null +++ b/build/compare-mozconfig/compare-mozconfigs.py @@ -0,0 +1,176 @@ +#!/usr/bin/python +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# originally from https://hg.mozilla.org/build/tools/file/4ab9c1a4e05b/scripts/release/compare-mozconfigs.py # NOQA: E501 + +import difflib +import logging +import os +import unittest + +import buildconfig +import mozunit + +FAILURE_CODE = 1 +SUCCESS_CODE = 0 + +PLATFORMS = ( + "linux32", + "linux64", + "macosx64", + "win32", + "win64", + "win64-aarch64", +) + +log = logging.getLogger(__name__) + + +class ConfigError(Exception): + pass + + +def readConfig(configfile): + c = {} + execfile(configfile, c) + return c["whitelist"] + + +def verify_mozconfigs( + mozconfig_pair, nightly_mozconfig_pair, platform, mozconfigWhitelist +): + """Compares mozconfig to nightly_mozconfig and compare to an optional + whitelist of known differences. mozconfig_pair and nightly_mozconfig_pair + are pairs containing the mozconfig's identifier and the list of lines in + the mozconfig.""" + + # unpack the pairs to get the names, the names are just for + # identifying the mozconfigs when logging the error messages + mozconfig_name, mozconfig_lines = mozconfig_pair + nightly_mozconfig_name, nightly_mozconfig_lines = nightly_mozconfig_pair + + if not mozconfig_lines or not nightly_mozconfig_lines: + log.info("Missing mozconfigs to compare for %s" % platform) + return False + + success = True + + diff_instance = difflib.Differ() + diff_result = diff_instance.compare(mozconfig_lines, nightly_mozconfig_lines) + diff_list = list(diff_result) + + for line in diff_list: + clean_line = line[1:].strip() + if (line[0] == "-" or line[0] == "+") and len(clean_line) > 1: + # skip comment lines + if clean_line.startswith("#"): + continue + # compare to whitelist + message = "" + if line[0] == "-": + # handle lines that move around in diff + if "+" + line[1:] in diff_list: + continue + if platform in mozconfigWhitelist.get("release", {}): + if clean_line in mozconfigWhitelist["release"][platform]: + continue + elif line[0] == "+": + if "-" + line[1:] in diff_list: + continue + if platform in mozconfigWhitelist.get("nightly", {}): + if clean_line in mozconfigWhitelist["nightly"][platform]: + continue + else: + log.warning( + "%s not in %s %s!" + % ( + clean_line, + platform, + mozconfigWhitelist["nightly"][platform], + ) + ) + else: + log.error("Skipping line %s!" % line) + continue + message = "found in %s but not in %s: %s" + if line[0] == "-": + log.error( + message % (mozconfig_name, nightly_mozconfig_name, clean_line) + ) + else: + log.error( + message % (nightly_mozconfig_name, mozconfig_name, clean_line) + ) + success = False + return success + + +def get_mozconfig(path): + """Consumes a path and returns a list of lines from the mozconfig file.""" + with open(path, "rb") as fh: + return fh.readlines() + + +def compare(topsrcdir): + app = os.path.join(topsrcdir, "browser") + whitelist = readConfig(os.path.join(app, "config", "mozconfigs", "whitelist")) + + success = True + + def normalize_lines(lines): + return {l.strip() for l in lines} + + for platform in PLATFORMS: + log.info("Comparing platform %s" % platform) + + mozconfigs_path = os.path.join(app, "config", "mozconfigs", platform) + + nightly_path = os.path.join(mozconfigs_path, "nightly") + beta_path = os.path.join(mozconfigs_path, "beta") + release_path = os.path.join(mozconfigs_path, "release") + + nightly_lines = get_mozconfig(nightly_path) + beta_lines = get_mozconfig(beta_path) + release_lines = get_mozconfig(release_path) + + # Validate that entries in whitelist['nightly'][platform] are actually + # present. + whitelist_normalized = normalize_lines(whitelist["nightly"].get(platform, [])) + nightly_normalized = normalize_lines(nightly_lines) + + for line in sorted(whitelist_normalized - nightly_normalized): + log.error("extra line in nightly whitelist: %s" % line) + success = False + + log.info("Comparing beta and nightly mozconfigs") + passed = verify_mozconfigs( + (beta_path, beta_lines), (nightly_path, nightly_lines), platform, whitelist + ) + + if not passed: + success = False + + log.info("Comparing release and nightly mozconfigs") + passed = verify_mozconfigs( + (release_path, release_lines), + (nightly_path, nightly_lines), + platform, + whitelist, + ) + if not passed: + success = False + + return success + + +class TestCompareMozconfigs(unittest.TestCase): + def test_compare_mozconfigs(self): + topsrcdir = buildconfig.substs["top_srcdir"] + self.assertTrue(compare(topsrcdir)) + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + mozunit.main() diff --git a/build/compare-mozconfig/python.toml b/build/compare-mozconfig/python.toml new file mode 100644 index 0000000000..8398d582f2 --- /dev/null +++ b/build/compare-mozconfig/python.toml @@ -0,0 +1,5 @@ +[DEFAULT] +skip-if = ["true"] # fails on Python 3 +subsuite = "mozbuild" + +["compare-mozconfigs.py"] diff --git a/build/debian-packages/pygobject.diff b/build/debian-packages/pygobject.diff new file mode 100644 index 0000000000..b56edfae54 --- /dev/null +++ b/build/debian-packages/pygobject.diff @@ -0,0 +1,117 @@ +diff -Nru pygobject-3.26.1/debian/changelog pygobject-3.26.1/debian/changelog +--- pygobject-3.26.1/debian/changelog 2019-01-29 21:46:03.000000000 +0900 ++++ pygobject-3.26.1/debian/changelog 2023-12-08 09:22:32.000000000 +0900 +@@ -1,3 +1,9 @@ ++pygobject (3.26.1-2ubuntu1.ub18moz1) bionic; urgency=medium ++ ++ * Backport fix for python 3.8 support. ++ ++ -- Mike Hommey Fri, 08 Dec 2023 09:22:32 +0900 ++ + pygobject (3.26.1-2ubuntu1) bionic; urgency=medium + + * Update Vcs fields for ubuntu/bionic branch +diff -Nru pygobject-3.26.1/debian/patches/python3.8.patch pygobject-3.26.1/debian/patches/python3.8.patch +--- pygobject-3.26.1/debian/patches/python3.8.patch 1970-01-01 09:00:00.000000000 +0900 ++++ pygobject-3.26.1/debian/patches/python3.8.patch 2023-12-08 09:22:32.000000000 +0900 +@@ -0,0 +1,94 @@ ++Description: Backport fix for python 3.8 support ++ ++Original upstream patch: ++https://gitlab.gnome.org/GNOME/pygobject/-/commit/bfc759c9c0bb ++ ++Original backport to 3.28: ++https://svnweb.freebsd.org/ports/head/devel/pygobject3-common/files/patch-python38?view=markup&pathrev=537996 ++ ++--- pygobject-3.26.1.orig/gi/gimodule.c +++++ pygobject-3.26.1/gi/gimodule.c ++@@ -689,7 +689,10 @@ PYGLIB_MODULE_START(_gi, "_gi") ++ pygi_error_register_types (module); ++ _pygi_repository_register_types (module); ++ _pygi_info_register_types (module); +++ pygobject_type_register_types (module_dict); +++ pygobject_pointer_register_types (module_dict); ++ _pygi_struct_register_types (module); +++ pygobject_boxed_register_types (module_dict); ++ _pygi_boxed_register_types (module); ++ _pygi_ccallback_register_types (module); ++ pygi_resulttuple_register_types (module); ++@@ -703,12 +706,9 @@ PYGLIB_MODULE_START(_gi, "_gi") ++ pygobject_register_features (module_dict); ++ pygobject_register_version_tuples (module_dict); ++ pygobject_register_warnings (module_dict); ++- pygobject_type_register_types (module_dict); ++ pygobject_object_register_types (module_dict); ++ pygobject_interface_register_types (module_dict); ++ pygobject_paramspec_register_types (module_dict); ++- pygobject_boxed_register_types (module_dict); ++- pygobject_pointer_register_types (module_dict); ++ pygobject_enum_register_types (module_dict); ++ pygobject_flags_register_types (module_dict); ++ ++--- pygobject-3.26.1.orig/gi/pygboxed.c +++++ pygobject-3.26.1/gi/pygboxed.c ++@@ -162,6 +162,7 @@ pyg_register_boxed(PyObject *dict, const ++ if (!type->tp_dealloc) type->tp_dealloc = (destructor)pyg_boxed_dealloc; ++ ++ Py_TYPE(type) = &PyType_Type; +++ g_assert (Py_TYPE (&PyGBoxed_Type) != NULL); ++ type->tp_base = &PyGBoxed_Type; ++ ++ if (PyType_Ready(type) < 0) { ++--- pygobject-3.26.1.orig/gi/pygi-boxed.c +++++ pygobject-3.26.1/gi/pygi-boxed.c ++@@ -242,6 +242,7 @@ void ++ _pygi_boxed_register_types (PyObject *m) ++ { ++ Py_TYPE(&PyGIBoxed_Type) = &PyType_Type; +++ g_assert (Py_TYPE (&PyGBoxed_Type) != NULL); ++ PyGIBoxed_Type.tp_base = &PyGBoxed_Type; ++ PyGIBoxed_Type.tp_new = (newfunc) _boxed_new; ++ PyGIBoxed_Type.tp_init = (initproc) _boxed_init; ++--- pygobject-3.26.1.orig/gi/pygi-struct.c +++++ pygobject-3.26.1/gi/pygi-struct.c ++@@ -221,6 +221,7 @@ void ++ _pygi_struct_register_types (PyObject *m) ++ { ++ Py_TYPE(&PyGIStruct_Type) = &PyType_Type; +++ g_assert (Py_TYPE (&PyGPointer_Type) != NULL); ++ PyGIStruct_Type.tp_base = &PyGPointer_Type; ++ PyGIStruct_Type.tp_new = (newfunc) _struct_new; ++ PyGIStruct_Type.tp_init = (initproc) _struct_init; ++--- pygobject-3.26.1.orig/gi/pyginterface.c +++++ pygobject-3.26.1/gi/pyginterface.c ++@@ -72,6 +72,7 @@ pyg_register_interface(PyObject *dict, c ++ PyObject *o; ++ ++ Py_TYPE(type) = &PyType_Type; +++ g_assert (Py_TYPE (&PyGInterface_Type) != NULL); ++ type->tp_base = &PyGInterface_Type; ++ ++ if (PyType_Ready(type) < 0) { ++--- pygobject-3.26.1.orig/gi/pygpointer.c +++++ pygobject-3.26.1/gi/pygpointer.c ++@@ -117,6 +117,7 @@ pyg_register_pointer(PyObject *dict, con ++ if (!type->tp_dealloc) type->tp_dealloc = (destructor)pyg_pointer_dealloc; ++ ++ Py_TYPE(type) = &PyType_Type; +++ g_assert (Py_TYPE (&PyGPointer_Type) != NULL); ++ type->tp_base = &PyGPointer_Type; ++ ++ if (PyType_Ready(type) < 0) { ++--- pygobject-3.26.1.orig/gi/pygtype.c +++++ pygobject-3.26.1/gi/pygtype.c ++@@ -345,6 +345,7 @@ pyg_type_wrapper_new(GType type) ++ { ++ PyGTypeWrapper *self; ++ +++ g_assert (Py_TYPE (&PyGTypeWrapper_Type) != NULL); ++ self = (PyGTypeWrapper *)PyObject_NEW(PyGTypeWrapper, ++ &PyGTypeWrapper_Type); ++ if (self == NULL) +diff -Nru pygobject-3.26.1/debian/patches/series pygobject-3.26.1/debian/patches/series +--- pygobject-3.26.1/debian/patches/series 2019-01-29 21:46:03.000000000 +0900 ++++ pygobject-3.26.1/debian/patches/series 2023-12-08 09:22:20.000000000 +0900 +@@ -1 +1,2 @@ + fix-tests-with-newest-glib.patch ++python3.8.patch diff --git a/build/debian-packages/ubuntu-glibc.diff b/build/debian-packages/ubuntu-glibc.diff new file mode 100644 index 0000000000..949d7b393b --- /dev/null +++ b/build/debian-packages/ubuntu-glibc.diff @@ -0,0 +1,13 @@ +diff -Nru glibc-2.27/debian/changelog glibc-2.27/debian/changelog +--- glibc-2.27/debian/changelog 2020-06-05 02:25:26.000000000 +0900 ++++ glibc-2.27/debian/changelog 2021-06-25 17:54:19.000000000 +0900 +@@ -1,3 +1,9 @@ ++glibc (2.27-3ubuntu1.2.ub18moz1) bionic; urgency=medium ++ ++ * Mozilla backport for bionic. ++ ++ -- Mike Hommey Fri, 25 Jun 2021 17:54:19 +0900 ++ + glibc (2.27-3ubuntu1.2) bionic-security; urgency=medium + + * SECURITY UPDATE: integer overflow in realpath diff --git a/build/defines.sh b/build/defines.sh new file mode 100644 index 0000000000..cf98c3d8bf --- /dev/null +++ b/build/defines.sh @@ -0,0 +1,3 @@ +# Define indicating that this build is prior to one of the early betas. To be +# unset mid-way through the beta cycle. +EARLY_BETA_OR_EARLIER= diff --git a/build/docs/build-overview.rst b/build/docs/build-overview.rst new file mode 100644 index 0000000000..a7784e7b1a --- /dev/null +++ b/build/docs/build-overview.rst @@ -0,0 +1,117 @@ +.. _build_overview: + +===================== +Build System Overview +===================== + +This document provides an overview on how the build system works. It is +targeted at people wanting to learn about internals of the build system. +It is not meant for persons who casually interact with the build system. +That being said, knowledge empowers, so consider reading on. + +The build system is composed of many different components working in +harmony to build the source tree. We begin with a graphic overview. + +.. graphviz:: + + digraph build_components { + rankdir="LR"; + "configure" -> "config.status" -> "build backend" -> "build output" + } + +Phase 1: Configuration +====================== + +Phase 1 centers around the ``configure`` script, which is a bash shell script. +The file is generated from a file called ``configure.in`` which is written in M4 +and processed using Autoconf 2.13 to create the final configure script. +You don't have to worry about how you obtain a ``configure`` file: the build +system does this for you. + +The primary job of ``configure`` is to determine characteristics of the system +and compiler, apply options passed into it, and validate everything looks OK to +build. The primary output of the ``configure`` script is an executable file +in the object directory called ``config.status``. ``configure`` also produces +some additional files (like ``autoconf.mk``). However, the most important file +in terms of architecture is ``config.status``. + +The existence of a ``config.status`` file may be familiar to those who have worked +with Autoconf before. However, Mozilla's ``config.status`` is different from almost +any other ``config.status`` you've ever seen: it's written in Python! Instead of +having our ``configure`` script produce a shell script, we have it generating +Python. + +Now is as good a time as any to mention that Python is prevalent in our build +system. If we need to write code for the build system, we do it in Python. +That's just how we roll. For more, see :ref:`python`. + +``config.status`` contains 2 parts: data structures representing the output of +``configure`` and a command-line interface for preparing/configuring/generating +an appropriate build backend. (A build backend is merely a tool used to build +the tree - like GNU Make or Tup). These data structures essentially describe +the current state of the system and what the existing build configuration looks +like. For example, it defines which compiler to use, how to invoke it, which +application features are enabled, etc. You are encouraged to open up +``config.status`` to have a look for yourself! + +Once we have emitted a ``config.status`` file, we pass into the realm of +phase 2. + +Phase 2: Build Backend Preparation and the Build Definition +=========================================================== + +Once ``configure`` has determined what the current build configuration is, +we need to apply this to the source tree so we can actually build. + +What essentially happens is the automatically-produced ``config.status`` Python +script is executed as soon as ``configure`` has generated it. ``config.status`` +is charged with the task of tell a tool how to build the tree. To do this, +``config.status`` must first scan the build system definition. + +The build system definition consists of various ``moz.build`` files in the tree. +There is roughly one ``moz.build`` file per directory or per set of related directories. +Each ``moz.build`` files defines how its part of the build config works. For +example it says *I want these C++ files compiled* or *look for additional +information in these directories.* config.status starts with the ``moz.build`` +file from the root directory and then descends into referenced ``moz.build`` +files by following ``DIRS`` variables or similar. + +As the ``moz.build`` files are read, data structures describing the overall +build system definition are emitted. These data structures are then fed into a +build backend, which then performs actions, such as writing out files to +be read by a build tool. e.g. a ``make`` backend will write a +``Makefile``. + +When ``config.status`` runs, you'll see the following output:: + + Reticulating splines... + Finished reading 1096 moz.build files into 1276 descriptors in 2.40s + Backend executed in 2.39s + 2188 total backend files. 0 created; 1 updated; 2187 unchanged + Total wall time: 5.03s; CPU time: 3.79s; Efficiency: 75% + +What this is saying is that a total of *1096* ``moz.build`` files were read. +Altogether, *1276* data structures describing the build configuration were +derived from them. It took *2.40s* wall time to just read these files and +produce the data structures. The *1276* data structures were fed into the +build backend which then determined it had to manage *2188* files derived +from those data structures. Most of them already existed and didn't need +changed. However, *1* was updated as a result of the new configuration. +The whole process took *5.03s*. Although, only *3.79s* was in +CPU time. That likely means we spent roughly *25%* of the time waiting on +I/O. + +For more on how ``moz.build`` files work, see :ref:`mozbuild-files`. + +Phase 3: Invocation of the Build Backend +======================================== + +When most people think of the build system, they think of phase 3. This is +where we take all the code in the tree and produce Firefox or whatever +application you are creating. Phase 3 effectively takes whatever was +generated by phase 2 and runs it. Since the dawn of Mozilla, this has been +make consuming Makefiles. However, with the transition to moz.build files, +you may soon see non-Make build backends, such as Tup or Visual Studio. + +When building the tree, most of the time is spent in phase 3. This is when +header files are installed, C++ files are compiled, files are preprocessed, etc. diff --git a/build/docs/build-targets.rst b/build/docs/build-targets.rst new file mode 100644 index 0000000000..dacd46c7f4 --- /dev/null +++ b/build/docs/build-targets.rst @@ -0,0 +1,62 @@ +.. _build_targets: + +============= +Build Targets +============= + +When you build with ``mach build``, there are some special targets that can be +built. This page attempts to document them. + +Partial Tree Targets +==================== + +The targets in this section only build part of the tree. Please note that +partial tree builds can be unreliable. Use at your own risk. + +export + Build the *export* tier. The *export* tier builds everything that is + required for C/C++ compilation. It stages all header files, processes + IDLs, etc. + +compile + Build the *compile* tier. The *compile* tier compiles all C/C++ files. + +libs + Build the *libs* tier. The *libs* tier performs linking and performs + most build steps which aren't related to compilation. + +tools + Build the *tools* tier. The *tools* tier mostly deals with supplementary + tools and compiled tests. It will link tools against libXUL, including + compiled test binaries. + +binaries: + Recompiles and relinks C/C++ files. Only works after a complete normal + build, but allows for much faster rebuilds of C/C++ code. For performance + reasons, however, it skips nss, nspr, icu and ffi. This is targeted to + improve local developer workflow when touching C/C++ code. + +install-manifests + Process install manifests. Install manifests handle the installation of + files into the object directory. + + Unless ``NO_REMOVE=1`` is defined in the environment, files not accounted + in the install manifests will be deleted from the object directory. + +install-tests + Processes the tests install manifest. + +Common Actions +============== + +The targets in this section correspond to common build-related actions. Many +of the actions in this section are effectively frontends to shell scripts. +These actions will likely all be replaced by mach commands someday. + +buildsymbols + Create a symbols archive for the current build. + + This must be performed after a successful build. + +check + Run build system tests. diff --git a/build/docs/chrome-registration.rst b/build/docs/chrome-registration.rst new file mode 100644 index 0000000000..5c40f5ced7 --- /dev/null +++ b/build/docs/chrome-registration.rst @@ -0,0 +1,459 @@ +Chrome Registration +------------------- + +What is chrome? +--------------- + +`Chrome` is the set of user interface elements of the +application window that are outside the window's content area. Toolbars, +menu bars, progress bars, and window title bars are all examples of +elements that are typically part of the chrome. + +``chrome.manifest`` files are used to register XPCOM components and sources for the chrome protocol. +Every application supplies a root ``chrome.manifest`` file that Mozilla reads on startup. + +Chrome providers +---------------- + +A supplier of chrome for a given window type (e.g., for the browser +window) is called a chrome provider. The providers work together to +supply a complete set of chrome for a particular window, from the images +on the toolbar buttons to the files that describe the text, content, and +appearance of the window itself. + +There are three basic types of chrome providers: + +Content + The main source file for a window description comes from the content + provider, and it can be any file type viewable from within Mozilla. + It will typically be a XUL file, since XUL is designed for describing + the contents of windows and dialogs. The JavaScript files that define + the user interface are also contained within the content packages. + +Locale + Localizable applications keep all their localized information in + locale providers and Fluent FTL files, which are handled separately. + This allows translators to plug in a different + chrome package to translate an application without altering the rest + of the source code. In a chrome provider, localizable files are mostly + Java-style properties files. +Skin + A skin provider is responsible for providing a complete set of files + that describe the visual appearance of the chrome. Typically a skin + provider will provide CSS files and + images. + +The chrome registry +------------------- + +The Gecko runtime maintains a service known as the chrome registry that +provides mappings from chrome package names to the physical location of +chrome packages on disk. + +This chrome registry is configurable and persistent, and thus a user can +install different chrome providers, and select a preferred skin and +locale. This is accomplished through xpinstall and the extension +manager. + +In order to inform the chrome registry of the available chrome, a text +manifest is used: this manifest is "chrome.manifest" in the root of an +extension, or theme, or XULRunner application. + +The plaintext chrome manifests are in a simple line-based format. Each +line is parsed individually; if the line is parsable the chrome registry +takes the action identified by that line, otherwise the chrome registry +ignores that line (and prints a warning message in the runtime error +console). + +.. code:: text + + locale packagename localename path/to/files + skin packagename skinname path/to/files + +.. note:: + + The characters @ # ; : ? / are not allowed in the + packagename. + +Manifest instructions +--------------------- + +comments +~~~~~~~~ + +.. code:: text + + # this line is a comment - you can put here whatever you want + +A line is a comment if it begins with the character '#'. Any following +character in the same line is ignored. + +manifest +~~~~~~~~ + +:: + + manifest subdirectory/foo.manifest [flags] + +This will load a secondary manifest file. This can be useful for +separating component and chrome registration instructions, or separate +platform-specific registration data. + +component +~~~~~~~~~ + +:: + + component {00000000-0000-0000-0000-000000000000} components/mycomponent.js [flags] + +Informs Mozilla about a component CID implemented by an XPCOM component +implemented in JavaScript (or another scripting language, if +applicable). The ClassID {0000...} must match the ClassID implemented by +the component. To generate a unique ClassID, use a UUID generator +program or site. + +contract +~~~~~~~~ + +:: + + contract @foobar/mycontract;1 {00000000-0000-0000-0000-000000000000} [flags] + +Maps a contract ID (a readable string) to the ClassID for a specific +implementation. Typically a contract ID will be paired with a component +entry immediately preceding. + +category +~~~~~~~~ + +:: + + category category entry-name value [flags] + +Registers an entry in the `category manager`. The +specific format and meaning of category entries depend on the category. + +content +~~~~~~~ + +A content package is registered with the line: + +:: + + content packagename uri/to/files/ [flags] + +This will register a location to use when resolving the URI +``chrome://packagename/content/...``. The URI may be absolute or +relative to the location of the manifest file. Note: it must end with a +'/'. + +locale +~~~~~~ + +A locale package is registered with the line: + +.. code:: text + + locale packagename localename uri/to/files/ [flags] + +This will register a locale package when resolving the URI +chrome://*packagename*/locale/... . The *localename* is usually a plain +language identifier "en" or a language-country identifier "en-US". If +more than one locale is registered for a package, the chrome registry +will select the best-fit locale using the user's preferences. + +skin +~~~~ + +A skin package is registered with the line: + +.. code:: text + + skin packagename skinname uri/to/files/ [flags] + +This will register a skin package when resolving the URI +chrome://packagename/skin/... . The *skinname* is an opaque string +identifying an installed skin. If more than one skin is registered for a +package, the chrome registry will select the best-fit skin using the +user's preferences. + +style +~~~~~ + +Style overlays (custom CSS which will be applied to a chrome page) are +registered with the following syntax: + +.. code:: text + + style chrome://URI-to-style chrome://stylesheet-URI [flags] + +override +~~~~~~~~ + +In some cases an extension or embedder may wish to override a chrome +file provided by the application or XULRunner. In order to allow for +this, the chrome registration manifest allows for "override" +instructions: + +.. code:: text + + override chrome://package/type/original-uri.whatever new-resolved-URI [flags] + +Note: overrides are not recursive (so overriding +chrome://foo/content/bar/ with file:///home/john/blah/ will not usually +do what you want or expect it to do). Also, the path inside overridden +files is relative to the overridden path, not the original one (this can +be annoying and/or useful in CSS files, for example). + +.. _chrome_manifest_resource: + +resource +~~~~~~~~ + +Aliases can be created using the ``resource`` instruction: + +.. code:: text + + resource aliasname uri/to/files/ [flags] + +This will create a mapping for ``resource:///`` URIs to the +path given. + +.. note:: + + **Note:** There are no security restrictions preventing web content + from including content at resource: URIs, so take care what you make + visible there. + +Manifest flags +-------------- + +Manifest lines can have multiple, space-delimited flags added at the end +of the registration line. These flags mark special attributes of chrome +in that package, or limit the conditions under which the line is used. + +application +~~~~~~~~~~~ + +Extensions may install into multiple applications. There may be chrome +registration lines which only apply to one particular application. The +flag + +.. code:: text + + application=app-ID + +indicates that the instruction should only be applied if the extension +is installed into the application identified by *app-ID*. Multiple +application flags may be included on a single line, in which case the +line is applied if any of the flags match. + +This example shows how a different overlay can be used for different +applications: + +:: + + overlay chrome://browser/content/browser.xul chrome://myaddon/content/ffOverlay.xul application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} + overlay chrome://messenger/content/mailWindowOverlay.xul chrome://myaddon/content/tbOverlay.xul application={3550f703-e582-4d05-9a08-453d09bdfdc6} + overlay chrome://songbird/content/xul/layoutBaseOverlay.xul chrome://myaddon/content/sbOverlay.xul application=songbird@songbirdnest.com + +appversion +~~~~~~~~~~ + +Extensions may install into multiple versions of an application. There +may be chrome registration lines which only apply to a particular +application version. The flag + +.. code:: text + + appversion=version + appversionversion + appversion>=version + +indicates that the instruction should only be applied if the extension +is installed into the application version identified. Multiple +``appversion`` flags may be included on a single line, in which case the +line is applied if any of the flags match. The version string must +conform to the `Toolkit version format`. + +platformversion +~~~~~~~~~~~~~~~ + +When supporting more then one application, it is often more convenient +for an extension to specify which Gecko version it is compatible with. +This is particularly true for binary components. If there are chrome +registration lines which only apply to a particular Gecko version, the +flag + +.. code:: text + + platformversion=version + platformversionversion + platformversion>=version + +indicates that the instruction should only be applied if the extension +is installed into an application using the Gecko version identified. +Multiple ``platformversion`` flags may be included on a single line, in +which case the line is applied if any of the flags match. + +contentaccessible +~~~~~~~~~~~~~~~~~ + +Chrome resources can no longer be referenced from within , + diff --git a/build/pgo/js-input/3d-thingy.html b/build/pgo/js-input/3d-thingy.html new file mode 100644 index 0000000000..9e54299df4 --- /dev/null +++ b/build/pgo/js-input/3d-thingy.html @@ -0,0 +1,390 @@ + + +3d thingy + + + + +
Text to be replaced with graphics.
+ + + + + diff --git a/build/pgo/js-input/crypto-otp.html b/build/pgo/js-input/crypto-otp.html new file mode 100644 index 0000000000..b811538ba2 --- /dev/null +++ b/build/pgo/js-input/crypto-otp.html @@ -0,0 +1,1344 @@ + + + + +One-Time Pad Generator + + + + + + + + + + +

  One-Time Pad Generator

+ +
+ +
+ +

+Output: +Number of keys: +Line length: +
+Format: +Key length: +Group length: + +
+Composition: +Key text: Numeric + Word-like + Alphabetic + Gibberish +
+Letters: + + + Random separators + Include signatures + +
+Seed: + From clock + User-defined: + +
+ +  + +  +
+ +

+ +
+ + + +

Details

+ +

+Each of the fields in the one-time pad request form is described +below. +

+ +

Output

+ +

Number of keys

+ +

+Enter the number of keys you'd like to generate. If you generate +more than fit in the results text box, you can use the scroll +bar to view the additional lines. +

+ +

Line length

+ +

+Lines in the output will be limited to the given length (or contain +only one key if the line length is less than required for a single +key). If the line length is greater than the width of the results +box, you can use the horizontal scroll bar to view the rest of the +line. Enter 0 to force one key per line; this is handy +when you're preparing a list of keys to be read by a computer program. +

+ +

Format

+ +

Key length

+ +

+Each key will contain this number of characters, not counting +separators between groups. +

+ +

Group length

+ +

+If a nonzero value is entered in this field, the key will be broken +into groups of the given number of characters by separators. Humans +find it easier to read and remember sequences of characters when +divided into groups of five or fewer characters. +

+ +

Composition

+ +

Key text

+ +

+This set of radio buttons lets you select the character set used in +the keys. The alternatives are listed in order of +increasing security. +

+ +
+
+
Numeric
+
Keys contain only the decimal digits “0” through “9”. + Least secure.
+ +
Word-like
+
Keys are composed of alphabetic characters which obey the + digraph statistics of English text. Such keys contain + sequences of vowels and consonants familiar to speakers + of Western languages, and are therefore usually easier to + memorise but, for a given key length, are less secure than + purely random letters.
+ +
Alphabetic
+
Keys consist of letters of the alphabet chosen at random. + Each character has an equal probability of being one of + the 26 letters.
+ +
Gibberish
+
Keys use most of the printable ASCII character set, excluding + only characters frequently used for quoting purposes. This + option provides the greatest security for a given key length, + but most people find keys like this difficult to memorise or + even transcribe from a printed pad. If a human is in the loop, + it's often better to use a longer alphabetic or word-like key. + Most secure.
+
+ +
+ +

Letters

+ +

+The case of letters in keys generated with Word-like, Alphabetic, and +Gibberish key text will be as chosen. Most people find it easier to +read lower case letters than all capitals, but for some applications +(for example, where keys must be scanned optically by hardware that +only recognises capital letters), capitals are required. Selecting +“Mixed case” creates keys with a mix of upper- and +lower-case letters; such keys are more secure than those with uniform +letter case, but do not pass the “telephone test”: you +can't read them across a (hopefully secure) voice link without having +to indicate whether each letter is or is not a capital. +

+ +

Random separators

+ +

+When the Key length is longer than +a nonzero Group length specification, +the key is divided into sequences of the given group length +by separator characters. By default, a hyphen, “-”, is used +to separate groups. If you check this box, separators will be +chosen at random among punctuation marks generally acceptable +for applications such as passwords. If you're generating passwords +for a computer system, random separators dramatically increase +the difficulty of guessing passwords by exhaustive search. +

+ +

Include signatures

+ +

+ +When this box is checked, at the end of the list of keys, preceded by +a line beginning with ten dashes “-”, the 128 bit MD5 signature of +each key is given, one per line, with signatures expressed as 32 +hexadecimal digits. Key signatures can be used to increase security +when keys are used to control access to computer systems or databases. +Instead of storing a copy of the keys, the computer stores their +signatures. When the user enters a key, its signature is computed +with the same MD5 algorithm used to generate it initially, and the key +is accepted only if the signature matches. Since discovering +a key which will generate a given signature is believed to be +computationally prohibitive, even if the list of signatures stored on +the computer is compromised, that information will not permit an +intruder to deduce a valid key. +

+ +

+Signature calculation is a computationally intense process for which +JavaScript is not ideally suited; be patient while signatures are +generated, especially if your computer has modest +processing speed. +

+ +

+For signature-based validation to be secure, it is essential +the original keys be long enough to prohibit discovery of matching +signatures by exhaustive search. Suppose, for example, one used +four digit numeric keys, as used for Personal Identification +Numbers (PINs) by many credit card systems. Since only 10,000 +different keys exist, one could simply compute the signatures of +every possible key from 0000 through 9999, permitting an attacker who +came into possession of the table of signatures to recover the +keys by a simple lookup process. For maximum security, keys must +contain at least as much information as the 128 bit signatures +computed from them. This implies a minimum key length (not counting +non-random separator characters) for the various key formats as +follows: +

+ + + + + + + + +
Key Composition Minimum Characters
Numeric 39
Word-like 30
Alphabetic 28
Gibberish 20
+ +

+It should be noted that for many practical applications there is no +need for anything approaching 128-bit security. The guidelines above +apply only in the case where maximum protection in the event of +undetected compromise of key signatures occurs. In many +cases, much shorter keys are acceptable, especially when it is assumed +that a compromise of the system's password or signature database would +be only part of a much more serious subversion of all resources +on the system. +

+ +

Seed

+ +

+The seed is the starting value which determines all +subsequent values in the pseudorandom sequence used to generate +the one-time pad. Given the seed, the pad can be reproduced. The +seed is a 31-bit number which can be derived from the date and +time at which the one-time pad was requested, or from a +user-defined seed value. If the user-defined seed consists +entirely of decimal digits, it is used directly as the seed, +modulo 231; if a string containing non-digit characters +is entered, it is used to compute a hash code which is +used to seed the generator. + +

+ +

+When the clock is used to create the seed, the seed value is entered +in the User-defined box to allow you, by checking “User-defined”, +to produce additional pads with the same seed. +

+ +

Why JavaScript?

+ +

+At first glance, JavaScript may seem an odd choice for programming +a page such as this. The one-time pad generator program is rather +large and complicated, and downloading it to your browser takes longer +than would be required for a Java applet or to transfer a +one-time pad generated by a CGI program on the Web server. I chose +JavaScript for two reasons: security and transparency. + +

+ +

+Security. +The sole reason for the existence of one-time pads is to +provide a source of information known only to people to whom +they have been distributed in a secure manner. This means +the generation process cannot involve any link whose security +is suspect. If the pad were generated on a Web server and +transmitted to you, it would have to pass over the +Internet, where any intermediate site might make a copy +of your pad before you even received it. Even if some +mechanism such as encryption could absolutely prevent the +pad's being intercepted, you'd still have no way to be sure +the site generating the pad didn't keep a copy +in a file, conveniently tagged with your Internet address. +

+ +

+In order to have any degree of security, it is essential +that the pad be generated on your computer, without +involving any transmission or interaction with other +sites on the Internet. A Web browser with JavaScript makes +this possible, since the generation program embedded in this +page runs entirely on your own computer and does not +transmit anything over the Internet. Its output appears +only in the text box, allowing you to cut and paste it +to another application. From there on, its security is +up to you. +

+ +

+Security is never absolute. A one-time pad generated with +this page might be compromised in a variety of ways, including +the following: + +

+ +
    +
  • Your Web browser and/or JavaScript interpreter may + contain bugs or deliberate security violations + which report activity on your computer back to some + other Internet site.
  • + +
  • Some other applet running on another page of your + browser, perhaps without your being aware of its + existence, is spying on other windows.
  • + +
  • Some other application running on your computer + may have compromised your system's security and + be snooping on your activity.
  • + +
  • Your Web browser may be keeping a “history log” + + or “cache” of data you generate. Somebody may + come along later and recover a copy of the pad + from that log.
  • + +
  • The implementation of this page may contain a bug + or deliberate error which makes its output + predictable. This is why transparency, + discussed below, is essential.
  • + +
  • Your computer's security may have been compromised + physically; when's the last time you checked that a + bug that transmits your keystrokes and/or screen + contents to that white van parked down the street + wasn't lurking inside your computer cabinet?
  • +
+ +

+One can whip oneself into a fine fever of paranoia worrying about +things like this. One way to rule out the most probable risks +is to download a copy of the generator page and run it +from a “file:” URL on a computer which has no network +connection whatsoever and is located in a secure location +under your control. And look very carefully at any files +created by your Web browser. You may find the most interesting +things squirreled away there…. +

+ +

+Transparency. +Any security-related tool is only as good as its design +and implementation. Transparency means that, in +essence, all the moving parts are visible so you can judge +for yourself whether the tool merits your confidence. In +the case of a program, this means that source code must +be available, and that you can verify that the program +you're running corresponds to the source code provided. + +

+ +

+The very nature of JavaScript achieves this transparency. +The program is embedded into this actual Web page; to +examine it you need only use your browser's “View Source” +facility, or save the page into a file on your computer +and read it with a text editor. JavaScript's being +an interpreted language eliminates the risk of your running +a program different from the purported source code: with +an interpreted language what you read is what you run. +

+ +

+Transparency is important even if you don't know enough about +programming or security to determine whether the program +contains any flaws. The very fact that it can be examined +by anybody allows those with the required expertise to pass +judgment, and you can form your own conclusions based on +their analysis. +

+ +

Credits

+ +

+ +The pseudorandom sequence generator is based on L'Ecuyer's +two-sequence generator as described in +Communications of the ACM, Vol. 31 (1968), page 742. +A Bays-Durham shuffle is used to guard against regularities +lurking in L'Ecuyer's algorithm; see +ACM Transactions on Mathematical Software, Vol. 2 (1976) +pages 59–64 for details. +

+ +

+The JavaScript implementation of the +MD5 message-digest algorithm +was developed by Henri Torgemane; please view the source code of this +page to examine the code, including the copyright notice and +conditions of use. The MD5 algorithm was developed by Ron Rivest. +

+ +

+ +


+ +

+ + + +
+ Valid XHTML 1.0 +
+ +

+by John Walker
+May 26, 1997
+ +Updated: November 2006 +
+ +

+This document is in the public domain. +

+ + + diff --git a/build/pgo/js-input/key.gif b/build/pgo/js-input/key.gif new file mode 100644 index 0000000000..050311fc6b Binary files /dev/null and b/build/pgo/js-input/key.gif differ diff --git a/build/pgo/js-input/sunspider/3d-cube.html b/build/pgo/js-input/sunspider/3d-cube.html new file mode 100644 index 0000000000..453167d44d --- /dev/null +++ b/build/pgo/js-input/sunspider/3d-cube.html @@ -0,0 +1,387 @@ + + + + +SunSpider 3d-cube + + + + +

3d-cube

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/3d-morph.html b/build/pgo/js-input/sunspider/3d-morph.html new file mode 100644 index 0000000000..aca991d395 --- /dev/null +++ b/build/pgo/js-input/sunspider/3d-morph.html @@ -0,0 +1,104 @@ + + + + +SunSpider 3d-morph + + + + +

3d-morph

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/3d-raytrace.html b/build/pgo/js-input/sunspider/3d-raytrace.html new file mode 100644 index 0000000000..2097d4238d --- /dev/null +++ b/build/pgo/js-input/sunspider/3d-raytrace.html @@ -0,0 +1,490 @@ + + + + +SunSpider 3d-raytrace + + + +

3d-raytrace

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/access-binary-trees.html b/build/pgo/js-input/sunspider/access-binary-trees.html new file mode 100644 index 0000000000..c2c6cf3d93 --- /dev/null +++ b/build/pgo/js-input/sunspider/access-binary-trees.html @@ -0,0 +1,100 @@ + + + + +SunSpider access-binary-trees + + + + +

access-binary-trees

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/access-fannkuch.html b/build/pgo/js-input/sunspider/access-fannkuch.html new file mode 100644 index 0000000000..02b306ff25 --- /dev/null +++ b/build/pgo/js-input/sunspider/access-fannkuch.html @@ -0,0 +1,116 @@ + + + + +SunSpider access-fannkuch + + + + +

access-fannkuch

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/access-nbody.html b/build/pgo/js-input/sunspider/access-nbody.html new file mode 100644 index 0000000000..4ef73c8552 --- /dev/null +++ b/build/pgo/js-input/sunspider/access-nbody.html @@ -0,0 +1,219 @@ + + + + +SunSpider access-nbody + + + + +

access-nbody

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/access-nsieve.html b/build/pgo/js-input/sunspider/access-nsieve.html new file mode 100644 index 0000000000..c3ed067f11 --- /dev/null +++ b/build/pgo/js-input/sunspider/access-nsieve.html @@ -0,0 +1,88 @@ + + + + +SunSpider access-nsieve + + + + +

access-nsieve

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/bitops-3bit-bits-in-byte.html b/build/pgo/js-input/sunspider/bitops-3bit-bits-in-byte.html new file mode 100644 index 0000000000..c40be94ef0 --- /dev/null +++ b/build/pgo/js-input/sunspider/bitops-3bit-bits-in-byte.html @@ -0,0 +1,82 @@ + + + + +SunSpider bitops-3bit-bits-in-byte + + + + +

bitops-3bit-bits-in-byte

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/bitops-bits-in-byte.html b/build/pgo/js-input/sunspider/bitops-bits-in-byte.html new file mode 100644 index 0000000000..4022c777f4 --- /dev/null +++ b/build/pgo/js-input/sunspider/bitops-bits-in-byte.html @@ -0,0 +1,72 @@ + + + + +SunSpider bitops-bits-in-byte + + + + +

bitops-bits-in-byte

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/bitops-bitwise-and.html b/build/pgo/js-input/sunspider/bitops-bitwise-and.html new file mode 100644 index 0000000000..cca5130400 --- /dev/null +++ b/build/pgo/js-input/sunspider/bitops-bitwise-and.html @@ -0,0 +1,78 @@ + + + + +SunSpider bitops-bitwise-and + + + + +

bitops-bitwise-and

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/bitops-nsieve-bits.html b/build/pgo/js-input/sunspider/bitops-nsieve-bits.html new file mode 100644 index 0000000000..1849f9da2f --- /dev/null +++ b/build/pgo/js-input/sunspider/bitops-nsieve-bits.html @@ -0,0 +1,82 @@ + + + + +SunSpider bitops-nsieve-bits + + + + +

bitops-nsieve-bits

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/controlflow-recursive.html b/build/pgo/js-input/sunspider/controlflow-recursive.html new file mode 100644 index 0000000000..9a9651d4b6 --- /dev/null +++ b/build/pgo/js-input/sunspider/controlflow-recursive.html @@ -0,0 +1,75 @@ + + + + +SunSpider controlflow-recursive + + + + +

controlflow-recursive

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/crypto-aes.html b/build/pgo/js-input/sunspider/crypto-aes.html new file mode 100644 index 0000000000..12f26b2fb7 --- /dev/null +++ b/build/pgo/js-input/sunspider/crypto-aes.html @@ -0,0 +1,472 @@ + + + + +SunSpider crypto-aes + + + + +

crypto-aes

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/crypto-md5.html b/build/pgo/js-input/sunspider/crypto-md5.html new file mode 100644 index 0000000000..8395107ce6 --- /dev/null +++ b/build/pgo/js-input/sunspider/crypto-md5.html @@ -0,0 +1,336 @@ + + + + +SunSpider crypto-md5 + + + + +

crypto-md5

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/crypto-sha1.html b/build/pgo/js-input/sunspider/crypto-sha1.html new file mode 100644 index 0000000000..01d0b56f37 --- /dev/null +++ b/build/pgo/js-input/sunspider/crypto-sha1.html @@ -0,0 +1,274 @@ + + + + +SunSpider crypto-sha1 + + + + +

crypto-sha1

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/date-format-tofte.html b/build/pgo/js-input/sunspider/date-format-tofte.html new file mode 100644 index 0000000000..b8e4773423 --- /dev/null +++ b/build/pgo/js-input/sunspider/date-format-tofte.html @@ -0,0 +1,349 @@ + + + + +SunSpider date-format-tofte + + + + +

date-format-tofte

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/date-format-xparb.html b/build/pgo/js-input/sunspider/date-format-xparb.html new file mode 100644 index 0000000000..dd35713d1d --- /dev/null +++ b/build/pgo/js-input/sunspider/date-format-xparb.html @@ -0,0 +1,467 @@ + + + + +SunSpider date-format-xparb + + + + +

date-format-xparb

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/math-cordic.html b/build/pgo/js-input/sunspider/math-cordic.html new file mode 100644 index 0000000000..ec28f9ddde --- /dev/null +++ b/build/pgo/js-input/sunspider/math-cordic.html @@ -0,0 +1,145 @@ + + + + +SunSpider math-cordic + + + + +

math-cordic

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/math-partial-sums.html b/build/pgo/js-input/sunspider/math-partial-sums.html new file mode 100644 index 0000000000..b78b962489 --- /dev/null +++ b/build/pgo/js-input/sunspider/math-partial-sums.html @@ -0,0 +1,83 @@ + + + + +SunSpider math-partial-sums + + + + +

math-partial-sums

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/math-spectral-norm.html b/build/pgo/js-input/sunspider/math-spectral-norm.html new file mode 100644 index 0000000000..2949f9d780 --- /dev/null +++ b/build/pgo/js-input/sunspider/math-spectral-norm.html @@ -0,0 +1,101 @@ + + + + +SunSpider math-spectral-norm + + + + +

math-spectral-norm

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/regexp-dna.html b/build/pgo/js-input/sunspider/regexp-dna.html new file mode 100644 index 0000000000..4a00399b80 --- /dev/null +++ b/build/pgo/js-input/sunspider/regexp-dna.html @@ -0,0 +1,1762 @@ + + + + +SunSpider regexp-dna + + + + +

regexp-dna

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/string-base64.html b/build/pgo/js-input/sunspider/string-base64.html new file mode 100644 index 0000000000..53280ef2bb --- /dev/null +++ b/build/pgo/js-input/sunspider/string-base64.html @@ -0,0 +1,151 @@ + + + + +SunSpider string-base64 + + + + +

string-base64

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/string-fasta.html b/build/pgo/js-input/sunspider/string-fasta.html new file mode 100644 index 0000000000..240e60147c --- /dev/null +++ b/build/pgo/js-input/sunspider/string-fasta.html @@ -0,0 +1,135 @@ + + + + +SunSpider string-fasta + + + + +

string-fasta

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/string-tagcloud.html b/build/pgo/js-input/sunspider/string-tagcloud.html new file mode 100644 index 0000000000..893a927acd --- /dev/null +++ b/build/pgo/js-input/sunspider/string-tagcloud.html @@ -0,0 +1,315 @@ + + + + +SunSpider string-tagcloud + + + + +

string-tagcloud

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/string-unpack-code.html b/build/pgo/js-input/sunspider/string-unpack-code.html new file mode 100644 index 0000000000..ba80c99ea1 --- /dev/null +++ b/build/pgo/js-input/sunspider/string-unpack-code.html @@ -0,0 +1,117 @@ + + + + +SunSpider string-unpack-code + + + + +

string-unpack-code

+
+
+ + + + + + diff --git a/build/pgo/js-input/sunspider/string-validate-input.html b/build/pgo/js-input/sunspider/string-validate-input.html new file mode 100644 index 0000000000..72cf920b26 --- /dev/null +++ b/build/pgo/js-input/sunspider/string-validate-input.html @@ -0,0 +1,139 @@ + + + + +SunSpider string-validate-input + + + + +

string-validate-input

+
+
+ + + + + + diff --git a/build/pgo/js-input/valid-xhtml10.png b/build/pgo/js-input/valid-xhtml10.png new file mode 100644 index 0000000000..2275ee6ea1 Binary files /dev/null and b/build/pgo/js-input/valid-xhtml10.png differ diff --git a/build/pgo/profileserver.py b/build/pgo/profileserver.py new file mode 100755 index 0000000000..6eab7889b0 --- /dev/null +++ b/build/pgo/profileserver.py @@ -0,0 +1,254 @@ +#!/usr/bin/python +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import glob +import json +import os +import subprocess +import sys + +import mozcrash +from mozbuild.base import BinaryNotFoundException, MozbuildObject +from mozfile import TemporaryDirectory +from mozhttpd import MozHttpd +from mozprofile import FirefoxProfile, Preferences +from mozprofile.permissions import ServerLocations +from mozrunner import CLI, FirefoxRunner +from six import string_types + +PORT = 8888 + +PATH_MAPPINGS = { + "/webkit/PerformanceTests": "third_party/webkit/PerformanceTests", + # It is tempting to map to `testing/talos/talos/tests` instead, to avoid + # writing `tests/` in every path, but we can't do that because some files + # refer to scripts located in `../..`. + "/talos": "testing/talos/talos", +} + + +def get_crashreports(directory, name=None): + rc = 0 + upload_path = os.environ.get("UPLOAD_PATH") + if not upload_path: + upload_path = os.environ.get("UPLOAD_DIR") + if upload_path: + # For automation, log the minidumps with stackwalk and get them moved to + # the artifacts directory. + fetches_dir = os.environ.get("MOZ_FETCHES_DIR") + if not fetches_dir: + raise Exception( + "Unable to process minidump in automation because " + "$MOZ_FETCHES_DIR is not set in the environment" + ) + stackwalk_binary = os.path.join( + fetches_dir, "minidump-stackwalk", "minidump-stackwalk" + ) + if sys.platform == "win32": + stackwalk_binary += ".exe" + minidump_path = os.path.join(directory, "minidumps") + rc = mozcrash.check_for_crashes( + minidump_path, + symbols_path=fetches_dir, + stackwalk_binary=stackwalk_binary, + dump_save_path=upload_path, + test_name=name, + ) + return rc + + +if __name__ == "__main__": + cli = CLI() + debug_args, interactive = cli.debugger_arguments() + runner_args = cli.runner_args() + + build = MozbuildObject.from_environment() + + binary = runner_args.get("binary") + if not binary: + try: + binary = build.get_binary_path(where="staged-package") + except BinaryNotFoundException as e: + print("{}\n\n{}\n".format(e, e.help())) + sys.exit(1) + binary = os.path.normpath(os.path.abspath(binary)) + + path_mappings = { + k: os.path.join(build.topsrcdir, v) for k, v in PATH_MAPPINGS.items() + } + httpd = MozHttpd( + port=PORT, + docroot=os.path.join(build.topsrcdir, "build", "pgo"), + path_mappings=path_mappings, + ) + httpd.start(block=False) + + sp3_httpd = MozHttpd( + port=8000, + docroot=os.path.join( + build.topsrcdir, "third_party", "webkit", "PerformanceTests", "Speedometer3" + ), + path_mappings=path_mappings, + ) + sp3_httpd.start(block=False) + print("started SP3 server on port 8000") + locations = ServerLocations() + locations.add_host(host="127.0.0.1", port=PORT, options="primary,privileged") + + old_profraw_files = glob.glob("*.profraw") + for f in old_profraw_files: + os.remove(f) + + with TemporaryDirectory() as profilePath: + # TODO: refactor this into mozprofile + profile_data_dir = os.path.join(build.topsrcdir, "testing", "profiles") + with open(os.path.join(profile_data_dir, "profiles.json"), "r") as fh: + base_profiles = json.load(fh)["profileserver"] + + prefpaths = [ + os.path.join(profile_data_dir, profile, "user.js") + for profile in base_profiles + ] + + prefs = {} + for path in prefpaths: + prefs.update(Preferences.read_prefs(path)) + + interpolation = {"server": "%s:%d" % httpd.httpd.server_address} + sp3_interpolation = {"server": "%s:%d" % sp3_httpd.httpd.server_address} + for k, v in prefs.items(): + if isinstance(v, string_types): + v = v.format(**interpolation) + prefs[k] = Preferences.cast(v) + + profile = FirefoxProfile( + profile=profilePath, + preferences=prefs, + addons=[ + os.path.join( + build.topsrcdir, "tools", "quitter", "quitter@mozilla.org.xpi" + ) + ], + locations=locations, + ) + + env = os.environ.copy() + env["MOZ_CRASHREPORTER_NO_REPORT"] = "1" + env["MOZ_CRASHREPORTER_SHUTDOWN"] = "1" + env["XPCOM_DEBUG_BREAK"] = "warn" + # We disable sandboxing to make writing profiling data actually work + # Bug 1553850 considers fixing this. + env["MOZ_DISABLE_CONTENT_SANDBOX"] = "1" + env["MOZ_DISABLE_RDD_SANDBOX"] = "1" + env["MOZ_DISABLE_SOCKET_PROCESS_SANDBOX"] = "1" + env["MOZ_DISABLE_GPU_SANDBOX"] = "1" + env["MOZ_DISABLE_GMP_SANDBOX"] = "1" + env["MOZ_DISABLE_NPAPI_SANDBOX"] = "1" + env["MOZ_DISABLE_VR_SANDBOX"] = "1" + + # Ensure different pids write to different files + env["LLVM_PROFILE_FILE"] = "default_%p_random_%m.profraw" + + # Write to an output file if we're running in automation + process_args = {"universal_newlines": True} + if "UPLOAD_PATH" in env: + process_args["logfile"] = os.path.join( + env["UPLOAD_PATH"], "profile-run-1.log" + ) + + # Run Firefox a first time to initialize its profile + runner = FirefoxRunner( + profile=profile, + binary=binary, + cmdargs=["data:text/html,"], + env=env, + process_args=process_args, + ) + runner.start() + ret = runner.wait() + if ret: + print("Firefox exited with code %d during profile initialization" % ret) + logfile = process_args.get("logfile") + if logfile: + print("Firefox output (%s):" % logfile) + with open(logfile) as f: + print(f.read()) + sp3_httpd.stop() + httpd.stop() + get_crashreports(profilePath, name="Profile initialization") + sys.exit(ret) + + jarlog = os.getenv("JARLOG_FILE") + if jarlog: + env["MOZ_JAR_LOG_FILE"] = os.path.abspath(jarlog) + print("jarlog: %s" % env["MOZ_JAR_LOG_FILE"]) + if os.path.exists(jarlog): + os.remove(jarlog) + + if "UPLOAD_PATH" in env: + process_args["logfile"] = os.path.join( + env["UPLOAD_PATH"], "profile-run-2.log" + ) + cmdargs = ["http://localhost:%d/index.html" % PORT] + runner = FirefoxRunner( + profile=profile, + binary=binary, + cmdargs=cmdargs, + env=env, + process_args=process_args, + ) + runner.start(debug_args=debug_args, interactive=interactive) + ret = runner.wait() + sp3_httpd.stop() + httpd.stop() + if ret: + print("Firefox exited with code %d during profiling" % ret) + logfile = process_args.get("logfile") + if logfile: + print("Firefox output (%s):" % logfile) + with open(logfile) as f: + print(f.read()) + get_crashreports(profilePath, name="Profiling run") + sys.exit(ret) + + # Try to move the crash reports to the artifacts even if Firefox appears + # to exit successfully, in case there's a crash that doesn't set the + # return code to non-zero for some reason. + if get_crashreports(profilePath, name="Firefox exited successfully?") != 0: + print("Firefox exited successfully, but produced a crashreport") + sys.exit(1) + + llvm_profdata = env.get("LLVM_PROFDATA") + if llvm_profdata: + profraw_files = glob.glob("*.profraw") + if not profraw_files: + print( + "Could not find profraw files in the current directory: %s" + % os.getcwd() + ) + sys.exit(1) + + merged_profdata = "merged.profdata" + merge_cmd = [ + llvm_profdata, + "merge", + "-o", + merged_profdata, + ] + profraw_files + rc = subprocess.call(merge_cmd) + if rc != 0: + print("INFRA-ERROR: Failed to merge profile data. Corrupt profile?") + # exit with TBPL_RETRY + sys.exit(4) + + # llvm-profdata may fail while still exiting without an error. + if not os.path.isfile(merged_profdata): + print(merged_profdata, "was not created", file=sys.stderr) + sys.exit(1) + + if os.path.getsize(merged_profdata) == 0: + print(merged_profdata, "was created but it is empty", file=sys.stderr) + sys.exit(1) diff --git a/build/pgo/server-locations.txt b/build/pgo/server-locations.txt new file mode 100644 index 0000000000..2d97a79f3f --- /dev/null +++ b/build/pgo/server-locations.txt @@ -0,0 +1,394 @@ +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# +# This file defines the locations at which this HTTP server may be accessed. +# It is referred to by the following page, so if this file moves, that page must +# be modified accordingly: +# +# https://firefox-source-docs.mozilla.org/testing/mochitest-plain/faq.html +# +# Empty lines and lines which begin with "#" are ignored and may be used for +# storing comments. All other lines consist of an origin followed by whitespace +# and a comma-separated list of options (if indeed any options are needed). +# +# The format of an origin is, referring to RFC 2396, a scheme (either "http" or +# "https"), followed by "://", followed by a host, followed by ":", followed by +# a port number. The colon and port number must be present even if the port +# number is the default for the protocol. +# +# Unrecognized options are ignored. Recognized options are "primary" and +# "privileged", "nocert", "cert=some_cert_nickname", "redir=hostname" and +# "failHandshake". +# +# "primary" denotes a location which is the canonical location of +# the server; this location is the one assumed for requests which don't +# otherwise identify a particular origin (e.g. HTTP/1.0 requests). +# +# "privileged" denotes a location which should have the ability to request +# elevated privileges; the default is no privileges. +# +# "nocert" makes sense only for https:// hosts and means there is not +# any certificate automatically generated for this host. +# +# "failHandshake" causes the tls handshake to fail (by sending a client hello to +# the client). +# +# "cert=nickname" tells the pgo server to use a particular certificate +# for this host. The certificate is referenced by its nickname that must +# not contain any spaces. The certificate key files (PKCS12 modules) +# for custom certification are loaded from build/pgo/certs +# directory. When new certificate is added to this dir pgo/ssltunnel +# must be built then. This is only necessary for cases where we really do +# want specific certs. +# You can find instructions on how to add or modify certificates at: +# https://firefox-source-docs.mozilla.org/build/buildsystem/test_certificates.html +# +# "redir=hostname" tells the pgo server is only used for https:// +# hosts while processing the CONNECT tunnel request. It responds +# to the CONNECT with a 302 and redirection to the hostname instead +# of connecting to the real back end and replying with a 200. This +# mode exists primarily to ensure we don't allow a proxy to do that. +# + +# +# This is the primary location from which tests run. +# +http://mochi.test:8888 primary,privileged + +# +# These are a common set of prefixes scattered across one TLD with two ports and +# another TLD on a single port. +# +http://127.0.0.1:80 privileged +http://127.0.0.1:8888 privileged +http://test:80 privileged +http://mochi.test:8888 privileged +http://mochi.xorigin-test:8888 privileged +http://test1.mochi.test:8888 +http://sub1.test1.mochi.test:8888 +http://sub2.xn--lt-uia.mochi.test:8888 +http://test2.mochi.test:8888 +http://example.org:80 privileged +http://test1.example.org:80 privileged +http://test2.example.org:80 privileged +http://test3.example.org:80 privileged +http://sub1.test1.example.org:80 privileged +http://sub1.test2.example.org:80 privileged +http://sub2.test1.example.org:80 privileged +http://sub2.test2.example.org:80 privileged +http://example.org:8000 privileged +http://test1.example.org:8000 privileged +http://test2.example.org:8000 privileged +http://sub1.test1.example.org:8000 privileged +http://sub1.test2.example.org:8000 privileged +http://sub2.test1.example.org:8000 privileged +http://sub2.test2.example.org:8000 privileged +http://example.com:80 privileged +http://www.example.com:80 privileged +http://test1.example.com:80 privileged +http://test2.example.com:80 privileged +http://sub1.test1.example.com:80 privileged +http://sub1.test2.example.com:80 privileged +http://sub2.test1.example.com:80 privileged +http://sub2.test2.example.com:80 privileged +http://example.net:80 privileged +http://supports-insecure.expired.example.com:80 privileged +# Used to test that clearing Service Workers for domain example.com, does not clear prefixexample.com +http://prefixexample.com:80 + +# The first HTTPS location is used to generate the Common Name (CN) value of the +# certificate's Issued To field. +https://example.com:443 privileged +https://www.example.com:443 privileged +https://test1.example.com:443 privileged +https://test2.example.com:443 privileged +https://example.org:443 privileged +https://test1.example.org:443 privileged +https://test2.example.org:443 privileged +https://sub1.test1.example.org:443 privileged +https://sub1.test2.example.org:443 privileged +https://sub2.test1.example.org:443 privileged +https://sub2.test2.example.org:443 privileged +https://sub1.test1.example.com:443 privileged +https://sub1.test2.example.com:443 privileged +https://sub2.test1.example.com:443 privileged +https://sub2.test2.example.com:443 privileged +https://example.net:443 privileged +https://nocert.example.com:443 privileged,nocert +https://nocert.example.org:443 privileged,nocert +https://self-signed.example.com:443 privileged,cert=selfsigned +https://untrusted.example.com:443 privileged,cert=untrusted +https://expired.example.com:443 privileged,cert=expired +https://requestclientcert.example.com:443 privileged,clientauth=request +https://requireclientcert.example.com:443 privileged,clientauth=require +https://requireclientcert-2.example.com:443 privileged,clientauth=require +https://requireclientcert-untrusted.example.com:443 privileged,clientauth=require,cert=untrusted +https://mismatch.expired.example.com:443 privileged,cert=expired +https://mismatch.untrusted.example.com:443 privileged,cert=untrusted +https://untrusted-expired.example.com:443 privileged,cert=untrustedandexpired +https://mismatch.untrusted-expired.example.com:443 privileged,cert=untrustedandexpired +https://supports-insecure.expired.example.com:443 privileged,cert=expired +https://no-subject-alt-name.example.com:443 cert=noSubjectAltName + +# Used for secure contexts on ip addresses, see bug 1616675. Note that +# 127.0.0.1 prompts ssltunnel.cpp to do special-cases, so we use .2 +https://127.0.0.2:443 privileged,ipV4Address +https://secureonly.example.com:443 + +# Prevent safebrowsing tests from hitting the network for its-a-trap.html and +# its-an-attack.html. +http://www.itisatrap.org:80 +https://www.itisatrap.org:443 + +# +# These are subdomains of <ält.example.org>. +# +http://sub1.xn--lt-uia.example.org:8000 privileged +http://sub2.xn--lt-uia.example.org:80 privileged +http://xn--exmple-cua.test:80 privileged +http://sub1.xn--exmple-cua.test:80 privileged +http://xn--exaple-kqf.test:80 privileged +http://sub1.xn--exaple-kqf.test:80 privileged + +https://xn--hxajbheg2az3al.xn--jxalpdlp:443 privileged +https://sub1.xn--hxajbheg2az3al.xn--jxalpdlp:443 privileged + +# +# These are subdomains of <παράδειγμα.δοκιμή>, the Greek IDN for example.test. +# +http://xn--hxajbheg2az3al.xn--jxalpdlp:80 privileged +http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp:80 privileged + +# Bug 413909 test host +https://bug413909.xn--hxajbheg2az3al.xn--jxalpdlp:443 privileged,cert=bug413909cert + +# +# These hosts are used in tests which exercise privilege-granting functionality; +# we could reuse some of the names above, but specific names make it easier to +# distinguish one from the other in tests (as well as what functionality is +# being tested). +# +http://sectest1.example.org:80 privileged +http://sub.sectest2.example.org:80 privileged +http://sectest2.example.org:80 +http://sub.sectest1.example.org:80 + +https://sectest1.example.org:443 privileged +https://sub.sectest2.example.org:443 privileged +https://sectest2.example.org:443 +https://sub.sectest1.example.org:443 + +# +# Used while testing the url-classifier +# +http://malware.example.com:80 +http://unwanted.example.com:80 +http://tracking.example.com:80 +http://cryptomining.example.com:80 +http://fingerprinting.example.com:80 +http://not-tracking.example.com:80 +http://tracking.example.org:80 +http://another-tracking.example.net:80 +http://social-tracking.example.org:80 +http://itisatracker.org:80 +https://itisatracker.org:443 +http://trackertest.org:80 +http://email-tracking.example.org:80 +# +# Used while testing TLS session ticket resumption for third-party trackers (bug 1500533) +# (DO NOT USE THIS HOST IN OTHER TESTS!) +# +https://tlsresumptiontest.example.org:443 + +https://malware.example.com:443 +https://unwanted.example.com:443 +https://tracking.example.com:443 +https://cryptomining.example.com:443 +https://fingerprinting.example.com:443 +https://not-tracking.example.com:443 +https://tracking.example.org:443 +https://another-tracking.example.net:443 +https://social-tracking.example.org:443 +https://email-tracking.example.org:443 + +# +# Used while testing flash blocking (Bug 1307604) +# +http://flashallow.example.com:80 +http://exception.flashallow.example.com:80 +http://flashblock.example.com:80 +http://exception.flashblock.example.com:80 +http://subdocument.example.com:80 +https://subdocument.example.com:443 +http://exception.subdocument.example.com:80 + +# +# Used while testing tracking protection (Bug 1580416) +# Not that apps.fbsbx.com is a public suffix +# +http://mochitest.apps.fbsbx.com:80 + +# +# Flash usage can fail unless this URL exists +# +http://fpdownload2.macromedia.com:80 +https://fpdownload2.macromedia.com:443 + +# Bug 1281083 +http://bug1281083.example.com:80 + +# Bug 483437, 484111 +https://www.bank1.com:443 privileged,cert=escapeattack1 + +# +# CONNECT for redirproxy results in a 302 redirect to +# test1.example.com +# +https://redirproxy.example.com:443 privileged,redir=test1.example.com + +# Host used for IndexedDB Quota testing +http://bug704464-1.example.com:80 privileged +http://bug704464-2.example.com:80 privileged +http://bug704464-3.example.com:80 privileged +http://bug702292.example.com:80 privileged + +# W3C hosts. +# See http://www.w3.org/wiki/Testing/Requirements#The_Web_test_server_must_be_available_through_different_domain_names +http://w3c-test.org:80 +http://w3c-test.org:81 +http://w3c-test.org:82 +http://w3c-test.org:83 +http://www.w3c-test.org:80 +http://www.w3c-test.org:81 +http://www.w3c-test.org:82 +http://www.w3c-test.org:83 +http://www1.w3c-test.org:80 +http://www1.w3c-test.org:81 +http://www1.w3c-test.org:82 +http://www1.w3c-test.org:83 +http://www2.w3c-test.org:80 +http://www2.w3c-test.org:81 +http://www2.w3c-test.org:82 +http://www2.w3c-test.org:83 +# http://天気の良い日.w3c-test.org +http://xn--n8j6ds53lwwkrqhv28a.w3c-test.org:80 +http://xn--n8j6ds53lwwkrqhv28a.w3c-test.org:81 +http://xn--n8j6ds53lwwkrqhv28a.w3c-test.org:82 +http://xn--n8j6ds53lwwkrqhv28a.w3c-test.org:83 +# http://élève.w3c-test.org +http://xn--lve-6lad.w3c-test.org:80 +http://xn--lve-6lad.w3c-test.org:81 +http://xn--lve-6lad.w3c-test.org:82 +http://xn--lve-6lad.w3c-test.org:83 +# HTTPS versions of the above +https://w3c-test.org:443 +https://www.w3c-test.org:443 +https://www1.w3c-test.org:443 +https://www2.w3c-test.org:443 +https://xn--n8j6ds53lwwkrqhv28a.w3c-test.org:443 +https://xn--lve-6lad.w3c-test.org:443 +http://test.w3.org:80 + +# Hosts for testing TLD-based fallback encoding +http://example.tw:80 privileged +http://example.cn:80 privileged +http://example.co.jp:80 privileged +http://example.fi:80 privileged +http://example.in:80 privileged +http://example.lk:80 privileged + +# Host for HPKP +https://include-subdomains.pinning-dynamic.example.com:443 privileged,cert=dynamicPinningGood +https://bad.include-subdomains.pinning-dynamic.example.com:443 privileged,cert=dynamicPinningBad + +# Host for static pin tests +https://badchain.include-subdomains.pinning.example.com:443 privileged,cert=staticPinningBad +https://fail-handshake.example.com:443 privileged,failHandshake + +# Host for bad cert domain fixup test +https://badcertdomain.example.com:443 privileged,cert=badCertDomain +https://www.badcertdomain.example.com:443 privileged,cert=badCertDomain +https://127.0.0.3:433 privileged,cert=badCertDomain +https://badcertdomain.example.com:82 privileged,cert=badCertDomain +https://mismatch.badcertdomain.example.com:443 privileged,cert=badCertDomain + +# Hosts for HTTPS-First upgrades/downgrades +http://httpsfirst.com:80 privileged +https://httpsfirst.com:443 privileged,nocert + +# Hosts for sha1 console warning tests +https://sha1ee.example.com:443 privileged,cert=sha1_end_entity +https://sha256ee.example.com:443 privileged,cert=sha256_end_entity + +# Hosts for imminent distrust warning tests +https://imminently-distrusted.example.com:443 privileged,cert=imminently_distrusted + +# Hosts for ssl3/3des/tls1 tests +https://ssl3.example.com:443 privileged,ssl3 +https://3des.example.com:443 privileged,3des,tls1,tls1_2 +https://tls1.example.com:443 privileged,tls1 +https://tls11.example.com:443 privileged,tls1_1 +https://tls12.example.com:443 privileged,tls1_2 +https://tls13.example.com:443 privileged,tls1,tls1_3 + +# Hosts for youtube rewrite tests +https://mochitest.youtube.com:443 + +# Host for U2F localhost tests +https://localhost:443 + +# Bug 1402530 +http://localhost:80 privileged + +http://localhost:9898 +http://localhost:9899 + +# Host for testing APIs whitelisted for mozilla.org +https://www.mozilla.org:443 + +# local-IP origins for password manager tests (Bug 1582499) +http://10.0.0.0:80 privileged +http://192.168.0.0:80 privileged + +# testing HTTPS-Only Suggestions on the Error Page (Bug 1665057) +https://www.suggestion-example.com:443 privileged,cert=bug1665057cert +http://suggestion-example.com:80 privileged +https://suggestion-example.com:443 privileged,cert=badCertDomain +http://no-suggestion-example.com:80 privileged +https://no-suggestion-example.com:443 privileged,cert=badCertDomain + +# testing HTTPS-First doesn't show warning page for bad cert +http://nocert.example.com:80 privileged +http://self-signed.example.com:80 privileged +http://untrusted.example.com:80 privileged +http://untrusted-expired.example.com:80 privileged +http://no-subject-alt-name.example.com:80 privileged +http://expired.example.com:80 privileged + +# testing HTTPS-First behaviour for redirection (Bug 1706126) +http://redirect-example.com:80 privileged +https://redirect-example.com:443 privileged,cert=bug1706126cert +https://www.redirect-example.com:443 privileged,cert=bug1706126cert + +# DoH server +https://foo.example.com:4433 privileged,cert=http2-cert.pem + +# Mochitest +https://mochi.test:443 privileged,cert=mochitest-cert.pem + +# condprof common transactions +http://profile.stage.mozaws.net:80 privileged +https://profile.stage.mozaws.net:443 privileged +http://ocsp.pki.goog:80 privileged +https://ocsp.pki.goog:443 privileged + +# External IP address only available via http (Bug 1855734) +http://123.123.123.123:80 privileged +https://123.123.123.123:443 privileged,nocert + +# Domain with HSTS preloaded +http://includesubdomains.preloaded.test:80 privileged +https://includesubdomains.preloaded.test:443 privileged diff --git a/build/psutil_requirements.in b/build/psutil_requirements.in new file mode 100644 index 0000000000..22cc083951 --- /dev/null +++ b/build/psutil_requirements.in @@ -0,0 +1,2 @@ +psutil==5.9.4 + diff --git a/build/psutil_requirements.txt b/build/psutil_requirements.txt new file mode 100644 index 0000000000..cd14f98539 --- /dev/null +++ b/build/psutil_requirements.txt @@ -0,0 +1,22 @@ +# +# This file is autogenerated by pip-compile with python 3.9 +# To update, run: +# +# pip-compile --generate-hashes --output-file=build/psutil_requirements.txt build/psutil_requirements.in +# +psutil==5.9.4 \ + --hash=sha256:149555f59a69b33f056ba1c4eb22bb7bf24332ce631c44a319cec09f876aaeff \ + --hash=sha256:16653106f3b59386ffe10e0bad3bb6299e169d5327d3f187614b1cb8f24cf2e1 \ + --hash=sha256:3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62 \ + --hash=sha256:3ff89f9b835100a825b14c2808a106b6fdcc4b15483141482a12c725e7f78549 \ + --hash=sha256:54c0d3d8e0078b7666984e11b12b88af2db11d11249a8ac8920dd5ef68a66e08 \ + --hash=sha256:54d5b184728298f2ca8567bf83c422b706200bcbbfafdc06718264f9393cfeb7 \ + --hash=sha256:6001c809253a29599bc0dfd5179d9f8a5779f9dffea1da0f13c53ee568115e1e \ + --hash=sha256:68908971daf802203f3d37e78d3f8831b6d1014864d7a85937941bb35f09aefe \ + --hash=sha256:6b92c532979bafc2df23ddc785ed116fced1f492ad90a6830cf24f4d1ea27d24 \ + --hash=sha256:852dd5d9f8a47169fe62fd4a971aa07859476c2ba22c2254d4a1baa4e10b95ad \ + --hash=sha256:9120cd39dca5c5e1c54b59a41d205023d436799b1c8c4d3ff71af18535728e94 \ + --hash=sha256:c1ca331af862803a42677c120aff8a814a804e09832f166f226bfd22b56feee8 \ + --hash=sha256:efeae04f9516907be44904cc7ce08defb6b665128992a56957abc9b61dca94b7 \ + --hash=sha256:fd8522436a6ada7b4aad6638662966de0d61d241cb821239b2ae7013d41a43d4 + # via -r build/psutil_requirements.in diff --git a/build/pure_virtual/moz.build b/build/pure_virtual/moz.build new file mode 100644 index 0000000000..2e5169fec6 --- /dev/null +++ b/build/pure_virtual/moz.build @@ -0,0 +1,23 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Library("pure_virtual") + +SOURCES += ["pure_virtual.c"] + +FORCE_STATIC_LIB = True + +USE_STATIC_LIBS = True + +# Build a real library so that the linker can remove it if the symbol +# is never used. +NO_EXPAND_LIBS = True + +# LTO can mess things up. +if CONFIG["CC_TYPE"] == "clang-cl": + CFLAGS += ["-clang:-fno-lto"] +else: + CFLAGS += ["-fno-lto"] diff --git a/build/pure_virtual/pure_virtual.c b/build/pure_virtual/pure_virtual.c new file mode 100644 index 0000000000..23b18f2aae --- /dev/null +++ b/build/pure_virtual/pure_virtual.c @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include + +// This function is used in vtables to point at pure virtual methods. +// The implementation in the standard library usually aborts, but +// the function is normally never called (a call would be a bug). +// Each of these entries in vtables, however, require an unnecessary +// dynamic relocation. Defining our own function makes the linker +// point the vtables here instead of the standard library, replacing +// the dynamic relocations with relative relocations. +// +// On Windows, it doesn't really make a difference, but on macOS it +// can be packed better, saving about 10KB in libxul, and on 64-bits +// ELF systems, with packed relative relocations, it saves 140KB. +// +// Another advantage of having our own is that we can use MOZ_CRASH +// instead of the system's abort. +#ifdef _MSC_VER +int __cdecl _purecall() { MOZ_CRASH("pure virtual call"); } +#else +__attribute__((visibility("hidden"))) void __cxa_pure_virtual() { + MOZ_CRASH("pure virtual call"); +} +#endif diff --git a/build/qemu-wrap b/build/qemu-wrap new file mode 100755 index 0000000000..e33938955d --- /dev/null +++ b/build/qemu-wrap @@ -0,0 +1,24 @@ +#!/bin/bash +# this script creates a wrapper shell script for an executable. The idea is the actual executable cannot be +# executed natively (it was cross compiled), but we want to run tests natively. Running this script +# as part of the compilation process will move the non-native executable to a new location, and replace it +# with a script that will run it under qemu. +while [[ -n $1 ]]; do + case $1 in + --qemu) QEMU="$2"; shift 2;; + --libdir) LIBDIR="$2"; shift 2;; + --ld) LD="$2"; shift 2;; + *) exe="$1"; shift;; + esac +done +if [[ -z $LIBDIR ]]; then + echo "You need to specify a directory for the cross libraries when you configure the shell" + echo "You can do this with --with-cross-lib=" + exit 1 +fi +LD=${LD:-$LIBDIR/ld-linux.so.3} +mv $exe $exe.target +# Just hardcode the path to the executable. It'll be pretty obvious if it is doing the wrong thing. + +echo $'#!/bin/bash\n' $QEMU -E LD_LIBRARY_PATH="${LIBDIR}" "$LD" "$(readlink -f "$exe.target")" '"$@"' >"$exe" +chmod +x $exe \ No newline at end of file diff --git a/build/rust/backtrace/Cargo.toml b/build/rust/backtrace/Cargo.toml new file mode 100644 index 0000000000..a251228e71 --- /dev/null +++ b/build/rust/backtrace/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "backtrace" +version = "0.3.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" diff --git a/build/rust/backtrace/lib.rs b/build/rust/backtrace/lib.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/build/rust/base64/Cargo.toml b/build/rust/base64/Cargo.toml new file mode 100644 index 0000000000..ce9fdc2836 --- /dev/null +++ b/build/rust/base64/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "base64" +version = "0.13.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[dependencies.base64] +version = "0.21.0" diff --git a/build/rust/base64/lib.rs b/build/rust/base64/lib.rs new file mode 100644 index 0000000000..d5d4ce6af4 --- /dev/null +++ b/build/rust/base64/lib.rs @@ -0,0 +1,42 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use base64::engine::general_purpose::*; +pub use base64::DecodeError; +use base64::Engine; + +// Re-implement some of the 0.13 APIs on top of 0.21 + +pub fn decode>(input: T) -> Result, DecodeError> { + STANDARD.decode(input) +} + +pub fn encode>(input: T) -> String { + STANDARD.encode(input) +} + +pub fn decode_config>( + input: T, + engine: GeneralPurpose, +) -> Result, DecodeError> { + engine.decode(input) +} + +pub fn encode_config>(input: T, engine: GeneralPurpose) -> String { + engine.encode(input) +} + +pub fn encode_config_slice>( + input: T, + engine: GeneralPurpose, + output: &mut [u8], +) -> usize { + engine + .encode_slice(input, output) + .expect("Output buffer too small") +} + +pub fn encode_config_buf>(input: T, engine: GeneralPurpose, buf: &mut String) { + engine.encode_string(input, buf) +} diff --git a/build/rust/bindgen-0.63/Cargo.toml b/build/rust/bindgen-0.63/Cargo.toml new file mode 100644 index 0000000000..200ff7a961 --- /dev/null +++ b/build/rust/bindgen-0.63/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "bindgen" +version = "0.63.999" +edition = "2018" +license = "BSD-3-Clause" + +[lib] +path = "lib.rs" + +[dependencies.bindgen] +version = "0.69" +default-features = false + +[features] +logging = ["bindgen/logging"] +runtime = ["bindgen/runtime"] +static = ["bindgen/static"] +which-rustfmt = ["bindgen/which-rustfmt"] diff --git a/build/rust/bindgen-0.63/lib.rs b/build/rust/bindgen-0.63/lib.rs new file mode 100644 index 0000000000..6828a430d5 --- /dev/null +++ b/build/rust/bindgen-0.63/lib.rs @@ -0,0 +1,26 @@ +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +pub use bindgen::*; diff --git a/build/rust/bitflags/Cargo.toml b/build/rust/bitflags/Cargo.toml new file mode 100644 index 0000000000..7595f3b5bb --- /dev/null +++ b/build/rust/bitflags/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "bitflags" +version = "1.999.999" +edition = "2018" +license = "MIT/Apache-2.0" + +[lib] +path = "lib.rs" + +[dependencies.bitflags] +version = "2" diff --git a/build/rust/bitflags/lib.rs b/build/rust/bitflags/lib.rs new file mode 100644 index 0000000000..3a3c67e4fd --- /dev/null +++ b/build/rust/bitflags/lib.rs @@ -0,0 +1,61 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use bitflags::bitflags as bitflags2; +pub use bitflags::parser; + +// Copy of the macro from bitflags 1.3.2, with the implicit derives +// removed, because in 2.0, they're expected to be explicitly given +// in the macro invocation. And because bitflags 1.3.2 itself always +// adds an impl Debug, we need to remove #[derive(Debug)] from what +// is passed in, which is what the __impl_bitflags_remove_derive_debug +// macro does. +#[macro_export(local_inner_macros)] +macro_rules! bitflags { + ( + $(#[$($outer:tt)+])* + $vis:vis struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )* + } + + $($t:tt)* + ) => { + $(#[$($outer)+])* + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + $vis struct $BitFlags($T); + + impl core::fmt::Debug for $BitFlags { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + if self.is_empty() { + core::write!(f, "{:#x}", Self::empty().bits()) + } else { + $crate::parser::to_writer(self, f) + } + } + } + + bitflags2! { + impl $BitFlags: $T { + $( + $(#[$inner $($args)*])* + const $Flag = $value; + )* + } + } + + bitflags! { + $($t)* + } + }; + () => {}; +} diff --git a/build/rust/cfg-if/Cargo.toml b/build/rust/cfg-if/Cargo.toml new file mode 100644 index 0000000000..fff5b54155 --- /dev/null +++ b/build/rust/cfg-if/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "cfg-if" +version = "0.1.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[dependencies] +cfg-if = "1.0" diff --git a/build/rust/cfg-if/lib.rs b/build/rust/cfg-if/lib.rs new file mode 100644 index 0000000000..70c009f840 --- /dev/null +++ b/build/rust/cfg-if/lib.rs @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use cfg_if::*; diff --git a/build/rust/cmake/Cargo.toml b/build/rust/cmake/Cargo.toml new file mode 100644 index 0000000000..8bae1af5eb --- /dev/null +++ b/build/rust/cmake/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "cmake" +version = "0.1.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" diff --git a/build/rust/cmake/lib.rs b/build/rust/cmake/lib.rs new file mode 100644 index 0000000000..e0032240a4 --- /dev/null +++ b/build/rust/cmake/lib.rs @@ -0,0 +1,3 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ diff --git a/build/rust/derive_more/Cargo.toml b/build/rust/derive_more/Cargo.toml new file mode 100644 index 0000000000..6df64025d9 --- /dev/null +++ b/build/rust/derive_more/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "derive_more" +version = "0.99.999" +edition = "2021" +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[dependencies.derive_more] +version = "1.0.0-beta.2" + +[features] +add = ["derive_more/add"] +add_assign = ["derive_more/add_assign"] +as_mut = ["derive_more/as_mut"] +as_ref = ["derive_more/as_ref"] +constructor = ["derive_more/constructor"] +debug = ["derive_more/debug"] +default = ["derive_more/default"] +deref = ["derive_more/deref"] +deref_mut = ["derive_more/deref_mut"] +display = ["derive_more/display"] +error = ["derive_more/error"] +from = ["derive_more/from"] +from_str = ["derive_more/from_str"] +full = ["derive_more/full"] +index = ["derive_more/index"] +index_mut = ["derive_more/index_mut"] +into = ["derive_more/into"] +into_iterator = ["derive_more/into_iterator"] +is_variant = ["derive_more/is_variant"] +iterator = ["derive_more/iterator"] +mul = ["derive_more/mul"] +mul_assign = ["derive_more/mul_assign"] +not = ["derive_more/not"] +std = ["derive_more/std"] diff --git a/build/rust/derive_more/lib.rs b/build/rust/derive_more/lib.rs new file mode 100644 index 0000000000..1df30b23ca --- /dev/null +++ b/build/rust/derive_more/lib.rs @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use derive_more::*; diff --git a/build/rust/dummy-web/js-sys/Cargo.toml b/build/rust/dummy-web/js-sys/Cargo.toml new file mode 100644 index 0000000000..b0d3999ef2 --- /dev/null +++ b/build/rust/dummy-web/js-sys/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "js-sys" +version = "0.3.100" +edition = "2018" +license = "MIT OR Apache-2.0" + +[lib] +path = "lib.rs" diff --git a/build/rust/dummy-web/js-sys/lib.rs b/build/rust/dummy-web/js-sys/lib.rs new file mode 100644 index 0000000000..e0032240a4 --- /dev/null +++ b/build/rust/dummy-web/js-sys/lib.rs @@ -0,0 +1,3 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ diff --git a/build/rust/dummy-web/wasm-bindgen/Cargo.toml b/build/rust/dummy-web/wasm-bindgen/Cargo.toml new file mode 100644 index 0000000000..a4a421466e --- /dev/null +++ b/build/rust/dummy-web/wasm-bindgen/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "wasm-bindgen" +version = "0.2.100" +edition = "2018" +license = "MIT OR Apache-2.0" + +[lib] +path = "lib.rs" diff --git a/build/rust/dummy-web/wasm-bindgen/lib.rs b/build/rust/dummy-web/wasm-bindgen/lib.rs new file mode 100644 index 0000000000..e0032240a4 --- /dev/null +++ b/build/rust/dummy-web/wasm-bindgen/lib.rs @@ -0,0 +1,3 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ diff --git a/build/rust/dummy-web/web-sys/Cargo.toml b/build/rust/dummy-web/web-sys/Cargo.toml new file mode 100644 index 0000000000..4251c3e73d --- /dev/null +++ b/build/rust/dummy-web/web-sys/Cargo.toml @@ -0,0 +1,1423 @@ +[package] +name = "web-sys" +version = "0.3.100" +edition = "2018" +license = "MIT OR Apache-2.0" + +[lib] +path = "lib.rs" + +# This list is taken from web-sys 0.3.55's Cargo.toml +[features] +AbortController = [] +AbortSignal = ["EventTarget"] +AddEventListenerOptions = [] +AesCbcParams = [] +AesCtrParams = [] +AesDerivedKeyParams = [] +AesGcmParams = [] +AesKeyAlgorithm = [] +AesKeyGenParams = [] +Algorithm = [] +AlignSetting = [] +AllowedBluetoothDevice = [] +AllowedUsbDevice = [] +AnalyserNode = ["AudioNode", "EventTarget"] +AnalyserOptions = [] +AngleInstancedArrays = [] +Animation = ["EventTarget"] +AnimationEffect = [] +AnimationEvent = ["Event"] +AnimationEventInit = [] +AnimationPlayState = [] +AnimationPlaybackEvent = ["Event"] +AnimationPlaybackEventInit = [] +AnimationPropertyDetails = [] +AnimationPropertyValueDetails = [] +AnimationTimeline = [] +AssignedNodesOptions = [] +AttestationConveyancePreference = [] +Attr = ["EventTarget", "Node"] +AttributeNameValue = [] +AudioBuffer = [] +AudioBufferOptions = [] +AudioBufferSourceNode = ["AudioNode", "AudioScheduledSourceNode", "EventTarget"] +AudioBufferSourceOptions = [] +AudioConfiguration = [] +AudioContext = ["BaseAudioContext", "EventTarget"] +AudioContextOptions = [] +AudioContextState = [] +AudioDestinationNode = ["AudioNode", "EventTarget"] +AudioListener = [] +AudioNode = ["EventTarget"] +AudioNodeOptions = [] +AudioParam = [] +AudioParamMap = [] +AudioProcessingEvent = ["Event"] +AudioScheduledSourceNode = ["AudioNode", "EventTarget"] +AudioStreamTrack = ["EventTarget", "MediaStreamTrack"] +AudioTrack = [] +AudioTrackList = ["EventTarget"] +AudioWorklet = ["Worklet"] +AudioWorkletGlobalScope = ["WorkletGlobalScope"] +AudioWorkletNode = ["AudioNode", "EventTarget"] +AudioWorkletNodeOptions = [] +AudioWorkletProcessor = [] +AuthenticationExtensionsClientInputs = [] +AuthenticationExtensionsClientOutputs = [] +AuthenticatorAssertionResponse = ["AuthenticatorResponse"] +AuthenticatorAttachment = [] +AuthenticatorAttestationResponse = ["AuthenticatorResponse"] +AuthenticatorResponse = [] +AuthenticatorSelectionCriteria = [] +AuthenticatorTransport = [] +AutoKeyword = [] +AutocompleteInfo = [] +BarProp = [] +BaseAudioContext = ["EventTarget"] +BaseComputedKeyframe = [] +BaseKeyframe = [] +BasePropertyIndexedKeyframe = [] +BasicCardRequest = [] +BasicCardResponse = [] +BasicCardType = [] +BatteryManager = ["EventTarget"] +BeforeUnloadEvent = ["Event"] +BinaryType = [] +BiquadFilterNode = ["AudioNode", "EventTarget"] +BiquadFilterOptions = [] +BiquadFilterType = [] +Blob = [] +BlobEvent = ["Event"] +BlobEventInit = [] +BlobPropertyBag = [] +BlockParsingOptions = [] +Bluetooth = ["EventTarget"] +BluetoothAdvertisingEvent = ["Event"] +BluetoothAdvertisingEventInit = [] +BluetoothCharacteristicProperties = [] +BluetoothDataFilterInit = [] +BluetoothDevice = ["EventTarget"] +BluetoothLeScanFilterInit = [] +BluetoothManufacturerDataMap = [] +BluetoothPermissionDescriptor = [] +BluetoothPermissionResult = ["EventTarget", "PermissionStatus"] +BluetoothPermissionStorage = [] +BluetoothRemoteGattCharacteristic = ["EventTarget"] +BluetoothRemoteGattDescriptor = [] +BluetoothRemoteGattServer = [] +BluetoothRemoteGattService = ["EventTarget"] +BluetoothServiceDataMap = [] +BluetoothUuid = [] +BoxQuadOptions = [] +BroadcastChannel = ["EventTarget"] +BrowserElementDownloadOptions = [] +BrowserElementExecuteScriptOptions = [] +BrowserFeedWriter = [] +BrowserFindCaseSensitivity = [] +BrowserFindDirection = [] +Cache = [] +CacheBatchOperation = [] +CacheQueryOptions = [] +CacheStorage = [] +CacheStorageNamespace = [] +CanvasCaptureMediaStream = ["EventTarget", "MediaStream"] +CanvasGradient = [] +CanvasPattern = [] +CanvasRenderingContext2d = [] +CanvasWindingRule = [] +CaretChangedReason = [] +CaretPosition = [] +CaretStateChangedEventInit = [] +CdataSection = ["CharacterData", "EventTarget", "Node", "Text"] +ChannelCountMode = [] +ChannelInterpretation = [] +ChannelMergerNode = ["AudioNode", "EventTarget"] +ChannelMergerOptions = [] +ChannelPixelLayout = [] +ChannelPixelLayoutDataType = [] +ChannelSplitterNode = ["AudioNode", "EventTarget"] +ChannelSplitterOptions = [] +CharacterData = ["EventTarget", "Node"] +CheckerboardReason = [] +CheckerboardReport = [] +CheckerboardReportService = [] +ChromeFilePropertyBag = [] +ChromeWorker = ["EventTarget", "Worker"] +Client = [] +ClientQueryOptions = [] +ClientRectsAndTexts = [] +ClientType = [] +Clients = [] +Clipboard = ["EventTarget"] +ClipboardEvent = ["Event"] +ClipboardEventInit = [] +ClipboardItem = [] +ClipboardItemOptions = [] +ClipboardPermissionDescriptor = [] +CloseEvent = ["Event"] +CloseEventInit = [] +CollectedClientData = [] +Comment = ["CharacterData", "EventTarget", "Node"] +CompositeOperation = [] +CompositionEvent = ["Event", "UiEvent"] +CompositionEventInit = [] +ComputedEffectTiming = [] +ConnStatusDict = [] +ConnectionType = [] +ConsoleCounter = [] +ConsoleCounterError = [] +ConsoleEvent = [] +ConsoleInstance = [] +ConsoleInstanceOptions = [] +ConsoleLevel = [] +ConsoleLogLevel = [] +ConsoleProfileEvent = [] +ConsoleStackEntry = [] +ConsoleTimerError = [] +ConsoleTimerLogOrEnd = [] +ConsoleTimerStart = [] +ConstantSourceNode = ["AudioNode", "AudioScheduledSourceNode", "EventTarget"] +ConstantSourceOptions = [] +ConstrainBooleanParameters = [] +ConstrainDomStringParameters = [] +ConstrainDoubleRange = [] +ConstrainLongRange = [] +ContextAttributes2d = [] +ConvertCoordinateOptions = [] +ConvolverNode = ["AudioNode", "EventTarget"] +ConvolverOptions = [] +Coordinates = [] +Credential = [] +CredentialCreationOptions = [] +CredentialRequestOptions = [] +CredentialsContainer = [] +Crypto = [] +CryptoKey = [] +CryptoKeyPair = [] +Csp = [] +CspPolicies = [] +CspReport = [] +CspReportProperties = [] +CssAnimation = ["Animation", "EventTarget"] +CssBoxType = [] +CssConditionRule = ["CssGroupingRule", "CssRule"] +CssCounterStyleRule = ["CssRule"] +CssFontFaceRule = ["CssRule"] +CssFontFeatureValuesRule = ["CssRule"] +CssGroupingRule = ["CssRule"] +CssImportRule = ["CssRule"] +CssKeyframeRule = ["CssRule"] +CssKeyframesRule = ["CssRule"] +CssMediaRule = ["CssConditionRule", "CssGroupingRule", "CssRule"] +CssNamespaceRule = ["CssRule"] +CssPageRule = ["CssRule"] +CssPseudoElement = [] +CssRule = [] +CssRuleList = [] +CssStyleDeclaration = [] +CssStyleRule = ["CssRule"] +CssStyleSheet = ["StyleSheet"] +CssStyleSheetParsingMode = [] +CssSupportsRule = ["CssConditionRule", "CssGroupingRule", "CssRule"] +CssTransition = ["Animation", "EventTarget"] +CustomElementRegistry = [] +CustomEvent = ["Event"] +CustomEventInit = [] +DataTransfer = [] +DataTransferItem = [] +DataTransferItemList = [] +DateTimeValue = [] +DecoderDoctorNotification = [] +DecoderDoctorNotificationType = [] +DedicatedWorkerGlobalScope = ["EventTarget", "WorkerGlobalScope"] +DelayNode = ["AudioNode", "EventTarget"] +DelayOptions = [] +DeviceAcceleration = [] +DeviceAccelerationInit = [] +DeviceLightEvent = ["Event"] +DeviceLightEventInit = [] +DeviceMotionEvent = ["Event"] +DeviceMotionEventInit = [] +DeviceOrientationEvent = ["Event"] +DeviceOrientationEventInit = [] +DeviceProximityEvent = ["Event"] +DeviceProximityEventInit = [] +DeviceRotationRate = [] +DeviceRotationRateInit = [] +DhKeyDeriveParams = [] +DirectionSetting = [] +Directory = [] +DisplayMediaStreamConstraints = [] +DisplayNameOptions = [] +DisplayNameResult = [] +DistanceModelType = [] +DnsCacheDict = [] +DnsCacheEntry = [] +DnsLookupDict = [] +Document = ["EventTarget", "Node"] +DocumentFragment = ["EventTarget", "Node"] +DocumentTimeline = ["AnimationTimeline"] +DocumentTimelineOptions = [] +DocumentType = ["EventTarget", "Node"] +DomError = [] +DomException = [] +DomImplementation = [] +DomMatrix = ["DomMatrixReadOnly"] +DomMatrixReadOnly = [] +DomParser = [] +DomPoint = ["DomPointReadOnly"] +DomPointInit = [] +DomPointReadOnly = [] +DomQuad = [] +DomQuadInit = [] +DomQuadJson = [] +DomRect = ["DomRectReadOnly"] +DomRectInit = [] +DomRectList = [] +DomRectReadOnly = [] +DomRequest = ["EventTarget"] +DomRequestReadyState = [] +DomStringList = [] +DomStringMap = [] +DomTokenList = [] +DomWindowResizeEventDetail = [] +DragEvent = ["Event", "MouseEvent", "UiEvent"] +DragEventInit = [] +DynamicsCompressorNode = ["AudioNode", "EventTarget"] +DynamicsCompressorOptions = [] +EcKeyAlgorithm = [] +EcKeyGenParams = [] +EcKeyImportParams = [] +EcdhKeyDeriveParams = [] +EcdsaParams = [] +EffectTiming = [] +Element = ["EventTarget", "Node"] +ElementCreationOptions = [] +ElementDefinitionOptions = [] +EndingTypes = [] +ErrorCallback = [] +ErrorEvent = ["Event"] +ErrorEventInit = [] +Event = [] +EventInit = [] +EventListener = [] +EventListenerOptions = [] +EventModifierInit = [] +EventSource = ["EventTarget"] +EventSourceInit = [] +EventTarget = [] +Exception = [] +ExtBlendMinmax = [] +ExtColorBufferFloat = [] +ExtColorBufferHalfFloat = [] +ExtDisjointTimerQuery = [] +ExtFragDepth = [] +ExtSRgb = [] +ExtShaderTextureLod = [] +ExtTextureFilterAnisotropic = [] +ExtendableEvent = ["Event"] +ExtendableEventInit = [] +ExtendableMessageEvent = ["Event", "ExtendableEvent"] +ExtendableMessageEventInit = [] +External = [] +FakePluginMimeEntry = [] +FakePluginTagInit = [] +FetchEvent = ["Event", "ExtendableEvent"] +FetchEventInit = [] +FetchObserver = ["EventTarget"] +FetchReadableStreamReadDataArray = [] +FetchReadableStreamReadDataDone = [] +FetchState = [] +File = ["Blob"] +FileCallback = [] +FileList = [] +FilePropertyBag = [] +FileReader = ["EventTarget"] +FileReaderSync = [] +FileSystem = [] +FileSystemDirectoryEntry = ["FileSystemEntry"] +FileSystemDirectoryReader = [] +FileSystemEntriesCallback = [] +FileSystemEntry = [] +FileSystemEntryCallback = [] +FileSystemFileEntry = ["FileSystemEntry"] +FileSystemFlags = [] +FillMode = [] +FlashClassification = [] +FlexLineGrowthState = [] +FocusEvent = ["Event", "UiEvent"] +FocusEventInit = [] +FontFace = [] +FontFaceDescriptors = [] +FontFaceLoadStatus = [] +FontFaceSet = ["EventTarget"] +FontFaceSetIterator = [] +FontFaceSetIteratorResult = [] +FontFaceSetLoadEvent = ["Event"] +FontFaceSetLoadEventInit = [] +FontFaceSetLoadStatus = [] +FormData = [] +FrameType = [] +FuzzingFunctions = [] +GainNode = ["AudioNode", "EventTarget"] +GainOptions = [] +Gamepad = [] +GamepadAxisMoveEvent = ["Event", "GamepadEvent"] +GamepadAxisMoveEventInit = [] +GamepadButton = [] +GamepadButtonEvent = ["Event", "GamepadEvent"] +GamepadButtonEventInit = [] +GamepadEvent = ["Event"] +GamepadEventInit = [] +GamepadHand = [] +GamepadHapticActuator = [] +GamepadHapticActuatorType = [] +GamepadMappingType = [] +GamepadPose = [] +GamepadServiceTest = [] +Geolocation = [] +GetNotificationOptions = [] +GetRootNodeOptions = [] +GetUserMediaRequest = [] +Gpu = [] +GpuAdapter = [] +GpuAddressMode = [] +GpuBindGroup = [] +GpuBindGroupDescriptor = [] +GpuBindGroupEntry = [] +GpuBindGroupLayout = [] +GpuBindGroupLayoutDescriptor = [] +GpuBindGroupLayoutEntry = [] +GpuBlendComponent = [] +GpuBlendFactor = [] +GpuBlendOperation = [] +GpuBlendState = [] +GpuBuffer = [] +GpuBufferBinding = [] +GpuBufferBindingLayout = [] +GpuBufferBindingType = [] +GpuBufferDescriptor = [] +GpuBufferUsage = [] +GpuCanvasCompositingAlphaMode = [] +GpuCanvasConfiguration = [] +GpuCanvasContext = [] +GpuColorDict = [] +GpuColorTargetState = [] +GpuColorWrite = [] +GpuCommandBuffer = [] +GpuCommandBufferDescriptor = [] +GpuCommandEncoder = [] +GpuCommandEncoderDescriptor = [] +GpuCompareFunction = [] +GpuCompilationInfo = [] +GpuCompilationMessage = [] +GpuCompilationMessageType = [] +GpuComputePassDescriptor = [] +GpuComputePassEncoder = [] +GpuComputePipeline = [] +GpuComputePipelineDescriptor = [] +GpuCullMode = [] +GpuDepthStencilState = [] +GpuDevice = ["EventTarget"] +GpuDeviceDescriptor = [] +GpuDeviceLostInfo = [] +GpuDeviceLostReason = [] +GpuErrorFilter = [] +GpuExtent3dDict = [] +GpuExternalTexture = [] +GpuExternalTextureBindingLayout = [] +GpuExternalTextureDescriptor = [] +GpuFeatureName = [] +GpuFilterMode = [] +GpuFragmentState = [] +GpuFrontFace = [] +GpuImageCopyBuffer = [] +GpuImageCopyExternalImage = [] +GpuImageCopyTexture = [] +GpuImageCopyTextureTagged = [] +GpuImageDataLayout = [] +GpuIndexFormat = [] +GpuLoadOp = [] +GpuMapMode = [] +GpuMultisampleState = [] +GpuObjectDescriptorBase = [] +GpuOrigin2dDict = [] +GpuOrigin3dDict = [] +GpuOutOfMemoryError = [] +GpuPipelineDescriptorBase = [] +GpuPipelineLayout = [] +GpuPipelineLayoutDescriptor = [] +GpuPipelineStatisticName = [] +GpuPowerPreference = [] +GpuPredefinedColorSpace = [] +GpuPrimitiveState = [] +GpuPrimitiveTopology = [] +GpuProgrammableStage = [] +GpuQuerySet = [] +GpuQuerySetDescriptor = [] +GpuQueryType = [] +GpuQueue = [] +GpuRenderBundle = [] +GpuRenderBundleDescriptor = [] +GpuRenderBundleEncoder = [] +GpuRenderBundleEncoderDescriptor = [] +GpuRenderPassColorAttachment = [] +GpuRenderPassDepthStencilAttachment = [] +GpuRenderPassDescriptor = [] +GpuRenderPassEncoder = [] +GpuRenderPassLayout = [] +GpuRenderPipeline = [] +GpuRenderPipelineDescriptor = [] +GpuRequestAdapterOptions = [] +GpuSampler = [] +GpuSamplerBindingLayout = [] +GpuSamplerBindingType = [] +GpuSamplerDescriptor = [] +GpuShaderModule = [] +GpuShaderModuleDescriptor = [] +GpuShaderStage = [] +GpuStencilFaceState = [] +GpuStencilOperation = [] +GpuStorageTextureAccess = [] +GpuStorageTextureBindingLayout = [] +GpuStoreOp = [] +GpuSupportedFeatures = [] +GpuSupportedLimits = [] +GpuTexture = [] +GpuTextureAspect = [] +GpuTextureBindingLayout = [] +GpuTextureDescriptor = [] +GpuTextureDimension = [] +GpuTextureFormat = [] +GpuTextureSampleType = [] +GpuTextureUsage = [] +GpuTextureView = [] +GpuTextureViewDescriptor = [] +GpuTextureViewDimension = [] +GpuUncapturedErrorEvent = ["Event"] +GpuUncapturedErrorEventInit = [] +GpuValidationError = [] +GpuVertexAttribute = [] +GpuVertexBufferLayout = [] +GpuVertexFormat = [] +GpuVertexState = [] +GpuVertexStepMode = [] +GridDeclaration = [] +GridTrackState = [] +GroupedHistoryEventInit = [] +HalfOpenInfoDict = [] +HashChangeEvent = ["Event"] +HashChangeEventInit = [] +Headers = [] +HeadersGuardEnum = [] +Hid = ["EventTarget"] +HidCollectionInfo = [] +HidConnectionEvent = ["Event"] +HidConnectionEventInit = [] +HidDevice = ["EventTarget"] +HidDeviceFilter = [] +HidDeviceRequestOptions = [] +HidInputReportEvent = ["Event"] +HidInputReportEventInit = [] +HidReportInfo = [] +HidReportItem = [] +HidUnitSystem = [] +HiddenPluginEventInit = [] +History = [] +HitRegionOptions = [] +HkdfParams = [] +HmacDerivedKeyParams = [] +HmacImportParams = [] +HmacKeyAlgorithm = [] +HmacKeyGenParams = [] +HtmlAllCollection = [] +HtmlAnchorElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlAreaElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlAudioElement = ["Element", "EventTarget", "HtmlElement", "HtmlMediaElement", "Node"] +HtmlBaseElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlBodyElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlBrElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlButtonElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlCanvasElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlCollection = [] +HtmlDListElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlDataElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlDataListElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlDetailsElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlDialogElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlDirectoryElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlDivElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlDocument = ["Document", "EventTarget", "Node"] +HtmlElement = ["Element", "EventTarget", "Node"] +HtmlEmbedElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlFieldSetElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlFontElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlFormControlsCollection = ["HtmlCollection"] +HtmlFormElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlFrameElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlFrameSetElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlHeadElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlHeadingElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlHrElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlHtmlElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlIFrameElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlImageElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlInputElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlLabelElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlLegendElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlLiElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlLinkElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlMapElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlMediaElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlMenuElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlMenuItemElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlMetaElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlMeterElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlModElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlOListElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlObjectElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlOptGroupElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlOptionElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlOptionsCollection = ["HtmlCollection"] +HtmlOutputElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlParagraphElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlParamElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlPictureElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlPreElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlProgressElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlQuoteElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlScriptElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlSelectElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlSlotElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlSourceElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlSpanElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlStyleElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlTableCaptionElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlTableCellElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlTableColElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlTableElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlTableRowElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlTableSectionElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlTemplateElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlTextAreaElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlTimeElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlTitleElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlTrackElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlUListElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlUnknownElement = ["Element", "EventTarget", "HtmlElement", "Node"] +HtmlVideoElement = ["Element", "EventTarget", "HtmlElement", "HtmlMediaElement", "Node"] +HttpConnDict = [] +HttpConnInfo = [] +HttpConnectionElement = [] +IdbCursor = [] +IdbCursorDirection = [] +IdbCursorWithValue = ["IdbCursor"] +IdbDatabase = ["EventTarget"] +IdbFactory = [] +IdbFileHandle = ["EventTarget"] +IdbFileMetadataParameters = [] +IdbFileRequest = ["DomRequest", "EventTarget"] +IdbIndex = [] +IdbIndexParameters = [] +IdbKeyRange = [] +IdbLocaleAwareKeyRange = ["IdbKeyRange"] +IdbMutableFile = ["EventTarget"] +IdbObjectStore = [] +IdbObjectStoreParameters = [] +IdbOpenDbOptions = [] +IdbOpenDbRequest = ["EventTarget", "IdbRequest"] +IdbRequest = ["EventTarget"] +IdbRequestReadyState = [] +IdbTransaction = ["EventTarget"] +IdbTransactionMode = [] +IdbVersionChangeEvent = ["Event"] +IdbVersionChangeEventInit = [] +IdleDeadline = [] +IdleRequestOptions = [] +IirFilterNode = ["AudioNode", "EventTarget"] +IirFilterOptions = [] +ImageBitmap = [] +ImageBitmapFormat = [] +ImageBitmapRenderingContext = [] +ImageCapture = [] +ImageCaptureError = [] +ImageCaptureErrorEvent = ["Event"] +ImageCaptureErrorEventInit = [] +ImageData = [] +InputEvent = ["Event", "UiEvent"] +InputEventInit = [] +InstallTriggerData = [] +IntersectionObserver = [] +IntersectionObserverEntry = [] +IntersectionObserverEntryInit = [] +IntersectionObserverInit = [] +IntlUtils = [] +IterableKeyAndValueResult = [] +IterableKeyOrValueResult = [] +IterationCompositeOperation = [] +JsonWebKey = [] +KeyAlgorithm = [] +KeyEvent = [] +KeyIdsInitData = [] +KeyboardEvent = ["Event", "UiEvent"] +KeyboardEventInit = [] +KeyframeEffect = ["AnimationEffect"] +KeyframeEffectOptions = [] +L10nElement = [] +L10nValue = [] +LifecycleCallbacks = [] +LineAlignSetting = [] +ListBoxObject = [] +LocalMediaStream = ["EventTarget", "MediaStream"] +LocaleInfo = [] +Location = [] +MediaCapabilities = [] +MediaCapabilitiesInfo = [] +MediaConfiguration = [] +MediaDecodingConfiguration = [] +MediaDecodingType = [] +MediaDeviceInfo = [] +MediaDeviceKind = [] +MediaDevices = ["EventTarget"] +MediaElementAudioSourceNode = ["AudioNode", "EventTarget"] +MediaElementAudioSourceOptions = [] +MediaEncodingConfiguration = [] +MediaEncodingType = [] +MediaEncryptedEvent = ["Event"] +MediaError = [] +MediaKeyError = ["Event"] +MediaKeyMessageEvent = ["Event"] +MediaKeyMessageEventInit = [] +MediaKeyMessageType = [] +MediaKeyNeededEventInit = [] +MediaKeySession = ["EventTarget"] +MediaKeySessionType = [] +MediaKeyStatus = [] +MediaKeyStatusMap = [] +MediaKeySystemAccess = [] +MediaKeySystemConfiguration = [] +MediaKeySystemMediaCapability = [] +MediaKeySystemStatus = [] +MediaKeys = [] +MediaKeysPolicy = [] +MediaKeysRequirement = [] +MediaList = [] +MediaQueryList = ["EventTarget"] +MediaQueryListEvent = ["Event"] +MediaQueryListEventInit = [] +MediaRecorder = ["EventTarget"] +MediaRecorderErrorEvent = ["Event"] +MediaRecorderErrorEventInit = [] +MediaRecorderOptions = [] +MediaSource = ["EventTarget"] +MediaSourceEndOfStreamError = [] +MediaSourceEnum = [] +MediaSourceReadyState = [] +MediaStream = ["EventTarget"] +MediaStreamAudioDestinationNode = ["AudioNode", "EventTarget"] +MediaStreamAudioSourceNode = ["AudioNode", "EventTarget"] +MediaStreamAudioSourceOptions = [] +MediaStreamConstraints = [] +MediaStreamError = [] +MediaStreamEvent = ["Event"] +MediaStreamEventInit = [] +MediaStreamTrack = ["EventTarget"] +MediaStreamTrackEvent = ["Event"] +MediaStreamTrackEventInit = [] +MediaStreamTrackState = [] +MediaTrackConstraintSet = [] +MediaTrackConstraints = [] +MediaTrackSettings = [] +MediaTrackSupportedConstraints = [] +MessageChannel = [] +MessageEvent = ["Event"] +MessageEventInit = [] +MessagePort = ["EventTarget"] +MidiAccess = ["EventTarget"] +MidiConnectionEvent = ["Event"] +MidiConnectionEventInit = [] +MidiInput = ["EventTarget", "MidiPort"] +MidiInputMap = [] +MidiMessageEvent = ["Event"] +MidiMessageEventInit = [] +MidiOptions = [] +MidiOutput = ["EventTarget", "MidiPort"] +MidiOutputMap = [] +MidiPort = ["EventTarget"] +MidiPortConnectionState = [] +MidiPortDeviceState = [] +MidiPortType = [] +MimeType = [] +MimeTypeArray = [] +MouseEvent = ["Event", "UiEvent"] +MouseEventInit = [] +MouseScrollEvent = ["Event", "MouseEvent", "UiEvent"] +MozDebug = [] +MutationEvent = ["Event"] +MutationObserver = [] +MutationObserverInit = [] +MutationObservingInfo = [] +MutationRecord = [] +NamedNodeMap = [] +NativeOsFileReadOptions = [] +NativeOsFileWriteAtomicOptions = [] +NavigationType = [] +Navigator = [] +NavigatorAutomationInformation = [] +NetworkCommandOptions = [] +NetworkInformation = ["EventTarget"] +NetworkResultOptions = [] +Node = ["EventTarget"] +NodeFilter = [] +NodeIterator = [] +NodeList = [] +Notification = ["EventTarget"] +NotificationBehavior = [] +NotificationDirection = [] +NotificationEvent = ["Event", "ExtendableEvent"] +NotificationEventInit = [] +NotificationOptions = [] +NotificationPermission = [] +ObserverCallback = [] +OesElementIndexUint = [] +OesStandardDerivatives = [] +OesTextureFloat = [] +OesTextureFloatLinear = [] +OesTextureHalfFloat = [] +OesTextureHalfFloatLinear = [] +OesVertexArrayObject = [] +OfflineAudioCompletionEvent = ["Event"] +OfflineAudioCompletionEventInit = [] +OfflineAudioContext = ["BaseAudioContext", "EventTarget"] +OfflineAudioContextOptions = [] +OfflineResourceList = ["EventTarget"] +OffscreenCanvas = ["EventTarget"] +OpenWindowEventDetail = [] +OptionalEffectTiming = [] +OrientationLockType = [] +OrientationType = [] +OscillatorNode = ["AudioNode", "AudioScheduledSourceNode", "EventTarget"] +OscillatorOptions = [] +OscillatorType = [] +OverSampleType = [] +PageTransitionEvent = ["Event"] +PageTransitionEventInit = [] +PaintRequest = [] +PaintRequestList = [] +PaintWorkletGlobalScope = ["WorkletGlobalScope"] +PannerNode = ["AudioNode", "EventTarget"] +PannerOptions = [] +PanningModelType = [] +Path2d = [] +PaymentAddress = [] +PaymentComplete = [] +PaymentMethodChangeEvent = ["Event", "PaymentRequestUpdateEvent"] +PaymentMethodChangeEventInit = [] +PaymentRequestUpdateEvent = ["Event"] +PaymentRequestUpdateEventInit = [] +PaymentResponse = [] +Pbkdf2Params = [] +PcImplIceConnectionState = [] +PcImplIceGatheringState = [] +PcImplSignalingState = [] +PcObserverStateType = [] +Performance = ["EventTarget"] +PerformanceEntry = [] +PerformanceEntryEventInit = [] +PerformanceEntryFilterOptions = [] +PerformanceMark = ["PerformanceEntry"] +PerformanceMeasure = ["PerformanceEntry"] +PerformanceNavigation = [] +PerformanceNavigationTiming = ["PerformanceEntry", "PerformanceResourceTiming"] +PerformanceObserver = [] +PerformanceObserverEntryList = [] +PerformanceObserverInit = [] +PerformanceResourceTiming = ["PerformanceEntry"] +PerformanceServerTiming = [] +PerformanceTiming = [] +PeriodicWave = [] +PeriodicWaveConstraints = [] +PeriodicWaveOptions = [] +PermissionDescriptor = [] +PermissionName = [] +PermissionState = [] +PermissionStatus = ["EventTarget"] +Permissions = [] +PlaybackDirection = [] +Plugin = [] +PluginArray = [] +PluginCrashedEventInit = [] +PointerEvent = ["Event", "MouseEvent", "UiEvent"] +PointerEventInit = [] +PopStateEvent = ["Event"] +PopStateEventInit = [] +PopupBlockedEvent = ["Event"] +PopupBlockedEventInit = [] +Position = [] +PositionAlignSetting = [] +PositionError = [] +PositionOptions = [] +Presentation = [] +PresentationAvailability = ["EventTarget"] +PresentationConnection = ["EventTarget"] +PresentationConnectionAvailableEvent = ["Event"] +PresentationConnectionAvailableEventInit = [] +PresentationConnectionBinaryType = [] +PresentationConnectionCloseEvent = ["Event"] +PresentationConnectionCloseEventInit = [] +PresentationConnectionClosedReason = [] +PresentationConnectionList = ["EventTarget"] +PresentationConnectionState = [] +PresentationReceiver = [] +PresentationRequest = ["EventTarget"] +PresentationStyle = [] +ProcessingInstruction = ["CharacterData", "EventTarget", "Node"] +ProfileTimelineLayerRect = [] +ProfileTimelineMarker = [] +ProfileTimelineMessagePortOperationType = [] +ProfileTimelineStackFrame = [] +ProfileTimelineWorkerOperationType = [] +ProgressEvent = ["Event"] +ProgressEventInit = [] +PromiseNativeHandler = [] +PromiseRejectionEvent = ["Event"] +PromiseRejectionEventInit = [] +PublicKeyCredential = ["Credential"] +PublicKeyCredentialCreationOptions = [] +PublicKeyCredentialDescriptor = [] +PublicKeyCredentialEntity = [] +PublicKeyCredentialParameters = [] +PublicKeyCredentialRequestOptions = [] +PublicKeyCredentialRpEntity = [] +PublicKeyCredentialType = [] +PublicKeyCredentialUserEntity = [] +PushEncryptionKeyName = [] +PushEvent = ["Event", "ExtendableEvent"] +PushEventInit = [] +PushManager = [] +PushMessageData = [] +PushPermissionState = [] +PushSubscription = [] +PushSubscriptionInit = [] +PushSubscriptionJson = [] +PushSubscriptionKeys = [] +PushSubscriptionOptions = [] +PushSubscriptionOptionsInit = [] +QueuingStrategy = [] +RadioNodeList = ["NodeList"] +Range = [] +RcwnPerfStats = [] +RcwnStatus = [] +ReadableStream = [] +ReadableStreamByobReadResult = [] +ReadableStreamByobReader = [] +ReadableStreamDefaultReadResult = [] +ReadableStreamDefaultReader = [] +ReadableStreamGetReaderOptions = [] +ReadableStreamIteratorOptions = [] +ReadableStreamReaderMode = [] +ReadableWritablePair = [] +RecordingState = [] +ReferrerPolicy = [] +RegisterRequest = [] +RegisterResponse = [] +RegisteredKey = [] +RegistrationOptions = [] +Request = [] +RequestCache = [] +RequestCredentials = [] +RequestDestination = [] +RequestDeviceOptions = [] +RequestInit = [] +RequestMediaKeySystemAccessNotification = [] +RequestMode = [] +RequestRedirect = [] +ResizeObserver = [] +ResizeObserverBoxOptions = [] +ResizeObserverEntry = [] +ResizeObserverOptions = [] +ResizeObserverSize = [] +Response = [] +ResponseInit = [] +ResponseType = [] +RsaHashedImportParams = [] +RsaOaepParams = [] +RsaOtherPrimesInfo = [] +RsaPssParams = [] +RtcAnswerOptions = [] +RtcBundlePolicy = [] +RtcCertificate = [] +RtcCertificateExpiration = [] +RtcCodecStats = [] +RtcConfiguration = [] +RtcDataChannel = ["EventTarget"] +RtcDataChannelEvent = ["Event"] +RtcDataChannelEventInit = [] +RtcDataChannelInit = [] +RtcDataChannelState = [] +RtcDataChannelType = [] +RtcDegradationPreference = [] +RtcFecParameters = [] +RtcIceCandidate = [] +RtcIceCandidateInit = [] +RtcIceCandidatePairStats = [] +RtcIceCandidateStats = [] +RtcIceComponentStats = [] +RtcIceConnectionState = [] +RtcIceCredentialType = [] +RtcIceGatheringState = [] +RtcIceServer = [] +RtcIceTransportPolicy = [] +RtcIdentityAssertion = [] +RtcIdentityAssertionResult = [] +RtcIdentityProvider = [] +RtcIdentityProviderDetails = [] +RtcIdentityProviderOptions = [] +RtcIdentityProviderRegistrar = [] +RtcIdentityValidationResult = [] +RtcInboundRtpStreamStats = [] +RtcLifecycleEvent = [] +RtcMediaStreamStats = [] +RtcMediaStreamTrackStats = [] +RtcOfferAnswerOptions = [] +RtcOfferOptions = [] +RtcOutboundRtpStreamStats = [] +RtcPeerConnection = ["EventTarget"] +RtcPeerConnectionIceEvent = ["Event"] +RtcPeerConnectionIceEventInit = [] +RtcPriorityType = [] +RtcRtcpParameters = [] +RtcRtpCodecParameters = [] +RtcRtpContributingSource = [] +RtcRtpEncodingParameters = [] +RtcRtpHeaderExtensionParameters = [] +RtcRtpParameters = [] +RtcRtpReceiver = [] +RtcRtpSender = [] +RtcRtpSourceEntry = [] +RtcRtpSourceEntryType = [] +RtcRtpSynchronizationSource = [] +RtcRtpTransceiver = [] +RtcRtpTransceiverDirection = [] +RtcRtpTransceiverInit = [] +RtcRtxParameters = [] +RtcSdpType = [] +RtcSessionDescription = [] +RtcSessionDescriptionInit = [] +RtcSignalingState = [] +RtcStats = [] +RtcStatsIceCandidatePairState = [] +RtcStatsIceCandidateType = [] +RtcStatsReport = [] +RtcStatsReportInternal = [] +RtcStatsType = [] +RtcTrackEvent = ["Event"] +RtcTrackEventInit = [] +RtcTransportStats = [] +RtcdtmfSender = ["EventTarget"] +RtcdtmfToneChangeEvent = ["Event"] +RtcdtmfToneChangeEventInit = [] +RtcrtpContributingSourceStats = [] +RtcrtpStreamStats = [] +Screen = ["EventTarget"] +ScreenColorGamut = [] +ScreenLuminance = [] +ScreenOrientation = ["EventTarget"] +ScriptProcessorNode = ["AudioNode", "EventTarget"] +ScrollAreaEvent = ["Event", "UiEvent"] +ScrollBehavior = [] +ScrollBoxObject = [] +ScrollIntoViewOptions = [] +ScrollLogicalPosition = [] +ScrollOptions = [] +ScrollRestoration = [] +ScrollSetting = [] +ScrollState = [] +ScrollToOptions = [] +ScrollViewChangeEventInit = [] +SecurityPolicyViolationEvent = ["Event"] +SecurityPolicyViolationEventDisposition = [] +SecurityPolicyViolationEventInit = [] +Selection = [] +ServerSocketOptions = [] +ServiceWorker = ["EventTarget"] +ServiceWorkerContainer = ["EventTarget"] +ServiceWorkerGlobalScope = ["EventTarget", "WorkerGlobalScope"] +ServiceWorkerRegistration = ["EventTarget"] +ServiceWorkerState = [] +ServiceWorkerUpdateViaCache = [] +ShadowRoot = ["DocumentFragment", "EventTarget", "Node"] +ShadowRootInit = [] +ShadowRootMode = [] +SharedWorker = ["EventTarget"] +SharedWorkerGlobalScope = ["EventTarget", "WorkerGlobalScope"] +SignResponse = [] +SocketElement = [] +SocketOptions = [] +SocketReadyState = [] +SocketsDict = [] +SourceBuffer = ["EventTarget"] +SourceBufferAppendMode = [] +SourceBufferList = ["EventTarget"] +SpeechGrammar = [] +SpeechGrammarList = [] +SpeechRecognition = ["EventTarget"] +SpeechRecognitionAlternative = [] +SpeechRecognitionError = ["Event"] +SpeechRecognitionErrorCode = [] +SpeechRecognitionErrorInit = [] +SpeechRecognitionEvent = ["Event"] +SpeechRecognitionEventInit = [] +SpeechRecognitionResult = [] +SpeechRecognitionResultList = [] +SpeechSynthesis = ["EventTarget"] +SpeechSynthesisErrorCode = [] +SpeechSynthesisErrorEvent = ["Event", "SpeechSynthesisEvent"] +SpeechSynthesisErrorEventInit = [] +SpeechSynthesisEvent = ["Event"] +SpeechSynthesisEventInit = [] +SpeechSynthesisUtterance = ["EventTarget"] +SpeechSynthesisVoice = [] +StereoPannerNode = ["AudioNode", "EventTarget"] +StereoPannerOptions = [] +Storage = [] +StorageEstimate = [] +StorageEvent = ["Event"] +StorageEventInit = [] +StorageManager = [] +StorageType = [] +StreamPipeOptions = [] +StyleRuleChangeEventInit = [] +StyleSheet = [] +StyleSheetApplicableStateChangeEventInit = [] +StyleSheetChangeEventInit = [] +StyleSheetList = [] +SubtleCrypto = [] +SupportedType = [] +SvgAngle = [] +SvgAnimateElement = ["Element", "EventTarget", "Node", "SvgAnimationElement", "SvgElement"] +SvgAnimateMotionElement = ["Element", "EventTarget", "Node", "SvgAnimationElement", "SvgElement"] +SvgAnimateTransformElement = ["Element", "EventTarget", "Node", "SvgAnimationElement", "SvgElement"] +SvgAnimatedAngle = [] +SvgAnimatedBoolean = [] +SvgAnimatedEnumeration = [] +SvgAnimatedInteger = [] +SvgAnimatedLength = [] +SvgAnimatedLengthList = [] +SvgAnimatedNumber = [] +SvgAnimatedNumberList = [] +SvgAnimatedPreserveAspectRatio = [] +SvgAnimatedRect = [] +SvgAnimatedString = [] +SvgAnimatedTransformList = [] +SvgAnimationElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgBoundingBoxOptions = [] +SvgCircleElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGeometryElement", "SvgGraphicsElement"] +SvgClipPathElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgComponentTransferFunctionElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgDefsElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"] +SvgDescElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgElement = ["Element", "EventTarget", "Node"] +SvgEllipseElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGeometryElement", "SvgGraphicsElement"] +SvgFilterElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgForeignObjectElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"] +SvgGeometryElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"] +SvgGradientElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgGraphicsElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgImageElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"] +SvgLength = [] +SvgLengthList = [] +SvgLineElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGeometryElement", "SvgGraphicsElement"] +SvgLinearGradientElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGradientElement"] +SvgMarkerElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgMaskElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgMatrix = [] +SvgMetadataElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgNumber = [] +SvgNumberList = [] +SvgPathElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGeometryElement", "SvgGraphicsElement"] +SvgPathSeg = [] +SvgPathSegArcAbs = ["SvgPathSeg"] +SvgPathSegArcRel = ["SvgPathSeg"] +SvgPathSegClosePath = ["SvgPathSeg"] +SvgPathSegCurvetoCubicAbs = ["SvgPathSeg"] +SvgPathSegCurvetoCubicRel = ["SvgPathSeg"] +SvgPathSegCurvetoCubicSmoothAbs = ["SvgPathSeg"] +SvgPathSegCurvetoCubicSmoothRel = ["SvgPathSeg"] +SvgPathSegCurvetoQuadraticAbs = ["SvgPathSeg"] +SvgPathSegCurvetoQuadraticRel = ["SvgPathSeg"] +SvgPathSegCurvetoQuadraticSmoothAbs = ["SvgPathSeg"] +SvgPathSegCurvetoQuadraticSmoothRel = ["SvgPathSeg"] +SvgPathSegLinetoAbs = ["SvgPathSeg"] +SvgPathSegLinetoHorizontalAbs = ["SvgPathSeg"] +SvgPathSegLinetoHorizontalRel = ["SvgPathSeg"] +SvgPathSegLinetoRel = ["SvgPathSeg"] +SvgPathSegLinetoVerticalAbs = ["SvgPathSeg"] +SvgPathSegLinetoVerticalRel = ["SvgPathSeg"] +SvgPathSegList = [] +SvgPathSegMovetoAbs = ["SvgPathSeg"] +SvgPathSegMovetoRel = ["SvgPathSeg"] +SvgPatternElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgPoint = [] +SvgPointList = [] +SvgPolygonElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGeometryElement", "SvgGraphicsElement"] +SvgPolylineElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGeometryElement", "SvgGraphicsElement"] +SvgPreserveAspectRatio = [] +SvgRadialGradientElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGradientElement"] +SvgRect = [] +SvgRectElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGeometryElement", "SvgGraphicsElement"] +SvgScriptElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgSetElement = ["Element", "EventTarget", "Node", "SvgAnimationElement", "SvgElement"] +SvgStopElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgStringList = [] +SvgStyleElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgSwitchElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"] +SvgSymbolElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgTextContentElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"] +SvgTextElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement", "SvgTextContentElement", "SvgTextPositioningElement"] +SvgTextPathElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement", "SvgTextContentElement"] +SvgTextPositioningElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement", "SvgTextContentElement"] +SvgTitleElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgTransform = [] +SvgTransformList = [] +SvgUnitTypes = [] +SvgUseElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"] +SvgViewElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgZoomAndPan = [] +SvgaElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"] +SvgfeBlendElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeColorMatrixElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeComponentTransferElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeCompositeElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeConvolveMatrixElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeDiffuseLightingElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeDisplacementMapElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeDistantLightElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeDropShadowElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeFloodElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeFuncAElement = ["Element", "EventTarget", "Node", "SvgComponentTransferFunctionElement", "SvgElement"] +SvgfeFuncBElement = ["Element", "EventTarget", "Node", "SvgComponentTransferFunctionElement", "SvgElement"] +SvgfeFuncGElement = ["Element", "EventTarget", "Node", "SvgComponentTransferFunctionElement", "SvgElement"] +SvgfeFuncRElement = ["Element", "EventTarget", "Node", "SvgComponentTransferFunctionElement", "SvgElement"] +SvgfeGaussianBlurElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeImageElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeMergeElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeMergeNodeElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeMorphologyElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeOffsetElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfePointLightElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeSpecularLightingElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeSpotLightElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeTileElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgfeTurbulenceElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvggElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"] +SvgmPathElement = ["Element", "EventTarget", "Node", "SvgElement"] +SvgsvgElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"] +SvgtSpanElement = ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement", "SvgTextContentElement", "SvgTextPositioningElement"] +TcpReadyState = [] +TcpServerSocket = ["EventTarget"] +TcpServerSocketEvent = ["Event"] +TcpServerSocketEventInit = [] +TcpSocket = ["EventTarget"] +TcpSocketBinaryType = [] +TcpSocketErrorEvent = ["Event"] +TcpSocketErrorEventInit = [] +TcpSocketEvent = ["Event"] +TcpSocketEventInit = [] +Text = ["CharacterData", "EventTarget", "Node"] +TextDecodeOptions = [] +TextDecoder = [] +TextDecoderOptions = [] +TextEncoder = [] +TextMetrics = [] +TextTrack = ["EventTarget"] +TextTrackCue = ["EventTarget"] +TextTrackCueList = [] +TextTrackKind = [] +TextTrackList = ["EventTarget"] +TextTrackMode = [] +TimeEvent = ["Event"] +TimeRanges = [] +Touch = [] +TouchEvent = ["Event", "UiEvent"] +TouchEventInit = [] +TouchInit = [] +TouchList = [] +TrackEvent = ["Event"] +TrackEventInit = [] +TransformStream = [] +TransitionEvent = ["Event"] +TransitionEventInit = [] +Transport = [] +TreeBoxObject = [] +TreeCellInfo = [] +TreeView = [] +TreeWalker = [] +U2f = [] +U2fClientData = [] +UdpMessageEventInit = [] +UdpOptions = [] +UiEvent = ["Event"] +UiEventInit = [] +Url = [] +UrlSearchParams = [] +Usb = ["EventTarget"] +UsbAlternateInterface = [] +UsbConfiguration = [] +UsbConnectionEvent = ["Event"] +UsbConnectionEventInit = [] +UsbControlTransferParameters = [] +UsbDevice = [] +UsbDeviceFilter = [] +UsbDeviceRequestOptions = [] +UsbDirection = [] +UsbEndpoint = [] +UsbEndpointType = [] +UsbInTransferResult = [] +UsbInterface = [] +UsbIsochronousInTransferPacket = [] +UsbIsochronousInTransferResult = [] +UsbIsochronousOutTransferPacket = [] +UsbIsochronousOutTransferResult = [] +UsbOutTransferResult = [] +UsbPermissionDescriptor = [] +UsbPermissionResult = ["EventTarget", "PermissionStatus"] +UsbPermissionStorage = [] +UsbRecipient = [] +UsbRequestType = [] +UsbTransferStatus = [] +UserProximityEvent = ["Event"] +UserProximityEventInit = [] +UserVerificationRequirement = [] +ValidityState = [] +ValueEvent = ["Event"] +ValueEventInit = [] +VideoConfiguration = [] +VideoFacingModeEnum = [] +VideoPlaybackQuality = [] +VideoStreamTrack = ["EventTarget", "MediaStreamTrack"] +VideoTrack = [] +VideoTrackList = ["EventTarget"] +VisibilityState = [] +VoidCallback = [] +VrDisplay = ["EventTarget"] +VrDisplayCapabilities = [] +VrEye = [] +VrEyeParameters = [] +VrFieldOfView = [] +VrFrameData = [] +VrLayer = [] +VrMockController = [] +VrMockDisplay = [] +VrPose = [] +VrServiceTest = [] +VrStageParameters = [] +VrSubmitFrameResult = [] +VttCue = ["EventTarget", "TextTrackCue"] +VttRegion = [] +WakeLock = [] +WakeLockSentinel = ["EventTarget"] +WakeLockType = [] +WatchAdvertisementsOptions = [] +WaveShaperNode = ["AudioNode", "EventTarget"] +WaveShaperOptions = [] +WebGl2RenderingContext = [] +WebGlActiveInfo = [] +WebGlBuffer = [] +WebGlContextAttributes = [] +WebGlContextEvent = ["Event"] +WebGlContextEventInit = [] +WebGlFramebuffer = [] +WebGlPowerPreference = [] +WebGlProgram = [] +WebGlQuery = [] +WebGlRenderbuffer = [] +WebGlRenderingContext = [] +WebGlSampler = [] +WebGlShader = [] +WebGlShaderPrecisionFormat = [] +WebGlSync = [] +WebGlTexture = [] +WebGlTransformFeedback = [] +WebGlUniformLocation = [] +WebGlVertexArrayObject = [] +WebKitCssMatrix = ["DomMatrix", "DomMatrixReadOnly"] +WebSocket = ["EventTarget"] +WebSocketDict = [] +WebSocketElement = [] +WebglColorBufferFloat = [] +WebglCompressedTextureAstc = [] +WebglCompressedTextureAtc = [] +WebglCompressedTextureEtc = [] +WebglCompressedTextureEtc1 = [] +WebglCompressedTexturePvrtc = [] +WebglCompressedTextureS3tc = [] +WebglCompressedTextureS3tcSrgb = [] +WebglDebugRendererInfo = [] +WebglDebugShaders = [] +WebglDepthTexture = [] +WebglDrawBuffers = [] +WebglLoseContext = [] +WebrtcGlobalStatisticsReport = [] +WheelEvent = ["Event", "MouseEvent", "UiEvent"] +WheelEventInit = [] +WidevineCdmManifest = [] +Window = ["EventTarget"] +WindowClient = ["Client"] +Worker = ["EventTarget"] +WorkerDebuggerGlobalScope = ["EventTarget"] +WorkerGlobalScope = ["EventTarget"] +WorkerLocation = [] +WorkerNavigator = [] +WorkerOptions = [] +WorkerType = [] +Worklet = [] +WorkletGlobalScope = [] +WorkletOptions = [] +WritableStream = [] +WritableStreamDefaultWriter = [] +XPathExpression = [] +XPathNsResolver = [] +XPathResult = [] +XmlDocument = ["Document", "EventTarget", "Node"] +XmlHttpRequest = ["EventTarget", "XmlHttpRequestEventTarget"] +XmlHttpRequestEventTarget = ["EventTarget"] +XmlHttpRequestResponseType = [] +XmlHttpRequestUpload = ["EventTarget", "XmlHttpRequestEventTarget"] +XmlSerializer = [] +Xr = ["EventTarget"] +XrBoundedReferenceSpace = ["EventTarget", "XrReferenceSpace", "XrSpace"] +XrEye = [] +XrFrame = [] +XrHandedness = [] +XrInputSource = [] +XrInputSourceArray = [] +XrInputSourceEvent = ["Event"] +XrInputSourceEventInit = [] +XrInputSourcesChangeEvent = ["Event"] +XrInputSourcesChangeEventInit = [] +XrPose = [] +XrReferenceSpace = ["EventTarget", "XrSpace"] +XrReferenceSpaceEvent = ["Event"] +XrReferenceSpaceEventInit = [] +XrReferenceSpaceType = [] +XrRenderState = [] +XrRenderStateInit = [] +XrRigidTransform = [] +XrSession = ["EventTarget"] +XrSessionEvent = ["Event"] +XrSessionEventInit = [] +XrSessionInit = [] +XrSessionMode = [] +XrSpace = ["EventTarget"] +XrTargetRayMode = [] +XrView = [] +XrViewerPose = ["XrPose"] +XrViewport = [] +XrVisibilityState = [] +XrWebGlLayer = [] +XrWebGlLayerInit = [] +XsltProcessor = [] +console = [] +css = [] diff --git a/build/rust/dummy-web/web-sys/lib.rs b/build/rust/dummy-web/web-sys/lib.rs new file mode 100644 index 0000000000..e0032240a4 --- /dev/null +++ b/build/rust/dummy-web/web-sys/lib.rs @@ -0,0 +1,3 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ diff --git a/build/rust/goblin/Cargo.toml b/build/rust/goblin/Cargo.toml new file mode 100644 index 0000000000..52e8dfe66d --- /dev/null +++ b/build/rust/goblin/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "goblin" +version = "0.6.999" +edition = "2018" +license = "MIT/Apache-2.0" + +[lib] +path = "lib.rs" + +[dependencies.goblin] +version = "0.7.0" diff --git a/build/rust/goblin/lib.rs b/build/rust/goblin/lib.rs new file mode 100644 index 0000000000..ba9ee61592 --- /dev/null +++ b/build/rust/goblin/lib.rs @@ -0,0 +1,11 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use goblin::*; diff --git a/build/rust/indexmap/Cargo.toml b/build/rust/indexmap/Cargo.toml new file mode 100644 index 0000000000..de45a4f02d --- /dev/null +++ b/build/rust/indexmap/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "indexmap" +version = "2.999.999" +edition = "2021" +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +serde = ["indexmap/serde-1"] +std = ["indexmap/std"] + +[dependencies.indexmap] +version = "1.9.3" diff --git a/build/rust/indexmap/lib.rs b/build/rust/indexmap/lib.rs new file mode 100644 index 0000000000..8142a8bd1d --- /dev/null +++ b/build/rust/indexmap/lib.rs @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use indexmap::*; diff --git a/build/rust/memmap2-0.5/Cargo.toml b/build/rust/memmap2-0.5/Cargo.toml new file mode 100644 index 0000000000..331e3a955e --- /dev/null +++ b/build/rust/memmap2-0.5/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "memmap2" +version = "0.5.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[dependencies.memmap2] +version = "0.8.0" diff --git a/build/rust/memmap2-0.5/lib.rs b/build/rust/memmap2-0.5/lib.rs new file mode 100644 index 0000000000..214110099a --- /dev/null +++ b/build/rust/memmap2-0.5/lib.rs @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use memmap2::*; diff --git a/build/rust/memmap2/Cargo.toml b/build/rust/memmap2/Cargo.toml new file mode 100644 index 0000000000..eb9ed01134 --- /dev/null +++ b/build/rust/memmap2/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "memmap2" +version = "0.8.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[dependencies.memmap2] +version = "0.9" diff --git a/build/rust/memmap2/lib.rs b/build/rust/memmap2/lib.rs new file mode 100644 index 0000000000..214110099a --- /dev/null +++ b/build/rust/memmap2/lib.rs @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use memmap2::*; diff --git a/build/rust/memoffset/Cargo.toml b/build/rust/memoffset/Cargo.toml new file mode 100644 index 0000000000..24eb01a58b --- /dev/null +++ b/build/rust/memoffset/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "memoffset" +version = "0.8.999" +edition = "2018" +license = "MIT/Apache-2.0" + +[lib] +path = "lib.rs" + +[dependencies.memoffset] +version = "0.9" diff --git a/build/rust/memoffset/lib.rs b/build/rust/memoffset/lib.rs new file mode 100644 index 0000000000..5bc4a399a7 --- /dev/null +++ b/build/rust/memoffset/lib.rs @@ -0,0 +1,11 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use memoffset::*; diff --git a/build/rust/mozbuild/Cargo.toml b/build/rust/mozbuild/Cargo.toml new file mode 100644 index 0000000000..ef9b4c6ccf --- /dev/null +++ b/build/rust/mozbuild/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "mozbuild" +version = "0.1.0" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" diff --git a/build/rust/mozbuild/build.rs b/build/rust/mozbuild/build.rs new file mode 100644 index 0000000000..e9fb6b91b0 --- /dev/null +++ b/build/rust/mozbuild/build.rs @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::path::PathBuf; + +fn main() { + let out_dir = PathBuf::from(std::env::var_os("OUT_DIR").unwrap()); + if let Some(topobjdir) = out_dir + .ancestors() + .find(|dir| dir.join("config.status").exists()) + { + println!( + "cargo:rustc-env=BUILDCONFIG_RS={}", + topobjdir + .join("build/rust/mozbuild/buildconfig.rs") + .display() + ); + } +} diff --git a/build/rust/mozbuild/generate_buildconfig.py b/build/rust/mozbuild/generate_buildconfig.py new file mode 100644 index 0000000000..2252276319 --- /dev/null +++ b/build/rust/mozbuild/generate_buildconfig.py @@ -0,0 +1,95 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import string +import textwrap + +import buildconfig + + +def generate_bool(name): + value = buildconfig.substs.get(name) + return f"pub const {name}: bool = {'true' if value else 'false'};\n" + + +def escape_rust_string(value): + """escape the string into a Rust literal""" + # This could be more generous, but we're only escaping paths with it. + unescaped = string.ascii_letters + string.digits + "/$+-_~ " + result = "" + for ch in str(value): + if ch in unescaped: + result += ch + elif ch == "\r": + result += "\\r" + elif ch == "\n": + result += "\\n" + elif ch == "\\": + result += "\\\\" + elif ch == '"': + result += '\\"' + else: + result += "\\u{%x}" % ord(ch) + return '"%s"' % result + + +def generate(output): + # Write out a macro which can be used within `include!`-like methods to + # reference the topobjdir. + output.write( + textwrap.dedent( + f""" + /// Macro used to name a path in the objdir for use with macros like `include!` + #[macro_export] + macro_rules! objdir_path {{ + ($path:literal) => {{ + concat!({escape_rust_string(buildconfig.topobjdir + "/")}, $path) + }} + }} + + /// Macro used to name a path in the srcdir for use with macros like `include!` + #[macro_export] + macro_rules! srcdir_path {{ + ($path:literal) => {{ + concat!({escape_rust_string(buildconfig.topsrcdir + "/")}, $path) + }} + }} + + /// The objdir path for use in build scripts + pub const TOPOBJDIR: &str = {escape_rust_string(buildconfig.topobjdir)}; + /// The srcdir path for use in build scripts + pub const TOPSRCDIR: &str = {escape_rust_string(buildconfig.topsrcdir)}; + + """ + ) + ) + + windows_rs_dir = buildconfig.substs.get("MOZ_WINDOWS_RS_DIR") + if windows_rs_dir: + output.write( + textwrap.dedent( + f""" + /// Macro used to name a path in the srcdir for use with macros like `include!` + #[macro_export] + macro_rules! windows_rs_path {{ + ($path:literal) => {{ + concat!({escape_rust_string(windows_rs_dir + "/")}, $path) + }} + }} + + /// The path to the windows-rs crate, for use in build scripts + pub const WINDOWS_RS_DIR: &str = {escape_rust_string(windows_rs_dir)}; + + """ + ) + ) + + # Finally, write out some useful booleans from the buildconfig. + output.write(generate_bool("MOZ_FOLD_LIBS")) + output.write(generate_bool("NIGHTLY_BUILD")) + output.write(generate_bool("RELEASE_OR_BETA")) + output.write(generate_bool("EARLY_BETA_OR_EARLIER")) + output.write(generate_bool("MOZ_DEV_EDITION")) + output.write(generate_bool("MOZ_ESR")) + output.write(generate_bool("MOZ_DIAGNOSTIC_ASSERT_ENABLED")) diff --git a/build/rust/mozbuild/lib.rs b/build/rust/mozbuild/lib.rs new file mode 100644 index 0000000000..a22b1d9176 --- /dev/null +++ b/build/rust/mozbuild/lib.rs @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::path::Path; + +// Path::new is not const at the moment. This is a non-generic version +// of Path::new, similar to libstd's implementation of Path::new. +#[inline(always)] +const fn const_path(s: &'static str) -> &'static std::path::Path { + unsafe { &*(s as *const str as *const std::path::Path) } +} + +pub const TOPOBJDIR: &Path = const_path(config::TOPOBJDIR); + +pub const TOPSRCDIR: &Path = const_path(config::TOPSRCDIR); + +pub mod config { + include!(env!("BUILDCONFIG_RS")); +} diff --git a/build/rust/mozbuild/moz.build b/build/rust/mozbuild/moz.build new file mode 100644 index 0000000000..3cc09a7c5a --- /dev/null +++ b/build/rust/mozbuild/moz.build @@ -0,0 +1,9 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +GeneratedFile( + "buildconfig.rs", script="generate_buildconfig.py", entry_point="generate" +) diff --git a/build/rust/nix/Cargo.toml b/build/rust/nix/Cargo.toml new file mode 100644 index 0000000000..4ecba71164 --- /dev/null +++ b/build/rust/nix/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "nix" +version = "0.26.99" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[dependencies.nix] +version = "0.27" +default-features = false + +[features] +acct = ["nix/acct"] +aio = ["nix/aio"] +default = ["nix/default"] +dir = ["nix/dir"] +env = ["nix/env"] +event = ["nix/event"] +feature = ["nix/feature"] +fs = ["nix/fs"] +hostname = ["nix/hostname"] +inotify = ["nix/inotify"] +ioctl = ["nix/ioctl"] +kmod = ["nix/kmod"] +mman = ["nix/mman"] +mount = ["nix/mount"] +mqueue = ["nix/mqueue"] +net = ["nix/net"] diff --git a/build/rust/nix/lib.rs b/build/rust/nix/lib.rs new file mode 100644 index 0000000000..d1039ae71a --- /dev/null +++ b/build/rust/nix/lib.rs @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use nix::*; diff --git a/build/rust/oslog/Cargo.toml b/build/rust/oslog/Cargo.toml new file mode 100644 index 0000000000..fa647f9646 --- /dev/null +++ b/build/rust/oslog/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "oslog" +version = "0.1.999" +edition = "2018" +license = "MIT" + +[lib] +path = "lib.rs" + +[dependencies.log] +version = "0.4" +default-features = false + +[features] +logger = [] diff --git a/build/rust/oslog/LICENSE b/build/rust/oslog/LICENSE new file mode 100644 index 0000000000..13b609c25b --- /dev/null +++ b/build/rust/oslog/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Steven Joruk + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/build/rust/oslog/lib.rs b/build/rust/oslog/lib.rs new file mode 100644 index 0000000000..4a529e7afa --- /dev/null +++ b/build/rust/oslog/lib.rs @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub struct OsLogger; + +use log::{LevelFilter, SetLoggerError}; + +impl OsLogger { + pub fn new(_subsystem: &str) -> Self { + Self + } + + pub fn level_filter(self, _level: LevelFilter) -> Self { + self + } + + pub fn category_level_filter(self, _category: &str, _level: LevelFilter) -> Self { + self + } + + pub fn init(self) -> Result<(), SetLoggerError> { + Ok(()) + } +} diff --git a/build/rust/redox_syscall/Cargo.toml b/build/rust/redox_syscall/Cargo.toml new file mode 100644 index 0000000000..41ba6ba33d --- /dev/null +++ b/build/rust/redox_syscall/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "redox_syscall" +version = "0.4.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" diff --git a/build/rust/redox_syscall/lib.rs b/build/rust/redox_syscall/lib.rs new file mode 100644 index 0000000000..e0032240a4 --- /dev/null +++ b/build/rust/redox_syscall/lib.rs @@ -0,0 +1,3 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ diff --git a/build/rust/redox_users/Cargo.toml b/build/rust/redox_users/Cargo.toml new file mode 100644 index 0000000000..9ea9b4a086 --- /dev/null +++ b/build/rust/redox_users/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "redox_users" +version = "0.4.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" diff --git a/build/rust/redox_users/lib.rs b/build/rust/redox_users/lib.rs new file mode 100644 index 0000000000..e0032240a4 --- /dev/null +++ b/build/rust/redox_users/lib.rs @@ -0,0 +1,3 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ diff --git a/build/rust/terminal_size/Cargo.toml b/build/rust/terminal_size/Cargo.toml new file mode 100644 index 0000000000..f787ebdd15 --- /dev/null +++ b/build/rust/terminal_size/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "terminal_size" +version = "0.3.999" +edition = "2018" +license = "MIT OR Apache-2.0" + +[lib] +path = "lib.rs" diff --git a/build/rust/terminal_size/lib.rs b/build/rust/terminal_size/lib.rs new file mode 100644 index 0000000000..e2e6512604 --- /dev/null +++ b/build/rust/terminal_size/lib.rs @@ -0,0 +1,26 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Width(pub u16); +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Height(pub u16); + +pub fn terminal_size() -> Option<(Width, Height)> { + Some((Width(80), Height(25))) +} + +#[cfg(unix)] +pub fn terminal_size_using_fd(_fd: std::os::unix::io::RawFd) -> Option<(Width, Height)> { + Some((Width(80), Height(25))) +} + +#[cfg(windows)] +pub fn terminal_size_using_handle( + _handle: std::os::windows::io::RawHandle, +) -> Option<(Width, Height)> { + Some((Width(80), Height(25))) +} diff --git a/build/rust/tinyvec/Cargo.toml b/build/rust/tinyvec/Cargo.toml new file mode 100644 index 0000000000..d40a4db514 --- /dev/null +++ b/build/rust/tinyvec/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "tinyvec" +version = "1.999.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[dependencies] +smallvec = "1" + +[features] +alloc = [] +default = [] +std = ["alloc"] diff --git a/build/rust/tinyvec/lib.rs b/build/rust/tinyvec/lib.rs new file mode 100644 index 0000000000..decdb0efdc --- /dev/null +++ b/build/rust/tinyvec/lib.rs @@ -0,0 +1,6 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use smallvec::SmallVec as ArrayVec; +pub use smallvec::SmallVec as TinyVec; diff --git a/build/rust/vcpkg/Cargo.toml b/build/rust/vcpkg/Cargo.toml new file mode 100644 index 0000000000..2128be7ad8 --- /dev/null +++ b/build/rust/vcpkg/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "vcpkg" +version = "0.2.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" diff --git a/build/rust/vcpkg/lib.rs b/build/rust/vcpkg/lib.rs new file mode 100644 index 0000000000..630f19f4be --- /dev/null +++ b/build/rust/vcpkg/lib.rs @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::path::PathBuf; + +pub struct Config; + +pub struct Library { + pub include_paths: Vec, +} + +pub struct Error; + +impl Config { + pub fn new() -> Config { + Config + } + + pub fn probe(&mut self, _: &str) -> Result { + Err(Error) + } +} diff --git a/build/rust/wasi/Cargo.toml b/build/rust/wasi/Cargo.toml new file mode 100644 index 0000000000..e1f392a961 --- /dev/null +++ b/build/rust/wasi/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[dependencies.wasi] +version = "0.11" +default-features = false + +[features] +default = ["wasi/default"] +rustc-dep-of-std = ["wasi/rustc-dep-of-std"] +std = ["wasi/std"] diff --git a/build/rust/wasi/lib.rs b/build/rust/wasi/lib.rs new file mode 100644 index 0000000000..1bb1206202 --- /dev/null +++ b/build/rust/wasi/lib.rs @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use wasi::*; diff --git a/build/rust/windows-sys/Cargo.toml b/build/rust/windows-sys/Cargo.toml new file mode 100644 index 0000000000..b668eb5f7f --- /dev/null +++ b/build/rust/windows-sys/Cargo.toml @@ -0,0 +1,232 @@ +[package] +name = "windows-sys" +version = "0.48.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[dependencies.windows-sys] +version = "0.52" +default-features = false + +[features] +Wdk = ["windows-sys/Wdk"] +Wdk_System = ["windows-sys/Wdk_System"] +Wdk_System_OfflineRegistry = ["windows-sys/Wdk_System_OfflineRegistry"] +Win32 = ["windows-sys/Win32"] +Win32_Data = ["windows-sys/Win32_Data"] +Win32_Data_HtmlHelp = ["windows-sys/Win32_Data_HtmlHelp"] +Win32_Data_RightsManagement = ["windows-sys/Win32_Data_RightsManagement"] +Win32_Devices = ["windows-sys/Win32_Devices"] +Win32_Devices_AllJoyn = ["windows-sys/Win32_Devices_AllJoyn"] +Win32_Devices_BiometricFramework = ["windows-sys/Win32_Devices_BiometricFramework"] +Win32_Devices_Bluetooth = ["windows-sys/Win32_Devices_Bluetooth"] +Win32_Devices_Communication = ["windows-sys/Win32_Devices_Communication"] +Win32_Devices_DeviceAndDriverInstallation = ["windows-sys/Win32_Devices_DeviceAndDriverInstallation"] +Win32_Devices_DeviceQuery = ["windows-sys/Win32_Devices_DeviceQuery"] +Win32_Devices_Display = ["windows-sys/Win32_Devices_Display"] +Win32_Devices_Enumeration = ["windows-sys/Win32_Devices_Enumeration"] +Win32_Devices_Enumeration_Pnp = ["windows-sys/Win32_Devices_Enumeration_Pnp"] +Win32_Devices_Fax = ["windows-sys/Win32_Devices_Fax"] +Win32_Devices_HumanInterfaceDevice = ["windows-sys/Win32_Devices_HumanInterfaceDevice"] +Win32_Devices_PortableDevices = ["windows-sys/Win32_Devices_PortableDevices"] +Win32_Devices_Properties = ["windows-sys/Win32_Devices_Properties"] +Win32_Devices_Pwm = ["windows-sys/Win32_Devices_Pwm"] +Win32_Devices_Sensors = ["windows-sys/Win32_Devices_Sensors"] +Win32_Devices_SerialCommunication = ["windows-sys/Win32_Devices_SerialCommunication"] +Win32_Devices_Tapi = ["windows-sys/Win32_Devices_Tapi"] +Win32_Devices_Usb = ["windows-sys/Win32_Devices_Usb"] +Win32_Devices_WebServicesOnDevices = ["windows-sys/Win32_Devices_WebServicesOnDevices"] +Win32_Foundation = ["windows-sys/Win32_Foundation"] +Win32_Gaming = ["windows-sys/Win32_Gaming"] +Win32_Globalization = ["windows-sys/Win32_Globalization"] +Win32_Graphics = ["windows-sys/Win32_Graphics"] +Win32_Graphics_Dwm = ["windows-sys/Win32_Graphics_Dwm"] +Win32_Graphics_Gdi = ["windows-sys/Win32_Graphics_Gdi"] +Win32_Graphics_Hlsl = ["windows-sys/Win32_Graphics_Hlsl"] +Win32_Graphics_OpenGL = ["windows-sys/Win32_Graphics_OpenGL"] +Win32_Graphics_Printing = ["windows-sys/Win32_Graphics_Printing"] +Win32_Graphics_Printing_PrintTicket = ["windows-sys/Win32_Graphics_Printing_PrintTicket"] +Win32_Management = ["windows-sys/Win32_Management"] +Win32_Management_MobileDeviceManagementRegistration = ["windows-sys/Win32_Management_MobileDeviceManagementRegistration"] +Win32_Media = ["windows-sys/Win32_Media"] +Win32_Media_Audio = ["windows-sys/Win32_Media_Audio"] +Win32_Media_DxMediaObjects = ["windows-sys/Win32_Media_DxMediaObjects"] +Win32_Media_KernelStreaming = ["windows-sys/Win32_Media_KernelStreaming"] +Win32_Media_Multimedia = ["windows-sys/Win32_Media_Multimedia"] +Win32_Media_Streaming = ["windows-sys/Win32_Media_Streaming"] +Win32_Media_WindowsMediaFormat = ["windows-sys/Win32_Media_WindowsMediaFormat"] +Win32_NetworkManagement = ["windows-sys/Win32_NetworkManagement"] +Win32_NetworkManagement_Dhcp = ["windows-sys/Win32_NetworkManagement_Dhcp"] +Win32_NetworkManagement_Dns = ["windows-sys/Win32_NetworkManagement_Dns"] +Win32_NetworkManagement_InternetConnectionWizard = ["windows-sys/Win32_NetworkManagement_InternetConnectionWizard"] +Win32_NetworkManagement_IpHelper = ["windows-sys/Win32_NetworkManagement_IpHelper"] +Win32_NetworkManagement_Multicast = ["windows-sys/Win32_NetworkManagement_Multicast"] +Win32_NetworkManagement_Ndis = ["windows-sys/Win32_NetworkManagement_Ndis"] +Win32_NetworkManagement_NetBios = ["windows-sys/Win32_NetworkManagement_NetBios"] +Win32_NetworkManagement_NetManagement = ["windows-sys/Win32_NetworkManagement_NetManagement"] +Win32_NetworkManagement_NetShell = ["windows-sys/Win32_NetworkManagement_NetShell"] +Win32_NetworkManagement_NetworkDiagnosticsFramework = ["windows-sys/Win32_NetworkManagement_NetworkDiagnosticsFramework"] +Win32_NetworkManagement_P2P = ["windows-sys/Win32_NetworkManagement_P2P"] +Win32_NetworkManagement_QoS = ["windows-sys/Win32_NetworkManagement_QoS"] +Win32_NetworkManagement_Rras = ["windows-sys/Win32_NetworkManagement_Rras"] +Win32_NetworkManagement_Snmp = ["windows-sys/Win32_NetworkManagement_Snmp"] +Win32_NetworkManagement_WNet = ["windows-sys/Win32_NetworkManagement_WNet"] +Win32_NetworkManagement_WebDav = ["windows-sys/Win32_NetworkManagement_WebDav"] +Win32_NetworkManagement_WiFi = ["windows-sys/Win32_NetworkManagement_WiFi"] +Win32_NetworkManagement_WindowsConnectionManager = ["windows-sys/Win32_NetworkManagement_WindowsConnectionManager"] +Win32_NetworkManagement_WindowsFilteringPlatform = ["windows-sys/Win32_NetworkManagement_WindowsFilteringPlatform"] +Win32_NetworkManagement_WindowsFirewall = ["windows-sys/Win32_NetworkManagement_WindowsFirewall"] +Win32_NetworkManagement_WindowsNetworkVirtualization = ["windows-sys/Win32_NetworkManagement_WindowsNetworkVirtualization"] +Win32_Networking = ["windows-sys/Win32_Networking"] +Win32_Networking_ActiveDirectory = ["windows-sys/Win32_Networking_ActiveDirectory"] +Win32_Networking_Clustering = ["windows-sys/Win32_Networking_Clustering"] +Win32_Networking_HttpServer = ["windows-sys/Win32_Networking_HttpServer"] +Win32_Networking_Ldap = ["windows-sys/Win32_Networking_Ldap"] +Win32_Networking_WebSocket = ["windows-sys/Win32_Networking_WebSocket"] +Win32_Networking_WinHttp = ["windows-sys/Win32_Networking_WinHttp"] +Win32_Networking_WinInet = ["windows-sys/Win32_Networking_WinInet"] +Win32_Networking_WinSock = ["windows-sys/Win32_Networking_WinSock"] +Win32_Networking_WindowsWebServices = ["windows-sys/Win32_Networking_WindowsWebServices"] +Win32_Security = ["windows-sys/Win32_Security"] +Win32_Security_AppLocker = ["windows-sys/Win32_Security_AppLocker"] +Win32_Security_Authentication = ["windows-sys/Win32_Security_Authentication"] +Win32_Security_Authentication_Identity = ["windows-sys/Win32_Security_Authentication_Identity"] +Win32_Security_Authorization = ["windows-sys/Win32_Security_Authorization"] +Win32_Security_Credentials = ["windows-sys/Win32_Security_Credentials"] +Win32_Security_Cryptography = ["windows-sys/Win32_Security_Cryptography"] +Win32_Security_Cryptography_Catalog = ["windows-sys/Win32_Security_Cryptography_Catalog"] +Win32_Security_Cryptography_Certificates = ["windows-sys/Win32_Security_Cryptography_Certificates"] +Win32_Security_Cryptography_Sip = ["windows-sys/Win32_Security_Cryptography_Sip"] +Win32_Security_Cryptography_UI = ["windows-sys/Win32_Security_Cryptography_UI"] +Win32_Security_DiagnosticDataQuery = ["windows-sys/Win32_Security_DiagnosticDataQuery"] +Win32_Security_DirectoryServices = ["windows-sys/Win32_Security_DirectoryServices"] +Win32_Security_EnterpriseData = ["windows-sys/Win32_Security_EnterpriseData"] +Win32_Security_ExtensibleAuthenticationProtocol = ["windows-sys/Win32_Security_ExtensibleAuthenticationProtocol"] +Win32_Security_Isolation = ["windows-sys/Win32_Security_Isolation"] +Win32_Security_LicenseProtection = ["windows-sys/Win32_Security_LicenseProtection"] +Win32_Security_NetworkAccessProtection = ["windows-sys/Win32_Security_NetworkAccessProtection"] +Win32_Security_WinTrust = ["windows-sys/Win32_Security_WinTrust"] +Win32_Security_WinWlx = ["windows-sys/Win32_Security_WinWlx"] +Win32_Storage = ["windows-sys/Win32_Storage"] +Win32_Storage_Cabinets = ["windows-sys/Win32_Storage_Cabinets"] +Win32_Storage_CloudFilters = ["windows-sys/Win32_Storage_CloudFilters"] +Win32_Storage_Compression = ["windows-sys/Win32_Storage_Compression"] +Win32_Storage_DistributedFileSystem = ["windows-sys/Win32_Storage_DistributedFileSystem"] +Win32_Storage_FileHistory = ["windows-sys/Win32_Storage_FileHistory"] +Win32_Storage_FileSystem = ["windows-sys/Win32_Storage_FileSystem"] +Win32_Storage_Imapi = ["windows-sys/Win32_Storage_Imapi"] +Win32_Storage_IndexServer = ["windows-sys/Win32_Storage_IndexServer"] +Win32_Storage_InstallableFileSystems = ["windows-sys/Win32_Storage_InstallableFileSystems"] +Win32_Storage_IscsiDisc = ["windows-sys/Win32_Storage_IscsiDisc"] +Win32_Storage_Jet = ["windows-sys/Win32_Storage_Jet"] +Win32_Storage_OfflineFiles = ["windows-sys/Win32_Storage_OfflineFiles"] +Win32_Storage_OperationRecorder = ["windows-sys/Win32_Storage_OperationRecorder"] +Win32_Storage_Packaging = ["windows-sys/Win32_Storage_Packaging"] +Win32_Storage_Packaging_Appx = ["windows-sys/Win32_Storage_Packaging_Appx"] +Win32_Storage_ProjectedFileSystem = ["windows-sys/Win32_Storage_ProjectedFileSystem"] +Win32_Storage_StructuredStorage = ["windows-sys/Win32_Storage_StructuredStorage"] +Win32_Storage_Vhd = ["windows-sys/Win32_Storage_Vhd"] +Win32_Storage_Xps = ["windows-sys/Win32_Storage_Xps"] +Win32_System = ["windows-sys/Win32_System"] +Win32_System_AddressBook = ["windows-sys/Win32_System_AddressBook"] +Win32_System_Antimalware = ["windows-sys/Win32_System_Antimalware"] +Win32_System_ApplicationInstallationAndServicing = ["windows-sys/Win32_System_ApplicationInstallationAndServicing"] +Win32_System_ApplicationVerifier = ["windows-sys/Win32_System_ApplicationVerifier"] +Win32_System_ClrHosting = ["windows-sys/Win32_System_ClrHosting"] +Win32_System_Com = ["windows-sys/Win32_System_Com"] +Win32_System_Com_Marshal = ["windows-sys/Win32_System_Com_Marshal"] +Win32_System_Com_StructuredStorage = ["windows-sys/Win32_System_Com_StructuredStorage"] +Win32_System_Com_Urlmon = ["windows-sys/Win32_System_Com_Urlmon"] +Win32_System_ComponentServices = ["windows-sys/Win32_System_ComponentServices"] +Win32_System_Console = ["windows-sys/Win32_System_Console"] +Win32_System_CorrelationVector = ["windows-sys/Win32_System_CorrelationVector"] +Win32_System_DataExchange = ["windows-sys/Win32_System_DataExchange"] +Win32_System_DeploymentServices = ["windows-sys/Win32_System_DeploymentServices"] +Win32_System_DeveloperLicensing = ["windows-sys/Win32_System_DeveloperLicensing"] +Win32_System_Diagnostics = ["windows-sys/Win32_System_Diagnostics"] +Win32_System_Diagnostics_Ceip = ["windows-sys/Win32_System_Diagnostics_Ceip"] +Win32_System_Diagnostics_Debug = ["windows-sys/Win32_System_Diagnostics_Debug"] +Win32_System_Diagnostics_Debug_Extensions = ["windows-sys/Win32_System_Diagnostics_Debug_Extensions"] +Win32_System_Diagnostics_Etw = ["windows-sys/Win32_System_Diagnostics_Etw"] +Win32_System_Diagnostics_ProcessSnapshotting = ["windows-sys/Win32_System_Diagnostics_ProcessSnapshotting"] +Win32_System_Diagnostics_ToolHelp = ["windows-sys/Win32_System_Diagnostics_ToolHelp"] +Win32_System_DistributedTransactionCoordinator = ["windows-sys/Win32_System_DistributedTransactionCoordinator"] +Win32_System_Environment = ["windows-sys/Win32_System_Environment"] +Win32_System_ErrorReporting = ["windows-sys/Win32_System_ErrorReporting"] +Win32_System_EventCollector = ["windows-sys/Win32_System_EventCollector"] +Win32_System_EventLog = ["windows-sys/Win32_System_EventLog"] +Win32_System_EventNotificationService = ["windows-sys/Win32_System_EventNotificationService"] +Win32_System_GroupPolicy = ["windows-sys/Win32_System_GroupPolicy"] +Win32_System_HostCompute = ["windows-sys/Win32_System_HostCompute"] +Win32_System_HostComputeNetwork = ["windows-sys/Win32_System_HostComputeNetwork"] +Win32_System_HostComputeSystem = ["windows-sys/Win32_System_HostComputeSystem"] +Win32_System_Hypervisor = ["windows-sys/Win32_System_Hypervisor"] +Win32_System_IO = ["windows-sys/Win32_System_IO"] +Win32_System_Iis = ["windows-sys/Win32_System_Iis"] +Win32_System_Ioctl = ["windows-sys/Win32_System_Ioctl"] +Win32_System_JobObjects = ["windows-sys/Win32_System_JobObjects"] +Win32_System_Js = ["windows-sys/Win32_System_Js"] +Win32_System_Kernel = ["windows-sys/Win32_System_Kernel"] +Win32_System_LibraryLoader = ["windows-sys/Win32_System_LibraryLoader"] +Win32_System_Mailslots = ["windows-sys/Win32_System_Mailslots"] +Win32_System_Mapi = ["windows-sys/Win32_System_Mapi"] +Win32_System_Memory = ["windows-sys/Win32_System_Memory"] +Win32_System_Memory_NonVolatile = ["windows-sys/Win32_System_Memory_NonVolatile"] +Win32_System_MessageQueuing = ["windows-sys/Win32_System_MessageQueuing"] +Win32_System_MixedReality = ["windows-sys/Win32_System_MixedReality"] +Win32_System_Ole = ["windows-sys/Win32_System_Ole"] +Win32_System_PasswordManagement = ["windows-sys/Win32_System_PasswordManagement"] +Win32_System_Performance = ["windows-sys/Win32_System_Performance"] +Win32_System_Performance_HardwareCounterProfiling = ["windows-sys/Win32_System_Performance_HardwareCounterProfiling"] +Win32_System_Pipes = ["windows-sys/Win32_System_Pipes"] +Win32_System_Power = ["windows-sys/Win32_System_Power"] +Win32_System_ProcessStatus = ["windows-sys/Win32_System_ProcessStatus"] +Win32_System_Recovery = ["windows-sys/Win32_System_Recovery"] +Win32_System_Registry = ["windows-sys/Win32_System_Registry"] +Win32_System_RemoteDesktop = ["windows-sys/Win32_System_RemoteDesktop"] +Win32_System_RemoteManagement = ["windows-sys/Win32_System_RemoteManagement"] +Win32_System_RestartManager = ["windows-sys/Win32_System_RestartManager"] +Win32_System_Restore = ["windows-sys/Win32_System_Restore"] +Win32_System_Rpc = ["windows-sys/Win32_System_Rpc"] +Win32_System_Search = ["windows-sys/Win32_System_Search"] +Win32_System_Search_Common = ["windows-sys/Win32_System_Search_Common"] +Win32_System_SecurityCenter = ["windows-sys/Win32_System_SecurityCenter"] +Win32_System_Services = ["windows-sys/Win32_System_Services"] +Win32_System_SetupAndMigration = ["windows-sys/Win32_System_SetupAndMigration"] +Win32_System_Shutdown = ["windows-sys/Win32_System_Shutdown"] +Win32_System_StationsAndDesktops = ["windows-sys/Win32_System_StationsAndDesktops"] +Win32_System_SubsystemForLinux = ["windows-sys/Win32_System_SubsystemForLinux"] +Win32_System_SystemInformation = ["windows-sys/Win32_System_SystemInformation"] +Win32_System_SystemServices = ["windows-sys/Win32_System_SystemServices"] +Win32_System_Threading = ["windows-sys/Win32_System_Threading"] +Win32_System_Time = ["windows-sys/Win32_System_Time"] +Win32_System_TpmBaseServices = ["windows-sys/Win32_System_TpmBaseServices"] +Win32_System_UserAccessLogging = ["windows-sys/Win32_System_UserAccessLogging"] +Win32_System_VirtualDosMachines = ["windows-sys/Win32_System_VirtualDosMachines"] +Win32_System_WindowsProgramming = ["windows-sys/Win32_System_WindowsProgramming"] +Win32_System_Wmi = ["windows-sys/Win32_System_Wmi"] +Win32_UI = ["windows-sys/Win32_UI"] +Win32_UI_Accessibility = ["windows-sys/Win32_UI_Accessibility"] +Win32_UI_ColorSystem = ["windows-sys/Win32_UI_ColorSystem"] +Win32_UI_Controls = ["windows-sys/Win32_UI_Controls"] +Win32_UI_Controls_Dialogs = ["windows-sys/Win32_UI_Controls_Dialogs"] +Win32_UI_HiDpi = ["windows-sys/Win32_UI_HiDpi"] +Win32_UI_Input = ["windows-sys/Win32_UI_Input"] +Win32_UI_Input_Ime = ["windows-sys/Win32_UI_Input_Ime"] +Win32_UI_Input_KeyboardAndMouse = ["windows-sys/Win32_UI_Input_KeyboardAndMouse"] +Win32_UI_Input_Pointer = ["windows-sys/Win32_UI_Input_Pointer"] +Win32_UI_Input_Touch = ["windows-sys/Win32_UI_Input_Touch"] +Win32_UI_Input_XboxController = ["windows-sys/Win32_UI_Input_XboxController"] +Win32_UI_InteractionContext = ["windows-sys/Win32_UI_InteractionContext"] +Win32_UI_Magnification = ["windows-sys/Win32_UI_Magnification"] +Win32_UI_Shell = ["windows-sys/Win32_UI_Shell"] +Win32_UI_Shell_PropertiesSystem = ["windows-sys/Win32_UI_Shell_PropertiesSystem"] +Win32_UI_TabletPC = ["windows-sys/Win32_UI_TabletPC"] +Win32_UI_TextServices = ["windows-sys/Win32_UI_TextServices"] +Win32_UI_WindowsAndMessaging = ["windows-sys/Win32_UI_WindowsAndMessaging"] +Win32_Web = ["windows-sys/Win32_Web"] +Win32_Web_InternetExplorer = ["windows-sys/Win32_Web_InternetExplorer"] +default = ["windows-sys/default"] diff --git a/build/rust/windows-sys/lib.rs b/build/rust/windows-sys/lib.rs new file mode 100644 index 0000000000..15c89411fe --- /dev/null +++ b/build/rust/windows-sys/lib.rs @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use windows_sys::*; diff --git a/build/rust/windows-targets-0.48/Cargo.toml b/build/rust/windows-targets-0.48/Cargo.toml new file mode 100644 index 0000000000..2649448d0a --- /dev/null +++ b/build/rust/windows-targets-0.48/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "windows-targets" +version = "0.48.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[dependencies.windows-targets] +version = "0.52" diff --git a/build/rust/windows-targets-0.48/lib.rs b/build/rust/windows-targets-0.48/lib.rs new file mode 100644 index 0000000000..d3fd808887 --- /dev/null +++ b/build/rust/windows-targets-0.48/lib.rs @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use windows_targets::*; diff --git a/build/rust/windows-targets/Cargo.toml b/build/rust/windows-targets/Cargo.toml new file mode 100644 index 0000000000..5d3f665d7b --- /dev/null +++ b/build/rust/windows-targets/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "windows-targets" +version = "0.52.999" +edition = "2018" +license = "MIT OR Apache-2.0" + +[lib] +proc-macro = true +path = "lib.rs" + +[dependencies] +syn = { version = "2", features = ["full"] } +quote = "1" diff --git a/build/rust/windows-targets/lib.rs b/build/rust/windows-targets/lib.rs new file mode 100644 index 0000000000..439bc46946 --- /dev/null +++ b/build/rust/windows-targets/lib.rs @@ -0,0 +1,86 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use proc_macro::TokenStream; +use quote::quote; +use syn::parse::{Parse, ParseStream, Result}; +use syn::{parse_macro_input, Attribute, LitStr, Signature}; + +/* Proc macro equivalent to the following rust macro: + * ``` + * macro_rules! link { + * ($library:literal $abi:literal $($link_name:literal)? $(#[$($doc:tt)*])* fn $name:ident($($arg:ident: $argty:ty),*)->$ret:ty) => ( + * extern $abi { + * #[link(name = $library)] + * $(#[link_name=$link_name])? + * pub fn $name($($arg: $argty),*) -> $ret; + * } + * ) + * } + * ``` + * with the additional feature of removing ".dll" from the $library literal. + * + * The macro is derived from the equivalent macro in the real windows-targets crate, + * with the difference that it uses #[link] with the name of the library rather than + * a single "windows.$version" library, so as to avoid having to vendor all the fake + * "windows.$version" import libraries. We can do that because we also require MSVC + * to build, so we do have the real import libraries available. + * + * As the library name is there in the original for raw-dylib support, it contains + * a suffixed name, but plain #[link] expects a non-suffixed name, which is why we + * remove the suffix (and why this had to be a proc-macro). + * + * Once raw-dylib is more widely available and tested, we'll be able to use the + * raw-dylib variants directly. + */ + +struct LinkMacroInput { + library: LitStr, + abi: LitStr, + link_name: Option, + function: Signature, +} + +impl Parse for LinkMacroInput { + fn parse(input: ParseStream) -> Result { + let library: LitStr = input.parse()?; + let abi: LitStr = input.parse()?; + let link_name: Option = input.parse().ok(); + let _doc_comments = Attribute::parse_outer(input)?; + let function: Signature = input.parse()?; + Ok(LinkMacroInput { + library, + abi, + link_name, + function, + }) + } +} + +#[proc_macro] +pub fn link(input: TokenStream) -> TokenStream { + let LinkMacroInput { + library, + abi, + link_name, + function, + } = parse_macro_input!(input as LinkMacroInput); + + let link_name_attr = link_name.map(|lit| quote! { #[link_name = #lit] }); + + let library = library.value(); + let library = library.strip_suffix(".dll").unwrap_or(&library); + + let generated = quote! { + extern #abi { + #[link(name = #library)] + #link_name_attr + pub #function; + } + }; + + TokenStream::from(generated) +} diff --git a/build/rust/windows/Cargo.toml b/build/rust/windows/Cargo.toml new file mode 100644 index 0000000000..491a053d53 --- /dev/null +++ b/build/rust/windows/Cargo.toml @@ -0,0 +1,736 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.56" +name = "windows" +version = "0.52.0" +authors = ["Microsoft"] +description = "Rust for Windows" +documentation = "https://microsoft.github.io/windows-docs-rs/" +readme = "readme.md" +categories = ["os::windows-apis"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/microsoft/windows-rs" + +[package.metadata.docs.rs] +default-target = "x86_64-pc-windows-msvc" +rustdoc-args = [ + "--cfg", + "docsrs", +] +targets = [] + +[dependencies.windows-core] +version = "0.52.0" + +[dependencies.windows-implement] +version = "0.52.0" +optional = true + +[dependencies.windows-interface] +version = "0.52.0" +optional = true + +[dependencies.windows-targets] +version = "0.52.0" + +[features] +AI = [] +AI_MachineLearning = ["AI"] +ApplicationModel = [] +ApplicationModel_Activation = ["ApplicationModel"] +ApplicationModel_AppExtensions = ["ApplicationModel"] +ApplicationModel_AppService = ["ApplicationModel"] +ApplicationModel_Appointments = ["ApplicationModel"] +ApplicationModel_Appointments_AppointmentsProvider = ["ApplicationModel_Appointments"] +ApplicationModel_Appointments_DataProvider = ["ApplicationModel_Appointments"] +ApplicationModel_Background = ["ApplicationModel"] +ApplicationModel_Calls = ["ApplicationModel"] +ApplicationModel_Calls_Background = ["ApplicationModel_Calls"] +ApplicationModel_Calls_Provider = ["ApplicationModel_Calls"] +ApplicationModel_Chat = ["ApplicationModel"] +ApplicationModel_CommunicationBlocking = ["ApplicationModel"] +ApplicationModel_Contacts = ["ApplicationModel"] +ApplicationModel_Contacts_DataProvider = ["ApplicationModel_Contacts"] +ApplicationModel_Contacts_Provider = ["ApplicationModel_Contacts"] +ApplicationModel_ConversationalAgent = ["ApplicationModel"] +ApplicationModel_Core = ["ApplicationModel"] +ApplicationModel_DataTransfer = ["ApplicationModel"] +ApplicationModel_DataTransfer_DragDrop = ["ApplicationModel_DataTransfer"] +ApplicationModel_DataTransfer_DragDrop_Core = ["ApplicationModel_DataTransfer_DragDrop"] +ApplicationModel_DataTransfer_ShareTarget = ["ApplicationModel_DataTransfer"] +ApplicationModel_Email = ["ApplicationModel"] +ApplicationModel_Email_DataProvider = ["ApplicationModel_Email"] +ApplicationModel_ExtendedExecution = ["ApplicationModel"] +ApplicationModel_ExtendedExecution_Foreground = ["ApplicationModel_ExtendedExecution"] +ApplicationModel_Holographic = ["ApplicationModel"] +ApplicationModel_LockScreen = ["ApplicationModel"] +ApplicationModel_Payments = ["ApplicationModel"] +ApplicationModel_Payments_Provider = ["ApplicationModel_Payments"] +ApplicationModel_Preview = ["ApplicationModel"] +ApplicationModel_Preview_Holographic = ["ApplicationModel_Preview"] +ApplicationModel_Preview_InkWorkspace = ["ApplicationModel_Preview"] +ApplicationModel_Preview_Notes = ["ApplicationModel_Preview"] +ApplicationModel_Resources = ["ApplicationModel"] +ApplicationModel_Resources_Core = ["ApplicationModel_Resources"] +ApplicationModel_Resources_Management = ["ApplicationModel_Resources"] +ApplicationModel_Search = ["ApplicationModel"] +ApplicationModel_Search_Core = ["ApplicationModel_Search"] +ApplicationModel_Store = ["ApplicationModel"] +ApplicationModel_Store_LicenseManagement = ["ApplicationModel_Store"] +ApplicationModel_Store_Preview = ["ApplicationModel_Store"] +ApplicationModel_Store_Preview_InstallControl = ["ApplicationModel_Store_Preview"] +ApplicationModel_UserActivities = ["ApplicationModel"] +ApplicationModel_UserActivities_Core = ["ApplicationModel_UserActivities"] +ApplicationModel_UserDataAccounts = ["ApplicationModel"] +ApplicationModel_UserDataAccounts_Provider = ["ApplicationModel_UserDataAccounts"] +ApplicationModel_UserDataAccounts_SystemAccess = ["ApplicationModel_UserDataAccounts"] +ApplicationModel_UserDataTasks = ["ApplicationModel"] +ApplicationModel_UserDataTasks_DataProvider = ["ApplicationModel_UserDataTasks"] +ApplicationModel_VoiceCommands = ["ApplicationModel"] +ApplicationModel_Wallet = ["ApplicationModel"] +ApplicationModel_Wallet_System = ["ApplicationModel_Wallet"] +Data = [] +Data_Html = ["Data"] +Data_Json = ["Data"] +Data_Pdf = ["Data"] +Data_Text = ["Data"] +Data_Xml = ["Data"] +Data_Xml_Dom = ["Data_Xml"] +Data_Xml_Xsl = ["Data_Xml"] +Devices = [] +Devices_Adc = ["Devices"] +Devices_Adc_Provider = ["Devices_Adc"] +Devices_Background = ["Devices"] +Devices_Bluetooth = ["Devices"] +Devices_Bluetooth_Advertisement = ["Devices_Bluetooth"] +Devices_Bluetooth_Background = ["Devices_Bluetooth"] +Devices_Bluetooth_GenericAttributeProfile = ["Devices_Bluetooth"] +Devices_Bluetooth_Rfcomm = ["Devices_Bluetooth"] +Devices_Custom = ["Devices"] +Devices_Display = ["Devices"] +Devices_Display_Core = ["Devices_Display"] +Devices_Enumeration = ["Devices"] +Devices_Enumeration_Pnp = ["Devices_Enumeration"] +Devices_Geolocation = ["Devices"] +Devices_Geolocation_Geofencing = ["Devices_Geolocation"] +Devices_Geolocation_Provider = ["Devices_Geolocation"] +Devices_Gpio = ["Devices"] +Devices_Gpio_Provider = ["Devices_Gpio"] +Devices_Haptics = ["Devices"] +Devices_HumanInterfaceDevice = ["Devices"] +Devices_I2c = ["Devices"] +Devices_I2c_Provider = ["Devices_I2c"] +Devices_Input = ["Devices"] +Devices_Input_Preview = ["Devices_Input"] +Devices_Lights = ["Devices"] +Devices_Lights_Effects = ["Devices_Lights"] +Devices_Midi = ["Devices"] +Devices_PointOfService = ["Devices"] +Devices_PointOfService_Provider = ["Devices_PointOfService"] +Devices_Portable = ["Devices"] +Devices_Power = ["Devices"] +Devices_Printers = ["Devices"] +Devices_Printers_Extensions = ["Devices_Printers"] +Devices_Pwm = ["Devices"] +Devices_Pwm_Provider = ["Devices_Pwm"] +Devices_Radios = ["Devices"] +Devices_Scanners = ["Devices"] +Devices_Sensors = ["Devices"] +Devices_Sensors_Custom = ["Devices_Sensors"] +Devices_SerialCommunication = ["Devices"] +Devices_SmartCards = ["Devices"] +Devices_Sms = ["Devices"] +Devices_Spi = ["Devices"] +Devices_Spi_Provider = ["Devices_Spi"] +Devices_Usb = ["Devices"] +Devices_WiFi = ["Devices"] +Devices_WiFiDirect = ["Devices"] +Devices_WiFiDirect_Services = ["Devices_WiFiDirect"] +Embedded = [] +Embedded_DeviceLockdown = ["Embedded"] +Foundation = [] +Foundation_Collections = ["Foundation"] +Foundation_Diagnostics = ["Foundation"] +Foundation_Metadata = ["Foundation"] +Foundation_Numerics = ["Foundation"] +Gaming = [] +Gaming_Input = ["Gaming"] +Gaming_Input_Custom = ["Gaming_Input"] +Gaming_Input_ForceFeedback = ["Gaming_Input"] +Gaming_Input_Preview = ["Gaming_Input"] +Gaming_Preview = ["Gaming"] +Gaming_Preview_GamesEnumeration = ["Gaming_Preview"] +Gaming_UI = ["Gaming"] +Gaming_XboxLive = ["Gaming"] +Gaming_XboxLive_Storage = ["Gaming_XboxLive"] +Globalization = [] +Globalization_Collation = ["Globalization"] +Globalization_DateTimeFormatting = ["Globalization"] +Globalization_Fonts = ["Globalization"] +Globalization_NumberFormatting = ["Globalization"] +Globalization_PhoneNumberFormatting = ["Globalization"] +Graphics = [] +Graphics_Capture = ["Graphics"] +Graphics_DirectX = ["Graphics"] +Graphics_DirectX_Direct3D11 = ["Graphics_DirectX"] +Graphics_Display = ["Graphics"] +Graphics_Display_Core = ["Graphics_Display"] +Graphics_Effects = ["Graphics"] +Graphics_Holographic = ["Graphics"] +Graphics_Imaging = ["Graphics"] +Graphics_Printing = ["Graphics"] +Graphics_Printing3D = ["Graphics"] +Graphics_Printing_OptionDetails = ["Graphics_Printing"] +Graphics_Printing_PrintSupport = ["Graphics_Printing"] +Graphics_Printing_PrintTicket = ["Graphics_Printing"] +Graphics_Printing_Workflow = ["Graphics_Printing"] +Management = [] +Management_Core = ["Management"] +Management_Deployment = ["Management"] +Management_Deployment_Preview = ["Management_Deployment"] +Management_Policies = ["Management"] +Management_Update = ["Management"] +Management_Workplace = ["Management"] +Media = [] +Media_AppBroadcasting = ["Media"] +Media_AppRecording = ["Media"] +Media_Audio = ["Media"] +Media_Capture = ["Media"] +Media_Capture_Core = ["Media_Capture"] +Media_Capture_Frames = ["Media_Capture"] +Media_Casting = ["Media"] +Media_ClosedCaptioning = ["Media"] +Media_ContentRestrictions = ["Media"] +Media_Control = ["Media"] +Media_Core = ["Media"] +Media_Core_Preview = ["Media_Core"] +Media_Devices = ["Media"] +Media_Devices_Core = ["Media_Devices"] +Media_DialProtocol = ["Media"] +Media_Editing = ["Media"] +Media_Effects = ["Media"] +Media_FaceAnalysis = ["Media"] +Media_Import = ["Media"] +Media_MediaProperties = ["Media"] +Media_Miracast = ["Media"] +Media_Ocr = ["Media"] +Media_PlayTo = ["Media"] +Media_Playback = ["Media"] +Media_Playlists = ["Media"] +Media_Protection = ["Media"] +Media_Protection_PlayReady = ["Media_Protection"] +Media_Render = ["Media"] +Media_SpeechRecognition = ["Media"] +Media_SpeechSynthesis = ["Media"] +Media_Streaming = ["Media"] +Media_Streaming_Adaptive = ["Media_Streaming"] +Media_Transcoding = ["Media"] +Networking = [] +Networking_BackgroundTransfer = ["Networking"] +Networking_Connectivity = ["Networking"] +Networking_NetworkOperators = ["Networking"] +Networking_Proximity = ["Networking"] +Networking_PushNotifications = ["Networking"] +Networking_ServiceDiscovery = ["Networking"] +Networking_ServiceDiscovery_Dnssd = ["Networking_ServiceDiscovery"] +Networking_Sockets = ["Networking"] +Networking_Vpn = ["Networking"] +Networking_XboxLive = ["Networking"] +Perception = [] +Perception_Automation = ["Perception"] +Perception_Automation_Core = ["Perception_Automation"] +Perception_People = ["Perception"] +Perception_Spatial = ["Perception"] +Perception_Spatial_Preview = ["Perception_Spatial"] +Perception_Spatial_Surfaces = ["Perception_Spatial"] +Phone = [] +Phone_ApplicationModel = ["Phone"] +Phone_Devices = ["Phone"] +Phone_Devices_Notification = ["Phone_Devices"] +Phone_Devices_Power = ["Phone_Devices"] +Phone_Management = ["Phone"] +Phone_Management_Deployment = ["Phone_Management"] +Phone_Media = ["Phone"] +Phone_Media_Devices = ["Phone_Media"] +Phone_Notification = ["Phone"] +Phone_Notification_Management = ["Phone_Notification"] +Phone_PersonalInformation = ["Phone"] +Phone_PersonalInformation_Provisioning = ["Phone_PersonalInformation"] +Phone_Speech = ["Phone"] +Phone_Speech_Recognition = ["Phone_Speech"] +Phone_StartScreen = ["Phone"] +Phone_System = ["Phone"] +Phone_System_Power = ["Phone_System"] +Phone_System_Profile = ["Phone_System"] +Phone_System_UserProfile = ["Phone_System"] +Phone_System_UserProfile_GameServices = ["Phone_System_UserProfile"] +Phone_System_UserProfile_GameServices_Core = ["Phone_System_UserProfile_GameServices"] +Phone_UI = ["Phone"] +Phone_UI_Input = ["Phone_UI"] +Security = [] +Security_Authentication = ["Security"] +Security_Authentication_Identity = ["Security_Authentication"] +Security_Authentication_Identity_Core = ["Security_Authentication_Identity"] +Security_Authentication_OnlineId = ["Security_Authentication"] +Security_Authentication_Web = ["Security_Authentication"] +Security_Authentication_Web_Core = ["Security_Authentication_Web"] +Security_Authentication_Web_Provider = ["Security_Authentication_Web"] +Security_Authorization = ["Security"] +Security_Authorization_AppCapabilityAccess = ["Security_Authorization"] +Security_Credentials = ["Security"] +Security_Credentials_UI = ["Security_Credentials"] +Security_Cryptography = ["Security"] +Security_Cryptography_Certificates = ["Security_Cryptography"] +Security_Cryptography_Core = ["Security_Cryptography"] +Security_Cryptography_DataProtection = ["Security_Cryptography"] +Security_DataProtection = ["Security"] +Security_EnterpriseData = ["Security"] +Security_ExchangeActiveSyncProvisioning = ["Security"] +Security_Isolation = ["Security"] +Services = [] +Services_Maps = ["Services"] +Services_Maps_Guidance = ["Services_Maps"] +Services_Maps_LocalSearch = ["Services_Maps"] +Services_Maps_OfflineMaps = ["Services_Maps"] +Services_Store = ["Services"] +Services_TargetedContent = ["Services"] +Storage = [] +Storage_AccessCache = ["Storage"] +Storage_BulkAccess = ["Storage"] +Storage_Compression = ["Storage"] +Storage_FileProperties = ["Storage"] +Storage_Pickers = ["Storage"] +Storage_Pickers_Provider = ["Storage_Pickers"] +Storage_Provider = ["Storage"] +Storage_Search = ["Storage"] +Storage_Streams = ["Storage"] +System = [] +System_Diagnostics = ["System"] +System_Diagnostics_DevicePortal = ["System_Diagnostics"] +System_Diagnostics_Telemetry = ["System_Diagnostics"] +System_Diagnostics_TraceReporting = ["System_Diagnostics"] +System_Display = ["System"] +System_Implementation = ["System"] +System_Implementation_FileExplorer = ["System_Implementation"] +System_Inventory = ["System"] +System_Power = ["System"] +System_Profile = ["System"] +System_Profile_SystemManufacturers = ["System_Profile"] +System_RemoteDesktop = ["System"] +System_RemoteDesktop_Input = ["System_RemoteDesktop"] +System_RemoteSystems = ["System"] +System_Threading = ["System"] +System_Threading_Core = ["System_Threading"] +System_Update = ["System"] +System_UserProfile = ["System"] +UI = [] +UI_Accessibility = ["UI"] +UI_ApplicationSettings = ["UI"] +UI_Composition = ["UI"] +UI_Composition_Core = ["UI_Composition"] +UI_Composition_Desktop = ["UI_Composition"] +UI_Composition_Diagnostics = ["UI_Composition"] +UI_Composition_Effects = ["UI_Composition"] +UI_Composition_Interactions = ["UI_Composition"] +UI_Composition_Scenes = ["UI_Composition"] +UI_Core = ["UI"] +UI_Core_AnimationMetrics = ["UI_Core"] +UI_Core_Preview = ["UI_Core"] +UI_Input = ["UI"] +UI_Input_Core = ["UI_Input"] +UI_Input_Inking = ["UI_Input"] +UI_Input_Inking_Analysis = ["UI_Input_Inking"] +UI_Input_Inking_Core = ["UI_Input_Inking"] +UI_Input_Inking_Preview = ["UI_Input_Inking"] +UI_Input_Preview = ["UI_Input"] +UI_Input_Preview_Injection = ["UI_Input_Preview"] +UI_Input_Spatial = ["UI_Input"] +UI_Notifications = ["UI"] +UI_Notifications_Management = ["UI_Notifications"] +UI_Popups = ["UI"] +UI_Shell = ["UI"] +UI_StartScreen = ["UI"] +UI_Text = ["UI"] +UI_Text_Core = ["UI_Text"] +UI_UIAutomation = ["UI"] +UI_UIAutomation_Core = ["UI_UIAutomation"] +UI_ViewManagement = ["UI"] +UI_ViewManagement_Core = ["UI_ViewManagement"] +UI_WebUI = ["UI"] +UI_WebUI_Core = ["UI_WebUI"] +UI_WindowManagement = ["UI"] +UI_WindowManagement_Preview = ["UI_WindowManagement"] +Wdk = [] +Wdk_Foundation = ["Wdk"] +Wdk_Graphics = ["Wdk"] +Wdk_Graphics_Direct3D = ["Wdk_Graphics"] +Wdk_Storage = ["Wdk"] +Wdk_Storage_FileSystem = ["Wdk_Storage"] +Wdk_Storage_FileSystem_Minifilters = ["Wdk_Storage_FileSystem"] +Wdk_System = ["Wdk"] +Wdk_System_IO = ["Wdk_System"] +Wdk_System_OfflineRegistry = ["Wdk_System"] +Wdk_System_Registry = ["Wdk_System"] +Wdk_System_SystemInformation = ["Wdk_System"] +Wdk_System_SystemServices = ["Wdk_System"] +Wdk_System_Threading = ["Wdk_System"] +Web = [] +Web_AtomPub = ["Web"] +Web_Http = ["Web"] +Web_Http_Diagnostics = ["Web_Http"] +Web_Http_Filters = ["Web_Http"] +Web_Http_Headers = ["Web_Http"] +Web_Syndication = ["Web"] +Web_UI = ["Web"] +Web_UI_Interop = ["Web_UI"] +Win32 = [] +Win32_AI = ["Win32"] +Win32_AI_MachineLearning = ["Win32_AI"] +Win32_AI_MachineLearning_DirectML = ["Win32_AI_MachineLearning"] +Win32_AI_MachineLearning_WinML = ["Win32_AI_MachineLearning"] +Win32_Data = ["Win32"] +Win32_Data_HtmlHelp = ["Win32_Data"] +Win32_Data_RightsManagement = ["Win32_Data"] +Win32_Data_Xml = ["Win32_Data"] +Win32_Data_Xml_MsXml = ["Win32_Data_Xml"] +Win32_Data_Xml_XmlLite = ["Win32_Data_Xml"] +Win32_Devices = ["Win32"] +Win32_Devices_AllJoyn = ["Win32_Devices"] +Win32_Devices_BiometricFramework = ["Win32_Devices"] +Win32_Devices_Bluetooth = ["Win32_Devices"] +Win32_Devices_Communication = ["Win32_Devices"] +Win32_Devices_DeviceAccess = ["Win32_Devices"] +Win32_Devices_DeviceAndDriverInstallation = ["Win32_Devices"] +Win32_Devices_DeviceQuery = ["Win32_Devices"] +Win32_Devices_Display = ["Win32_Devices"] +Win32_Devices_Enumeration = ["Win32_Devices"] +Win32_Devices_Enumeration_Pnp = ["Win32_Devices_Enumeration"] +Win32_Devices_Fax = ["Win32_Devices"] +Win32_Devices_FunctionDiscovery = ["Win32_Devices"] +Win32_Devices_Geolocation = ["Win32_Devices"] +Win32_Devices_HumanInterfaceDevice = ["Win32_Devices"] +Win32_Devices_ImageAcquisition = ["Win32_Devices"] +Win32_Devices_PortableDevices = ["Win32_Devices"] +Win32_Devices_Properties = ["Win32_Devices"] +Win32_Devices_Pwm = ["Win32_Devices"] +Win32_Devices_Sensors = ["Win32_Devices"] +Win32_Devices_SerialCommunication = ["Win32_Devices"] +Win32_Devices_Tapi = ["Win32_Devices"] +Win32_Devices_Usb = ["Win32_Devices"] +Win32_Devices_WebServicesOnDevices = ["Win32_Devices"] +Win32_Foundation = ["Win32"] +Win32_Gaming = ["Win32"] +Win32_Globalization = ["Win32"] +Win32_Graphics = ["Win32"] +Win32_Graphics_CompositionSwapchain = ["Win32_Graphics"] +Win32_Graphics_DXCore = ["Win32_Graphics"] +Win32_Graphics_Direct2D = ["Win32_Graphics"] +Win32_Graphics_Direct2D_Common = ["Win32_Graphics_Direct2D"] +Win32_Graphics_Direct3D = ["Win32_Graphics"] +Win32_Graphics_Direct3D10 = ["Win32_Graphics"] +Win32_Graphics_Direct3D11 = ["Win32_Graphics"] +Win32_Graphics_Direct3D11on12 = ["Win32_Graphics"] +Win32_Graphics_Direct3D12 = ["Win32_Graphics"] +Win32_Graphics_Direct3D9 = ["Win32_Graphics"] +Win32_Graphics_Direct3D9on12 = ["Win32_Graphics"] +Win32_Graphics_Direct3D_Dxc = ["Win32_Graphics_Direct3D"] +Win32_Graphics_Direct3D_Fxc = ["Win32_Graphics_Direct3D"] +Win32_Graphics_DirectComposition = ["Win32_Graphics"] +Win32_Graphics_DirectDraw = ["Win32_Graphics"] +Win32_Graphics_DirectManipulation = ["Win32_Graphics"] +Win32_Graphics_DirectWrite = ["Win32_Graphics"] +Win32_Graphics_Dwm = ["Win32_Graphics"] +Win32_Graphics_Dxgi = ["Win32_Graphics"] +Win32_Graphics_Dxgi_Common = ["Win32_Graphics_Dxgi"] +Win32_Graphics_Gdi = ["Win32_Graphics"] +Win32_Graphics_GdiPlus = ["Win32_Graphics"] +Win32_Graphics_Hlsl = ["Win32_Graphics"] +Win32_Graphics_Imaging = ["Win32_Graphics"] +Win32_Graphics_Imaging_D2D = ["Win32_Graphics_Imaging"] +Win32_Graphics_OpenGL = ["Win32_Graphics"] +Win32_Graphics_Printing = ["Win32_Graphics"] +Win32_Graphics_Printing_PrintTicket = ["Win32_Graphics_Printing"] +Win32_Management = ["Win32"] +Win32_Management_MobileDeviceManagementRegistration = ["Win32_Management"] +Win32_Media = ["Win32"] +Win32_Media_Audio = ["Win32_Media"] +Win32_Media_Audio_Apo = ["Win32_Media_Audio"] +Win32_Media_Audio_DirectMusic = ["Win32_Media_Audio"] +Win32_Media_Audio_DirectSound = ["Win32_Media_Audio"] +Win32_Media_Audio_Endpoints = ["Win32_Media_Audio"] +Win32_Media_Audio_XAudio2 = ["Win32_Media_Audio"] +Win32_Media_DeviceManager = ["Win32_Media"] +Win32_Media_DirectShow = ["Win32_Media"] +Win32_Media_DirectShow_Tv = ["Win32_Media_DirectShow"] +Win32_Media_DirectShow_Xml = ["Win32_Media_DirectShow"] +Win32_Media_DxMediaObjects = ["Win32_Media"] +Win32_Media_KernelStreaming = ["Win32_Media"] +Win32_Media_LibrarySharingServices = ["Win32_Media"] +Win32_Media_MediaFoundation = ["Win32_Media"] +Win32_Media_MediaPlayer = ["Win32_Media"] +Win32_Media_Multimedia = ["Win32_Media"] +Win32_Media_PictureAcquisition = ["Win32_Media"] +Win32_Media_Speech = ["Win32_Media"] +Win32_Media_Streaming = ["Win32_Media"] +Win32_Media_WindowsMediaFormat = ["Win32_Media"] +Win32_NetworkManagement = ["Win32"] +Win32_NetworkManagement_Dhcp = ["Win32_NetworkManagement"] +Win32_NetworkManagement_Dns = ["Win32_NetworkManagement"] +Win32_NetworkManagement_InternetConnectionWizard = ["Win32_NetworkManagement"] +Win32_NetworkManagement_IpHelper = ["Win32_NetworkManagement"] +Win32_NetworkManagement_MobileBroadband = ["Win32_NetworkManagement"] +Win32_NetworkManagement_Multicast = ["Win32_NetworkManagement"] +Win32_NetworkManagement_Ndis = ["Win32_NetworkManagement"] +Win32_NetworkManagement_NetBios = ["Win32_NetworkManagement"] +Win32_NetworkManagement_NetManagement = ["Win32_NetworkManagement"] +Win32_NetworkManagement_NetShell = ["Win32_NetworkManagement"] +Win32_NetworkManagement_NetworkDiagnosticsFramework = ["Win32_NetworkManagement"] +Win32_NetworkManagement_NetworkPolicyServer = ["Win32_NetworkManagement"] +Win32_NetworkManagement_P2P = ["Win32_NetworkManagement"] +Win32_NetworkManagement_QoS = ["Win32_NetworkManagement"] +Win32_NetworkManagement_Rras = ["Win32_NetworkManagement"] +Win32_NetworkManagement_Snmp = ["Win32_NetworkManagement"] +Win32_NetworkManagement_WNet = ["Win32_NetworkManagement"] +Win32_NetworkManagement_WebDav = ["Win32_NetworkManagement"] +Win32_NetworkManagement_WiFi = ["Win32_NetworkManagement"] +Win32_NetworkManagement_WindowsConnectNow = ["Win32_NetworkManagement"] +Win32_NetworkManagement_WindowsConnectionManager = ["Win32_NetworkManagement"] +Win32_NetworkManagement_WindowsFilteringPlatform = ["Win32_NetworkManagement"] +Win32_NetworkManagement_WindowsFirewall = ["Win32_NetworkManagement"] +Win32_NetworkManagement_WindowsNetworkVirtualization = ["Win32_NetworkManagement"] +Win32_Networking = ["Win32"] +Win32_Networking_ActiveDirectory = ["Win32_Networking"] +Win32_Networking_BackgroundIntelligentTransferService = ["Win32_Networking"] +Win32_Networking_Clustering = ["Win32_Networking"] +Win32_Networking_HttpServer = ["Win32_Networking"] +Win32_Networking_Ldap = ["Win32_Networking"] +Win32_Networking_NetworkListManager = ["Win32_Networking"] +Win32_Networking_RemoteDifferentialCompression = ["Win32_Networking"] +Win32_Networking_WebSocket = ["Win32_Networking"] +Win32_Networking_WinHttp = ["Win32_Networking"] +Win32_Networking_WinInet = ["Win32_Networking"] +Win32_Networking_WinSock = ["Win32_Networking"] +Win32_Networking_WindowsWebServices = ["Win32_Networking"] +Win32_Security = ["Win32"] +Win32_Security_AppLocker = ["Win32_Security"] +Win32_Security_Authentication = ["Win32_Security"] +Win32_Security_Authentication_Identity = ["Win32_Security_Authentication"] +Win32_Security_Authentication_Identity_Provider = ["Win32_Security_Authentication_Identity"] +Win32_Security_Authorization = ["Win32_Security"] +Win32_Security_Authorization_UI = ["Win32_Security_Authorization"] +Win32_Security_ConfigurationSnapin = ["Win32_Security"] +Win32_Security_Credentials = ["Win32_Security"] +Win32_Security_Cryptography = ["Win32_Security"] +Win32_Security_Cryptography_Catalog = ["Win32_Security_Cryptography"] +Win32_Security_Cryptography_Certificates = ["Win32_Security_Cryptography"] +Win32_Security_Cryptography_Sip = ["Win32_Security_Cryptography"] +Win32_Security_Cryptography_UI = ["Win32_Security_Cryptography"] +Win32_Security_DiagnosticDataQuery = ["Win32_Security"] +Win32_Security_DirectoryServices = ["Win32_Security"] +Win32_Security_EnterpriseData = ["Win32_Security"] +Win32_Security_ExtensibleAuthenticationProtocol = ["Win32_Security"] +Win32_Security_Isolation = ["Win32_Security"] +Win32_Security_LicenseProtection = ["Win32_Security"] +Win32_Security_NetworkAccessProtection = ["Win32_Security"] +Win32_Security_Tpm = ["Win32_Security"] +Win32_Security_WinTrust = ["Win32_Security"] +Win32_Security_WinWlx = ["Win32_Security"] +Win32_Storage = ["Win32"] +Win32_Storage_Cabinets = ["Win32_Storage"] +Win32_Storage_CloudFilters = ["Win32_Storage"] +Win32_Storage_Compression = ["Win32_Storage"] +Win32_Storage_DataDeduplication = ["Win32_Storage"] +Win32_Storage_DistributedFileSystem = ["Win32_Storage"] +Win32_Storage_EnhancedStorage = ["Win32_Storage"] +Win32_Storage_FileHistory = ["Win32_Storage"] +Win32_Storage_FileServerResourceManager = ["Win32_Storage"] +Win32_Storage_FileSystem = ["Win32_Storage"] +Win32_Storage_Imapi = ["Win32_Storage"] +Win32_Storage_IndexServer = ["Win32_Storage"] +Win32_Storage_InstallableFileSystems = ["Win32_Storage"] +Win32_Storage_IscsiDisc = ["Win32_Storage"] +Win32_Storage_Jet = ["Win32_Storage"] +Win32_Storage_Nvme = ["Win32_Storage"] +Win32_Storage_OfflineFiles = ["Win32_Storage"] +Win32_Storage_OperationRecorder = ["Win32_Storage"] +Win32_Storage_Packaging = ["Win32_Storage"] +Win32_Storage_Packaging_Appx = ["Win32_Storage_Packaging"] +Win32_Storage_Packaging_Opc = ["Win32_Storage_Packaging"] +Win32_Storage_ProjectedFileSystem = ["Win32_Storage"] +Win32_Storage_StructuredStorage = ["Win32_Storage"] +Win32_Storage_Vhd = ["Win32_Storage"] +Win32_Storage_VirtualDiskService = ["Win32_Storage"] +Win32_Storage_Vss = ["Win32_Storage"] +Win32_Storage_Xps = ["Win32_Storage"] +Win32_Storage_Xps_Printing = ["Win32_Storage_Xps"] +Win32_System = ["Win32"] +Win32_System_AddressBook = ["Win32_System"] +Win32_System_Antimalware = ["Win32_System"] +Win32_System_ApplicationInstallationAndServicing = ["Win32_System"] +Win32_System_ApplicationVerifier = ["Win32_System"] +Win32_System_AssessmentTool = ["Win32_System"] +Win32_System_ClrHosting = ["Win32_System"] +Win32_System_Com = ["Win32_System"] +Win32_System_Com_CallObj = ["Win32_System_Com"] +Win32_System_Com_ChannelCredentials = ["Win32_System_Com"] +Win32_System_Com_Events = ["Win32_System_Com"] +Win32_System_Com_Marshal = ["Win32_System_Com"] +Win32_System_Com_StructuredStorage = ["Win32_System_Com"] +Win32_System_Com_UI = ["Win32_System_Com"] +Win32_System_Com_Urlmon = ["Win32_System_Com"] +Win32_System_ComponentServices = ["Win32_System"] +Win32_System_Console = ["Win32_System"] +Win32_System_Contacts = ["Win32_System"] +Win32_System_CorrelationVector = ["Win32_System"] +Win32_System_DataExchange = ["Win32_System"] +Win32_System_DeploymentServices = ["Win32_System"] +Win32_System_DesktopSharing = ["Win32_System"] +Win32_System_DeveloperLicensing = ["Win32_System"] +Win32_System_Diagnostics = ["Win32_System"] +Win32_System_Diagnostics_Ceip = ["Win32_System_Diagnostics"] +Win32_System_Diagnostics_ClrProfiling = ["Win32_System_Diagnostics"] +Win32_System_Diagnostics_Debug = ["Win32_System_Diagnostics"] +Win32_System_Diagnostics_Debug_ActiveScript = ["Win32_System_Diagnostics_Debug"] +Win32_System_Diagnostics_Debug_Extensions = ["Win32_System_Diagnostics_Debug"] +Win32_System_Diagnostics_Etw = ["Win32_System_Diagnostics"] +Win32_System_Diagnostics_ProcessSnapshotting = ["Win32_System_Diagnostics"] +Win32_System_Diagnostics_ToolHelp = ["Win32_System_Diagnostics"] +Win32_System_DistributedTransactionCoordinator = ["Win32_System"] +Win32_System_Environment = ["Win32_System"] +Win32_System_ErrorReporting = ["Win32_System"] +Win32_System_EventCollector = ["Win32_System"] +Win32_System_EventLog = ["Win32_System"] +Win32_System_EventNotificationService = ["Win32_System"] +Win32_System_GroupPolicy = ["Win32_System"] +Win32_System_HostCompute = ["Win32_System"] +Win32_System_HostComputeNetwork = ["Win32_System"] +Win32_System_HostComputeSystem = ["Win32_System"] +Win32_System_Hypervisor = ["Win32_System"] +Win32_System_IO = ["Win32_System"] +Win32_System_Iis = ["Win32_System"] +Win32_System_Ioctl = ["Win32_System"] +Win32_System_JobObjects = ["Win32_System"] +Win32_System_Js = ["Win32_System"] +Win32_System_Kernel = ["Win32_System"] +Win32_System_LibraryLoader = ["Win32_System"] +Win32_System_Mailslots = ["Win32_System"] +Win32_System_Mapi = ["Win32_System"] +Win32_System_Memory = ["Win32_System"] +Win32_System_Memory_NonVolatile = ["Win32_System_Memory"] +Win32_System_MessageQueuing = ["Win32_System"] +Win32_System_MixedReality = ["Win32_System"] +Win32_System_Mmc = ["Win32_System"] +Win32_System_Ole = ["Win32_System"] +Win32_System_ParentalControls = ["Win32_System"] +Win32_System_PasswordManagement = ["Win32_System"] +Win32_System_Performance = ["Win32_System"] +Win32_System_Performance_HardwareCounterProfiling = ["Win32_System_Performance"] +Win32_System_Pipes = ["Win32_System"] +Win32_System_Power = ["Win32_System"] +Win32_System_ProcessStatus = ["Win32_System"] +Win32_System_RealTimeCommunications = ["Win32_System"] +Win32_System_Recovery = ["Win32_System"] +Win32_System_Registry = ["Win32_System"] +Win32_System_RemoteAssistance = ["Win32_System"] +Win32_System_RemoteDesktop = ["Win32_System"] +Win32_System_RemoteManagement = ["Win32_System"] +Win32_System_RestartManager = ["Win32_System"] +Win32_System_Restore = ["Win32_System"] +Win32_System_Rpc = ["Win32_System"] +Win32_System_Search = ["Win32_System"] +Win32_System_Search_Common = ["Win32_System_Search"] +Win32_System_SecurityCenter = ["Win32_System"] +Win32_System_ServerBackup = ["Win32_System"] +Win32_System_Services = ["Win32_System"] +Win32_System_SettingsManagementInfrastructure = ["Win32_System"] +Win32_System_SetupAndMigration = ["Win32_System"] +Win32_System_Shutdown = ["Win32_System"] +Win32_System_SideShow = ["Win32_System"] +Win32_System_StationsAndDesktops = ["Win32_System"] +Win32_System_SubsystemForLinux = ["Win32_System"] +Win32_System_SystemInformation = ["Win32_System"] +Win32_System_SystemServices = ["Win32_System"] +Win32_System_TaskScheduler = ["Win32_System"] +Win32_System_Threading = ["Win32_System"] +Win32_System_Time = ["Win32_System"] +Win32_System_TpmBaseServices = ["Win32_System"] +Win32_System_TransactionServer = ["Win32_System"] +Win32_System_UpdateAgent = ["Win32_System"] +Win32_System_UpdateAssessment = ["Win32_System"] +Win32_System_UserAccessLogging = ["Win32_System"] +Win32_System_Variant = ["Win32_System"] +Win32_System_VirtualDosMachines = ["Win32_System"] +Win32_System_WinRT = ["Win32_System"] +Win32_System_WinRT_AllJoyn = ["Win32_System_WinRT"] +Win32_System_WinRT_Composition = ["Win32_System_WinRT"] +Win32_System_WinRT_CoreInputView = ["Win32_System_WinRT"] +Win32_System_WinRT_Direct3D11 = ["Win32_System_WinRT"] +Win32_System_WinRT_Display = ["Win32_System_WinRT"] +Win32_System_WinRT_Graphics = ["Win32_System_WinRT"] +Win32_System_WinRT_Graphics_Capture = ["Win32_System_WinRT_Graphics"] +Win32_System_WinRT_Graphics_Direct2D = ["Win32_System_WinRT_Graphics"] +Win32_System_WinRT_Graphics_Imaging = ["Win32_System_WinRT_Graphics"] +Win32_System_WinRT_Holographic = ["Win32_System_WinRT"] +Win32_System_WinRT_Isolation = ["Win32_System_WinRT"] +Win32_System_WinRT_ML = ["Win32_System_WinRT"] +Win32_System_WinRT_Media = ["Win32_System_WinRT"] +Win32_System_WinRT_Metadata = ["Win32_System_WinRT"] +Win32_System_WinRT_Pdf = ["Win32_System_WinRT"] +Win32_System_WinRT_Printing = ["Win32_System_WinRT"] +Win32_System_WinRT_Shell = ["Win32_System_WinRT"] +Win32_System_WinRT_Storage = ["Win32_System_WinRT"] +Win32_System_WindowsProgramming = ["Win32_System"] +Win32_System_WindowsSync = ["Win32_System"] +Win32_System_Wmi = ["Win32_System"] +Win32_UI = ["Win32"] +Win32_UI_Accessibility = ["Win32_UI"] +Win32_UI_Animation = ["Win32_UI"] +Win32_UI_ColorSystem = ["Win32_UI"] +Win32_UI_Controls = ["Win32_UI"] +Win32_UI_Controls_Dialogs = ["Win32_UI_Controls"] +Win32_UI_Controls_RichEdit = ["Win32_UI_Controls"] +Win32_UI_HiDpi = ["Win32_UI"] +Win32_UI_Input = ["Win32_UI"] +Win32_UI_Input_Ime = ["Win32_UI_Input"] +Win32_UI_Input_Ink = ["Win32_UI_Input"] +Win32_UI_Input_KeyboardAndMouse = ["Win32_UI_Input"] +Win32_UI_Input_Pointer = ["Win32_UI_Input"] +Win32_UI_Input_Radial = ["Win32_UI_Input"] +Win32_UI_Input_Touch = ["Win32_UI_Input"] +Win32_UI_Input_XboxController = ["Win32_UI_Input"] +Win32_UI_InteractionContext = ["Win32_UI"] +Win32_UI_LegacyWindowsEnvironmentFeatures = ["Win32_UI"] +Win32_UI_Magnification = ["Win32_UI"] +Win32_UI_Notifications = ["Win32_UI"] +Win32_UI_Ribbon = ["Win32_UI"] +Win32_UI_Shell = ["Win32_UI"] +Win32_UI_Shell_Common = ["Win32_UI_Shell"] +Win32_UI_Shell_PropertiesSystem = ["Win32_UI_Shell"] +Win32_UI_TabletPC = ["Win32_UI"] +Win32_UI_TextServices = ["Win32_UI"] +Win32_UI_WindowsAndMessaging = ["Win32_UI"] +Win32_UI_Wpf = ["Win32_UI"] +Win32_Web = ["Win32"] +Win32_Web_InternetExplorer = ["Win32_Web"] +default = [] +deprecated = [] +docs = [] +implement = [ + "windows-implement", + "windows-interface", + "windows-core/implement", +] + +[dependencies.mozbuild] +version = "0.1" diff --git a/build/rust/windows/src/lib.rs b/build/rust/windows/src/lib.rs new file mode 100644 index 0000000000..9c5c49d089 --- /dev/null +++ b/build/rust/windows/src/lib.rs @@ -0,0 +1,24 @@ +#![allow(warnings)] +#![cfg_attr(docsrs, doc = "This is a stub. The latest API documentation is here: ")] +#![cfg_attr(docsrs, doc = "")] +/*! +Learn more about Rust for Windows here: +*/ + +#![doc(html_no_source)] +#![allow(non_snake_case, clashing_extern_declarations, non_upper_case_globals, non_camel_case_types, clippy::all)] +#![cfg_attr(not(feature = "docs"), doc(hidden))] + +extern crate self as windows; + +pub mod core { + pub use windows_core::*; + + #[cfg(feature = "implement")] + pub use windows_implement::implement; + + #[cfg(feature = "implement")] + pub use windows_interface::interface; +} + +include!(mozbuild::windows_rs_path!("src/Windows/mod.rs")); diff --git a/build/sanitizers/asan_blacklist_win.txt b/build/sanitizers/asan_blacklist_win.txt new file mode 100644 index 0000000000..3bc19ba437 --- /dev/null +++ b/build/sanitizers/asan_blacklist_win.txt @@ -0,0 +1,28 @@ +# This is originally copied from Chromium tools/memory/asan/blacklist_win.txt. +# The rules in this file are only applied at compile time. If you can modify the +# source in question, consider function attributes to disable instrumentation. + +# Bug 1200740 - ASan crash due to child process function interceptions +# Sandbox executes some of its code before the ASan RTL gets initialized and +# maps shadow memory. As a result, instrumented code tries to access unavailable +# shadow memory and faults. +fun:*TargetNtSetInformationThread* +fun:*TargetNtOpenThreadToken* +fun:*TargetNtOpenThreadTokenEx* +fun:*TargetNtMapViewOfSection* +fun:*AutoProtectMemory*sandbox* +fun:*EatResolverThunk*sandbox* +fun:*InterceptionAgent*sandbox* +fun:*ResolverThunk*sandbox* +fun:*Target*SandboxFactory*sandbox* +fun:*ProcessState*sandbox* +src:*pe_image.h +src:*pe_image.cc +src:*resolver_32.cc +src:*resolver_64.cc +src:*filesystem_interception.cc +src:*process_thread_interception.cc +src:*registry_interception.cc +src:*sandbox_nt_util.cc +src:*sync_interception.cc +src:*interceptors_64.cc diff --git a/build/sanitizers/ubsan_enum_blacklist.txt b/build/sanitizers/ubsan_enum_blacklist.txt new file mode 100644 index 0000000000..1be9d23d4a --- /dev/null +++ b/build/sanitizers/ubsan_enum_blacklist.txt @@ -0,0 +1,17 @@ +# All entries in this file are to suppress issues reported by enum. +# Blacklists for other reasons should go in separate blacklist files. + +[enum] + +# bug 1404151 +src:*/lul/LulDwarfExt.h +src:*/lul/LulDwarf.cpp + +# bug 1405142 +src:*/widget/gtk/* + +# bug 1619468 +src:*/security/manager/ssl/nsSiteSecurityService.cpp + +# bug 1619484 +src:*/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_and_cursor_composer.cc diff --git a/build/sanitizers/ubsan_function_blacklist.txt b/build/sanitizers/ubsan_function_blacklist.txt new file mode 100644 index 0000000000..58c8f33be4 --- /dev/null +++ b/build/sanitizers/ubsan_function_blacklist.txt @@ -0,0 +1,9 @@ +[function] +# Disable function sanitizer for all C files (new feature in clang 17) until we +# we can narrow this down. See bug 1841935. +src:*.c + +# RLBox allows automatic handling of differing machine models between the appplication and sandbox. +# To do this, RLBox carefully changes the types of function pointers to the sandbox with ones suitable for the applicaton. +# Unfortunately, this triggers the ubsan's check for calling functions with incorrect types. So disabling this. +fun:*impl_invoke_with_func_ptr* diff --git a/build/sanitizers/ubsan_object_size_blacklist.txt b/build/sanitizers/ubsan_object_size_blacklist.txt new file mode 100644 index 0000000000..e61b4eb1ec --- /dev/null +++ b/build/sanitizers/ubsan_object_size_blacklist.txt @@ -0,0 +1,7 @@ +# All entries in this file are to suppress issues reported by object-size. +# Blacklists for other reasons should go in separate blacklist files. + +[object-size] + +# bug 1577584 +src:*/gfx/harfbuzz/src/* diff --git a/build/sanitizers/ubsan_pointer_overflow_blacklist.txt b/build/sanitizers/ubsan_pointer_overflow_blacklist.txt new file mode 100644 index 0000000000..43b07ddae9 --- /dev/null +++ b/build/sanitizers/ubsan_pointer_overflow_blacklist.txt @@ -0,0 +1,30 @@ +# All entries in this file are to suppress issues reported by pointer-overflow. +# Blacklists for other reasons should go in separate blacklist files. + +[pointer-overflow] + +# cppunittest +src:*/mfbt/tests/TestArrayUtils.cpp +# gtest ImageDecodeToSurface.WebP +src:*/media/libwebp/src/dec/idec_dec.c +# gtest ImageDecoders.WebPLargeMultiChunk +src:*/media/libwebp/src/utils/bit_reader_utils.c +# gtest MediaDataDecoder.VP9 +src:*/media/ffvpx/libavcodec/avpacket.c +src:*/media/ffvpx/libavutil/imgutils.c +# gtest VP8VideoTrackEncoder.FrameEncode +src:*/media/libvpx/libvpx/vp8/encoder/encodeframe.c +# gtest ImageDecoders.AVIFSingleChunk +src:*/third_party/aom/av1/common/quant_common.c +# crashtest +src:*/parser/expat/lib/xmlparse.c +src:*/mfbt/lz4/lz4.c +src:*/media/libogg/src/ogg_framing.c +# mochitest gl2c dom/canvas/test/webgl-conf/generated/test_2_conformance2__reading__read-pixels-pack-parameters.html +src:*/dom/canvas/WebGLContextGL.cpp +# reftest J1 +src:*/js/src/builtin/TypedObject.cpp +# jittest Jit6 +src:*/js/src/jit/x86-shared/Assembler-x86-shared.h +# https://gitlab.freedesktop.org/mesa/mesa/-/issues/4477 +fun:remove_line_continuations diff --git a/build/sanitizers/ubsan_signed_overflow_blacklist.txt b/build/sanitizers/ubsan_signed_overflow_blacklist.txt new file mode 100644 index 0000000000..694eaa4737 --- /dev/null +++ b/build/sanitizers/ubsan_signed_overflow_blacklist.txt @@ -0,0 +1,257 @@ +# This file contains an extensive compile-time blacklist for silencing highly +# frequent signed integer overflows in our codebase, found by the use of +# -fsanitize=signed-integer-overflow. C/C++ say signed integer overflow is +# undefined behavior, so instances of this need to be fixed. But not all code +# has been properly written to not overflow, and overflow-checking can have +# significant compile time and runtime costs, so we will sometimes disable +# signed overflow checking. +# +# The rules in this file are applied at compile time; changes to this list +# usually require a full rebuild to apply. If you can modify the source in +# question to exempt specific functions using MOZ_NO_SANITIZE_SIGNED_OVERFLOW, +# do that instead. +# +# The extensive number of entries below is for two reasons. +# +# First, compiler instrumentation for signed integer overflows has a cost, at +# compile time and at runtime. In performance-critical code proven to have no +# signed overflow, it makes sense to turn off overflow detection to avoid both +# costs. (Indeed, -fsanitize=signed-integer-overflow is unusably slow without +# this.) +# +# Second, many entries here are overly aggressive to get the build into a state +# that allows any testing to happen at all. Some of the entries here are for +# issues that are highly frequent in our test suites -- over 500 times per run. +# Aggressive entries now let us start using this mode, without having to first +# fix wide swaths of existing code. +# +# Entries should be removed 1) as issues are fixed; and 2) as blacklist entries +# can be moved out of this centralized file, into source-level blacklist +# attributes on individual functions. + +# All entries in this file are to suppress signed-integer-overflow problems. +# Blacklists for other reasons should go in separate blacklist files. +[signed-integer-overflow] + +# Overflows in the C++ std headers aren't necessarily bugs, because code inside +# a language implementation can depend on compiler-specific behavior where C/C++ +# leave the behavior undefined. +src:*bits/basic_string.h + +# Assume everything running through CheckedInt.h is ok. Signed overflows here +# should generally have been guarded by safe overflow checks, so it's likely +# safe to exempt it from overflow checking. (This should eventually be verified +# and functions individually tagged safe so this entry can be removed.) +src:*/CheckedInt.h + +# Exclude bignum +src:*/mfbt/double-conversion/source/bignum.cc + +# Exclude anything within gtests +src:*/gtest/* + +# Atomics can overflow, but without a full stack we can't trace these back +# to what is actually causing the overflow. Ignoring these for now, as it will +# be too much effort to determine every single source here. +src:*/mfbt/Atomics.h + +# No reason to instrument certain parts of NSS that explicitely deal with +# arithmetics and crypto. +src:*/security/nss/lib/freebl/mpi/* +src:*/security/nss/lib/freebl/ecl/* + +# nsTArray_base::ShiftData performs overflows +fun:*nsTArray_base*ShiftData* + +### Frequent 0 - 1 overflows +# +# We have several code patterns in our codebase that cause these overflows, +# but they are typically all harmless and could be filtered easily at runtime. +# However, some of them are so frequent that suppressing them at compile-time +# makes sense to increase runtime performance. +# +src:*/netwerk/base/nsSocketTransportService2.cpp +src:*/nsCharTraits.h +# Code in xpcom/base/CycleCollectedJSContext.cpp +fun:*CycleCollectedJSContext*ProcessMetastableStateQueue* +# Code in layout/painting/nsDisplayList.cpp +fun:*nsDisplayOpacity*ShouldFlattenAway* +# Code in modules/libpref/Preferences.cpp +fun:*pref_InitInitialObjects* +# Code in netwerk/base/nsIOService.cpp +fun:*nsIOService*GetCachedProtocolHandler* +# Code in layout/xul/nsXULPopupManager.cpp +fun:*nsXULPopupManager*AdjustPopupsOnWindowChange* +# Code in dom/base/nsDocument.cpp +fun:*1nsDocument@@* +# Code in gfx/layers/ipc/CompositorBridgeChild.cpp +fun:*CompositorBridgeChild*Destroy* +# Code in gfx/layers/ipc/ImageBridgeChild.cpp +fun:*ImageBridgeChild*ShutdownStep1* +# Code in dom/base/nsGlobalWindow.cpp +fun:*nsGlobalWindow*ClearControllers* +# Code in layout/style/AnimationCollection.cpp +fun:*AnimationCollection*PropertyDtor* +# Code in layout/style/nsStyleSet.cpp +fun:*nsStyleSet*AddImportantRules* +fun:*nsStyleSet*CounterStyleRuleForName* + + +### Misc overflows + +# Hot function in protobuf producing overflows +fun:*CodedInputStream*ReadTagWithCutoff* + + +# SQLite3 is full of overflows :/ +src:*/third_party/sqlite3/src/sqlite3.c + +# zlib has some overflows, we can't deal with them right now +src:*/modules/zlib/src/* + +# Our LZ4 implementation uses overflows. By listing it here we might +# miss some unintended overflows in that implementation, but we can't +# check for it right now. +src:*/mfbt/lz4.c + +# Apparently this overflows a lot, because it contains some allocators +# that keep overflowing, not sure why. Disabling by function didn't seem +# to work here for operator new. +src:*/xpcom/ds/nsArrayEnumerator.cpp + +# Memory usage reporting code in gfx/thebes/gfxASurface.cpp +# We probably don't care about the frequent overflows there. +fun:*SurfaceMemoryReporter*AdjustUsedMemory* + +# Frequent overflower in gfx/thebes/gfxFontEntry.cpp +fun:*WeightDistance* + +# Another frequent overflower +fun:*nsTObserverArray_base*AdjustIterators* + +# Overflows in Skia +fun:*SkPathRef*makeSpace* +fun:*SkPathRef*resetToSize* + +# Expat Parser has some overflows +fun:*nsExpatDriver*ConsumeToken* + +# Frequent overflowers in harfbuzz +fun:*hb_in_range* +fun:*OT*collect_glyphs* + +# These look like harmless layouting-related overflows +src:*/gfx/cairo/libpixman/src/pixman-region.c + +# Code in ipc/chromium/src/base/file_path.cc where a function returns -1 +# being cast to unsigned and then overflowed. +fun:*FilePath*Append* +fun:*FilePath*StripTrailingSeparatorsInternal* + +# Code in dom/base/nsJSEnvironment.cpp +fun:*FireForgetSkippable* + +# Code in gfx/thebes/gfxSkipChars.h +fun:*gfxSkipCharsIterator*AdvanceSkipped* + +# Code in gfx/thebes/gfxScriptItemizer.cpp +fun:*gfxScriptItemizer*fixup* +fun:*gfxScriptItemizer*push* + +# Code in dom/base/nsDocument.cpp +fun:*nsDocument*BlockOnload* + +# Code in layout/base/nsCSSFrameConstructor.cpp +fun:*nsCSSFrameConstructor*FrameConstructionItemList*AdjustCountsForItem* + +# Code in nsprpub/lib/ds/plarena.c doing ptrdiffs +fun:*PL_ArenaRelease* + +# This file contains a bunch of arithmetic operations on timestamps that +# apparently are allowed to overflow. +src:*/src/widget/SystemTimeConverter.h + +# Code in dom/media/flac/FlacDemuxer.cpp purposely uses overflowing arithmetics +fun:*Frame*FindNext* + +# Code in netwerk/base/nsStandardURL.cpp, +# these methods return signed but the subtraction is first performed unsigned +fun:*nsStandardURL*ReplaceSegment* + +# Code in netwerk/protocol/http/nsHttpChannel.cpp +# same as previous with the previous entry. +fun:*nsHttpChannel*ReportNetVSCacheTelemetry* + +# Code in layout/tables/nsCellMap.cpp +# again subtraction then cast to signed. +fun:*nsTableCellMap*GetColInfoAt* + +# Code in layout/generic/nsTextFrame.cpp +# again subtraction then cast to signed. +fun:*nsTextFrame*CharacterDataChanged* + +# Not sure what is going on in this file, but it doesn't look +# related to what we are looking for. +src:*/xpcom/base/CountingAllocatorBase.h + +# Code in dom/base/nsDOMNavigationTiming.cpp +# Timestamp related, probably expecting the overflow +fun:*nsDOMNavigationTiming*TimeStampToDOM* + +# Several unsigned arithmetic operations with -1 +src:*/hal/HalWakeLock.cpp + +# Code in layout/generic/nsGfxScrollFrame.cpp that produces +# somewhat frequent signed integer overflows. Probably harmless +# because it's layout code. +fun:*ClampAndAlignWithPixels* + +# Likely benign overflow in mozglue/misc/TimeStamp_posix.cpp +fun:*ClockResolutionNs* + +# This header has all sorts of operators that do post-operation +# overflow and underflow checking, triggering frequent reports +src:*/mozglue/misc/TimeStamp.h + +# +# Various hashing functions, both regular and cryptographic ones +# +src:*/dom/canvas/MurmurHash3.cpp +src:*/gfx/skia/skia/include/private/SkChecksum.h +src:*/intl/icu/source/common/unifiedcache.h +src:*/mfbt/SHA1.cpp +src:*/modules/zlib/src/adler32.c +src:*/netwerk/cache2/CacheHashUtils.cpp +src:*/netwerk/sctp/src/netinet/sctp_sha1.c +src:*/netwerk/srtp/src/crypto/hash/sha1.c +src:*/netwerk/sctp/src/netinet/sctp_sha1.c +src:*/nsprpub/lib/ds/plhash.c +src:*/security/manager/ssl/md4.c +src:*/security/nss/lib/dbm/src/h_func.c +src:*/security/nss/lib/freebl/sha512.c +src:*/security/nss/lib/freebl/md5.c +src:*/xpcom/ds/PLDHashTable.cpp + +# Hash/Cache function in Skia +fun:*GradientShaderCache*Build32bitCache* + +# Hashing functions in Cairo +fun:*_hash_matrix_fnv* +fun:*_hash_mix_bits* +fun:*_cairo_hash_string* +fun:*_cairo_hash_bytes* + +# intl code hashing functions +fun:*ustr_hash*CharsN* +fun:*hashEntry* + +# harfbuzz hash/digest functions +fun:*hb_set_digest_lowest_bits_t* + +# Hash function in gfx +fun:*gfxFontStyle*Hash* + +# expat uses a CHAR_HASH macro in several places that causes +# a high amount of overflows. We should try finding a better +# way to disable this rather than blacklisting the whole thing. +src:*/parser/expat/* diff --git a/build/sanitizers/ubsan_unsigned_overflow_blacklist.txt b/build/sanitizers/ubsan_unsigned_overflow_blacklist.txt new file mode 100644 index 0000000000..46bb4f6f12 --- /dev/null +++ b/build/sanitizers/ubsan_unsigned_overflow_blacklist.txt @@ -0,0 +1,264 @@ +# This file contains an extensive compile-time blacklist for silencing highly +# frequent *un*signed integer overflows in our codebase, found by the use of +# -fsanitize=unsigned-integer-overflow. Such overflows are not necessarily +# bugs -- unsigned integer overflow has well-defined semantics in C/C++. But +# overflow may still be *unexpected* and incorrectly handled, so we try to +# annotate those places where unsigned overflow is correct and desired. +# +# The rules in this file are applied at compile time; changes to this list +# usually require a full rebuild to apply. If you can modify the source in +# question to exempt specific functions using MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW, +# do that instead. +# +# The extensive number of entries below is for two reasons. +# +# First, compiler instrumentation for unsigned integer overflows has a cost, at +# compile time and at runtime. In places where code expects and depends upon +# overflow behavior -- and especially in performance-critical code -- it makes +# sense to turn off overflow detection to avoid both costs. (Indeed, +# -fsanitize=signed-integer-overflow is unusably slow without this.) +# +# Second, many entries here are overly aggressive to get the build into a state +# that allows any testing to happen at all. Some of the entries here are for +# issues that are highly frequent in our test suites -- over 500 times per run. +# Aggressive entries now let us start using this mode, without having to first +# fix wide swaths of existing code. +# +# Entries should be removed 1) as issues are fixed; and 2) as blacklist entries +# can be moved out of this centralized file, into source-level blacklist +# attributes on individual functions. + +# All entries in this file are to suppress unsigned-integer-overflow problems. +# Blacklists for other reasons should go in separate blacklist files. +[unsigned-integer-overflow] + +# Overflows in the C++ std headers aren't necessarily bugs, because code inside +# a language implementation can depend on compiler-specific behavior where C/C++ +# leave the behavior undefined. +src:*bits/basic_string.h + +# Assume everything running through CheckedInt.h is ok. The CheckedInt class +# casts signed integers to unsigned first and then does a post-overflow +# check causing lots of unsigned integer overflow messages. +src:*/CheckedInt.h + +# Exclude bignum +src:*/mfbt/double-conversion/source/bignum.cc + +# Exclude anything within gtests +src:*/gtest/* + +# The JS engine has a lot of code doing all sorts of overflows. This code +# is pretty well tested though and excluding it here will allow us to go +# for other, less tested code. Ideally, we would include the JS engine here +# at some point. +src:*/js/src/* +src:*/js/public/* +src:*/js/*.h +src:*/jsfriendapi.h + +# Atomics can overflow, but without a full stack we can't trace these back +# to what is actually causing the overflow. Ignoring these for now, as it will +# be too much effort to determine every single source here. +src:*/mfbt/Atomics.h + +# No reason to instrument certain parts of NSS that explicitely deal with +# arithmetics and crypto. +src:*/security/nss/lib/freebl/mpi/* +src:*/security/nss/lib/freebl/ecl/* + +# nsTArray_base::ShiftData performs overflows +fun:*nsTArray_base*ShiftData* + +### Frequent 0 - 1 overflows +# +# We have several code patterns in our codebase that cause these overflows, +# but they are typically all harmless and could be filtered easily at runtime. +# However, some of them are so frequent that suppressing them at compile-time +# makes sense to increase runtime performance. +# +src:*/netwerk/base/nsSocketTransportService2.cpp +src:*/nsCharTraits.h +# Code in xpcom/base/CycleCollectedJSContext.cpp +fun:*CycleCollectedJSContext*ProcessMetastableStateQueue* +# Code in layout/painting/nsDisplayList.cpp +fun:*nsDisplayOpacity*ShouldFlattenAway* +# Code in modules/libpref/Preferences.cpp +fun:*pref_InitInitialObjects* +# Code in netwerk/base/nsIOService.cpp +fun:*nsIOService*GetCachedProtocolHandler* +# Code in layout/xul/nsXULPopupManager.cpp +fun:*nsXULPopupManager*AdjustPopupsOnWindowChange* +# Code in dom/base/nsDocument.cpp +fun:*1nsDocument@@* +# Code in gfx/layers/ipc/CompositorBridgeChild.cpp +fun:*CompositorBridgeChild*Destroy* +# Code in gfx/layers/ipc/ImageBridgeChild.cpp +fun:*ImageBridgeChild*ShutdownStep1* +# Code in dom/base/nsGlobalWindow.cpp +fun:*nsGlobalWindow*ClearControllers* +# Code in layout/style/AnimationCollection.cpp +fun:*AnimationCollection*PropertyDtor* +# Code in layout/style/nsStyleSet.cpp +fun:*nsStyleSet*AddImportantRules* +fun:*nsStyleSet*CounterStyleRuleForName* + + +### Misc overflows + +# Hot function in protobuf producing overflows +fun:*CodedInputStream*ReadTagWithCutoff* + + +# SQLite3 is full of overflows :/ +src:*/third_party/sqlite3/src/sqlite3.c + +# zlib has some overflows, we can't deal with them right now +src:*/modules/zlib/src/* + +# Our LZ4 implementation uses overflows. By listing it here we might +# miss some unintended overflows in that implementation, but we can't +# check for it right now. +src:*/mfbt/lz4/* + +# Apparently this overflows a lot, because it contains some allocators +# that keep overflowing, not sure why. Disabling by function didn't seem +# to work here for operator new. +src:*/xpcom/ds/nsArrayEnumerator.cpp + +# Memory usage reporting code in gfx/thebes/gfxASurface.cpp +# We probably don't care about the frequent overflows there. +fun:*SurfaceMemoryReporter*AdjustUsedMemory* + +# Frequent overflower in gfx/thebes/gfxFontEntry.cpp +fun:*WeightDistance* + +# Another frequent overflower +fun:*nsTObserverArray_base*AdjustIterators* + +# Overflows in Skia +fun:*SkPathRef*makeSpace* +fun:*SkPathRef*resetToSize* + +# Expat Parser has some overflows +fun:*nsExpatDriver*ConsumeToken* + +# Frequent overflowers in harfbuzz +fun:*hb_in_range* +fun:*OT*collect_glyphs* + +# These look like harmless layouting-related overflows +src:*/gfx/cairo/libpixman/src/pixman-region.c + +# Code in ipc/chromium/src/base/file_path.cc where a function returns -1 +# being cast to unsigned and then overflowed. +fun:*FilePath*Append* +fun:*FilePath*StripTrailingSeparatorsInternal* + +# Code in dom/base/nsJSEnvironment.cpp +fun:*FireForgetSkippable* + +# Code in gfx/thebes/gfxSkipChars.h +fun:*gfxSkipCharsIterator*AdvanceSkipped* + +# Code in gfx/thebes/gfxScriptItemizer.cpp +fun:*gfxScriptItemizer*fixup* +fun:*gfxScriptItemizer*push* + +# Code in dom/base/nsDocument.cpp +fun:*nsDocument*BlockOnload* + +# Code in layout/base/nsCSSFrameConstructor.cpp +fun:*nsCSSFrameConstructor*FrameConstructionItemList*AdjustCountsForItem* + +# Code in nsprpub/lib/ds/plarena.c doing ptrdiffs +fun:*PL_ArenaRelease* + +# This file contains a bunch of arithmetic operations on timestamps that +# apparently are allowed to overflow. +src:*/src/widget/SystemTimeConverter.h + +# Code in dom/media/flac/FlacDemuxer.cpp purposely uses overflowing arithmetics +fun:*Frame*FindNext* + +# Code in netwerk/base/nsStandardURL.cpp, +# these methods return signed but the subtraction is first performed unsigned +fun:*nsStandardURL*ReplaceSegment* + +# Code in netwerk/protocol/http/nsHttpChannel.cpp +# same as previous with the previous entry. +fun:*nsHttpChannel*ReportNetVSCacheTelemetry* + +# Code in layout/tables/nsCellMap.cpp +# again subtraction then cast to signed. +fun:*nsTableCellMap*GetColInfoAt* + +# Code in layout/generic/nsTextFrame.cpp +# again subtraction then cast to signed. +fun:*nsTextFrame*CharacterDataChanged* + +# Not sure what is going on in this file, but it doesn't look +# related to what we are looking for. +src:*/xpcom/base/CountingAllocatorBase.h + +# Code in dom/base/nsDOMNavigationTiming.cpp +# Timestamp related, probably expecting the overflow +fun:*nsDOMNavigationTiming*TimeStampToDOM* + +# Several unsigned arithmetic operations with -1 +src:*/hal/HalWakeLock.cpp + +# Code in layout/generic/nsGfxScrollFrame.cpp that produces +# somewhat frequent signed integer overflows. Probably harmless +# because it's layout code. +fun:*ClampAndAlignWithPixels* + +# Likely benign overflow in mozglue/misc/TimeStamp_posix.cpp +fun:*ClockResolutionNs* + +# This header has all sorts of operators that do post-operation +# overflow and underflow checking, triggering frequent reports +src:*/mozglue/misc/TimeStamp.h + +# +# Various hashing functions, both regular and cryptographic ones +# +src:*/dom/canvas/MurmurHash3.cpp +src:*/gfx/skia/skia/include/private/SkChecksum.h +src:*/intl/icu/source/common/unifiedcache.h +src:*/mfbt/SHA1.cpp +src:*/modules/zlib/src/adler32.c +src:*/netwerk/cache2/CacheHashUtils.cpp +src:*/netwerk/sctp/src/netinet/sctp_sha1.c +src:*/netwerk/srtp/src/crypto/hash/sha1.c +src:*/netwerk/sctp/src/netinet/sctp_sha1.c +src:*/nsprpub/lib/ds/plhash.c +src:*/security/manager/ssl/md4.c +src:*/security/nss/lib/dbm/src/h_func.c +src:*/security/nss/lib/freebl/sha512.c +src:*/security/nss/lib/freebl/md5.c +src:*/xpcom/ds/PLDHashTable.cpp + +# Hash/Cache function in Skia +fun:*GradientShaderCache*Build32bitCache* + +# Hashing functions in Cairo +fun:*_hash_matrix_fnv* +fun:*_hash_mix_bits* +fun:*_cairo_hash_string* +fun:*_cairo_hash_bytes* + +# intl code hashing functions +fun:*ustr_hash*CharsN* +fun:*hashEntry* + +# harfbuzz hash/digest functions +fun:*hb_set_digest_lowest_bits_t* + +# Hash function in gfx +fun:*gfxFontStyle*Hash* + +# expat uses a CHAR_HASH macro in several places that causes +# a high amount of overflows. We should try finding a better +# way to disable this rather than blacklisting the whole thing. +src:*/parser/expat/* diff --git a/build/sparse-profiles/docker-image b/build/sparse-profiles/docker-image new file mode 100644 index 0000000000..9fb1329530 --- /dev/null +++ b/build/sparse-profiles/docker-image @@ -0,0 +1,26 @@ +%include build/sparse-profiles/mach + +[include] +path:taskcluster/ + +# Required for loading taskgraph.parameters. +path:browser/config/version_display.txt +path:browser/config/version.txt + +# Result from `grep -hr %include taskcluster/docker | grep -v " taskcluster/" | sort -u` +path:python/mozbuild/mozbuild/action/tooltool.py +path:testing/mozharness/external_tools/performance-artifact-schema.json +path:testing/mozharness/external_tools/robustcheckout.py +path:tools/lint/spell/codespell_requirements.txt +path:tools/lint/eslint/eslint-plugin-mozilla/manifest.tt +path:tools/lint/eslint/manifest.tt +path:tools/lint/python/flake8_requirements.txt +path:tools/lint/python/pylint_requirements.txt +path:tools/lint/python/black_requirements.txt +path:tools/lint/tox/tox_requirements.txt + +# Required for the webrender docker image +path:gfx/wr/ci-scripts/docker-image/setup.sh + +# for the system-symbol images +path:tools/crashreporter/system-symbols/ diff --git a/build/sparse-profiles/github-sync b/build/sparse-profiles/github-sync new file mode 100644 index 0000000000..72f265b3a1 --- /dev/null +++ b/build/sparse-profiles/github-sync @@ -0,0 +1,7 @@ +%include build/sparse-profiles/mach +%include build/sparse-profiles/taskgraph + +[include] +path:gfx/wr/ +path:taskcluster/scripts/misc/ +path:tools/github-sync/ diff --git a/build/sparse-profiles/mach b/build/sparse-profiles/mach new file mode 100644 index 0000000000..118b79ff8c --- /dev/null +++ b/build/sparse-profiles/mach @@ -0,0 +1,19 @@ +[include] +# Various mach commands call config.guess to resolve the default objdir name. +path:build/autoconf/config.guess +path:build/autoconf/config.sub +path:build/moz.configure/checks.configure +path:build/moz.configure/init.configure +path:build/moz.configure/util.configure +# Used for bootstrapping the mach driver. +path:build/mach_initialize.py +path:build/psutil_requirements.txt +path:build/zstandard_requirements.txt +path:mach +# Various dependencies. There is room to trim fat, especially in +# third_party/python. +path:python/ +path:testing/mozbase/ +path:third_party/python/ +# certifi is needed for Sentry +path:testing/web-platform/tests/tools/third_party/certifi diff --git a/build/sparse-profiles/mozharness b/build/sparse-profiles/mozharness new file mode 100644 index 0000000000..c2a49d412b --- /dev/null +++ b/build/sparse-profiles/mozharness @@ -0,0 +1,4 @@ +%include build/sparse-profiles/mach + +[include] +path:testing/mozharness diff --git a/build/sparse-profiles/perftest b/build/sparse-profiles/perftest new file mode 100644 index 0000000000..abb4d922ab --- /dev/null +++ b/build/sparse-profiles/perftest @@ -0,0 +1,8 @@ +%include build/sparse-profiles/docker-image + +[include] +path:tools/lint/eslint/ +path:testing/performance +path:testing/condprofile +path:python/mozbuild/mozbuild/action/tooltool.py +glob:**/perftest_*.js diff --git a/build/sparse-profiles/profile-generate b/build/sparse-profiles/profile-generate new file mode 100644 index 0000000000..be1fa53372 --- /dev/null +++ b/build/sparse-profiles/profile-generate @@ -0,0 +1,9 @@ +%include build/sparse-profiles/mach + +[include] +path:build/ +path:testing/talos/talos +path:testing/profiles/ +path:third_party/webkit/ +path:tools/quitter/ +path:taskcluster/scripts/misc diff --git a/build/sparse-profiles/push-to-try b/build/sparse-profiles/push-to-try new file mode 100644 index 0000000000..ff8fd73579 --- /dev/null +++ b/build/sparse-profiles/push-to-try @@ -0,0 +1,5 @@ +%include build/sparse-profiles/taskgraph + +[include] +path:tools/tryselect/ +path:try_task_config.json diff --git a/build/sparse-profiles/sphinx-docs b/build/sparse-profiles/sphinx-docs new file mode 100644 index 0000000000..491d18b080 --- /dev/null +++ b/build/sparse-profiles/sphinx-docs @@ -0,0 +1,56 @@ +%include build/sparse-profiles/mach + +[include] +# List of dependencies for the command +path:python/sites/docs.txt + +# Code for generating docs. +glob:docs/** +glob:tools/moztreedocs/** + +# For icons +glob:browser/branding/nightly/** + +# Potential docs sources +glob:**/*.rst +glob:**/*.md +glob:**/*.mjs +glob:**/*.js +glob:**/*.jsm +glob:**/*.json + +# Potential included images. We don't glob all paths in order to avoid importing +# images unrelated to documentation (like branding or test images) +glob:**/docs/**.jpg +glob:**/docs/**.png +glob:**/docs/**.svg +glob:**/docs/**.gif +glob:**/devtools/**.gif +glob:**/devtools-user/**.gif +glob:**/Debugger/**.png +glob:**/Debugger/**.svg + +# Include everything found in the perfdocs generated folder +glob:testing/perfdocs/generated/** + +# Python API docs. +glob:**/*.py +# Referenced by some python files. +path:taskcluster/ci/docker-image/kind.yml + +# Included in ipc docs +path:ipc/ipdl/test/ipdl/ok/PMyManaged.ipdl +path:ipc/ipdl/test/ipdl/ok/PMyManager.ipdl +path:ipc/ipdl/test/ipdl/ok/MyTypes.ipdlh + +# moz.build files are read to discover location of docs. +glob:**/moz.build + +# package*.json files are needed for node_modules +glob:**/package*.json + +# Read to set the version of the docs. +path:config/milestone.txt + +# mots configuration +path:mots.yaml diff --git a/build/sparse-profiles/startup-test b/build/sparse-profiles/startup-test new file mode 100644 index 0000000000..fd73995d86 --- /dev/null +++ b/build/sparse-profiles/startup-test @@ -0,0 +1,6 @@ +%include build/sparse-profiles/mozharness + +[include] +# for fetch-content +path:taskcluster/scripts/misc/ + diff --git a/build/sparse-profiles/taskgraph b/build/sparse-profiles/taskgraph new file mode 100644 index 0000000000..e2974b80e5 --- /dev/null +++ b/build/sparse-profiles/taskgraph @@ -0,0 +1,94 @@ +%include build/sparse-profiles/mach + +# In order to decide which docker images to build, we need all the +# files that docker images depend on as well +%include build/sparse-profiles/docker-image + +[include] +# These files are read as part of generating the taskgraph. +path:browser/locales/l10n-changesets.json +path:browser/locales/l10n-onchange-changesets.json +path:mobile/locales/l10n-changesets.json +path:mobile/locales/l10n-onchange-changesets.json +path:browser/locales/shipped-locales +path:browser/config/version_display.txt +path:browser/config/version.txt +path:browser/config/whats_new_page.yml +path:browser/installer/attribution.yml + +# Lots of random files in here are read. Just pull in the whole thing. +path:build/ + +# TODO remove once bug 1402010 is resolved and test manifests aren't +# processed in Files() reading mode in moz.build files. +path:layout/tools/reftest/ +path:testing/web-platform/tests/tools/ + +# The main meat of this profile. +path:taskcluster/ + +# Various files in these directories are read by taskgraph. Just pull +# them all in. +path:testing/config/tooltool-manifests/ +path:testing/mozharness/ +path:tools/lint/ + +# for new-style try pushes +path:try_task_config.json + +# Moz.build files are read in filesystem mode +glob:**/moz.build +glob:**/*.mozbuild + +# Moz.configure files could trigger changes +glob:**/*.configure + +# Tooltool manifests also need to be opened. Assume they +# are all somewhere in "tooltool-manifests" directories. +glob:**/tooltool-manifests/** + +# For test chunking +glob:**/*.ini +glob:**/*.list +glob:**/*.toml +path:testing/mozbase/manifestparser +path:testing/runtimes +path:testing/web-platform/tests/ +path:testing/web-platform/mozilla/tests/ +glob:testing/web-platform/*.py + +# For scheduling android-gradle-dependencies. +path:mobile/android/config/ +glob:**/*.gradle + +# for action-task building +path:.taskcluster.yml +path:.cron.yml + +# for the wrench-deps toolchain task +path:gfx/wr/Cargo.lock +path:gfx/wr/ci-scripts/ + +# for the mar-tools toolchain task +path:mfbt/ +path:modules/libmar/ +path:other-licenses/bsdiff/ +path:other-licenses/nsis/Contrib/CityHash/cityhash/ +path:toolkit/mozapps/update/updater + +# for the minidump-stackwalk toolchain task +path:toolkit/crashreporter +path:tools/crashreporter/ +path:mfbt +path:config/external/zlib +path:build/moz.configure + +# for the browsertime toolchain task +path:tools/browsertime/mach_commands.py +path:tools/browsertime/package.json +path:tools/browsertime/package-lock.json + +# for the geckodriver toolchain task +path:testing/geckodriver +path:testing/mozbase/rust +path:testing/webdriver diff --git a/build/sparse-profiles/toolchain-build b/build/sparse-profiles/toolchain-build new file mode 100644 index 0000000000..fe542dd219 --- /dev/null +++ b/build/sparse-profiles/toolchain-build @@ -0,0 +1,9 @@ +# Profile needed to build toolchain tasks. + +# This is probably a little wider than we need it to be. But it is +# still relatively small and it keeps this profile simple. +%include build/sparse-profiles/taskgraph + +[include] +# Needed by build-clang.py. +path:tools/rewriting/ \ No newline at end of file diff --git a/build/sparse-profiles/tps b/build/sparse-profiles/tps new file mode 100644 index 0000000000..fe9b238f90 --- /dev/null +++ b/build/sparse-profiles/tps @@ -0,0 +1,5 @@ +%include build/sparse-profiles/mach + +[include] +path:services/sync/tps/ +path:testing/tps/ diff --git a/build/sparse-profiles/update-verify b/build/sparse-profiles/update-verify new file mode 100644 index 0000000000..83589d1f3b --- /dev/null +++ b/build/sparse-profiles/update-verify @@ -0,0 +1,4 @@ +%include build/sparse-profiles/mach + +[include] +path:tools/update-verify/ diff --git a/build/sparse-profiles/upload-generated-sources b/build/sparse-profiles/upload-generated-sources new file mode 100644 index 0000000000..3e39d32b66 --- /dev/null +++ b/build/sparse-profiles/upload-generated-sources @@ -0,0 +1,4 @@ +%include build/sparse-profiles/mach + +[include] +path:build/upload_generated_sources.py diff --git a/build/sparse-profiles/upload-symbols b/build/sparse-profiles/upload-symbols new file mode 100644 index 0000000000..1b46f04f99 --- /dev/null +++ b/build/sparse-profiles/upload-symbols @@ -0,0 +1,4 @@ +%include build/sparse-profiles/mach + +[include] +path:toolkit/crashreporter/tools/upload_symbols.py diff --git a/build/sparse-profiles/webrender b/build/sparse-profiles/webrender new file mode 100644 index 0000000000..3ed69aa3b1 --- /dev/null +++ b/build/sparse-profiles/webrender @@ -0,0 +1,7 @@ +%include build/sparse-profiles/mach +%include build/sparse-profiles/taskgraph + +[include] +path:gfx/wr/ +path:taskcluster/scripts/misc/ +path:xpcom/rust/ diff --git a/build/templates.mozbuild b/build/templates.mozbuild new file mode 100644 index 0000000000..811b96bb7e --- /dev/null +++ b/build/templates.mozbuild @@ -0,0 +1,237 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +@template +def Binary(): + """Generic template for target binaries. Meant to be used by other + templates.""" + + # Add -llog by default, since we use it all over the place. + if CONFIG["OS_TARGET"] == "Android": + OS_LIBS += ["log"] + + +@template +def Program(name): + """Template for program executables.""" + PROGRAM = name + + Binary() + + +@template +def SimplePrograms(names, ext=".cpp"): + """Template for simple program executables. + + Those have a single source with the same base name as the executable. + """ + SIMPLE_PROGRAMS += names + SOURCES += ["%s%s" % (name, ext) for name in names] + + Binary() + + +@template +def CppUnitTests(names, ext=".cpp"): + """Template for C++ unit tests. + + Those have a single source with the same base name as the executable. + """ + COMPILE_FLAGS["EXTRA_INCLUDES"] = [ + "-I%s/dist/include" % TOPOBJDIR, + "-I%s/dist/include/testing" % TOPOBJDIR, + ] + CPP_UNIT_TESTS += names + SOURCES += ["%s%s" % (name, ext) for name in names] + + Binary() + + +@template +def Library(name): + """Template for libraries.""" + LIBRARY_NAME = name + + +@template +def AllowCompilerWarnings(): + COMPILE_FLAGS["WARNINGS_AS_ERRORS"] = [] + WASM_FLAGS["WARNINGS_AS_ERRORS"] = [] + + +@template +def DisableCompilerWarnings(): + # Keep the -Wno-* flags to disable warnings that may be enabled through other means. + def filter(flags): + return [f for f in flags or [] if f.startswith("-Wno-")] + + COMPILE_FLAGS["WARNINGS_CFLAGS"] = filter(CONFIG["WARNINGS_CFLAGS"]) + COMPILE_FLAGS["WARNINGS_CXXFLAGS"] = filter(CONFIG["WARNINGS_CXXFLAGS"]) + HOST_COMPILE_FLAGS["WARNINGS_CFLAGS"] = filter(CONFIG["WARNINGS_HOST_CFLAGS"]) + HOST_COMPILE_FLAGS["WARNINGS_CXXFLAGS"] = filter(CONFIG["WARNINGS_HOST_CXXFLAGS"]) + + +@template +def RustLibrary(name, features=None, output_category=None, is_gkrust=False): + """Template for Rust libraries.""" + Library(name) + + IS_RUST_LIBRARY = True + # Some Rust build scripts compile C/C++ sources, don't error on warnings for them. + AllowCompilerWarnings() + + # And furthermore, don't even show warnings for them, so they don't regress + # the Compiler Warnings build metric + # . + DisableCompilerWarnings() + + if features: + RUST_LIBRARY_FEATURES = features + + if output_category: + RUST_LIBRARY_OUTPUT_CATEGORY = output_category + + if is_gkrust: + IS_GKRUST = True + + +@template +def SharedLibrary(name, output_category=None): + """Template for shared libraries.""" + Library(name) + + FORCE_SHARED_LIB = True + + if output_category: + SHARED_LIBRARY_OUTPUT_CATEGORY = output_category + + Binary() + + +@template +def Framework(name, output_category=None): + """Template for OSX Frameworks.""" + SharedLibrary(name, output_category) + + IS_FRAMEWORK = True + + +@template +def HostProgram(name): + """Template for build tools executables.""" + HOST_PROGRAM = name + + +@template +def HostSimplePrograms(names, ext=".cpp"): + """Template for simple build tools executables. + + Those have a single source with the same base name as the executable. + """ + HOST_SIMPLE_PROGRAMS += names + HOST_SOURCES += ["%s%s" % (name.replace("host_", ""), ext) for name in names] + + +@template +def HostSharedLibrary(name): + """Template for build tools libraries.""" + if name != "clang-plugin": + error( + "Please make sure host shared library support is complete " + "before using for something else than the clang plugin" + ) + + HOST_LIBRARY_NAME = name + + FORCE_SHARED_LIB = True + + +@template +def HostLibrary(name): + """Template for build tools libraries.""" + HOST_LIBRARY_NAME = name + + +@template +def HostRustLibrary(name, features=None): + """Template for host Rust libraries.""" + HostLibrary(name) + + IS_RUST_LIBRARY = True + # Some Rust build scripts compile C/C++ sources, don't error on warnings for them. + AllowCompilerWarnings() + + if features: + HOST_RUST_LIBRARY_FEATURES = features + + +@template +def DisableStlWrapping(): + COMPILE_FLAGS["STL"] = [] + + +@template +def NoVisibilityFlags(): + COMPILE_FLAGS["VISIBILITY"] = [] + + +@template +def ForceInclude(*headers): + """Force includes a set of header files in C++ compilations""" + if CONFIG["CC_TYPE"] == "clang-cl": + include_flag = "-FI" + else: + include_flag = "-include" + for header in headers: + CXXFLAGS += [include_flag, header] + + +@template +def GeneratedFile(name, *names, **kwargs): + """Add one or more GENERATED_FILES with the given attributes. + + You must pass in at least one generated file (the "name" argument). Other + names can be included as positional arguments after "name".""" + script = kwargs.pop("script", None) + entry_point = kwargs.pop("entry_point", None) + inputs = kwargs.pop("inputs", []) + flags = kwargs.pop("flags", []) + force = kwargs.pop("force", False) + if kwargs: + error("Unrecognized argument(s) to GeneratedFile: %s" % ", ".join(kwargs)) + if entry_point and not script: + error("entry_point cannot be provided if script is not provided") + if script and ":" in script: + error( + "script should not include a `:`. If you want to provide an " + "alternative entry point for your script, use the entry_point " + "parameter." + ) + + key = (name,) + names if names else name + GENERATED_FILES += [key] + generated_file = GENERATED_FILES[key] + if script and not entry_point: + generated_file.script = script + if script and entry_point: + generated_file.script = script + ":" + entry_point + generated_file.inputs = inputs + generated_file.flags = flags + generated_file.force = force + + +@template +def CbindgenHeader(name, inputs): + """Add one GENERATED_FILES by running RunCbindgen.py""" + + inputs = ["!/config/cbindgen-metadata.json"] + inputs + GeneratedFile( + name, script="/build/RunCbindgen.py", entry_point="generate", inputs=inputs + ) + + +include("gecko_templates.mozbuild") diff --git a/build/tests/cram/cram.toml b/build/tests/cram/cram.toml new file mode 100644 index 0000000000..99a5883548 --- /dev/null +++ b/build/tests/cram/cram.toml @@ -0,0 +1 @@ +["test_configure_help.t"] diff --git a/build/tests/cram/test_configure_help.t b/build/tests/cram/test_configure_help.t new file mode 100644 index 0000000000..f606991260 --- /dev/null +++ b/build/tests/cram/test_configure_help.t @@ -0,0 +1,14 @@ +configure --help works + + $ cd $TESTDIR/../../.. + + $ touch $TMP/mozconfig + $ export MOZCONFIG=$TMP/mozconfig + $ ./configure --help 2>& 1 | head -n 7 + Adding configure options from */tmp/mozconfig (glob) + checking for vcs source checkout... hg + checking for vcs source checkout... hg + Usage: configure.py [options] + + Options: [defaults in brackets after descriptions] + --help print this message diff --git a/build/unix/aix.exp b/build/unix/aix.exp new file mode 100644 index 0000000000..20f7cb4313 --- /dev/null +++ b/build/unix/aix.exp @@ -0,0 +1,5 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +NSGetModule diff --git a/build/unix/build-binutils/3A24BC1E8FB409FA9F14371813FCEF89DD9E3C4F.key b/build/unix/build-binutils/3A24BC1E8FB409FA9F14371813FCEF89DD9E3C4F.key new file mode 100644 index 0000000000..a76485a9fc --- /dev/null +++ b/build/unix/build-binutils/3A24BC1E8FB409FA9F14371813FCEF89DD9E3C4F.key @@ -0,0 +1,51 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFm/2cUBEADkvRqMWfAryJ52T4J/640Av5cam9ojdFih9MjcX7QWFxIzJfTF +Yq2z+nb4omdfZosdCJL2zGcn6C0AxpHNvxR9HMDkEyFHKrjDh4xWU+pH4z9azQEq +Jh331X7UzbZldqQo16VkuVavgsTJaHcXm+nGIBTcUbl2oiTtHhmuaYxx6JTMcFjC +7vyO5mLBw78wt52HBYweJ0NjHBvvH/JxbAAULSPRUC61K0exlO49VFbFETQNG1hZ +TKEji95fPbre7PpXQ0ewQShUgttEE/J3UA4jYaF9lOcZgUzbA27xTV//KomP0D30 +yr4e4EJEJYYNKa3hofTEHDXeeNgM25tprhBUMdbVRZpf2Keuk2uDVwc+EiOVri48 +rb1NU+60sOXvoGO6Ks81+mhAGmrBrlgLhAp8K1HPHI4MG4gHnrMqX2rEGUGRPFjC +3qqVVlPm8H05PnosNqDLQ1Pf7C0pVgsCx6hKQB7Y1qBui7aoj9zeFaQgpYef+CEE +RIKEcWwrjaOJwK3pi9HFdxS0NNWYZj8HPzz/AsgTTQdsbulPlVq2SsctmOnL42CZ +OCTppGYwl53CG/EqVY+UQBzFzJBaY8TJRFFYVEy5/HH4H11rMoZwqIkk71EOGU3X +6mWlANRikR3M4GhVITRzuaV69Fed+OeXcCmP94ASLfuhBR2uynmcHpBKpwARAQAB +tDtOaWNrIENsaWZ0b24gKENoaWVmIEJpbnV0aWxzIE1haW50YWluZXIpIDxuaWNr +Y0ByZWRoYXQuY29tPokCOAQTAQIAIgUCWb/ZxQIbAwYLCQgHAwIGFQgCCQoLBBYC +AwECHgECF4AACgkQE/zvid2ePE9cOxAA3cX1bdDaTFttTqukdPXLCtD2aNwJos4v +B4LYPSgugLkYaHIQH9d1NQPhS0TlUeovnFNESLaVsoihv0YmBUCyL4jE52FRoTjE +6fUhYkFNqIWN2HYwkVrSap2UUJFquRVoVbPkbSup8P+D8eydBbdxsY6f+5E8Rtz5 +ibVnPZTib7CyqnFokJITWjzGdIP0Gn+JWVa6jtHTImWx1MtqiuVRDapUhrIoUIjf +98HQn9/N5ylEFYQTw7tzaJNWeGUoGYS8+8n/0sNbuYQUU/zwMVY9wpJcrXaas6yZ +XGpF/tua59t9LFCct+07YAUSWyaBXqBW3PKQz7QP+oE8yje91XrhOQam04eJhPIB +LO88g6/UrdKaY7evBB8bJ76Zpn1yqsYOXwAxifD0gDcRTQcB2s5MYXYmizn2GoUm +1MnCJeAfQCi/YMobR+c8xEEkRU83Tnnw3pmAbRU6OcPihEFuK/+SOMKIuV1QWmjk +bAr4g9XeXvaN+TRJ9Hl/k1k/sj+uOfyGIaFzM/fpaLmFk8vHeej4i2/C6cL4mnah +wYBDHAfHO65ZUIBAssdA6AeJ+PGsYeYhqs6zkpaA2b0wT4f9s7BPSqi0Veky8bUY +YY7WpjzDcHnj1gEeIU55EhOQ42dnEfv7WrIAXanOP8SjhgqAUkb3R88azZCpEMTH +iCE4bFxzOmi5Ag0EWb/ZxQEQALaJE/3u23rTvPLkitaTJFqKkwPVylzkwmKdvd2q +eEFk1qys2J3tACTMyYVnYTSXy5EJH2zJyhUfLnhLp8jJZF4oU5QehOaJPcMmzI/C +ZS1AmH+jnm6pukdZAowTzJyt4IKSapr+7mxcxX1YQ2XewMnFYpLkAA2dHaChLSU/ +EHJXe3+O4DgEURTFMa3SRN/J4GNMBacKXnMSSYylI5DcIOZ/v0IGa5MAXHrP1Hwm +1rBmloIcgmzexczBf+IcWgCLThyFPffv+2pfLK1XaS82OzBC7fS01pB/eDOkjQuK +y16sKZX6Rt57vud40uE5a0lpyItC2P7u7QWL4yT5pMF+oS8bm3YWgEntV380RyZp +qgJGZTZLNq2T4ZgfiaueEV4JzOnG2/QRGjOUrNQaYzKy5V127CTnRg4BYF/uLEmi +zLcI3O3U1+mEz6h48wkAojO1B6AZ8Lm+JuxOW5ouGcrkTEuIG56GcDwMWS/Pw/vN +sDyNmOCjy9eEKWJgmMmLaq59HpfTd8IOeaYyuAQHAsYt/zzKy0giMgjhCQtuc99E +4nQE9KZ44DKsnqRabK9s3zYE3PIkCFIEZcUiJXSXWWOIdJ43j+YyFHU5hqXfECM6 +rzKGBeBUGTzyWcOX6YwRM4LzQDVJwYG8cVfth+v4/ImcXR43D4WVxxBEAjKag02b ++1yfABEBAAGJAh8EGAECAAkFAlm/2cUCGwwACgkQE/zvid2ePE/dqQ/6ApUwgsZz +tps0MOdRddjPwz44pWXS5MG45irMQXELGQyxkrafc8lwHeABYstoK8dpopTcJGE3 +dZGL3JNz1YWxQ5AV4uyqBn5N8RubcA8NzR6DQP+OGPIwzMketvVC/cbbKDZqf0uT +Dy3jP65OFhSkTEIynYv1Mb4JJl3Sq+haUbfWLAV5nboSuHmiZE6Bz2+TjdoVkNwH +Bfpqxu6MlWka+P98SUcmY8iVhPy9QC1XFOGdFDFf1kYgHW27mFwds35NQhNARgft +AVz9FZXruW6tFIIfisjr3rVjD9R8VgL7l5vMr9ylOFpepnI6+wd2X1566HW7F1Zw +1DIrY2NHL7kL5635bHrJY4n7o/n7Elk/Ca/MAqzdIZxz6orfXeImsqZ6ODn4Y47P +ToS3Tr3bMNN9N6tmOPQZkJGHDBExbhAi/Jp8fpWxMmpVCUl6c85cOBCR4s8tZsvG +YOjR3CvqKrX4bb8GElrhOvAJa6DdmZXc7AyoVMaTvhpq3gJYKmC64oqt7zwIHwaC +xTbP6C6oUp9ENRV7nHnXN3BlvIgCo4QEs6HkDzkmgYlCEOKBiDyVMSkPDZdsspa+ +K4GlU2Swi/BDJMjtDxyo+K0M81LXXxOeRfEIfPtZ3ddxBKPva1uSsuz+pbN9d1JY +8Ko5T/h16susi2ReUyNJEJaSnjO5z13TQ1U= +=93P0 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/build/unix/build-binutils/build-binutils.sh b/build/unix/build-binutils/build-binutils.sh new file mode 100755 index 0000000000..338a9dd29a --- /dev/null +++ b/build/unix/build-binutils/build-binutils.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +set -x + +make_flags="-j$(nproc) MAKEINFO=true" + +root_dir="$1" + +cd $root_dir/binutils-source + +patch -p1 <<'EOF' +From 4476cc67e657d6b26cd453c555a611f1ab956660 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Thu, 30 Aug 2018 09:21:57 -0700 +Subject: [PATCH] ld: Lookup section in output with the same name + +When there are more than one input sections with the same section name, +SECNAME, linker picks the first one to define __start_SECNAME and +__stop_SECNAME symbols. When the first input section is removed by +comdat group, we need to check if there is still an output section +with section name SECNAME. + + PR ld/23591 + * ldlang.c (undef_start_stop): Lookup section in output with + the same name. +--- + ld/ldlang.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/ld/ldlang.c b/ld/ldlang.c +index 8878ccd..d644b56 100644 +--- a/ld/ldlang.c ++++ b/ld/ldlang.c +@@ -6097,6 +6097,24 @@ undef_start_stop (struct bfd_link_hash_entry *h) + || strcmp (h->u.def.section->name, + h->u.def.section->output_section->name) != 0) + { ++ asection *sec = bfd_get_section_by_name (link_info.output_bfd, ++ h->u.def.section->name); ++ if (sec != NULL) ++ { ++ /* When there are more than one input sections with the same ++ section name, SECNAME, linker picks the first one to define ++ __start_SECNAME and __stop_SECNAME symbols. When the first ++ input section is removed by comdat group, we need to check ++ if there is still an output section with section name ++ SECNAME. */ ++ asection *i; ++ for (i = sec->map_head.s; i != NULL; i = i->map_head.s) ++ if (strcmp (h->u.def.section->name, i->name) == 0) ++ { ++ h->u.def.section = i; ++ return; ++ } ++ } + h->type = bfd_link_hash_undefined; + h->u.undef.abfd = NULL; + } +-- +2.17.1 +EOF + +cd .. + +TARGETS="aarch64-linux-gnu arm-linux-gnueabi i686-w64-mingw32" + +gcc_major=8 +if [ -d $MOZ_FETCHES_DIR/sysroot ]; then + # Don't silently use a non-existing directory for C++ headers. + [ -d $MOZ_FETCHES_DIR/sysroot/usr/include/c++/$gcc_major ] || exit 1 + export CFLAGS="-g -O2 --sysroot=$MOZ_FETCHES_DIR/sysroot" + export CXXFLAGS="$CFLAGS -isystem $MOZ_FETCHES_DIR/sysroot/usr/include/c++/$gcc_major -isystem $MOZ_FETCHES_DIR/sysroot/usr/include/x86_64-linux-gnu/c++/$gcc_major" + export LDFLAGS="-L$MOZ_FETCHES_DIR/sysroot/lib/x86_64-linux-gnu -L$MOZ_FETCHES_DIR/sysroot/usr/lib/x86_64-linux-gnu -L$MOZ_FETCHES_DIR/sysroot/usr/lib/gcc/x86_64-linux-gnu/8" +fi + + +# Build target-specific GNU as ; build them first so that the few documentation +# files they install are overwritten by the full binutils build. + +for target in $TARGETS; do + + mkdir binutils-$target + cd binutils-$target + + ../binutils-source/configure --prefix /tools/binutils/ --disable-gold --disable-ld --disable-binutils --disable-gprof --disable-nls --target=$target $EXTRA_CONFIGURE_FLAGS || exit 1 + make $make_flags || exit 1 + make install $make_flags DESTDIR=$root_dir || exit 1 + + cd .. +done + +# Build binutils +mkdir binutils-objdir +cd binutils-objdir + +# --enable-targets builds extra target support in ld. +# Enabling aarch64 support brings in arm support, so we don't need to specify that too. +../binutils-source/configure --prefix /tools/binutils/ --enable-gold --enable-plugins --disable-nls --enable-targets="$TARGETS" $EXTRA_CONFIGURE_FLAGS || exit 1 +make $make_flags || exit 1 +make install $make_flags DESTDIR=$root_dir || exit 1 + +cd .. + +# Make a package of the built binutils +cd $root_dir/tools +tar caf $root_dir/binutils.tar.zst binutils/ diff --git a/build/unix/build-gcc/07F3DBBECC1A39605078094D980C197698C3739D.key b/build/unix/build-gcc/07F3DBBECC1A39605078094D980C197698C3739D.key new file mode 100644 index 0000000000..d78c28c2e6 --- /dev/null +++ b/build/unix/build-gcc/07F3DBBECC1A39605078094D980C197698C3739D.key @@ -0,0 +1,53 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGiBDpu6yARBACaqhVMzAymKhrUcY1uR1pjYxM5LSuYq6mmCPTNwlGRV5RqQL0p +uXrYlfofu8xsKiVuUKk+Dx5aJT6SDxMNkfogPGMgHK8iCaHiMrw4nTtvrJDaoxDo +k0k62fBa8pGv7N7G0FqfkpBS/x+SDNcgWGgsJugFgqetAiaHIVD4A2tRawCgt72R +OX0StnDnwQFxovV0pIy5ka8D/14GxPLs4qTGWWA6B8mycT67/isaAshq9eJKxZVq +M+0rjSRmhMO0/Ajl4PjzjJXA3PH0H8dTyYSkERjEKQ0McjVLmiTM9SYBtCdkra8Q +Fc+zTPqwjX3AayK5DocfHJ2GRhBXNb2DCdznX4A9zFCssb3FLYE/ZCDqwvrQWH6i +dobAA/0ftbhPLtpZnpgGq1InjDzsvEqHEEt97k/iiQxsRH0/52vLD6ZQaENOlDVt +WulDu3gI+TjI1YgGQq8B7VzW6wRR5JW3Gx9emjP3oTVjTz0bmyuaICyetldfu+yZ +A92SU7Wm4NiMMORB+KkMDfveEWT/XW35mMTJdjpgkQH9KgrEI7QkVmluY2VudCBM +ZWZldnJlIDx2aW5jZW50QHZpbmMxNy5uZXQ+iGIEExECACIFAksWVb0CGyMGCwkI +BwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEJgMGXaYw3OdKBwAn1gsYIqfmX7cFPVP +bRrQo44e7rZFAJ0RqZAd7PDqT0WectbqGWuaugerf4hlBBMRAgAlAhsjBgsJCAcD +AgYVCAIJCgsEFgIDAQIeAQIXgAUCS/PnRQIZAQAKCRCYDBl2mMNznXR7AJ9gDnrA +LCJfyqRjfVBP6aF4JfzxbQCfTXAAEbnlEhBECqgYF/S8ZjNJD8WIVgQTEQIAFgQL +CgQDAxUDAgMWAgECF4AFAkvz5lEACgkQmAwZdpjDc50eRwCgsQeoNoSgrDpFmfIy +gsU7a5qhqR0AoLQWp2fHpmlNhYua+A8HVxBjoyKJiFYEExECABYFAjpu6yAECwoE +AwMVAwIDFgIBAheAAAoJEJgMGXaYw3OdSgQAnRfkXJVySd9AhQYiMX0iIDqfiGRj +AJ4pLPdp4VvVBPloIt4SN2E559kNRIhZBBMRAgAZBAsKBAMDFQMCAxYCAQIXgAUC +SCGibQIZAQAKCRCYDBl2mMNznduQAJoCD5vaJOLGEO605eNKXTXRt2ygvwCfSNHR +RgaYU+5YIWf3zteNWBxC0K6IYgQTEQIAIgIbIwYLCQgHAwIGFQgCCQoLBBYCAwEC +HgECF4AFAkvz50AACgkQmAwZdpjDc534tACggJHDY3pXzW1T8vDLeysKNIVBkukA +nj6WfWlDjvVSGkZDfcJyhvBXDzsZiGIEExECACIFAksWVd8CGyMGCwkIBwMCBhUI +AgkKCwQWAgMBAh4BAheAAAoJEJgMGXaYw3Od6mYAn0JipNlCsSpyet3FelnGFWS0 +2eDzAJ9SFzy6w0IgIdJJdO0Y6/BAzq+jsIhgBBMRAgAgBQJIIaFtAhsjBgsJCAcD +AgQVAggDBBYCAwECHgECF4AACgkQmAwZdpjDc53gqACffa9gv0J/e9JEt6IFLkYY +fRmbt/YAnirKbsByzSvS0csLhOFx/uOA+qB5iGAEExECACACGyMGCwkIBwMCBBUC +CAMEFgIDAQIeAQIXgAUCSCGiaAAKCRCYDBl2mMNznfLyAKCqhRZQegYMDYoJ9Po+ +5RxOHteSlwCfVARE7QYuaEPWdRGE3hEI6l1rhRqIYAQTEQIAIAUCSCGenwIbIwYL +CQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEJgMGXaYw3OdNQYAn2/gJ1CdC6tTo1O3 +cc4GD+MG9227AJsEi9hD8xkIJqS9J/7KCpy6Cm+h9IhgBBMRAgAgBQJIIaGEAhsj +BgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQmAwZdpjDc52c8gCeNpU/yisNGveb +z10ifoz6d03XvyAAn3hNIG8aCemLdPgmHGdhATqTJcGmiGAEExECACAFAkghnsAC +GyMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRCYDBl2mMNznbGYAJ42N2JMtPSn +kVn4qVPHUc7WOU3YCACdFgBS10cg1wzkTF40k8PKy5IKnVOIYAQTEQIAIAUCSCGh +oAIbIwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEJgMGXaYw3OdvAwAn3Lux4sL ++FNQGaFKviI+4GG+1BlIAKCGu8WiBKIsUjxC98SjMVG+4xN16rkCDQQ6butMEAgA +gUyl/BQ0OA7B/GSDdx6J/wjS/S4QDx7ZehgigOhJAA74e1rUqeFykb1sqxxkKnCy +AOSqHu2BQXqk7G7ozor5bU8eE6Rki7H6Vf734TprsQgYqPrztgcVxL2InRHcMw8I +GMZZKhWbSzKST6XaEg7Yxy7pkvNhl29bc9scWNjOCxkUt6L9wtp2UEZQf5bL41k1 +A7B1/dGOAe+DOX64x2lNYAlry3f7WV7Yq99YgcFy+V+o2wW5OBb/404x8DIm7bKT +zBiOO1QNNe8vGJAEf1lAhldPE03T9aNNXr0tHytLcDsQbHkbnsJELtY6C2AQiAKy +thMo1OVC+y0+Kr3JMFfumwADBQf8CiymrdhZGEZYsgJfpih+eaoBVgnlY6lHx1bQ +Ovfol4x7B+szlNtHjA+r3PV9uPsrxa6J5qT31iPPHgwu1utTJ8tQov9OpXvEB/2J +8DV8lYzTMpAB/GKoDUFZEGc4q+BQAvTfYYv+6WKoFjRL6iKt+Qb6WyonjG6ViPeb +IURoMP6eE7wPFCVwK8xWHvB32jdf+ni9a2XuE9bLkF8pHcC2pz0gi7vIk88FPo8E +ypKTL5MjC0/7+nYK9K45PZwmWNO0m5BooyP6ddGP0xJq8gisZuSWAFW3I+SW5DyP +nvxpOXCzSj0vCHuHvDbdsUArdNWUTpxw5k3XvAIxPLMBsFK3qIhGBBgRAgAGBQI6 +butMAAoJEJgMGXaYw3OdiYYAn2SsLZg3Cj2Rg7ZziZ01NE5QpP5CAKCLyZeqvx28 +Lt44/DBv052TOb47tw== +=ERlK +-----END PGP PUBLIC KEY BLOCK----- diff --git a/build/unix/build-gcc/13975A70E63C361C73AE69EF6EEB81F8981C74C7.key b/build/unix/build-gcc/13975A70E63C361C73AE69EF6EEB81F8981C74C7.key new file mode 100644 index 0000000000..53591cf752 --- /dev/null +++ b/build/unix/build-gcc/13975A70E63C361C73AE69EF6EEB81F8981C74C7.key @@ -0,0 +1,82 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGiBDs4dV0RBACZII57dgbfnCC7RTrJ1yc0F1ofEZJJ/x4tAtSHMDNj2zTnLR25 +5AHmxN85namwJdn7ixXSZv1FMPCeTs6jDk98YuA9r5uuCNPqCNZsuQtREpN7h+wO +IeRrhvg9/F11mty/5NthXNh8P2ELnkWXSHu6DvTQyGppAtxueOL0CjRrpwCggVYu +vxui5mqNq9+lILbMi2Zm3UkD/0T/0HupthZFXbuzY/h/nyqzoPOxnSAAAx6N7SiE +2w9OQ1w3K8WOFoPH9P0cnIQ+KnMSGQV4C2WY/d8YtShnKkXRYZVvlK+aiwmvf1kU +yNyUqaA/GhW5FWN26zFQc3G5Y9TDjgBqjd6SequZztK5M5cknJGJn+otpdQtA1Dx +2KEABACSYjdRNT3OvQJ7OSz4x4C58JKz/P69WsNZxqYVo66P7PGxM7V2GykFPbG7 +agyEMWP1alvUK551IamVtXN+mD7h3uwi5Er0cFBBfV8bSLjmhSchVpyQpiMe2iAr +IFeWox7IUp3zoT35/CP4xMu5l8pza61U5+hK3G7ud5ZQzVvh8bQrUmljaGFyZCBH +dWVudGhlciAoV29yaykgPHJndWVudGhlckBzdXNlLmRlPohfBBMRAgAfBQJDJvJg +AhsDBwsJCAcDAgEDFQIDAxYCAQIeAQIXgAAKCRBu64H4mBx0x0IPAJ9OiDKdHqdX +2ETKcxD78PcKDCcg6gCfWuJ6TizPW0n5vV16NMKl74j528aIYgQTEQIAIgIbAwIe +AQIXgAUCVmLemAYLCQgHAwIGFQgCCQoLBBYCAwEACgkQbuuB+JgcdMdosgCeLZi7 +4DbKYbK6Sinww8ldLc0eRbgAnjcppbTLIHxcr6Lngb44v4fh8jm5iF8EExECAB8F +AkMm8uECGwMHCwkIBwMCAQMVAgMDFgIBAh4BAheAAAoJEG7rgfiYHHTHTcoAn0/u +FvF25feqywtGPSpL6gQ+VQZiAJ42Q8zMLMqHxd5g0e3L7mrag7EgVIhiBBMRAgAi +AhsDAh4BAheABQJWYt6YBgsJCAcDAgYVCAIJCgsEFgIDAQAKCRBu64H4mBx0x14N +AJ9lFQUMIHywsroHrCpGbAKxvcQrowCeNIbpm2Ct0SNJBKZ8BwhX/1bfrsyIXwQT +EQIAHwUCQybzCQIbAwcLCQgHAwIBAxUCAwMWAgECHgECF4AACgkQbuuB+JgcdMeg +1gCff0P5UUkRXbj/0n0ron/Xh3ji0isAnRZOtUOA2ILSNd9PNCLea9jstf6hiGIE +ExECACICGwMCHgECF4AFAlZi3pgGCwkIBwMCBhUIAgkKCwQWAgMBAAoJEG7rgfiY +HHTH1PAAnj/1LWl3pxLYweV1ZClR0i44GJQcAJoCM0+92pI3VIsSMfkYaUVmOjVz +f4hfBBMRAgAfBQJDJvKmAhsDBwsJCAcDAgEDFQIDAxYCAQIeAQIXgAAKCRBu64H4 +mBx0xyAgAJwN2SASDJN9Y2H9iMjRSCkEftC7PgCeOTjpR3vyDnM7QL8bjwEiR5l7 +l3qIYgQTEQIAIgIbAwcLCQgHAwIBAxUCAwMWAgECHgECF4AFAkm3jjkCGQEACgkQ +buuB+JgcdMcXrACfVTEyxl0EqQN+FpmssqVUXMuGIPkAnjuh0lk4rlWnFHuRPKFP +aLNcn7TbiGUEExECACUCGwMCHgECF4ACGQEFAlZi3pMGCwkIBwMCBhUIAgkKCwQW +AgMBAAoJEG7rgfiYHHTHIBIAn20wZDYF0KrfbJNzK4/VwAEAzN+wAJ9Dpbhtq4sR +oH3cbadBsD2mXXthOohXBBMRAgAXBQI7OHVdBQsHCgMEAxUDAgMWAgECF4AACgkQ +buuB+JgcdMexIACfUdyOhJRqUp4ENf5WMF7zbVVLryoAn2cNiUWC2u4za4NDyde6 ++JGW3yo4iFoEMBECABoFAkm3je4THSBBY2NvdW50IGRpc2FibGVkLgAKCRBu64H4 +mBx0xw8pAJ9f38BHfCYcFBFrzasWJ50aYiq9agCeJc39ixXix4rnOa8vzBvSqILU +3J2IXwQTEQIAHwUCPvYc2wIbAwcLCQgHAwIBAxUCAwMWAgECHgECF4AACgkQbuuB ++JgcdMcsEACfQPXptVqB3lVdH8NmJq9988UjdugAnjc51tLV7wP/omMaG6zxqOBe +bByGiFcEExECABcFAjs4dV0FCwcKAwQDFQMCAxYCAQIXgAAKCRBu64H4mBx0x7Eg +AJ9R3I6ElGpSngQ1/lYwXvNtVUuvKgCfZw2JRYLa7jNrg0PJ17r4kZbfKjiIVwQT +EQIAFwULBwoDBAMVAwIDFgIBAheABQJJt44zAAoJEG7rgfiYHHTHt1oAmwfqV/fy +BQtuo6iVwyrLTrv6SH8WAJ9+vQxODP5nLEVv0VDkPe9YDmnHIohaBBMRAgAaBQsH +CgMEAxUDAgMWAgECF4AFAkMm92MCGQEACgkQbuuB+JgcdMf9FgCffJBUSQIPBPWC +zQvDLdCCQKj1gS0AnjY8bbEU+8j9MJdoyti8VQqc063IiFoEMBECABoFAkm3jboT +HSBBY2NvdW50IGRpc2FibGVkLgAKCRBu64H4mBx0x3w4AJ9uJb1MnaB4XL2W4/ur +kpvbRPiNrgCfRnEpymRfBRjuqSZpLr6t2548MFaIWgQwEQIAGgUCSbeOjRMdIEFj +Y291bnQgZGlzYWJsZWQuAAoJEG7rgfiYHHTHsjkAn3kJ+cwIuWjR07f/1L87hC1x +MGmAAJ45JUNoUgl45+JYUVamI+Sno02roLkBCwRDJvHRAQgA+McP+S2zoZBu2xX7 +r5pmB8IroxVl7Xgw5cUbrQWacc/NfKaivO7sPFJA6QqIpTj2ZSSVMhDUSsYivycL +OOZUeabsIfnd3Lz86SU+Cl5wEsZI/1aKpDxMnE1SINZADSvYdZUCyLzo34Td725s +3hVIrjJ3okxHUynYqDJLYsrY+NGj6jua6U4VoACjGaLyBYhVHqy/l2SHeD/r8N8q +DfZTwJaMWnkhcqaTIw9Ifl45kvh4F/HghrVwVxZ8Mll2xhD4QH5q7MerKv8NLmif +hpLvZYCmlaTAfUy799ic4RjfvIXgbBg9v8zkujPbBMzF2N9+XMIx19DnoK4yV9zz +gx5P8wAGKYhJBBgRAgAJBQJDJvHRAhsCAAoJEG7rgfiYHHTH8bQAn3wHFhPW+umo +2VjoxvBftJ3dKzXnAJ0Q6iW7EvhZeCIUE4Wcs5AYavoaXIkBZwQYEQIACQIbAgUC +SXscKQEpwF0gBBkBAgAGBQJDJvHRAAoJEDqwCZb8JqZBuHQIAOoXgUMEyxCHz6+S +EW9c5NC+1eRAy5B52vJoIYdxL97n8nTFvm4vJsyecXKH20jLxyP2xzv3J5NO5dJA +smBTTZeHoQviiwal7klZa8VtjhLI2TJHdRyleDOQfzRyuwcXmLHALHLs9MSNDjzJ +PT2GKDh6IMdDV9LijHQXlpRDiraaThs21TpYcQ//yXoErBJQL3+V8VCYyeTtJ4hC +pPCAL1NqA9mEJDP+01kGj63cROVFx89nZ2MIZEmbmZswb+nATLUv1+t2inMFiTnr +ISm4D3seOYgO+3fhhsA6U9g9IKy+eHNl2hWtG/+oFwbE2F1gDvPCIYOWuNF/tGDU +pPyLO+gJEG7rgfiYHHTHVYMAlROqNeZ/TalCmF9ijupqU65WvW0AnRRSCD49emCs +/SWngtDxJuTG8FGFuQELBEMm8fwBCAC3KLX691TOFiizmWZTOeRNREUEZYy89I6c +HrYjYyrRkBrOHJGNvoS5JO4Zy6wlc9bNGWxQU92bJCMiqE8n1mRRIs6J4gExThWq +BZzsZlcrs/gu6HxPFCvPlg62emPkd6//KPrcAIMshvNKGLMFK15n5Nkv5ofv/xcr +/fqjisISnk4fr1GI9wJQUQdCTEXu9o92erIfzb8m1Q7FJbXNhyv7tcekdr5Q20jr +ZDgxX3H1aLq8EG8nrNlJqulWLtWIh/k9Uwa5ZvmcDVhKES1BUqdCefqkGpFQXiIt +zKu6cgs8anXeG1RRqFoOvipZQ/lUqYQtP0iK05NHQFfp7cTaHo2fAAYpiEYEGBEC +AAYFAjs4dV4ACgkQbuuB+JgcdMeqzACfeHjT2PFYdy88PHNVGw5se9PqGPYAnArp +X32fDdu/xhuqjqHrNkwyO/YoiEkEGBECAAkFAkMm8dECGwIACgkQbuuB+JgcdMfx +tACffAcWE9b66ajZWOjG8F+0nd0rNecAnRDqJbsS+Fl4IhQThZyzkBhq+hpciEkE +GBECAAkFAkMm8fwCGwwACgkQbuuB+JgcdMcy4QCdFw3ipNDVX3Z77ZHMmbYhhtUm +M8EAnA1jqzeVutwLtlzYT+Tl/HDB6dJOuQENBDs4dV4QBACXdavIYhl+L248s1mU +i9EUESu9QovNzuf79zUZpRUzFdwX8hq56BuWHjU6hXYpzPWwXHnYwsNINNXUPAOf +h83PA/sNg572HgQGkx48bUNLstDQugPrzau97LoK/DD54WYEFd2ISoJe8+5bh3dY +yc6xCovkGJJAf4aLAissU3vKPwADBQP+P0U7OJ/UYt2hIbx+wSL/9rGrSxcj421F +Q6u+auRMIbejmtk4k3DP4oFCk/jkt3Oiw7hX+Q9W4nlTgSmsQ9Gp6N9JNb6gr4GC +bSZ8iaDDsm9p2Q15d8l3BiJ263IXWOOuhV2qmtKMABqhmBKLazDTcIXHVaR0v4YJ +xzA3ohWXk4iIRgQYEQIABgUCOzh1XgAKCRBu64H4mBx0x6rMAJ94eNPY8Vh3Lzw8 +c1UbDmx70+oY9gCcCulffZ8N27/GG6qOoes2TDI79iiISQQYEQIACQUCQybx0QIb +AgAKCRBu64H4mBx0x/G0AJ98BxYT1vrpqNlY6MbwX7Sd3Ss15wCdEOoluxL4WXgi +FBOFnLOQGGr6Glw= +=XJ6e +-----END PGP PUBLIC KEY BLOCK----- diff --git a/build/unix/build-gcc/33C235A34C46AA3FFB293709A328C3A2C3C45C06.key b/build/unix/build-gcc/33C235A34C46AA3FFB293709A328C3A2C3C45C06.key new file mode 100644 index 0000000000..f183ce9e49 --- /dev/null +++ b/build/unix/build-gcc/33C235A34C46AA3FFB293709A328C3A2C3C45C06.key @@ -0,0 +1,33 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGiBECGYZsRBAC9VE8N8vHAG87MTC2wbtnmbSD8Wc2xYCaLofZAH+vXyio3Dnwx +jQLlj7IgwRWNAVq13uL0wn0WAsGop5Cs7nA/JD4MEBBNSdnvq1bMYitch2PTtAU+ +h6HaI9JXBDUh4AKZz2rllKgbigMHlgIugxnKTAMJIhS63lCTHWEDlnycJwCgqSX9 +hDs9eBC5coearGDhc0BDvTsD/A05YkZkQBgsYD6cjWFwNLJIcaHORKlLLZ9gRJO5 +LVcKaCEgYSWAM7dadJeqIFi9RkXdv+cWozxTgrGlY4T7/PakIBB7wWj2Zl72mW5a +NHT2vAemB8IFV1saiFXZM+qDhCHbV4yKSmNOQHY1VnSCUrgINiM0qlTz08yjUazK +fm2BBACDF3ZfUQNeHC9zwfsgCzKnqOm7FSlwOyI0f+j83B5PH2+KuzuyEqYoxGp+ +2d1zTxvbOeBBaX8T1M4n5d9ixiFMhgbTzuyit3nn6cp5j2L0IAS9pw0kaWpPMhpQ +zydNgnaBxHs1Y+cP4iM/4FWFCvfjUdR7xULdEzkgGxevu8pNEbQgSmFrdWIgSmVs +aW5layA8amFrdWJAcmVkaGF0LmNvbT6IZAQTEQIAJAIbAwYLCQgHAwIDFQIDAxYC +AQIeAQIXgAUCSe3VIgUJEs109wAKCRCjKMOiw8RcBqANAJ0VlFMTtevlkEM+ym4k +yE3YOrGZ+wCeP7lZGc2jVLHJfrOKxXsTM5YPWhqIZAQTEQIAJAIbAwYLCQgHAwID +FQIDAxYCAQIeAQIXgAUCTI3tMgUJHtOOlwAKCRCjKMOiw8RcBjySAJ9ApMXF3+gW +Ir0zpMxvWb53/oxsHgCaAl6V5JS9GJUnrPiHKdR+sMFPkd6IZAQTEQIAJAUCQIZh +mwIbAwUJCWYBgAYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRCjKMOiw8RcBrC+AJ9d +mQcWoZHFGoinHck309KD0m2FegCeMBjr/M6Ec1myCYMUhtpl5DI7zY25Ag0EQIZh +ohAIALrI1X59CM30/Ufg+O9FFRRyM8GefACfItrIvp6jx+0ZMY+/ZbYnlMzI7Gz4 +xNXc+83Zsz7zE5xogNcq9LILdhB7Ta1ZRkRttM8AdfyakRQTjzCPtxSPgSao/Dcu +CL09BZdaeeqMAxLmw9DnY3xmZqQtCau8PlgIiClq2db9Wy0bpQ+DDfQV4MlX6eoI +33TG9Moy59QQUG5reQ2JNkQZRebPxJAPiAgHoF/Q+XO1pLeCccIN7SApe7yVd/4A +sS3Y9lZj2JvEvutLojsRGL0E/CAwH8cJqPAt65qbOgQzCILhcc9aYZ234g9n7Kpx +Ck1h2QMtXfsmaA7GsrXo1Ddfra8ABA0H/0sa4SCQhWQ14tOFkN15xzuaqGOxUD+O +uAsgRdKaFdIhZnj0MRmvOfBSP7hONw7fE0m9DVq9NDPqFcMeyCuBNIMpGIuN6CAK +/G0K2UgzoCxMXUEYGncFfVnOoNURV9u2lGq7ZMNJmuzt0BhxXtUYRlH3WRPqPyGv +s/OrIqvgN+Kf9+i0kQSObWz6CeYnBKzCc++MPkVhYj8KR5Y6n3zPZpnOfmO3c0rY +C+KiNoMwchlZmiOh7zgcTybv4zuOU7bppEidreIq2/o4nBNTao/5uzYdDX9FBpDT +hhU9ErdO8Vd7Vf2I1/WQdt6dHUXPLfkwI8+ODE/4R/Oz8opFC5L22kSITwQYEQIA +DwIbDAUCTI3tTQUJHtOOqwAKCRCjKMOiw8RcBrBvAKCTFx5FOuuxM2VoQka8iBGj +f1vcugCdHV/JIhOwETTqOQEbkw3y9ng2+4U= +=K9Jj +-----END PGP PUBLIC KEY BLOCK----- diff --git a/build/unix/build-gcc/343C2FF0FBEE5EC2EDBEF399F3599FF828C67298.key b/build/unix/build-gcc/343C2FF0FBEE5EC2EDBEF399F3599FF828C67298.key new file mode 100644 index 0000000000..548a560202 --- /dev/null +++ b/build/unix/build-gcc/343C2FF0FBEE5EC2EDBEF399F3599FF828C67298.key @@ -0,0 +1,35 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQFNBFDrIWMBCgCyyYoTAD/aL6Yl90eSJ1xuFpODTcwyRZsNSUZKSmKwnqXo9LgS +2B00yVZ2nO2OrSmWPiYikTciitv04bAqFaggSstx6hlni6n3h2PL0jXpf9EI6qOO +oKwi2IVtbBnJAhWpfRcAce6WEqvnav6KjuBM3lr8/5GzDV8tm6+X/G/paTnBqTB9 +pBxrH7smB+iRjDt/6ykWkbYLd6uBKzIkAp4HqAZb/aZMvxI28PeWGjZJQYq2nVPf +LroM6Ub/sNlXpv/bmHJusFQjUL368njhZD1+aVLCUfBCCDzvZc3EYt3wBkbmuCiA +xOb9ramHgiVkNENtzXR+sbQHtKRQv/jllY1qxROM2/rWmL+HohdxL5E0VPple2bg +U/zqX0Hg2byb8FbpzPJO5PnBD+1PME3Uirsly4N7XT80OvhXlYe4t+9X0QARAQAB +tCROaWVscyBNw7ZsbGVyIDxuaXNzZUBseXNhdG9yLmxpdS5zZT6JAX4EEwECACgF +AlDrIWMCGwMFCRLMAwAGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEPNZn/go +xnKYqm0J/A4b6TE5qPWiWj0kriUBSmpys3qUz93gR6Ft7w2f478KJuzbSadvyn0u +PcnP26AGTOQq75RhtgCJgdYbvRocTjlMh9jOX584Hx8hi/QSrpCSYMnj6dQKbu0Y +QIFjZx8gPeYvzG8t34FCNEzZ09RQZqy/ukRyN99LkwEuP4FWq486b7dpgv7GC+SH +lZcMco6VW8FLOT7KMalH06cmdhFPrFSYAIHDu3CsYhC8knIQV99Xzno/KeSkEwkq +tYDOdz0x4HWdOwHrl2S2X6Ex1q3QRXcq84EYQwHz2WEGaPR7Vd76P5J1wiHN6rwO +4exfgsRyTvc6NDQPTFqmoCzwuPviYk6JNnHr9E5TkLT7lAnESEhMLyyIG/7Uwpgu +5C71IMaTpOpf8DEU9NU/zuxgHoMaKBZaeYKs0S26s1zwGOlQX0T9uQFNBFDrIWMB +CgDKlONI+5Bqcu69+72fmLZPizzEUsIRA2Y0w2RE7+uJ5Es9/YTp5PnWANpPT7GS +8JJnc6NJJeh6GkMkGGwq5Op7CDsjW9pQZ0vAW90XjnyniDa9W0W+m5+X/LPOzh+n +is9Zcf17P91tprLCLi+TOOb35xt396pZ+S+PwuV0dLiIYdVYV3e6LNCV0LjhEqp5 +3TRwTrLTNPQVnt0DPYTh/Kn1x6d5zOS0MK4QybKN1WJU6nYIQRXyWKkixjbs++jc +gV/juck96Ve0blvn6DfqfpG8YzbmqRCufLo683LtlBUZ0c+znrD1nouqX2Eb/Cyl +G8Q8ZUHXimCJ+g6RfH9kOmtVH/208u/nDofVL/Q0dvAXfU5MX49c7XYy7B2rTlk+ +4nuNeaHM0aU2Y14+SQy+sR6zydu7eGLdqjzV0CX/ekgrjQARAQABiQFlBBgBAgAP +BQJQ6yFjAhsMBQkSzAMAAAoJEPNZn/goxnKYGUcJ/j+L0/uzfwCR1aTBZ6FBT9Od +NyatVjmz20ahskF3BySmkT1R06K08YOGJ//LPajj0eKqU8WKgxMc7pWi5SG+yMFn +2db5HnJDGiSmSjCXW/BzsSt1786LtO0m0ehatj9kl6JrxQNXazOkRJ2ww13P6/91 +RBaV6R08BmFTrUco2P6w+djCF4NlnkOLa7fM6QtNZM+yB+EzaPjSBFjZG52BVWZk +cXEVN0cEjPuznuQOmx8Dny7lQikp49NumrbamaxZEilx2Bi9gSbovNaKBuncKi9X +boiEiNbAarGxP40Qvlk2AuXWvq+fiBnU1e1nU2oV7/7nAWH7kj/Vr/JxcBeOpsND +GkW7Yrd3mkJCrhG+jMs1V2qNb9Uhr5ZLOA40sIz2PHfDrR+gc8THm2p5OvCWEAeu +kYJ22XTUIt6XoPO0ERYD +=MH4q +-----END PGP PUBLIC KEY BLOCK----- diff --git a/build/unix/build-gcc/5ED46A6721D365587791E2AA783FCD8E58BCAFBA.key b/build/unix/build-gcc/5ED46A6721D365587791E2AA783FCD8E58BCAFBA.key new file mode 100644 index 0000000000..7cc6ba735c --- /dev/null +++ b/build/unix/build-gcc/5ED46A6721D365587791E2AA783FCD8E58BCAFBA.key @@ -0,0 +1,38 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGiBDuVqKgRBAD5Mcvdc41W5lpeZvYplEuyEBXwmxnUryE2KaCG1C06sGyqgiec +VPXPbgIPKOUt4veMycVoqU4U4ZNuIeCGPfUvkGKLKvy5lK3iexC1Qvat+9ek2+yX +9zFlTo9QyT4kjn+xaZQYVctL370gUNV4eoiWDdrTjIvBfQCb+bf87eHv0QCg/7xt +wnq3uMpQHX+k2LGD2QDEjUcEALalUPPX99ZDjBN75CFUtbE43a73+jtNOLJFqGo3 +ne/lB8DqVwavrgQQxQqjg2xBVvagNpu2Cpmz3HlWoaqEb5vwxjRjhF5WRE+4s4es +9536lQ6pd5tZK4tHMOjvICkSg2BLUsc8XzBreLv3GEdpHP6EeezgAVQyWMpZkCdn +Xk8FA/9gRmro4+X0KJilw1EShYzudEAi02xQbr9hGiA84pQ4hYkdnLLeRscChwxM +VmoiEuJ51ZzIPlcSifzvlQBHIyYCl0KJeVMECXyjLddWkQM32ZZmQvG02mL2XYmF +/UG+/0vd6b2ISmtns6WrULGPNtagHhul+8j7zUfedsWuqpwbm7QmTWFyayBBZGxl +ciA8bWFkbGVyQGFsdW1uaS5jYWx0ZWNoLmVkdT6IRgQQEQIABgUCPIx/xAAKCRDZ +on0lAZZxp+ETAJ0bn8ntrka3vrFPtI6pRwOlueDEgQCfdFqvNgLv1QTYZJQZ5rUn +oM+F+aGIRgQQEQIABgUCQ5GdzQAKCRAvWOuZeViwlP1AAJ4lI6tis2lruhG8DsQ0 +xtWvb2OCfACfb5B/CYDjmRInrAgbVEla3EiO9sKIWAQQEQIAGAUCO5WoqAgLAwkI +BwIBCgIZAQUbAwAAAAAKCRB4P82OWLyvunKOAJ9kOC1uyoYYiXp2SMdcPMj5J+8J +XQCeKBP9Orx0bXK6luyWnCS5LJhevTyJARwEEAECAAYFAlDH6cIACgkQdxZ3RMno +5CguZAf/dxDbnY+rad6GJ1fYVyB9PfboyXLY/vksmupE9rbYmuLP85Rq1hdN56aZ +Qwjm7EPQi6htFANKOPkjOhutSD4X530Dj6Y7To8t85lW3351OP07EfZGilolIugU +6IMZNaUHVF1T0I68frkNTrmRx0PcOJacWB6fkBdoNtd5NLASgI+cszgLsD6THJZk +58RUDINY6fGBYFZkl2/dBbkLaj3DFr+ed6Oe99d546nfSz+zsm454W2M+Wf/yplK +O8Sd641h1eRGD/vihsOO+4gRgS+tQNzwb+eivON0PMvsGAEPEQ+aPVQ/U/UIQSYA ++cYz2jGSXhVppatEpq5U3aJLbcZKOrkCDQQ7laipEAgA9kJXtwh/CBdyorrWqULz +Bej5UxE5T7bxbrlLOCDaAadWoxTpj0BV89AHxstDqZSt90xkhkn4DIO9ZekX1KHT +UPj1WV/cdlJPPT2N286Z4VeSWc39uK50T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq +01uejaClcjrUGvC/RgBYK+X0iP1YTknbzSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O +9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdXQ6MdGGzeMyEstSr/POGxKUAYEY18hKcK +ctaGxAMZyAcpesqVDNmWn6vQClCbAkbTCD1mpF1Bn5x8vYlLIhkmuquiXsNV6TIL +OwACAgf/aMWYoBCocATXsfSUAJb69OPUXWjevZiCf6n+7Id3L5X5um55L5sEBr8+ +8m5SIuHUippgNFJdu2xyulbb1MeegtTttEWymF9sM8cWfeTjXPOd7+ZQumiOXwk/ +g0qqjTrq7EYW5PlMjO2FbH/Ix9SHKVS9a0eGUUl+PBv3fkEZBJ4HhweqcSfLyKU/ +CHysN03Z36gtdu1BJlzHy8BPxWzP4vtPEi57Q1dFDY/+OrdlBnwKTpne6y0rAbi/ +wk6FxDGQ86vdapLI51kTxvkYx8+qZXqE4CG5fWbAFDQVTNZIWJNgYMX7Kgl8Fvw+ +7zCqJsv/KbuonIEb5hNViflVTWlBAIhMBBgRAgAMBQI7laipBRsMAAAAAAoJEHg/ +zY5YvK+6T88An1VSVGbeKbIL+k8HaPUsWB7qs5RhAKDdtkn0xqOr+0pE5eilEc61 +pMCmSQ== +=5shY +-----END PGP PUBLIC KEY BLOCK----- diff --git a/build/unix/build-gcc/7F74F97C103468EE5D750B583AB00996FC26A641.key b/build/unix/build-gcc/7F74F97C103468EE5D750B583AB00996FC26A641.key new file mode 100644 index 0000000000..6f23744afe --- /dev/null +++ b/build/unix/build-gcc/7F74F97C103468EE5D750B583AB00996FC26A641.key @@ -0,0 +1,54 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGiBDs4dV0RBACZII57dgbfnCC7RTrJ1yc0F1ofEZJJ/x4tAtSHMDNj2zTnLR25 +5AHmxN85namwJdn7ixXSZv1FMPCeTs6jDk98YuA9r5uuCNPqCNZsuQtREpN7h+wO +IeRrhvg9/F11mty/5NthXNh8P2ELnkWXSHu6DvTQyGppAtxueOL0CjRrpwCggVYu +vxui5mqNq9+lILbMi2Zm3UkD/0T/0HupthZFXbuzY/h/nyqzoPOxnSAAAx6N7SiE +2w9OQ1w3K8WOFoPH9P0cnIQ+KnMSGQV4C2WY/d8YtShnKkXRYZVvlK+aiwmvf1kU +yNyUqaA/GhW5FWN26zFQc3G5Y9TDjgBqjd6SequZztK5M5cknJGJn+otpdQtA1Dx +2KEABACSYjdRNT3OvQJ7OSz4x4C58JKz/P69WsNZxqYVo66P7PGxM7V2GykFPbG7 +agyEMWP1alvUK551IamVtXN+mD7h3uwi5Er0cFBBfV8bSLjmhSchVpyQpiMe2iAr +IFeWox7IUp3zoT35/CP4xMu5l8pza61U5+hK3G7ud5ZQzVvh8bQtUmljaGFyZCBH +dWVudGhlciA8cmljaGFyZC5ndWVudGhlckBnbWFpbC5jb20+iGUEExECACUCGwMC +HgECF4ACGQEFAlZi3pMGCwkIBwMCBhUIAgkKCwQWAgMBAAoJEG7rgfiYHHTHIBIA +n20wZDYF0KrfbJNzK4/VwAEAzN+wAJ9Dpbhtq4sRoH3cbadBsD2mXXthOohiBBMR +AgAiAhsDAh4BAheABQJWYt6YBgsJCAcDAgYVCAIJCgsEFgIDAQAKCRBu64H4mBx0 +x2iyAJ4tmLvgNsphsrpKKfDDyV0tzR5FuACeNymltMsgfFyvoueBvji/h+HyObmI +YgQTEQIAIgIbAwIeAQIXgAUCVmLemAYLCQgHAwIGFQgCCQoLBBYCAwEACgkQbuuB ++JgcdMdeDQCfZRUFDCB8sLK6B6wqRmwCsb3EK6MAnjSG6ZtgrdEjSQSmfAcIV/9W +367MiGIEExECACICGwMCHgECF4AFAlZi3pgGCwkIBwMCBhUIAgkKCwQWAgMBAAoJ +EG7rgfiYHHTH1PAAnj/1LWl3pxLYweV1ZClR0i44GJQcAJoCM0+92pI3VIsSMfkY +aUVmOjVzf4haBDARAgAaBQJJt43uEx0gQWNjb3VudCBkaXNhYmxlZC4ACgkQbuuB ++JgcdMcPKQCfX9/AR3wmHBQRa82rFiedGmIqvWoAniXN/YsV4seK5zmvL8wb0qiC +1NydiFoEMBECABoFAkm3jo0THSBBY2NvdW50IGRpc2FibGVkLgAKCRBu64H4mBx0 +x7I5AJ95CfnMCLlo0dO3/9S/O4QtcTBpgACeOSVDaFIJeOfiWFFWpiPkp6NNq6C5 +AQsEQybx0QEIAPjHD/kts6GQbtsV+6+aZgfCK6MVZe14MOXFG60FmnHPzXymorzu +7DxSQOkKiKU49mUklTIQ1ErGIr8nCzjmVHmm7CH53dy8/OklPgpecBLGSP9WiqQ8 +TJxNUiDWQA0r2HWVAsi86N+E3e9ubN4VSK4yd6JMR1Mp2KgyS2LK2PjRo+o7mulO +FaAAoxmi8gWIVR6sv5dkh3g/6/DfKg32U8CWjFp5IXKmkyMPSH5eOZL4eBfx4Ia1 +cFcWfDJZdsYQ+EB+auzHqyr/DS5on4aS72WAppWkwH1Mu/fYnOEY37yF4GwYPb/M +5Loz2wTMxdjfflzCMdfQ56CuMlfc84MeT/MABimJAWcEGBECAAkCGwIFAkl7HCkB +KcBdIAQZAQIABgUCQybx0QAKCRA6sAmW/CamQbh0CADqF4FDBMsQh8+vkhFvXOTQ +vtXkQMuQedryaCGHcS/e5/J0xb5uLybMnnFyh9tIy8cj9sc79yeTTuXSQLJgU02X +h6EL4osGpe5JWWvFbY4SyNkyR3UcpXgzkH80crsHF5ixwCxy7PTEjQ48yT09hig4 +eiDHQ1fS4ox0F5aUQ4q2mk4bNtU6WHEP/8l6BKwSUC9/lfFQmMnk7SeIQqTwgC9T +agPZhCQz/tNZBo+t3ETlRcfPZ2djCGRJm5mbMG/pwEy1L9frdopzBYk56yEpuA97 +HjmIDvt34YbAOlPYPSCsvnhzZdoVrRv/qBcGxNhdYA7zwiGDlrjRf7Rg1KT8izvo +CRBu64H4mBx0x1WDAJUTqjXmf02pQphfYo7qalOuVr1tAJ0UUgg+PXpgrP0lp4LQ +8SbkxvBRhbkBCwRDJvH8AQgAtyi1+vdUzhYos5lmUznkTURFBGWMvPSOnB62I2Mq +0ZAazhyRjb6EuSTuGcusJXPWzRlsUFPdmyQjIqhPJ9ZkUSLOieIBMU4VqgWc7GZX +K7P4Luh8TxQrz5YOtnpj5Hev/yj63ACDLIbzShizBSteZ+TZL+aH7/8XK/36o4rC +Ep5OH69RiPcCUFEHQkxF7vaPdnqyH82/JtUOxSW1zYcr+7XHpHa+UNtI62Q4MV9x +9Wi6vBBvJ6zZSarpVi7ViIf5PVMGuWb5nA1YShEtQVKnQnn6pBqRUF4iLcyrunIL +PGp13htUUahaDr4qWUP5VKmELT9IitOTR0BX6e3E2h6NnwAGKYhJBBgRAgAJBQJD +JvH8AhsMAAoJEG7rgfiYHHTHMuEAnRcN4qTQ1V92e+2RzJm2IYbVJjPBAJwNY6s3 +lbrcC7Zc2E/k5fxwwenSTrkBDQQ7OHVeEAQAl3WryGIZfi9uPLNZlIvRFBErvUKL +zc7n+/c1GaUVMxXcF/Iauegblh41OoV2Kcz1sFx52MLDSDTV1DwDn4fNzwP7DYOe +9h4EBpMePG1DS7LQ0LoD682rvey6Cvww+eFmBBXdiEqCXvPuW4d3WMnOsQqL5BiS +QH+GiwIrLFN7yj8AAwUD/j9FOzif1GLdoSG8fsEi//axq0sXI+NtRUOrvmrkTCG3 +o5rZOJNwz+KBQpP45LdzosO4V/kPVuJ5U4EprEPRqejfSTW+oK+Bgm0mfImgw7Jv +adkNeXfJdwYidutyF1jjroVdqprSjAAaoZgSi2sw03CFx1WkdL+GCccwN6IVl5OI +iEYEGBECAAYFAjs4dV4ACgkQbuuB+JgcdMeqzACfeHjT2PFYdy88PHNVGw5se9Pq +GPYAnArpX32fDdu/xhuqjqHrNkwyO/Yo +=TzkT +-----END PGP PUBLIC KEY BLOCK----- diff --git a/build/unix/build-gcc/AD17A21EF8AED8F1CC02DBD9F7D5C9BF765C61E3.key b/build/unix/build-gcc/AD17A21EF8AED8F1CC02DBD9F7D5C9BF765C61E3.key new file mode 100644 index 0000000000..95a04ebe6a --- /dev/null +++ b/build/unix/build-gcc/AD17A21EF8AED8F1CC02DBD9F7D5C9BF765C61E3.key @@ -0,0 +1,57 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQMuBEvtHBoRCACUnk4CbRKM5SsykvTko30oeZqmzDF4bS/usOEcZBjtpudsZBC4 +Po7zfIQAvRyCyEsXtBHCM9KhUNgIbfToDfb9quXvH0KR5D/lcHL3eOHfFPX+Yr34 +ouHj/+2yFQNNrsmEmteOFJVM+zX1KBx2I8XQWDNbnMbEbPj/DdCvsk7+3uoQCepG +bFD07pk7iFb1ny6DXgvM4fItJbY5z7+IQSJCv9blRNy55oCkOdGm1FE4Q/SPgbT4 +quZoec2IxGlFGt9ThUDpuYPcdejyjaC5eFDozhqXwMDh17yBDS53XF6lV02Djs7L +e6QbUJv4B3rqvOGV+eLfRxFuy6X6XEOh8FgrAQCzj7dNslwWI9nTwp5GCr7IO7jz +Ynmw+keMcaOUu0Gd2wf/f/uonF/RVy+Gp+PGHnPhi20xaKZ9unf3l3KWELTpizI9 +Of4R+N9AOpVR4Bf1MgkCV4VH8cpOUQOxQQUEYOpYYYH0EeuDlBItVgvcdG40bnQA +PUwWdqbHUh1cXjD0kGQLv8B2+O31GfnjDQhnNJ5C9KdhKf2sLRkNJtMLU5XsPFMF +qoAW7I0cak2XCuHokiOdJq3bhOX4FdxRGlFPOXNOQA53nYRb0kHv4gfKBHwPJbPT +T3MFgoqO23q+om2cFqwVRTVLW4Cg+Ki5dvFkJrufE/NNaCRuSlj3G2WF5K3OOZct +O7xsDsp5wPMQu1tkuwoZcnp+EmvI8QQkPl722eWf3wf7BFjLCIqi1ivu0GVVMLOM +DMGRZeSkjVrLj1xw5BbWsQ8jOAGvnrqC5zpQoMQLzYyPGb6KzXX8Df1kbQEys7M/ +FoLVIhSE/Elr4e5epNW+8zpmLSW61PlDNraHYHcCxf9RY9aZrxtzEXxdCpPZ+bk3 +8sh4kvAv6XUsmweAu2RRY97u5KNyWkIEhhJJcd96cK6FNc9GeOLCiXQPJqK1ORSj +bCBX8HL1U1r8iOo7Hh+Y25flZ0vRSE/6Fsw1X+seTakelh8EWQtIr+i+oClHgmrT +su9NhhQFFvAUFNdN0K1TcADhfj5nPTImet1x9oAUsU//lOXBFWYhs9sitE879uQs +d7QeQW5kcmVhcyBFbmdlIDxhbmRyZWFzQGVuZ2UuZnI+iIAEExEIACgCGwMGCwkI +BwMCBhUIAgkKCwQWAgMBAh4BAheABQJVWjYMBQkLTk1nAAoJEPfVyb92XGHjOqEB +AJsOI48xKPLh09bAzvzSOqS7H/KR6zWIfvLvu1gDhZVrAP92LZoj7qcgnZ15tY2Y +yqHYHk87zl3vRlMLJXizEz64xIiABBMRCAAoAhsDBgsJCAcDAgYVCAIJCgsEFgID +AQIeAQIXgAUCVqUDRgUJDJkamgAKCRD31cm/dlxh42vPAPoDs4RuOS7YWYM7gKiC +3oNVTTIDKz9foDlOIXUhlWf6dwD/S1ofL5UNLLubCdK3UYNHNj+8r4ynz3YezHaR +MDCTtGmIgAQTEQgAKAIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AFAldHXPUF +CQ07dFMACgkQ99XJv3ZcYeOc7wD/eE9W2sl2zI6h1LXTA6tVharyhP8cOAtzuuw7 +auZaE3wA/jaKo0HYrSnhrg8bF2zMnf9LQQdPdW99jZNVFIMcnOrniIAEExEIACgF +AlIWO54CGwMFCQlmAYAGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEPfVyb92 +XGHj9VkBAJe2uRxafZnUWpkTMD2CGg2EQgIP0R4bH3lykKtNKiZ/AQChGBkQWref +Z4eGsXhO205DYKq8TXKmAxuSVYv3UahXXIiABBMRCAAoAhsDBgsJCAcDAgYVCAIJ +CgsEFgIDAQIeAQIXgAUCVVo2GgUJC05NZwAKCRD31cm/dlxh4yb4AP9PxhxI7yE/ +PiCa9hmrl5rvilMGXNBzA80re3+G8un6EgD7BQPdd9hBlC98uC6WtYtB9xFgny3M +mNPpcUM7NHDjdYKIgAQTEQgAKAIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AF +AlalAz0FCQyZGpoACgkQ99XJv3ZcYeMR7gEAlSYGcUywSjjXJ+kjz6n3wddHZFGl +q3Z4zmdVeIJctv8A/R0qGx73rFDNN1aEB36RZmjf6s3OKEtZ+sFNPEXOWwpAiIAE +ExEIACgCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheABQJXR10BBQkNO3RTAAoJ +EPfVyb92XGHjgN4BAKeBkmxrmrSPU9HUDlE7L/ecR7rUlF2Go4ibuDvOWp0BAP9X +wXSHKxDlL2lh/IeiZSqIW09GXBItfQACaeoJz4s4oYiABBMRCAAoBQJL7RwaAhsD +BQkJZgGABgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRD31cm/dlxh4zhsAQCf +pbJqrGh6rGBAW1L3jCHNeYt9ughb6wxtlwFclThG/QD/bccAIkDT1lem8Bhf66d5 +sYEx+d27d2rvyBNblP3Urwa5Ag0ES+0cGhAIAI7fBR4UWKVQ8t5A0hPXbOhQkxyt +ztcIRo8rpGGMq//STIa4gBZjuyomkOGss8bElWFYeco09+OqGimD4fDEHXVpD/ev +IYiLq9U2sAUHZaKQAM3vE5LBfWa6zeuQwQj0/t9+cDyNCLTEjPsFQ5AdWyXxxO2c +XetgOHbKwtyjEEsjbJNms6ysjsmXzQGkDRCarGpWrqhAE+jweykpJLoCpCI8AmTv +1/dA5AOcDfsNlTDJnKwWsIaEnvscE4YMwcbCxwHUbhlzzEs8uS7Bk1LaQKQFUcvQ +Bt1nFiHD3uTHZLX5RjL2VTRArQFWN3PefAW1T5Ws+Fs+JwBy/VeKbuBud5sAAwYH +/167fa00yFiCtloWPJ/Xv7Marh/CIpAG0GOuPIJ4IqdEl/ZZ76A0KalUbrSL+fj1 +Eq/0auiNi9CbtlKI8lebn0AkKRYZe9j6JwIHJGomn1hgFhPGMKUToE4iUXmv+ZWN +BbH4iJz87xcrmtV9mLHiVZHGMwMBv5VVSnBoGcxcHHYnC3iAP8h+yaFt4pVIxQXR +NNfbXsUFvZaW2Tgat8knupmxOZfJfdesIf+n1X36OvhsZgFw6rHTSf2mAfkiBl47 +uYbB8v8BR2nDXbtpNlg2ssPbmPIfOE0Ft7pZ5VN1YiNY60w+Sbh5wD0A4mr7OZ/t +2NP0yxDMCLYN3jY5R+P/e4OIZwQYEQgADwIbDAUCV0dd7gUJDTt1RgAKCRD31cm/ +dlxh4xPFAQCXDeJBh1YPVkD8rgFlmMIEtorkzK0tHfCap6j1cG4iFAD/SCXCufA7 +8GOBvibrC/azKvoBKLY1/stpKCrecZdRFkk= +=SDN9 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/build/unix/build-gcc/D3A93CAD751C2AF4F8C7AD516C35B99309B5FA62.key b/build/unix/build-gcc/D3A93CAD751C2AF4F8C7AD516C35B99309B5FA62.key new file mode 100644 index 0000000000..21cd94ec1d --- /dev/null +++ b/build/unix/build-gcc/D3A93CAD751C2AF4F8C7AD516C35B99309B5FA62.key @@ -0,0 +1,62 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBF7Ps4YBEAC5i0PA1CA3te8UeAxWm8zH5KRyoXyD+IuVHar9fPR13J/IkUgO +0f4kebDaGQGjyPoBuLHWtshQwSjDP9059eMbfne6fhe3UxqRjfknWxr83S0pSrDI +xgdIsxMQT6dxm1YYpp+pK6PRs/tHMtXHtSJc4HwkW187nx7c7lfKXmwVoqUuEjvW +irKyJRVNw68WZjYLmmIsRIIZcUMOE2lItPkejerHZobOuTkuXslgkWH3zeKCK8JD +em9npzxIkLgrl8Ub0HxWdkAc6o+gj3Ih0QthvC8P7gxNuTJyf8SVaZFla+ky/t7Z +kLmIhSBLzNSosscOtz9sdI4seXsOGgWeGRORp/+zF5ISnD3kFg3OtIudW8p4J7oA +OICWkPIuEOXPCz5VIUmaY2Eswh76YgW7u60JMv/v0Agpjy23hovvG6HArMO8Letr +Y5CWC+G9wp/xTo3TeyQ9mrYcKMjvrZzCos+SFaGF0lcExWpk610XQf+8/1FlhJ4U +SiQCy78o1pW8dOpLWvWe7y9YtRm3DTgYDCDpcMzYVZPrp2oPg5h4nW5sfhPJ01yu +gwTLDo/AILMQSkr1IVbfMkP7Mxtev51nRjxL7JCMB4bHx+uyNs56LCqdLctrF6Aa +HrS7yaP3ym3BsHrH3TqAaTGW7rs/hrZ6MaWbU4bBxL49z4GyXWRJqglePwARAQAB +tCBKYWt1YiBKZWxpbmVrIDxqYWt1YkByZWRoYXQuY29tPokCOAQTAQIAIgUCXs+z +hgIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQbDW5kwm1+mJqRxAAtvq9 +NevjleUPVMJhz3X5pprhCNM/8LGSbhE284tDYv0inT9huKaMeaw/hQvSSoniac87 +zb0S5JDWYHEZ6PhOs7ZASuSwtBp3SdGtjQTMJMSuAHvEjSvBR+0EkCu+85oJxwDS +wMMNEy1xubsyqhETD6DF/wudDr5r8IpB0A4vzFmaFv5wdbdnywd/sQzU9Fnl7GyX +/1Wgd94dIiznr7fdxJtsdphw4WzoJf5EYTdozs+biVhnz+NJuniTjg8IKoEOl7oY +Nrmqwfijw7FqgcbuXb9UAsxaVLFHZl3GVhXAmbQoz4io3PVw5BR+p+zeWvndeONu +jndE8QN3PyFb/WHyWRnCv7goUb5uLZU4aDqf34PP8fral3HBaaaXB53NybvJVjEU +nMzvjpVQj4J0yFzy+NlFwJb3oT03EDNkEK+SQrKHv4xz/atgXbfFYZ8oynCkypmt +aw/udPuLpy2dBY6wTAhSvdzkiD9swgbgX2idNLXfoeU1AaiKd+mez3X51Arf49pn +nL5wDCBkT2BUwX41ntIGgrNMcMNFbfNt99kUNaZ15oWI9Ia3DyWMxvgmDg4Ev8m8 +pGHH3Hq3eueyPySdJh+I8x+ipyIpFW+7AYS49L4LI7A7jFs8Nas22Qi6RoTFV3ep +0qkEL4Lgrh8ooxhhSLOmsfyJDiXAHiz5sVUZ4wWJAjgEEwECACIFAl7PvJYCGwMG +CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEGw1uZMJtfpirV0P/jBD7DrOCdCt +AgS4F9uUM9MtR4uBvp+8dVuaGX37fMr8W5rDE+wYzBiYeIzc3UJ3QG2Nuh+VN7OT +rZS9cNpDKre2+/6PQT4y/p3SI7o4JEqzoecWlITwWy2hpoYmEs47y7F6L0RpeNQ/ +sJ3hQydx+X6JxXe/IB+ftpOWpO5oGIDrdBoU3hBTcQYL9TjDMWSfmoiIgKTBVbXO +Ktsy1sc0TcjHk1ACoSj08+Q8+Swq56cd/dXuIMfaU6mNuJgA1UUaw7T+2HYLDAz9 +J10ak28kbHP9MHFHZff3M1Ub80gAwmaJ96u4G+2q9yX6/+QhXTf9gEF8PyBKpBd6 +Uk/dNLPtVjGYTjkPxQ7fyehE7KunC9uPOze0AEnhnxe3HM1TikFNbbAYaZNlqsXt +HPCp7ATfCpautoNarO7CfFer77OuECzoLHpDNXqesPZ+/WeZsURtik2MoNN0to3h +CZJQBptcBQ4CAy+5LlWKZURU0Cxu2GkSNSM0YuiQnmKReLZbzX4Rrr7c1/AAx5Ps +mG55LIF4sSygbWPvY6kBL7XEhvMa6x3B4+pELNCJUUSgp4aW3oL3u05DQWVJDgZd +t+XPP2DTiEgFtZbOS6sXdqpPY5/fC+69HU9spcmEdaVCJeIOICy+sDfFTOTv0Tcq +XD7TIZko4pKA97L4lzekQENFcni9/YHkuQINBF7Ps4YBEAC4rhogalczpaUmgnMD +kRGpv7WFgpv96PQBKCoWfFTTsB8vW0Ge0J7ctOGevOjRqupDnNK1ycTuXUnqogOD +n4ZpKYoXg9xoBCmrlXAjdRA7Z9GG9Pv5SVgah4lwGvoWhFDbEZGXWywGggWOmht0 +vGPYUm9Xam3nfUKA3QuQ5Y6pUyVM0W0C93xQZbGHo7VkzVlBz/TnXlEyM3Twn9oh +DTKPj2GRty8cnMEDM2tEw85rlUi0WwWMS42MM41aIiO0WL1fmhbNh2UoLQND9gZg +vqY5Xnkn1nh4jQGcTx+krXm/EzDi/wMnS6zHBp45XkRHKNWFDS/IaNs1AL9Ifkt2 +8xoW+4LZDsVc7uhtRB6H5Uwq8HbAH3gPFggWTPii6iyXJ/OXoR+/zdGQcv2OQbu+ +iYrWDvwyb6gEeo0okdnyQUC4khAt0jr4VsCRGHsTViN3kqQ2L8XY0N97Rc+kE1B5 +3on7NWgcpejB9FsUQ2LKSLNXO1+mn6iFq1VLF5o4fyE9fIRjhHVQ2fJLStVNmnUD +99jpmXUOYo/OmHcsqa/XMByve+lXbbUSzSrOyhJRXpqZB7XXu7nvl8pa83jGEI9T +JrcOG2i/I8YOAB5pNOlN1RGk+z0CCaYWTMCzHrN4ZOHuO29wvGnggAGANbH5muKw +lPIU26wKEleaoQwg20WYgIRdAQARAQABiQIfBBgBAgAJBQJez7OGAhsMAAoJEGw1 +uZMJtfpiKzcP/izcvGB0oVTvhLkHomtxNHFbuv6gsjP1HYwn2kmB/TcEJXR1G3ne +9CGO9jKmH5PrKk6B7BmggKEnnwkkS7BC0O7ADLH6r8DW/HYmzjeqvSbuSRElMLuL +cZlZS5ZFxZcsYJP303gU0/PcE+2WF40lWu+VkQw8CaPASydTe9ulMVQ3FJuheBm/ +npWjItI1RgpSlRv2Ry4FkZXyuPHadWtgj66r0QHhr56skMuKulLVdRXMGJcc5dxt +rmwfGI5UINRRuwqEn4Bz2RWfnz7Qr1t5FI3kzmZQ0PFDRLMr1LcC/p7SgqSsMUXQ +BS1m31YJdR0bXCtHl0H/jXqZ+fpUYDUX1JcxSJ2FJJ9EBBSUEIAJncbkFS7rS84H +IcUfeDAa+nNfI4bvveaqCiHzaXkmjqcQ2cfVqpzArAZp7PmCpnWhWo+TLpMz1yEM +cOqPRM/gID2PVUZiA72iv9ASa4Fv3XhRnBddrTB82kOPiLe3onQ3s2J+glqr0QF+ +OcKVuYoOxlF5uV6fDEqvR1B6b8UhEg2qPfekIH0epRSe2CMvnEHAkucpx3CZKZyx +nUtBvFMzeImE/swLJzsmzaxExcRT7EwHXbvXPrDo0VB1BfK/ZBkGd3isQqd6zXxC +1FU48hr9sjqbp/mdcRwHiyKuTBKuDwcSic/+06T28Z+qcFGkqy3SQZF6 +=3+NJ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/build/unix/build-gcc/DA23579A74D4AD9AF9D3F945CEFAC8EAAF17519D.key b/build/unix/build-gcc/DA23579A74D4AD9AF9D3F945CEFAC8EAAF17519D.key new file mode 100644 index 0000000000..1b658e615b --- /dev/null +++ b/build/unix/build-gcc/DA23579A74D4AD9AF9D3F945CEFAC8EAAF17519D.key @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFY4SBYBEAC11sh4AMhIhiLxj76FXsluVJIU4nZjVmexar+/5WMlVvMX+Dxk +lUbKDCBOUMtPFsAXMpcxOGwscCr3WMuI8WszTjKDs3mdQ37o/pzXMbRhY0oZV29Z +EhNLds14qhMLlQiDEm5lJ5bOsLevHJ9hR4wvwY6UR881xsiXsNU+iNMRP0cWeRjQ +84pSCLOt9i+D8rdllVob871gN/tjY4Ll13Tg7qmtFE1YEFJaLb2yik0bO7gPkig/ +ADmKMBhOtgAHU9i+gmtP+x+agk7cbXkR06Pd9VBkd9nYlFXbR+zcE15AqauEF1Y2 +V9RbW/Ewt4Fmgr+QQnJhiSMO2BUTS2Q0CC3LznB9QOdEriUmeXGJdim0OJiwYDDX +4CNRk+2CAePbrZnGv+YXgeNPHvFa0Baj73HP8Ptok+OeyWIenRPHG3Ni+O5p1n5k +QK0bHqIwChMtAJvzdoC77XIJhbCtStmvo2FdSA8YcG4stlz+Wk1ZtNMen83ZEscS +OXEVpxcPGlbmWmkWj8DF5zbB1dRdh4T6LLM4nZViBu7oGD76z3c/x2zc7l3pyVHx +Cw70a+r+6LvUwnvCiApCBS72uDc4zZtnkNUQHlXHkz9wEeYUtUB0wkCYWPZy7BZy +0aFfKWK4Jg7uGx/mdHRCJ35MdXWxeQ4yPUE+tF951s167ANr1+ayt87pQwARAQAB +tChBbGV4YW5kcmUgSnVsbGlhcmQgPGp1bGxpYXJkQHdpbmVocS5vcmc+iQI3BBMB +AgAhAhsDAh4BAheABQJWOEvIBQsJCAcDBRUKCQgLBRYCAwEAAAoJEM76yOqvF1Gd +UqkQAJw6ot97efCon6qMA7ctJTqhOvnPSxf430aZgaTuNBEfY3RPeWC+k11cTvKV +dny9xwC+N8U2Jfdd0iXqlwUdM4ThOKZCXGOykCHJmrYGPqWsjGKUO7EoMwJB00qi +nOJdgj7zWLb6MuuKx2eavGYVLCFG4sQ8fjX0+sxuD+Cl++UyS9+t/C3ijeXTxaZn +qSLFKUFzyngXIUhFxMLkUdh397WeTaBtUTyLT0lwOKTllxIyC/+t2e9QcfgdLE/q +wKmRjihNq6I5JOQfO8JynUoR8WzKQaCX5VL6ZPaQa8ZzUdS/h0WlMlQuD5mrcDBa +ZQjqPEIL6/oExk1a7yeQFKNKisq94rVF0Ly1o7w+n+7X4lT9T9zhiPKVXvlxHB0h +SeJm4j/qDq1DSiGVfIR2CChObyeHAZhQZMMr/Ni9XtqzHsd2qhcP1ZYvbQZ2UK/N +Lv398VY/f+kXApFMDQLj1jGA8aXbkE8ChIAiZAAzVMg2wJ2x5/7bImbICsvGSwfx +awlsHzc7CR0Pj2Kdgr7UtsDk+cBRQMEqAIGWiCOKnBD8eoNGaiCoLHI/3ce4dJ/y +pXFtJSkJa8wpK4+xdckAvtPQZgOV5gLCJqNqEF+8aIjsTwwu7dcIXG2qLHD5C5tq +viuZtOYO7UdQbIHuYY5Xy8/W7hQRfIaq1NfKf9qJx4hrCWLviEYEEBECAAYFAlY4 +S3QACgkQ9ebp7rlGHdcg6ACfXNdYTmPe1Ej0rd+eO+yuDF/kwccAoItuIMi7EXu0 +FR4Ui8cBaZI3hweFuQINBFY4SBYBEAD7ZonYuSKxToJ4plL22rv4wPPbqACcLbIG +5t3s/Gb3/twOtaCgOEFhzNv+8K87jX6iSHJYeGhu7e2eRxeGHkrqliNJoHUi9Ddu +ygHqhoNmSHNSqI36/TU5yCRArKS3wwq7cafGnncdVOLBYfj497IxGK8fANhDf7TV +vqUGIb06gkpWbrwmUWgV8pk7MHgL93T5Ph+KSgdEbOSePFwQb9piyp9vWNmZnqK2 +9TFNtTULGtQa0y8ZCNSSEh4YP/DxDraq1OJ2Gh3WHSQ4f2hfGXJMzr4cyIrOJHQ8 +mby6xHmvldsAGsZJ/CSMj27UhJJYOzNCxWOp9NBNARB/6N1Ikvv9Vs6G7lZ4Dmuk +wvAWqzlomO/ctt0XmvY7N7ddIviDCQ0Z5bGJQlOWuIBR04tt7CePNzxG91q8x7FN +P8r+BSvxtGheeFiQYsC5FINYWUelL/SU8/U9sG30YLpujvjB5mqYZJtmotSqFbwl +81/bLU170OdG9n7FWp09f9yB1KlSq3hSwKBKu2bGUy2sS6w5MqEtxBHVUjLlS9oP +GQK+wr1m70rgfK/2N3HdcSqr2e2aKxnCx5wDvqB19Zq0TX5CXobEy3ohnul3Ez7a +2HBq543rdZpS9xuF2IHK6zMn5Xv0WKrODxIOnjs1mKbQzP5/6PVOejH/AnO38pCb +hoj0/zvnKQARAQABiQIfBBgBAgAJBQJWOEgWAhsMAAoJEM76yOqvF1Gde00QAJMF +OZhnPeiDFigLsqiqPGQzqSlZ5r4rQ3t6txfBYDclTq3rMqmk75bxteZHpSgMvdHF +SgqrvcyCJP5F8IRbk+J/tUb10icnl7+vsb6PfNXXflX0cIeAC9yqB3Z6RO77NoMy +HzMlw4EcNUXdmC46s+h6y74BeWWLBwYR18XgTSuw3gYpL7P0lqM2d7H6HCQMkZD/ +on9pT3lOc5k9YeM+B+Ak0nDyJGrdj6EES/ukrmq/szJhx+2zMbKU6Ds/uIRE0zuS +VUPnCy+3KPuJk+xLWtuVD2v2G0PXBrKKcgLfQzTQeGT5R/8rTt2w3ah4dXYRG5Ad +N5fIaTfjJTZGmht3pvHuucoloqMWl6DD7a3XZjWtUBMhPboAZiCmXiBWn3c26ITu +N9j4gSpl3hbWYJXjTWocGs2YyiuMRsO6Minfz5l2/iZjp8xHJ8GajuLGQES7CwGH +uShQ0hknHZmrH0d6xOhD64czgmTI2HraujWz+u31sHM1yEJgQKAtEL2AKWGSadly +/eI2rCQDEn6mIe34I04SPr/XrTpFClmUBbZBBir7KMRhB8B9ERdJElbtb4ubGZ0D +FCYpueJgVv9agvV2ONVb/K0BIevJy9v5+FbSFIQG/spkwf/71olib93iUr9tKTaE +mOMR1xJlCiQvAQYsmqwM9FHDmGJYTQE1WbVZu4gZ +=6vF7 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/build/unix/build-gcc/EAF1C276A747E9ED86210CBAC3126D3B4AE55E93.key b/build/unix/build-gcc/EAF1C276A747E9ED86210CBAC3126D3B4AE55E93.key new file mode 100644 index 0000000000..13ea6d69ec --- /dev/null +++ b/build/unix/build-gcc/EAF1C276A747E9ED86210CBAC3126D3B4AE55E93.key @@ -0,0 +1,29 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGiBEj3S14RBACUE+e2hRWwM6AFWaNKsLgDg6ebDNCI6z/Pk38t6JUeM+D5MAvq +fnL45bF/3CUrZRK+/qLg5iwRWehKh08VQ7GqDxMerZkPmfvirVxLwpc5ngCOGJwv +ba13xdaxfTLMkHxaQyGWiUqHIwdzFoNBgjq9XTY0GGqHwVA1Hb+xTAL8PwCg+wru +41p/aOq9cfPN1U1BjulWCSMD/2YP23pI19o9Hr26ltyJcd/xkSRiCUk84efIw5JH +7QlxoMoW/SdJQAGi2pZN9o4I/fPDB3Gna9M9rZfacKda857dwkALPK8xTsfHiZzH +40g+eYUvl9nloNidneSFcxbLO/euURcCJ6Ri6nb4QWWLVH1XF6wQxEGyn7ojYMOn +ihlkA/9KATtSt+T0zgWskqckgV1ZQg9Ysqwp3GAvezJuyUTXlB02ApVFEsRTQtLZ +2WPvo/gzfih/EdNLrq7UeeB4dr/nlpANn4IyBRN6EmBHaJ4MMKN77B7bB0GaBfGJ +rgNNp7W0xG0FLjaMoQzP62qqAtZHNlW1qCmkyJGUpAa6tJw9CbQlVHJpc3RhbiBH +aW5nb2xkIDxnaW5nb2xkQGFkYWNvcmUuY29tPohgBBMRAgAgBQJI90teAhsDBgsJ +CAcDAgQVAggDBBYCAwECHgECF4AACgkQwxJtO0rlXpMVcwCgoQ91OLI+m2bsu2SS +d5MsRQH3FWsAnRFG2YGk5o5zuoLzdZd6KlL9xJ+uuQINBEj3S2MQCACnDo5dHujc +u7QHRPnxNwiKhMP6eIZaEm9tavab3UxsRufMyVC8nQ8+EmCOwfBrqstfRVoQnoDI +s5UY1XAM3mBFXYqfY9wR6NISUlzK/HPyFhGE7t3lVjOkiqbWOftDt6GgRETeqYsW +XkDV/dL4+P3eSaOSP6KMZwdjgXPOciN59KIiii9NK4icxP0lJHDk5WJFwfucEyUt +Sz7uwuUFcajHZmMxxHAnWT3uJ+ZasSijduZevsHhKTTXaZRideqf+ur1/TcUaZDQ +O3wist1qc03NkL+oGu6HYPx9ZV40p/axdTaUXMcBjtAZIzvy984HF9EsFQnvbiXt +R8zg6SYXLRmbAAMGB/9JMKWsCuxUzXmU1jyJvMXdRBZ4YQYkKFYWrEXwjYlBEGx6 +01PkR//4QJVR4zFjy4zVnaUrOxtR+65Eedf+9fNZzSNeI24TGaqyVM0OYYQtp9cH +kRDu3wif1k2NW3BnrmTjVefdAWVH6zKT9lP9m6RPHCwVGyORhVQtB3+ZXOehNJwL +9NBU4MUpGKpoQCuODdgZ8iQXbo+plg0eCxcpNaYzSnq9DMAU+2qnP6d3x4DeWzlL +wvJ2K2Mw89gvCImy/JDe05EXqKowR6aiIPvw5ou9xSHmjT6rcaIBiROCe+1hh4XC +djCdb4kOskWCEXfFKcHax4N5fI9vmk3P5068BELMiEkEGBECAAkFAkj3S2MCGwwA +CgkQwxJtO0rlXpNxdwCgjr4sQRf2cyDkCSWe4AElbI74BREAoPdet3XvE6ZcZJGl +UIZySRkdpk/A +=dGh0 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/build/unix/build-gcc/build-gcc.sh b/build/unix/build-gcc/build-gcc.sh new file mode 100755 index 0000000000..0a27af1ecd --- /dev/null +++ b/build/unix/build-gcc/build-gcc.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +set -e +set -x + +make_flags="-j$(nproc)" + +apply_patch() { + if [ $# -ge 2 ]; then + pushd $root_dir/$1 + shift + else + pushd $root_dir/gcc-source + fi + patch -p1 < $1 + popd +} + +build_binutils() { + # if binutils_configure_flags is not set at all, give it the default value + if [ -z "${binutils_configure_flags+xxx}" ]; + then + # gold is disabled because we don't use it on automation, and also we ran into + # some issues with it using this script in build-clang.py. + # + # --enable-targets builds extra target support in ld. + # Enabling aarch64 support brings in arm support, so we don't need to specify that too. + # + # It is important to have the binutils --target and the gcc --target match, + # so binutils will install binaries in a place that gcc will look for them. + binutils_configure_flags="--enable-targets=aarch64-unknown-linux-gnu --build=x86_64-unknown-linux-gnu --target=x86_64-unknown-linux-gnu --disable-gold --enable-plugins --disable-nls --with-sysroot=/" + fi + + mkdir $root_dir/binutils-objdir + pushd $root_dir/binutils-objdir + ../binutils-source/configure --prefix=${prefix-/tools/gcc}/ $binutils_configure_flags + make $make_flags + make install $make_flags DESTDIR=$root_dir + export PATH=$root_dir/${prefix-/tools/gcc}/bin:$PATH + popd +} + +build_gcc() { + # Be explicit about --build and --target so header and library install + # directories are consistent. + local target="${1:-x86_64-unknown-linux-gnu}" + + mkdir $root_dir/gcc-objdir + pushd $root_dir/gcc-objdir + + if [ -d $MOZ_FETCHES_DIR/sysroot ]; then + EXTRA_CONFIGURE_FLAGS="--with-build-sysroot=$MOZ_FETCHES_DIR/sysroot" + export CFLAGS_FOR_BUILD="--sysroot=$MOZ_FETCHES_DIR/sysroot" + fi + ../gcc-source/configure --prefix=${prefix-/tools/gcc} --build=x86_64-unknown-linux-gnu --target="${target}" --enable-languages=c,c++ --disable-nls --disable-gnu-unique-object --enable-__cxa_atexit --with-arch-32=pentiumpro --with-sysroot=/ $EXTRA_CONFIGURE_FLAGS + make $make_flags + make $make_flags install-strip DESTDIR=$root_dir + + cd $root_dir/tools + ln -s gcc gcc/bin/cc + + tar caf $root_dir/gcc.tar.zst gcc/ + popd +} diff --git a/build/unix/build-hfsplus/build-hfsplus.sh b/build/unix/build-hfsplus/build-hfsplus.sh new file mode 100755 index 0000000000..5d3417e63e --- /dev/null +++ b/build/unix/build-hfsplus/build-hfsplus.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# hfsplus needs to be rebuilt when changing the clang version used to build it. +# Until bug 1471905 is addressed, increase the following number +# when that happens: 1 + +set -e +set -x + +hfplus_version=540.1.linux3 +dirname=diskdev_cmds-${hfplus_version} +make_flags="-j$(nproc)" + +root_dir="$1" +if [ -z "$root_dir" -o ! -d "$root_dir" ]; then + root_dir=$(mktemp -d) +fi +cd $root_dir + +if test -z $TMPDIR; then + TMPDIR=/tmp/ +fi + +# Build +cd $dirname +# We want to statically link against libcrypto. On CentOS, that requires zlib +# and libdl, because of FIPS functions pulling in more than necessary from +# libcrypto (only SHA1 functions are used), but not on Debian, thus +# --as-needed. +patch -p1 << 'EOF' +--- a/newfs_hfs.tproj/Makefile.lnx ++++ b/newfs_hfs.tproj/Makefile.lnx +@@ -6,3 +6,3 @@ + newfs_hfs: $(OFILES) +- ${CC} ${CFLAGS} ${LDFLAGS} -o newfs_hfs ${OFILES} -lcrypto ++ ${CC} ${CFLAGS} ${LDFLAGS} -o newfs_hfs ${OFILES} -Wl,-Bstatic -lcrypto -Wl,-Bdynamic,--as-needed,-lz,-ldl + +EOF +grep -rl sysctl.h . | xargs sed -i /sysctl.h/d +make $make_flags || exit 1 +cd .. + +mkdir hfsplus +cp $dirname/newfs_hfs.tproj/newfs_hfs hfsplus/newfs_hfs +## XXX fsck_hfs is unused, but is small and built from the package. +cp $dirname/fsck_hfs.tproj/fsck_hfs hfsplus/fsck_hfs + +# Make a package of the built utils +cd $root_dir +tar caf $root_dir/hfsplus.tar.zst hfsplus diff --git a/build/unix/elfhack/Makefile.in b/build/unix/elfhack/Makefile.in new file mode 100644 index 0000000000..d5e58efa67 --- /dev/null +++ b/build/unix/elfhack/Makefile.in @@ -0,0 +1,46 @@ +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include $(topsrcdir)/config/rules.mk + +ifdef COMPILE_ENVIRONMENT +ifndef RELRHACK +test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX): %$(DLL_SUFFIX): %.$(OBJ_SUFFIX) elfhack + $(MKSHLIB) $(LDFLAGS) $< -nostartfiles + @echo === + @echo === If you get failures below, please file a bug describing the error + @echo === and your environment \(compiler and linker versions\), and + @echo === provide the pre-elfhacked library as an attachment. + @echo === Use --disable-elf-hack until this is fixed. + @echo === + # Fail if the library doesn't have $(DT_TYPE) .dynamic info + $(READELF) -d $@ | grep '\b$(DT_TYPE)\b' + @rm -f $@.bak + $(CURDIR)/elfhack -b -f $@ + # Fail if the backup file doesn't exist + [ -f '$@.bak' ] + # Fail if the new library doesn't contain less relocations + [ $$($(READELF) -r $@.bak | wc -l) -gt $$($(READELF) -r $@ | wc -l) ] + +test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX): DSO_SONAME=$@ +test-array$(DLL_SUFFIX): DT_TYPE=INIT_ARRAY +test-ctors$(DLL_SUFFIX): DT_TYPE=INIT + +libs:: test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX) + +.PRECIOUS: test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX) + +ifndef CROSS_COMPILE +dummy: dummy.$(OBJ_SUFFIX) + $(CC) -o $@ $^ $(LDFLAGS) + +libs:: dummy + # Will either crash or return exit code 1 if elfhack is broken + LD_PRELOAD=$(CURDIR)/test-array$(DLL_SUFFIX) $(CURDIR)/dummy + LD_PRELOAD=$(CURDIR)/test-ctors$(DLL_SUFFIX) $(CURDIR)/dummy + +endif +endif +endif diff --git a/build/unix/elfhack/README b/build/unix/elfhack/README new file mode 100644 index 0000000000..8c68031e33 --- /dev/null +++ b/build/unix/elfhack/README @@ -0,0 +1,28 @@ +Elfhack is a program to optimize ELF binaries for size and cold startup +speed. + +Presently, it is quite experimental, though it works well for the target +it was created for: Firefox's libxul.so. + +Elfhack currently only does one thing: packing dynamic relocations ; +which ends up being a quite complex task, that can be summarized this +way: +- Remove RELATIVE relocations from the .rel.dyn/.rela.dyn section. +- Inject a small code able to apply relative relocations "by hand" + after the .rel.dyn/.rela.dyn section. +- Inject a section containing relocative relocations in a different + and more packed format, after the small code. +- Register the small code as DT_INIT function. Make the small code call + what was initially the DT_INIT function, if there was one. +- Remove the hole between the new section containing relative + relocations and the following sections, adjusting offsets and base + addresses accordingly. +- Adjust PT_LOAD entries to fit new offsets, and add an additional + PT_LOAD entry when that is necessary to handle the discrepancy between + offsets and base addresses, meaning the section offsets may yet again + need adjustments. +- Adjust various DT_* dynamic tags to fit the new ELF layout. +- Adjust section headers. +- Adjust ELF headers. + +See http://glandium.org/blog/?p=1177#relocations for some figures. diff --git a/build/unix/elfhack/dummy.c b/build/unix/elfhack/dummy.c new file mode 100644 index 0000000000..2cde16102e --- /dev/null +++ b/build/unix/elfhack/dummy.c @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +extern __attribute__((visibility("default"), weak)) int print_status(); + +int main() { return print_status(); } diff --git a/build/unix/elfhack/elf.cpp b/build/unix/elfhack/elf.cpp new file mode 100644 index 0000000000..b2a21e4901 --- /dev/null +++ b/build/unix/elfhack/elf.cpp @@ -0,0 +1,935 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#undef NDEBUG +#include +#include +#include "elfxx.h" + +template +void Elf_Ehdr_Traits::swap(T& t, R& r) { + memcpy(r.e_ident, t.e_ident, sizeof(r.e_ident)); + r.e_type = endian::swap(t.e_type); + r.e_machine = endian::swap(t.e_machine); + r.e_version = endian::swap(t.e_version); + r.e_entry = endian::swap(t.e_entry); + r.e_phoff = endian::swap(t.e_phoff); + r.e_shoff = endian::swap(t.e_shoff); + r.e_flags = endian::swap(t.e_flags); + r.e_ehsize = endian::swap(t.e_ehsize); + r.e_phentsize = endian::swap(t.e_phentsize); + r.e_phnum = endian::swap(t.e_phnum); + r.e_shentsize = endian::swap(t.e_shentsize); + r.e_shnum = endian::swap(t.e_shnum); + r.e_shstrndx = endian::swap(t.e_shstrndx); +} + +template +void Elf_Phdr_Traits::swap(T& t, R& r) { + r.p_type = endian::swap(t.p_type); + r.p_offset = endian::swap(t.p_offset); + r.p_vaddr = endian::swap(t.p_vaddr); + r.p_paddr = endian::swap(t.p_paddr); + r.p_filesz = endian::swap(t.p_filesz); + r.p_memsz = endian::swap(t.p_memsz); + r.p_flags = endian::swap(t.p_flags); + r.p_align = endian::swap(t.p_align); +} + +template +void Elf_Shdr_Traits::swap(T& t, R& r) { + r.sh_name = endian::swap(t.sh_name); + r.sh_type = endian::swap(t.sh_type); + r.sh_flags = endian::swap(t.sh_flags); + r.sh_addr = endian::swap(t.sh_addr); + r.sh_offset = endian::swap(t.sh_offset); + r.sh_size = endian::swap(t.sh_size); + r.sh_link = endian::swap(t.sh_link); + r.sh_info = endian::swap(t.sh_info); + r.sh_addralign = endian::swap(t.sh_addralign); + r.sh_entsize = endian::swap(t.sh_entsize); +} + +template +void Elf_Dyn_Traits::swap(T& t, R& r) { + r.d_tag = endian::swap(t.d_tag); + r.d_un.d_val = endian::swap(t.d_un.d_val); +} + +template +void Elf_Sym_Traits::swap(T& t, R& r) { + r.st_name = endian::swap(t.st_name); + r.st_value = endian::swap(t.st_value); + r.st_size = endian::swap(t.st_size); + r.st_info = t.st_info; + r.st_other = t.st_other; + r.st_shndx = endian::swap(t.st_shndx); +} + +template +struct _Rel_info { + static inline void swap(Elf32_Word& t, Elf32_Word& r) { r = endian::swap(t); } + static inline void swap(Elf64_Xword& t, Elf64_Xword& r) { + r = endian::swap(t); + } + static inline void swap(Elf64_Xword& t, Elf32_Word& r) { + r = endian::swap(ELF32_R_INFO(ELF64_R_SYM(t), ELF64_R_TYPE(t))); + } + static inline void swap(Elf32_Word& t, Elf64_Xword& r) { + r = endian::swap(ELF64_R_INFO(ELF32_R_SYM(t), ELF32_R_TYPE(t))); + } +}; + +template +void Elf_Rel_Traits::swap(T& t, R& r) { + r.r_offset = endian::swap(t.r_offset); + _Rel_info::swap(t.r_info, r.r_info); +} + +template +void Elf_Rela_Traits::swap(T& t, R& r) { + r.r_offset = endian::swap(t.r_offset); + _Rel_info::swap(t.r_info, r.r_info); + r.r_addend = endian::swap(t.r_addend); +} + +static const Elf64_Shdr null64_section = {0, SHT_NULL, 0, 0, 0, + 0, SHN_UNDEF, 0, 0, 0}; + +Elf_Shdr null_section(null64_section); + +Elf_Ehdr::Elf_Ehdr(std::ifstream& file, unsigned char ei_class, + unsigned char ei_data) + : serializable(file, ei_class, ei_data), + ElfSection(null_section, nullptr, nullptr) { + shdr.sh_size = Elf_Ehdr::size(ei_class); +} + +Elf::Elf(std::ifstream& file) { + if (!file.is_open()) throw std::runtime_error("Error opening file"); + + file.exceptions(std::ifstream::eofbit | std::ifstream::failbit | + std::ifstream::badbit); + // Read ELF magic number and identification information + unsigned char e_ident[EI_VERSION]; + file.seekg(0); + file.read((char*)e_ident, sizeof(e_ident)); + file.seekg(0); + ehdr = new Elf_Ehdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]); + + // ELFOSABI_LINUX is kept unsupported because I haven't looked whether + // STB_GNU_UNIQUE or STT_GNU_IFUNC would need special casing. + if ((ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE) && + (ehdr->e_ident[EI_ABIVERSION] != 0)) + throw std::runtime_error("unsupported ELF ABI"); + + if (ehdr->e_version != 1) throw std::runtime_error("unsupported ELF version"); + + // Sanity checks + if (ehdr->e_shnum == 0) + throw std::runtime_error("sstripped ELF files aren't supported"); + + if (ehdr->e_ehsize != Elf_Ehdr::size(e_ident[EI_CLASS])) + throw std::runtime_error( + "unsupported ELF inconsistency: ehdr.e_ehsize != sizeof(ehdr)"); + + if (ehdr->e_shentsize != Elf_Shdr::size(e_ident[EI_CLASS])) + throw std::runtime_error( + "unsupported ELF inconsistency: ehdr.e_shentsize != sizeof(shdr)"); + + if (ehdr->e_phnum == 0) { + if (ehdr->e_phoff != 0) + throw std::runtime_error( + "unsupported ELF inconsistency: e_phnum == 0 && e_phoff != 0"); + if (ehdr->e_phentsize != 0) + throw std::runtime_error( + "unsupported ELF inconsistency: e_phnum == 0 && e_phentsize != 0"); + } else if (ehdr->e_phoff != ehdr->e_ehsize) + throw std::runtime_error( + "unsupported ELF inconsistency: ehdr->e_phoff != ehdr->e_ehsize"); + else if (ehdr->e_phentsize != Elf_Phdr::size(e_ident[EI_CLASS])) + throw std::runtime_error( + "unsupported ELF inconsistency: ehdr->e_phentsize != sizeof(phdr)"); + + // Read section headers + Elf_Shdr** shdr = new Elf_Shdr*[ehdr->e_shnum]; + file.seekg(ehdr->e_shoff); + for (int i = 0; i < ehdr->e_shnum; i++) + shdr[i] = new Elf_Shdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]); + + // Sanity check in section header for index 0 + if ((shdr[0]->sh_name != 0) || (shdr[0]->sh_type != SHT_NULL) || + (shdr[0]->sh_flags != 0) || (shdr[0]->sh_addr != 0) || + (shdr[0]->sh_offset != 0) || (shdr[0]->sh_size != 0) || + (shdr[0]->sh_link != SHN_UNDEF) || (shdr[0]->sh_info != 0) || + (shdr[0]->sh_addralign != 0) || (shdr[0]->sh_entsize != 0)) + throw std::runtime_error( + "Section header for index 0 contains unsupported values"); + + if ((shdr[ehdr->e_shstrndx]->sh_link != 0) || + (shdr[ehdr->e_shstrndx]->sh_info != 0)) + throw std::runtime_error( + "unsupported ELF content: string table with sh_link != 0 || sh_info != " + "0"); + + // Store these temporarily + tmp_shdr = shdr; + tmp_file = &file; + + // Fill sections list + sections = new ElfSection*[ehdr->e_shnum]; + for (int i = 0; i < ehdr->e_shnum; i++) sections[i] = nullptr; + for (int i = 1; i < ehdr->e_shnum; i++) { + // The .dynamic section is going to have references to other sections, + // so it's better to start with that one and recursively initialize those + // other sections first, to avoid possible infinite recursion (bug 1606739). + if (tmp_shdr[i]->sh_type == SHT_DYNAMIC) { + getSection(i); + } + } + for (int i = 1; i < ehdr->e_shnum; i++) { + if (sections[i] != nullptr) continue; + getSection(i); + } + Elf_Shdr s; + s.sh_name = 0; + s.sh_type = SHT_NULL; + s.sh_flags = 0; + s.sh_addr = 0; + s.sh_offset = ehdr->e_shoff; + s.sh_entsize = Elf_Shdr::size(e_ident[EI_CLASS]); + s.sh_size = s.sh_entsize * ehdr->e_shnum; + s.sh_link = 0; + s.sh_info = 0; + s.sh_addralign = (e_ident[EI_CLASS] == ELFCLASS32) ? 4 : 8; + shdr_section = new ElfSection(s, nullptr, nullptr); + + // Fake section for program headers + s.sh_offset = ehdr->e_phoff; + s.sh_addr = ehdr->e_phoff; + s.sh_entsize = Elf_Phdr::size(e_ident[EI_CLASS]); + s.sh_size = s.sh_entsize * ehdr->e_phnum; + phdr_section = new ElfSection(s, nullptr, nullptr); + + phdr_section->insertAfter(ehdr, false); + + sections[1]->insertAfter(phdr_section, false); + for (int i = 2; i < ehdr->e_shnum; i++) { + // TODO: this should be done in a better way + if ((shdr_section->getPrevious() == nullptr) && + (shdr[i]->sh_offset > ehdr->e_shoff)) { + shdr_section->insertAfter(sections[i - 1], false); + sections[i]->insertAfter(shdr_section, false); + } else + sections[i]->insertAfter(sections[i - 1], false); + } + if (shdr_section->getPrevious() == nullptr) + shdr_section->insertAfter(sections[ehdr->e_shnum - 1], false); + + tmp_file = nullptr; + tmp_shdr = nullptr; + for (int i = 0; i < ehdr->e_shnum; i++) delete shdr[i]; + delete[] shdr; + + eh_shstrndx = (ElfStrtab_Section*)sections[ehdr->e_shstrndx]; + + // Skip reading program headers if there aren't any + if (ehdr->e_phnum == 0) return; + + bool adjusted_phdr_section = false; + // Read program headers + file.seekg(ehdr->e_phoff); + for (int i = 0; i < ehdr->e_phnum; i++) { + Elf_Phdr phdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]); + if (phdr.p_type == PT_LOAD) { + // Default alignment for PT_LOAD on x86-64 prevents elfhack from + // doing anything useful. However, the system doesn't actually + // require such a big alignment, so in order for elfhack to work + // efficiently, reduce alignment when it's originally the default + // one. + if ((ehdr->e_machine == EM_X86_64) && (phdr.p_align == 0x200000)) + phdr.p_align = 0x1000; + } + ElfSegment* segment = new ElfSegment(&phdr); + // Some segments aren't entirely filled (if at all) by sections + // For those, we use fake sections + if ((phdr.p_type == PT_LOAD) && (phdr.p_offset == 0)) { + // Use a fake section for ehdr and phdr + ehdr->getShdr().sh_addr = phdr.p_vaddr; + if (!adjusted_phdr_section) { + phdr_section->getShdr().sh_addr += phdr.p_vaddr; + adjusted_phdr_section = true; + } + segment->addSection(ehdr); + segment->addSection(phdr_section); + } + if (phdr.p_type == PT_PHDR) { + if (!adjusted_phdr_section) { + phdr_section->getShdr().sh_addr = phdr.p_vaddr; + adjusted_phdr_section = true; + } + segment->addSection(phdr_section); + } + for (int j = 1; j < ehdr->e_shnum; j++) + if (phdr.contains(sections[j])) segment->addSection(sections[j]); + // Make sure that our view of segments corresponds to the original + // ELF file. + // GNU gold likes to start some segments before the first section + // they contain. https://sourceware.org/bugzilla/show_bug.cgi?id=19392 + unsigned int gold_adjustment = segment->getAddr() - phdr.p_vaddr; + assert(segment->getFileSize() == phdr.p_filesz - gold_adjustment); + // gold makes TLS segments end on an aligned virtual address, even + // when the underlying section ends before that, while bfd ld + // doesn't. It's fine if we don't keep that alignment. + unsigned int memsize = segment->getMemSize(); + if (phdr.p_type == PT_TLS && memsize != phdr.p_memsz) { + unsigned int align = segment->getAlign(); + memsize = (memsize + align - 1) & ~(align - 1); + } + assert(memsize == phdr.p_memsz - gold_adjustment); + segments.push_back(segment); + } + + new (&eh_entry) ElfLocation(ehdr->e_entry, this); +} + +Elf::~Elf() { + for (std::vector::iterator seg = segments.begin(); + seg != segments.end(); seg++) + delete *seg; + delete[] sections; + ElfSection* section = ehdr; + while (section != nullptr) { + ElfSection* next = section->getNext(); + delete section; + section = next; + } +} + +// TODO: This shouldn't fail after inserting sections +ElfSection* Elf::getSection(int index) { + if ((index < -1) || (index >= ehdr->e_shnum)) + throw std::runtime_error("Section index out of bounds"); + if (index == -1) + index = ehdr->e_shstrndx; // TODO: should be fixed to use the actual + // current number + // Special case: the section at index 0 is void + if (index == 0) return nullptr; + // Infinite recursion guard + if (sections[index] == (ElfSection*)this) return nullptr; + if (sections[index] == nullptr) { + sections[index] = (ElfSection*)this; + switch (tmp_shdr[index]->sh_type) { + case SHT_DYNAMIC: + sections[index] = + new ElfDynamic_Section(*tmp_shdr[index], tmp_file, this); + break; + case SHT_REL: + sections[index] = + new ElfRel_Section(*tmp_shdr[index], tmp_file, this); + break; + case SHT_RELA: + sections[index] = + new ElfRel_Section(*tmp_shdr[index], tmp_file, this); + break; + case SHT_DYNSYM: + case SHT_SYMTAB: + sections[index] = + new ElfSymtab_Section(*tmp_shdr[index], tmp_file, this); + break; + case SHT_STRTAB: + sections[index] = + new ElfStrtab_Section(*tmp_shdr[index], tmp_file, this); + break; + default: + sections[index] = new ElfSection(*tmp_shdr[index], tmp_file, this); + } + } + return sections[index]; +} + +ElfSection* Elf::getSectionAt(Elf64_Off offset) { + for (int i = 1; i < ehdr->e_shnum; i++) { + ElfSection* section = getSection(i); + if ((section != nullptr) && (section->getFlags() & SHF_ALLOC) && + !(section->getFlags() & SHF_TLS) && (offset >= section->getAddr()) && + (offset < section->getAddr() + section->getSize())) + return section; + } + return nullptr; +} + +ElfSegment* Elf::getSegmentByType(unsigned int type, ElfSegment* last) { + std::vector::iterator seg; + if (last) { + seg = std::find(segments.begin(), segments.end(), last); + ++seg; + } else + seg = segments.begin(); + for (; seg != segments.end(); seg++) + if ((*seg)->getType() == type) return *seg; + return nullptr; +} + +void Elf::removeSegment(ElfSegment* segment) { + if (!segment) return; + std::vector::iterator seg; + seg = std::find(segments.begin(), segments.end(), segment); + if (seg == segments.end()) return; + segment->clear(); + segments.erase(seg); +} + +ElfDynamic_Section* Elf::getDynSection() { + for (std::vector::iterator seg = segments.begin(); + seg != segments.end(); seg++) + if (((*seg)->getType() == PT_DYNAMIC) && + ((*seg)->getFirstSection() != nullptr) && + (*seg)->getFirstSection()->getType() == SHT_DYNAMIC) + return (ElfDynamic_Section*)(*seg)->getFirstSection(); + + return nullptr; +} + +void Elf::normalize() { + // fixup section headers sh_name; TODO: that should be done by sections + // themselves + for (ElfSection* section = ehdr; section != nullptr; + section = section->getNext()) { + if (section->getIndex() == 0) + continue; + else + ehdr->e_shnum = section->getIndex() + 1; + section->getShdr().sh_name = eh_shstrndx->getStrIndex(section->getName()); + } + ehdr->markDirty(); + // Check segments consistency + int i = 0; + for (std::vector::iterator seg = segments.begin(); + seg != segments.end(); seg++, i++) { + std::list::iterator it = (*seg)->begin(); + for (ElfSection* last = *(it++); it != (*seg)->end(); last = *(it++)) { + if (((*it)->getType() != SHT_NOBITS) && + ((*it)->getAddr() - last->getAddr()) != + ((*it)->getOffset() - last->getOffset())) { + throw std::runtime_error("Segments inconsistency"); + } + } + } + + ElfSegment* prevLoad = nullptr; + for (auto& it : segments) { + if (it->getType() == PT_LOAD) { + if (prevLoad) { + size_t alignedPrevEnd = (prevLoad->getAddr() + prevLoad->getMemSize() + + prevLoad->getAlign() - 1) & + ~(prevLoad->getAlign() - 1); + size_t alignedStart = it->getAddr() & ~(it->getAlign() - 1); + if (alignedPrevEnd > alignedStart) { + throw std::runtime_error("Segments overlap"); + } + } + prevLoad = it; + } + } + + // fixup ehdr before writing + if (ehdr->e_phnum != segments.size()) { + ehdr->e_phnum = segments.size(); + phdr_section->getShdr().sh_size = + segments.size() * Elf_Phdr::size(ehdr->e_ident[EI_CLASS]); + phdr_section->getNext()->markDirty(); + } + // fixup shdr before writing + if (ehdr->e_shnum != shdr_section->getSize() / shdr_section->getEntSize()) + shdr_section->getShdr().sh_size = + ehdr->e_shnum * Elf_Shdr::size(ehdr->e_ident[EI_CLASS]); + ehdr->e_shoff = shdr_section->getOffset(); + ehdr->e_entry = eh_entry.getValue(); + ehdr->e_shstrndx = eh_shstrndx->getIndex(); + + // Check sections consistency + unsigned int minOffset = 0; + for (ElfSection* section = ehdr; section != nullptr; + section = section->getNext()) { + unsigned int offset = section->getOffset(); + if (offset < minOffset) { + throw std::runtime_error("Sections overlap"); + } + if (section->getType() != SHT_NOBITS) { + minOffset = offset + section->getSize(); + } + } +} + +void Elf::write(std::ofstream& file) { + normalize(); + for (ElfSection* section = ehdr; section != nullptr; + section = section->getNext()) { + file.seekp(section->getOffset()); + if (section == phdr_section) { + for (std::vector::iterator seg = segments.begin(); + seg != segments.end(); seg++) { + Elf_Phdr phdr; + phdr.p_type = (*seg)->getType(); + phdr.p_flags = (*seg)->getFlags(); + phdr.p_offset = (*seg)->getOffset(); + phdr.p_vaddr = (*seg)->getAddr(); + phdr.p_paddr = phdr.p_vaddr + (*seg)->getVPDiff(); + phdr.p_filesz = (*seg)->getFileSize(); + phdr.p_memsz = (*seg)->getMemSize(); + phdr.p_align = (*seg)->getAlign(); + phdr.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]); + } + } else if (section == shdr_section) { + null_section.serialize(file, ehdr->e_ident[EI_CLASS], + ehdr->e_ident[EI_DATA]); + for (ElfSection* sec = ehdr; sec != nullptr; sec = sec->getNext()) { + if (sec->getType() != SHT_NULL) + sec->getShdr().serialize(file, ehdr->e_ident[EI_CLASS], + ehdr->e_ident[EI_DATA]); + } + } else + section->serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]); + } +} + +ElfSection::ElfSection(Elf_Shdr& s, std::ifstream* file, Elf* parent) + : shdr(s), + link(shdr.sh_link == SHN_UNDEF ? nullptr + : parent->getSection(shdr.sh_link)), + next(nullptr), + previous(nullptr), + index(-1) { + if ((file == nullptr) || (shdr.sh_type == SHT_NULL) || + (shdr.sh_type == SHT_NOBITS)) + data = nullptr; + else { + data = static_cast(malloc(shdr.sh_size)); + if (!data) { + throw std::runtime_error("Could not malloc ElfSection data"); + } + auto pos = file->tellg(); + file->seekg(shdr.sh_offset); + file->read(data, shdr.sh_size); + file->seekg(pos); + } + if (shdr.sh_name == 0) + name = nullptr; + else { + ElfStrtab_Section* strtab = (ElfStrtab_Section*)parent->getSection(-1); + // Special case (see elfgeneric.cpp): if strtab is nullptr, the + // section being created is the strtab. + if (strtab == nullptr) + name = &data[shdr.sh_name]; + else + name = strtab->getStr(shdr.sh_name); + } + // Only SHT_REL/SHT_RELA sections use sh_info to store a section + // number. + if ((shdr.sh_type == SHT_REL) || (shdr.sh_type == SHT_RELA)) + info.section = shdr.sh_info ? parent->getSection(shdr.sh_info) : nullptr; + else + info.index = shdr.sh_info; +} + +Elf64_Addr ElfSection::getAddr() { + if (shdr.sh_addr != (Elf64_Addr)-1) return shdr.sh_addr; + + // It should be safe to adjust sh_addr for all allocated sections that + // are neither SHT_NOBITS nor SHT_PROGBITS + if ((previous != nullptr) && isRelocatable()) { + unsigned int addr = previous->getAddr(); + if (previous->getType() != SHT_NOBITS) addr += previous->getSize(); + + if (addr & (getAddrAlign() - 1)) addr = (addr | (getAddrAlign() - 1)) + 1; + + return (shdr.sh_addr = addr); + } + return shdr.sh_addr; +} + +Elf64_Off ElfSection::getOffset() { + if (shdr.sh_offset != (Elf64_Off)-1) return shdr.sh_offset; + + if (previous == nullptr) return (shdr.sh_offset = 0); + + Elf64_Off offset = previous->getOffset(); + + ElfSegment* ptload = getSegmentByType(PT_LOAD); + ElfSegment* prev_ptload = previous->getSegmentByType(PT_LOAD); + + if (ptload && (ptload == prev_ptload)) { + offset += getAddr() - previous->getAddr(); + return (shdr.sh_offset = offset); + } + + if (previous->getType() != SHT_NOBITS) offset += previous->getSize(); + + Elf32_Word align = 0x1000; + for (std::vector::iterator seg = segments.begin(); + seg != segments.end(); seg++) + align = std::max(align, (*seg)->getAlign()); + + Elf32_Word mask = align - 1; + // SHF_TLS is used for .tbss which is some kind of special case. + if (((getType() != SHT_NOBITS) || (getFlags() & SHF_TLS)) && + (getFlags() & SHF_ALLOC)) { + if ((getAddr() & mask) < (offset & mask)) + offset = (offset | mask) + (getAddr() & mask) + 1; + else + offset = (offset & ~mask) + (getAddr() & mask); + } + if ((getType() != SHT_NOBITS) && (offset & (getAddrAlign() - 1))) + offset = (offset | (getAddrAlign() - 1)) + 1; + + return (shdr.sh_offset = offset); +} + +int ElfSection::getIndex() { + if (index != -1) return index; + if (getType() == SHT_NULL) return (index = 0); + ElfSection* reference; + for (reference = previous; + (reference != nullptr) && (reference->getType() == SHT_NULL); + reference = reference->getPrevious()) + ; + if (reference == nullptr) return (index = 1); + return (index = reference->getIndex() + 1); +} + +Elf_Shdr& ElfSection::getShdr() { + getOffset(); + if (shdr.sh_link == (Elf64_Word)-1) + shdr.sh_link = getLink() ? getLink()->getIndex() : 0; + if (shdr.sh_info == (Elf64_Word)-1) + shdr.sh_info = ((getType() == SHT_REL) || (getType() == SHT_RELA)) + ? (getInfo().section ? getInfo().section->getIndex() : 0) + : getInfo().index; + + return shdr; +} + +ElfSegment::ElfSegment(Elf_Phdr* phdr) + : type(phdr->p_type), + v_p_diff(phdr->p_paddr - phdr->p_vaddr), + flags(phdr->p_flags), + align(phdr->p_align), + vaddr(phdr->p_vaddr), + filesz(phdr->p_filesz), + memsz(phdr->p_memsz) {} + +void ElfSegment::addSection(ElfSection* section) { + // Make sure all sections in PT_GNU_RELRO won't be moved by elfhack + assert(!((type == PT_GNU_RELRO) && (section->isRelocatable()))); + + // TODO: Check overlapping sections + std::list::iterator i; + for (i = sections.begin(); i != sections.end(); ++i) + if ((*i)->getAddr() > section->getAddr()) break; + sections.insert(i, section); + section->addToSegment(this); +} + +void ElfSegment::removeSection(ElfSection* section) { + sections.remove(section); + section->removeFromSegment(this); +} + +unsigned int ElfSegment::getFileSize() { + if (type == PT_GNU_RELRO) return filesz; + + if (sections.empty()) return 0; + // Search the last section that is not SHT_NOBITS + std::list::reverse_iterator i; + for (i = sections.rbegin(); + (i != sections.rend()) && ((*i)->getType() == SHT_NOBITS); ++i) + ; + // All sections are SHT_NOBITS + if (i == sections.rend()) return 0; + + unsigned int end = (*i)->getAddr() + (*i)->getSize(); + + return end - sections.front()->getAddr(); +} + +unsigned int ElfSegment::getMemSize() { + if (type == PT_GNU_RELRO) return memsz; + + if (sections.empty()) return 0; + + unsigned int end = sections.back()->getAddr() + sections.back()->getSize(); + + return end - sections.front()->getAddr(); +} + +unsigned int ElfSegment::getOffset() { + if ((type == PT_GNU_RELRO) && !sections.empty() && + (sections.front()->getAddr() != vaddr)) + throw std::runtime_error( + "PT_GNU_RELRO segment doesn't start on a section start"); + + return sections.empty() ? 0 : sections.front()->getOffset(); +} + +unsigned int ElfSegment::getAddr() { + if ((type == PT_GNU_RELRO) && !sections.empty() && + (sections.front()->getAddr() != vaddr)) + throw std::runtime_error( + "PT_GNU_RELRO segment doesn't start on a section start"); + + return sections.empty() ? 0 : sections.front()->getAddr(); +} + +void ElfSegment::clear() { + for (std::list::iterator i = sections.begin(); + i != sections.end(); ++i) + (*i)->removeFromSegment(this); + sections.clear(); +} + +ElfValue* ElfDynamic_Section::getValueForType(unsigned int tag) { + for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) + if (dyns[i].tag == tag) return dyns[i].value; + + return nullptr; +} + +ElfSection* ElfDynamic_Section::getSectionForType(unsigned int tag) { + ElfValue* value = getValueForType(tag); + return value ? value->getSection() : nullptr; +} + +bool ElfDynamic_Section::setValueForType(unsigned int tag, ElfValue* val) { + unsigned int i; + unsigned int shnum = shdr.sh_size / shdr.sh_entsize; + for (i = 0; (i < shnum) && (dyns[i].tag != DT_NULL); i++) + if (dyns[i].tag == tag) { + delete dyns[i].value; + dyns[i].value = val; + return true; + } + // If we get here, this means we didn't match for the given tag + // Most of the time, there are a few DT_NULL entries, that we can + // use to add our value, but if we are on the last entry, we can't. + if (i >= shnum - 1) return false; + + dyns[i].tag = tag; + dyns[i].value = val; + return true; +} + +ElfDynamic_Section::ElfDynamic_Section(Elf_Shdr& s, std::ifstream* file, + Elf* parent) + : ElfSection(s, file, parent) { + auto pos = file->tellg(); + dyns.resize(s.sh_size / s.sh_entsize); + file->seekg(shdr.sh_offset); + // Here we assume tags refer to only one section (e.g. DT_RELSZ accounts + // for .rel.dyn size) + for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) { + Elf_Dyn dyn(*file, parent->getClass(), parent->getData()); + dyns[i].tag = dyn.d_tag; + switch (dyn.d_tag) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + dyns[i].value = new ElfValue(); + break; + case DT_NEEDED: + case DT_SONAME: + case DT_RPATH: + case DT_PLTREL: + case DT_RUNPATH: + case DT_FLAGS: + case DT_RELACOUNT: + case DT_RELCOUNT: + case DT_VERDEFNUM: + case DT_VERNEEDNUM: + dyns[i].value = new ElfPlainValue(dyn.d_un.d_val); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_GNU_HASH: + case DT_VERSYM: + case DT_VERNEED: + case DT_VERDEF: + dyns[i].value = new ElfLocation(dyn.d_un.d_ptr, parent); + break; + default: + dyns[i].value = nullptr; + } + } + // Another loop to get the section sizes + for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) + switch (dyns[i].tag) { + case DT_PLTRELSZ: + dyns[i].value = new ElfSize(getSectionForType(DT_JMPREL)); + break; + case DT_RELASZ: + dyns[i].value = new ElfSize(getSectionForType(DT_RELA)); + break; + case DT_STRSZ: + dyns[i].value = new ElfSize(getSectionForType(DT_STRTAB)); + break; + case DT_RELSZ: + dyns[i].value = new ElfSize(getSectionForType(DT_REL)); + break; + case DT_INIT_ARRAYSZ: + dyns[i].value = new ElfSize(getSectionForType(DT_INIT_ARRAY)); + break; + case DT_FINI_ARRAYSZ: + dyns[i].value = new ElfSize(getSectionForType(DT_FINI_ARRAY)); + break; + case DT_RELAENT: + dyns[i].value = new ElfEntSize(getSectionForType(DT_RELA)); + break; + case DT_SYMENT: + dyns[i].value = new ElfEntSize(getSectionForType(DT_SYMTAB)); + break; + case DT_RELENT: + dyns[i].value = new ElfEntSize(getSectionForType(DT_REL)); + break; + } + + file->seekg(pos); +} + +ElfDynamic_Section::~ElfDynamic_Section() { + for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) + delete dyns[i].value; +} + +void ElfDynamic_Section::serialize(std::ofstream& file, unsigned char ei_class, + unsigned char ei_data) { + for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { + Elf_Dyn dyn; + dyn.d_tag = dyns[i].tag; + dyn.d_un.d_val = (dyns[i].value != nullptr) ? dyns[i].value->getValue() : 0; + dyn.serialize(file, ei_class, ei_data); + } +} + +ElfSymtab_Section::ElfSymtab_Section(Elf_Shdr& s, std::ifstream* file, + Elf* parent) + : ElfSection(s, file, parent) { + auto pos = file->tellg(); + syms.resize(s.sh_size / s.sh_entsize); + ElfStrtab_Section* strtab = (ElfStrtab_Section*)getLink(); + file->seekg(shdr.sh_offset); + for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { + Elf_Sym sym(*file, parent->getClass(), parent->getData()); + syms[i].name = strtab->getStr(sym.st_name); + syms[i].info = sym.st_info; + syms[i].other = sym.st_other; + ElfSection* section = + (sym.st_shndx == SHN_ABS) ? nullptr : parent->getSection(sym.st_shndx); + new (&syms[i].value) + ElfLocation(section, sym.st_value, ElfLocation::ABSOLUTE); + syms[i].size = sym.st_size; + syms[i].defined = (sym.st_shndx != SHN_UNDEF); + } + file->seekg(pos); +} + +void ElfSymtab_Section::serialize(std::ofstream& file, unsigned char ei_class, + unsigned char ei_data) { + ElfStrtab_Section* strtab = (ElfStrtab_Section*)getLink(); + for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { + Elf_Sym sym; + sym.st_name = strtab->getStrIndex(syms[i].name); + sym.st_info = syms[i].info; + sym.st_other = syms[i].other; + sym.st_value = syms[i].value.getValue(); + ElfSection* section = syms[i].value.getSection(); + if (syms[i].defined) + sym.st_shndx = section ? section->getIndex() : SHN_ABS; + else + sym.st_shndx = SHN_UNDEF; + sym.st_size = syms[i].size; + sym.serialize(file, ei_class, ei_data); + } +} + +Elf_SymValue* ElfSymtab_Section::lookup(const char* name, + unsigned int type_filter) { + for (std::vector::iterator sym = syms.begin(); + sym != syms.end(); sym++) { + if ((type_filter & (1 << ELF32_ST_TYPE(sym->info))) && + (strcmp(sym->name, name) == 0)) { + return &*sym; + } + } + return nullptr; +} + +const char* ElfStrtab_Section::getStr(unsigned int index) { + for (std::vector::iterator t = table.begin(); t != table.end(); + t++) { + if (index < t->used) return t->buf + index; + index -= t->used; + } + assert(1 == 0); + return nullptr; +} + +const char* ElfStrtab_Section::getStr(const char* string) { + if (string == nullptr) return nullptr; + + // If the given string is within the section, return it + for (std::vector::iterator t = table.begin(); t != table.end(); + t++) + if ((string >= t->buf) && (string < t->buf + t->used)) return string; + + // TODO: should scan in the section to find an existing string + + // If not, we need to allocate the string in the section + size_t len = strlen(string) + 1; + + if (table.back().size - table.back().used < len) + table.resize(table.size() + 1); + + char* alloc_str = table.back().buf + table.back().used; + memcpy(alloc_str, string, len); + table.back().used += len; + + shdr.sh_size += len; + markDirty(); + + return alloc_str; +} + +unsigned int ElfStrtab_Section::getStrIndex(const char* string) { + if (string == nullptr) return 0; + + unsigned int index = 0; + string = getStr(string); + for (std::vector::iterator t = table.begin(); t != table.end(); + t++) { + if ((string >= t->buf) && (string < t->buf + t->used)) + return index + (string - t->buf); + index += t->used; + } + + assert(1 == 0); + return 0; +} + +void ElfStrtab_Section::serialize(std::ofstream& file, unsigned char ei_class, + unsigned char ei_data) { + file.seekp(getOffset()); + for (std::vector::iterator t = table.begin(); t != table.end(); + t++) + file.write(t->buf, t->used); +} diff --git a/build/unix/elfhack/elfhack.cpp b/build/unix/elfhack/elfhack.cpp new file mode 100644 index 0000000000..719d4ac8f5 --- /dev/null +++ b/build/unix/elfhack/elfhack.cpp @@ -0,0 +1,1458 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#undef NDEBUG +#include +#include +#include +#include +#include + +#include "elfxx.h" +#include "mozilla/CheckedInt.h" + +#define ver "1" +#define elfhack_data ".elfhack.data.v" ver +#define elfhack_text ".elfhack.text.v" ver + +#ifndef R_ARM_V4BX +# define R_ARM_V4BX 0x28 +#endif +#ifndef R_ARM_CALL +# define R_ARM_CALL 0x1c +#endif +#ifndef R_ARM_JUMP24 +# define R_ARM_JUMP24 0x1d +#endif +#ifndef R_ARM_THM_JUMP24 +# define R_ARM_THM_JUMP24 0x1e +#endif + +char* rundir = nullptr; + +template +struct wrapped { + T value; +}; + +class Elf_Addr_Traits { + public: + typedef wrapped Type32; + typedef wrapped Type64; + + template + static inline void swap(T& t, R& r) { + r.value = endian::swap(t.value); + } +}; + +typedef serializable Elf_Addr; + +class ElfRelHack_Section : public ElfSection { + public: + ElfRelHack_Section(Elf_Shdr& s) + : ElfSection(s, nullptr, nullptr), + block_size((8 * s.sh_entsize - 1) * s.sh_entsize) { + name = elfhack_data; + }; + + void serialize(std::ofstream& file, unsigned char ei_class, + unsigned char ei_data) { + if (bitmap) { + relr.push_back((bitmap << 1) | 1); + } + for (std::vector::iterator i = relr.begin(); i != relr.end(); + ++i) { + Elf_Addr out; + out.value = *i; + out.serialize(file, ei_class, ei_data); + } + } + + bool isRelocatable() { return true; } + + void push_back(Elf64_Addr offset) { + // The format used for the packed relocations is SHT_RELR, described in + // https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ + // The gist of it is that an address is recorded, and the following words, + // if their LSB is 1, represent a bitmap of word-size-spaced relocations + // at the addresses that follow. There can be multiple such bitmaps, such + // that very long streaks of (possibly spaced) relocations can be recorded + // in a very compact way. + for (;;) { + // [block_start; block_start + block_size] represents the range of offsets + // the current bitmap can record. If the offset doesn't fall in that + // range, or if doesn't align properly to be recorded, we record the + // bitmap, and slide the block corresponding to a new bitmap. If the + // offset doesn't fall in the range for the new bitmap, or if there wasn't + // an active bitmap in the first place, we record the offset and start a + // new bitmap for the block that follows it. + if (!block_start || offset < block_start || + offset >= block_start + block_size || + (offset - block_start) % shdr.sh_entsize) { + if (bitmap) { + relr.push_back((bitmap << 1) | 1); + block_start += block_size; + bitmap = 0; + continue; + } + relr.push_back(offset); + block_start = offset + shdr.sh_entsize; + break; + } + bitmap |= 1ULL << ((offset - block_start) / shdr.sh_entsize); + break; + } + shdr.sh_size = (relr.size() + (bitmap ? 1 : 0)) * shdr.sh_entsize; + } + + private: + std::vector relr; + size_t block_size; + Elf64_Addr block_start = 0; + Elf64_Addr bitmap = 0; +}; + +class ElfRelHackCode_Section : public ElfSection { + public: + ElfRelHackCode_Section(Elf_Shdr& s, Elf& e, + ElfRelHack_Section& relhack_section, unsigned int init, + unsigned int mprotect_cb, unsigned int sysconf_cb) + : ElfSection(s, nullptr, nullptr), + parent(e), + relhack_section(relhack_section), + init(init), + init_trampoline(nullptr), + mprotect_cb(mprotect_cb), + sysconf_cb(sysconf_cb) { + std::string file(rundir); + file += "/inject/"; + switch (parent.getMachine()) { + case EM_386: + file += "x86"; + break; + case EM_X86_64: + file += "x86_64"; + break; + case EM_ARM: + file += "arm"; + break; + case EM_AARCH64: + file += "aarch64"; + break; + default: + throw std::runtime_error("unsupported architecture"); + } + file += ".o"; + std::ifstream inject(file.c_str(), std::ios::in | std::ios::binary); + elf = new Elf(inject); + if (elf->getType() != ET_REL) + throw std::runtime_error("object for injected code is not ET_REL"); + if (elf->getMachine() != parent.getMachine()) + throw std::runtime_error( + "architecture of object for injected code doesn't match"); + + ElfSymtab_Section* symtab = nullptr; + + // Find the symbol table. + for (ElfSection* section = elf->getSection(1); section != nullptr; + section = section->getNext()) { + if (section->getType() == SHT_SYMTAB) + symtab = (ElfSymtab_Section*)section; + } + if (symtab == nullptr) + throw std::runtime_error( + "Couldn't find a symbol table for the injected code"); + + relro = parent.getSegmentByType(PT_GNU_RELRO); + + // Find the init symbol + entry_point = -1; + std::string symbol = "init"; + if (!init) symbol += "_noinit"; + if (relro) symbol += "_relro"; + Elf_SymValue* sym = symtab->lookup(symbol.c_str()); + if (!sym) + throw std::runtime_error( + "Couldn't find an 'init' symbol in the injected code"); + + entry_point = sym->value.getValue(); + + // Get all relevant sections from the injected code object. + add_code_section(sym->value.getSection()); + + // If the original init function is located too far away, we're going to + // need to use a trampoline. See comment in inject.c. + // Theoretically, we should check for (init - instr) > boundary, where + // boundary is the platform-dependent limit, and instr is the virtual + // address of the instruction that calls the original init, but we don't + // have it at this point, so punt to just init. + if ((init > 0xffffff && parent.getMachine() == EM_ARM) || + (init > 0x07ffffff && parent.getMachine() == EM_AARCH64)) { + Elf_SymValue* trampoline = symtab->lookup("init_trampoline"); + if (!trampoline) { + throw std::runtime_error( + "Couldn't find an 'init_trampoline' symbol in the injected code"); + } + + init_trampoline = trampoline->value.getSection(); + add_code_section(init_trampoline); + } + + // Adjust code sections offsets according to their size + std::vector::iterator c = code.begin(); + (*c)->getShdr().sh_addr = 0; + for (ElfSection* last = *(c++); c != code.end(); ++c) { + unsigned int addr = last->getShdr().sh_addr + last->getSize(); + if (addr & ((*c)->getAddrAlign() - 1)) + addr = (addr | ((*c)->getAddrAlign() - 1)) + 1; + (*c)->getShdr().sh_addr = addr; + // We need to align this section depending on the greater + // alignment required by code sections. + if (shdr.sh_addralign < (*c)->getAddrAlign()) + shdr.sh_addralign = (*c)->getAddrAlign(); + last = *c; + } + shdr.sh_size = code.back()->getAddr() + code.back()->getSize(); + data = static_cast(malloc(shdr.sh_size)); + if (!data) { + throw std::runtime_error("Could not malloc ElfSection data"); + } + char* buf = data; + for (c = code.begin(); c != code.end(); ++c) { + memcpy(buf, (*c)->getData(), (*c)->getSize()); + buf += (*c)->getSize(); + } + name = elfhack_text; + } + + ~ElfRelHackCode_Section() { delete elf; } + + void serialize(std::ofstream& file, unsigned char ei_class, + unsigned char ei_data) override { + // Readjust code offsets + for (std::vector::iterator c = code.begin(); c != code.end(); + ++c) + (*c)->getShdr().sh_addr += getAddr(); + + // Apply relocations + for (std::vector::iterator c = code.begin(); c != code.end(); + ++c) { + for (ElfSection* rel = elf->getSection(1); rel != nullptr; + rel = rel->getNext()) + if (((rel->getType() == SHT_REL) || (rel->getType() == SHT_RELA)) && + (rel->getInfo().section == *c)) { + if (rel->getType() == SHT_REL) + apply_relocations((ElfRel_Section*)rel, *c); + else + apply_relocations((ElfRel_Section*)rel, *c); + } + } + + ElfSection::serialize(file, ei_class, ei_data); + } + + bool isRelocatable() override { return false; } + + unsigned int getEntryPoint() { return entry_point; } + + void insertBefore(ElfSection* section, bool dirty = true) override { + // Adjust the address so that this section is adjacent to the one it's + // being inserted before. This avoids creating holes which subsequently + // might lead the PHDR-adjusting code to create unnecessary additional + // PT_LOADs. + shdr.sh_addr = + (section->getAddr() - shdr.sh_size) & ~(shdr.sh_addralign - 1); + ElfSection::insertBefore(section, dirty); + } + + private: + void add_code_section(ElfSection* section) { + if (section) { + /* Don't add section if it's already been added in the past */ + for (auto s = code.begin(); s != code.end(); ++s) { + if (section == *s) return; + } + code.push_back(section); + find_code(section); + } + } + + /* Look at the relocations associated to the given section to find other + * sections that it requires */ + void find_code(ElfSection* section) { + for (ElfSection* s = elf->getSection(1); s != nullptr; s = s->getNext()) { + if (((s->getType() == SHT_REL) || (s->getType() == SHT_RELA)) && + (s->getInfo().section == section)) { + if (s->getType() == SHT_REL) + scan_relocs_for_code((ElfRel_Section*)s); + else + scan_relocs_for_code((ElfRel_Section*)s); + } + } + } + + template + void scan_relocs_for_code(ElfRel_Section* rel) { + ElfSymtab_Section* symtab = (ElfSymtab_Section*)rel->getLink(); + for (auto r = rel->rels.begin(); r != rel->rels.end(); ++r) { + ElfSection* section = + symtab->syms[ELF64_R_SYM(r->r_info)].value.getSection(); + add_code_section(section); + } + } + + // TODO: sort out which non-aarch64 relocation types should be using + // `value` (even though in practice it's either 0 or the same as addend) + class pc32_relocation { + public: + Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset, + Elf64_Sxword addend, unsigned int addr, + Elf64_Word value) { + return addr + addend - offset - base_addr; + } + }; + + class arm_plt32_relocation { + public: + Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset, + Elf64_Sxword addend, unsigned int addr, + Elf64_Word value) { + // We don't care about sign_extend because the only case where this is + // going to be used only jumps forward. + Elf32_Addr tmp = (Elf32_Addr)(addr - offset - base_addr) >> 2; + tmp = (addend + tmp) & 0x00ffffff; + return (addend & 0xff000000) | tmp; + } + }; + + class arm_thm_jump24_relocation { + public: + Elf32_Addr operator()(unsigned int base_addr, Elf64_Off offset, + Elf64_Sxword addend, unsigned int addr, + Elf64_Word value) { + /* Follows description of b.w and bl instructions as per + ARM Architecture Reference Manual ARM® v7-A and ARM® v7-R edition, + A8.6.16 We limit ourselves to Encoding T4 of b.w and Encoding T1 of bl. + We don't care about sign_extend because the only case where this is + going to be used only jumps forward. */ + Elf32_Addr tmp = (Elf32_Addr)(addr - offset - base_addr); + unsigned int word0 = addend & 0xffff, word1 = addend >> 16; + + /* Encoding T4 of B.W is 10x1 ; Encoding T1 of BL is 11x1. */ + unsigned int type = (word1 & 0xd000) >> 12; + if (((word0 & 0xf800) != 0xf000) || ((type & 0x9) != 0x9)) + throw std::runtime_error( + "R_ARM_THM_JUMP24/R_ARM_THM_CALL relocation only supported for B.W " + "

+This page, which requires that your browser support JavaScript +(see Why JavaScript below), +generates one-time pads or password lists in a variety of +forms. It is based a high-quality pseudorandom sequence +generator, which can be seeded either from the current date +and time, or from a seed you provide. Fill in the form below +to select the format of the pad and press “Generate” to +create the pad in the text box. You can then copy and paste +the generated pad into another window to use as you wish. +Each of the labels on the request form is linked to a description +of that parameter. +