Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -718,6 +718,10 @@ Group, Flags<[CC1Option]>, MetaVarName<"">, HelpText<"Strip (or keep only, if negative) a given number of path components " "when emitting check metadata.">; +def flink_sanitizer_runtimes : Flag<["-"], "flink-sanitizer-runtimes">, + Group, Flags<[DriverOption]>, + HelpText<"Force linking sanitizer runtime libraries even if -nostdlib or " + "-nodefaultlibs is passed.">; def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">, Group; def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">, Index: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ lib/Driver/ToolChains.h @@ -282,6 +282,10 @@ virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + virtual void + AddLinkSanitizerLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const {} + virtual void addStartObjectFileArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { } @@ -571,6 +575,10 @@ RuntimeLibType GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; + void + AddLinkSanitizerLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; Index: lib/Driver/ToolChains.cpp =================================================================== --- lib/Driver/ToolChains.cpp +++ lib/Driver/ToolChains.cpp @@ -425,22 +425,7 @@ return; } - const SanitizerArgs &Sanitize = getSanitizerArgs(); - if (Sanitize.needsAsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); - if (Sanitize.needsUbsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); - if (Sanitize.needsTsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); - if (Sanitize.needsStatsRt()) { - StringRef OS = isTargetMacOS() ? "osx" : "iossim"; - AddLinkRuntimeLib(Args, CmdArgs, - (Twine("libclang_rt.stats_client_") + OS + ".a").str(), - /*AlwaysLink=*/true); - AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); - } - if (Sanitize.needsEsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "esan"); + AddLinkSanitizerLibArgs(Args, CmdArgs); // Otherwise link libSystem, then the dynamic runtime library, and finally any // target specific static runtime library. @@ -495,6 +480,26 @@ } } +void DarwinClang::AddLinkSanitizerLibArgs( + const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { + const SanitizerArgs &Sanitize = getSanitizerArgs(); + if (Sanitize.needsAsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); + if (Sanitize.needsUbsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); + if (Sanitize.needsTsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); + if (Sanitize.needsStatsRt()) { + StringRef OS = isTargetMacOS() ? "osx" : "iossim"; + AddLinkRuntimeLib(Args, CmdArgs, + (Twine("libclang_rt.stats_client_") + OS + ".a").str(), + /*AlwaysLink=*/true); + AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); + } + if (Sanitize.needsEsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "esan"); +} + void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { const OptTable &Opts = getDriver().getOpts(); Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -3157,6 +3157,12 @@ // C runtime, etc). Returns true if sanitizer system deps need to be linked in. static bool addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { + // If -nostdlib or -nodefaultlibs is passed and -flink-sanitizer-runtimes is + // not, we can just bail out of this early. + if (Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs) && + !Args.hasArg(options::OPT_flink_sanitizer_runtimes)) + return false; + SmallVector SharedRuntimes, StaticRuntimes, NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols; collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, @@ -8002,7 +8008,10 @@ // SafeStack requires its own runtime libraries // These libraries should be linked first, to make sure the // __safestack_init constructor executes before everything else - if (getToolChain().getSanitizerArgs().needsSafeStackRt()) { + auto linkSanitizers = + !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) || + Args.hasArg(options::OPT_flink_sanitizer_runtimes); + if (linkSanitizers && getToolChain().getSanitizerArgs().needsSafeStackRt()) { getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.safestack_osx.a", /*AlwaysLink=*/true); @@ -8061,6 +8070,8 @@ // Let the tool chain choose which runtime library to link. getMachOToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs); + } else if (Args.hasArg(options::OPT_flink_sanitizer_runtimes)) { + getMachOToolChain().AddLinkSanitizerLibArgs(Args, CmdArgs); } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { Index: test/Driver/nodefaultlib.c =================================================================== --- test/Driver/nodefaultlib.c +++ test/Driver/nodefaultlib.c @@ -8,3 +8,18 @@ // RUN: %clang -target i686-pc-linux-gnu -stdlib=libc++ -nodefaultlibs -lstdc++ -### %s 2>&1 | FileCheck -check-prefix=TEST2 %s // TEST2-NOT: "-lc++" // TEST2: "-lstdc++" + +// RUN: %clang -target i686-apple-darwin -nodefaultlibs -fsanitize=address -### %s 2>&1 | FileCheck -check-prefix=DARWIN_SAN_LIB1 %s +// DARWIN_SAN_LIB1-NOT: libclang_rt.asan_osx_dynamic.dylib + +// RUN: %clang -target i686-apple-darwin -nodefaultlibs -fsanitize=address -flink-sanitizer-runtimes -### %s 2>&1 | FileCheck -check-prefix=DARWIN_SAN_LIB2 %s +// DARWIN_SAN_LIB2: libclang_rt.asan_osx_dynamic.dylib + + +// RUN: %clang -target i686-pc-linux-gnu -nodefaultlibs -fsanitize=address -### %s 2>&1 | FileCheck -check-prefix=NIX_SAN_LIB1 %s +// RUN: %clang -target i686-unknown-freebsd -nodefaultlibs -fsanitize=address -### %s 2>&1 | FileCheck -check-prefix=NIX_SAN_LIB1 %s +// NIX_SAN_LIB1-NOT: libclang_rt.asan-i686.a + +// RUN: %clang -target i686-pc-linux-gnu -nodefaultlibs -fsanitize=address -flink-sanitizer-runtimes -### %s 2>&1 | FileCheck -check-prefix=NIX_SAN_LIB2 %s +// RUN: %clang -target i686-unknown-freebsd -nodefaultlibs -fsanitize=address -flink-sanitizer-runtimes -### %s 2>&1 | FileCheck -check-prefix=NIX_SAN_LIB2 %s +// NIX_SAN_LIB2: libclang_rt.asan-i686.a Index: test/Driver/nostdlib.c =================================================================== --- test/Driver/nostdlib.c +++ test/Driver/nostdlib.c @@ -29,3 +29,17 @@ // CHECK-LINUX-NOSTDLIB: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}" // CHECK-LINUX-NOSTDLIB-NOT: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.builtins-i686.a" // CHECK-MSVC-NOSTDLIB: warning: argument unused during compilation: '--rtlib=compiler-rt' + +// RUN: %clang -target i686-apple-darwin -nostdlib -fsanitize=address -### %s 2>&1 | FileCheck -check-prefix=DARWIN_SAN_LIB1 %s +// DARWIN_SAN_LIB1-NOT: libclang_rt.asan_osx_dynamic.dylib + +// RUN: %clang -target i686-apple-darwin -nostdlib -fsanitize=address -flink-sanitizer-runtimes -### %s 2>&1 | FileCheck -check-prefix=DARWIN_SAN_LIB2 %s +// DARWIN_SAN_LIB2: libclang_rt.asan_osx_dynamic.dylib + +// RUN: %clang -target i686-pc-linux-gnu -nostdlib -fsanitize=address -### %s 2>&1 | FileCheck -check-prefix=NIX_SAN_LIB1 %s +// RUN: %clang -target i686-unknown-freebsd -nostdlib -fsanitize=address -### %s 2>&1 | FileCheck -check-prefix=NIX_SAN_LIB1 %s +// NIX_SAN_LIB1-NOT: libclang_rt.asan-i686.a + +// RUN: %clang -target i686-pc-linux-gnu -nostdlib -fsanitize=address -flink-sanitizer-runtimes -### %s 2>&1 | FileCheck -check-prefix=NIX_SAN_LIB2 %s +// RUN: %clang -target i686-unknown-freebsd -nostdlib -fsanitize=address -flink-sanitizer-runtimes -### %s 2>&1 | FileCheck -check-prefix=NIX_SAN_LIB2 %s +// NIX_SAN_LIB2: libclang_rt.asan-i686.a