Index: clang/docs/ClangCommandLineReference.rst =================================================================== --- clang/docs/ClangCommandLineReference.rst +++ clang/docs/ClangCommandLineReference.rst @@ -800,6 +800,10 @@ Enable linker dead stripping of globals in AddressSanitizer +.. option:: -fsanitize-address-use-odr-indicator, -fno-sanitize-address-use-odr-indicator + +Generate additional globals to improve ODR checks + .. option:: -fsanitize-address-poison-custom-array-cookie, -fno-sanitize-address-poison-custom-array-cookie Enable "poisoning" array cookies when allocating arrays with a custom operator new\[\] in Address Sanitizer, preventing accesses to the cookies from user code. An array cookie is a small implementation-defined header added to certain array allocations to record metadata such as the length of the array. Accesses to array cookies from user code are technically allowed by the standard but are more likely to be the result of an out-of-bounds array access. Index: clang/docs/UsersManual.rst =================================================================== --- clang/docs/UsersManual.rst +++ clang/docs/UsersManual.rst @@ -3089,6 +3089,8 @@ Level of field padding for AddressSanitizer -fsanitize-address-globals-dead-stripping Enable linker dead stripping of globals in AddressSanitizer + -fsanitize-address-use-odr-indicator + Generate additional globals to improve ODR checks -fsanitize-address-poison-custom-array-cookie Enable poisoning array cookies when using custom operator new[] in AddressSanitizer -fsanitize-address-use-after-scope Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -988,6 +988,14 @@ def fsanitize_address_globals_dead_stripping : Flag<["-"], "fsanitize-address-globals-dead-stripping">, Group, HelpText<"Enable linker dead stripping of globals in AddressSanitizer">; +def fsanitize_address_use_odr_indicator + : Flag<["-"], "fsanitize-address-use-odr-indicator">, + Group, + HelpText<"Generate additional globals to improve ODR checks">; +def fno_sanitize_address_use_odr_indicator + : Flag<["-"], "fno-sanitize-address-use-odr-indicator">, + Group, + HelpText<"Disable additional globals for ODR checks">; def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group; def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">, Flags<[CoreOption, DriverOption]>, Index: clang/include/clang/Driver/SanitizerArgs.h =================================================================== --- clang/include/clang/Driver/SanitizerArgs.h +++ clang/include/clang/Driver/SanitizerArgs.h @@ -38,6 +38,7 @@ bool AsanUseAfterScope = true; bool AsanPoisonCustomArrayCookie = false; bool AsanGlobalsDeadStripping = false; + bool AsanUseOdrIndicator = false; bool LinkCXXRuntimes = false; bool NeedPIE = false; bool SafeStackRuntime = false; Index: clang/include/clang/Frontend/CodeGenOptions.def =================================================================== --- clang/include/clang/Frontend/CodeGenOptions.def +++ clang/include/clang/Frontend/CodeGenOptions.def @@ -179,6 +179,8 @@ ///< global allocation function in AddressSanitizer CODEGENOPT(SanitizeAddressGlobalsDeadStripping, 1, 0) ///< Enable linker dead stripping ///< of globals in AddressSanitizer +CODEGENOPT(SanitizeAddressUseOdrIndicator, 1, 0) ///< Generate additional globals + ///< to improve ODR checks CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in ///< MemorySanitizer CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -236,11 +236,12 @@ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::Address); bool UseAfterScope = CGOpts.SanitizeAddressUseAfterScope; + bool UseOdrIndicator = CGOpts.SanitizeAddressUseOdrIndicator; bool UseGlobalsGC = asanUseGlobalsGC(T, CGOpts); PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/ false, Recover, UseAfterScope)); PM.add(createAddressSanitizerModulePass(/*CompileKernel*/ false, Recover, - UseGlobalsGC)); + UseGlobalsGC, UseOdrIndicator)); } static void addKernelAddressSanitizerPasses(const PassManagerBuilder &Builder, @@ -248,7 +249,8 @@ PM.add(createAddressSanitizerFunctionPass( /*CompileKernel*/ true, /*Recover*/ true, /*UseAfterScope*/ false)); PM.add(createAddressSanitizerModulePass( - /*CompileKernel*/ true, /*Recover*/ true)); + /*CompileKernel*/ true, /*Recover*/ true, /*UseGlobalsGC*/ true, + /*UseOdrIndicator*/ false)); } static void addHWAddressSanitizerPasses(const PassManagerBuilder &Builder, Index: clang/lib/Driver/SanitizerArgs.cpp =================================================================== --- clang/lib/Driver/SanitizerArgs.cpp +++ clang/lib/Driver/SanitizerArgs.cpp @@ -732,6 +732,11 @@ AsanGlobalsDeadStripping = !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() || Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping); + + AsanUseOdrIndicator = + Args.hasFlag(options::OPT_fsanitize_address_use_odr_indicator, + options::OPT_fno_sanitize_address_use_odr_indicator, + AsanUseOdrIndicator); } else { AsanUseAfterScope = false; } @@ -905,6 +910,9 @@ if (AsanGlobalsDeadStripping) CmdArgs.push_back("-fsanitize-address-globals-dead-stripping"); + if (AsanUseOdrIndicator) + CmdArgs.push_back("-fsanitize-address-use-odr-indicator"); + // MSan: Workaround for PR16386. // ASan: This is mainly to help LSan with cases such as // https://github.com/google/sanitizers/issues/373 Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -1115,6 +1115,11 @@ } Opts.SanitizeAddressGlobalsDeadStripping = Args.hasArg(OPT_fsanitize_address_globals_dead_stripping); + if (Arg *A = Args.getLastArg(OPT_fsanitize_address_use_odr_indicator, + OPT_fno_sanitize_address_use_odr_indicator)) { + Opts.SanitizeAddressUseOdrIndicator = + A->getOption().getID() == OPT_fsanitize_address_use_odr_indicator; + } Opts.SSPBufferSize = getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags); Opts.StackRealignment = Args.hasArg(OPT_mstackrealign); Index: clang/test/CodeGen/asan-globals-odr.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/asan-globals-odr.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -fsanitize=address -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefixes=CHECK,INDICATOR0,GLOB_VAR,ALIAS0 +// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-use-odr-indicator -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefixes=CHECK,INDICATOR1,GLOB_ALIAS_INDICATOR,ALIAS1 +// RUN: %clang_cc1 -fsanitize=address -fno-sanitize-address-use-odr-indicator -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefixes=CHECK,INDICATOR0,GLOB_VAR,ALIAS0 +// RUN: %clang_cc1 -fsanitize=address -fno-sanitize-address-use-odr-indicator -fsanitize-address-use-odr-indicator -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefixes=CHECK,INDICATOR1,GLOB_ALIAS_INDICATOR,ALIAS1 +// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-use-odr-indicator -fno-sanitize-address-use-odr-indicator -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefixes=CHECK,INDICATOR0,GLOB_VAR,ALIAS0 + +// No alias on Windows but indicators should work. +// RUN: %clang_cc1 -fsanitize=address -emit-llvm -o - -triple x86_64-windows-msvc %s | FileCheck %s --check-prefixes=CHECK,GLOB_VAR,ALIAS0 +// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-use-odr-indicator -emit-llvm -o - -triple x86_64-windows-msvc %s | FileCheck %s --check-prefixes=CHECK,INDICATOR1,GLOB_VAR_INDICATOR,ALIAS0 + +int global; + +int main() { + return global; +} + +// CHECK: [[VAR:@.*global.*]] ={{.*}} global { i32, [60 x i8] } zeroinitializer, align 32 + +// INDICATOR0-NOT: __odr_asan_gen +// INDICATOR1: [[ODR:@.*__odr_asan_gen_.*global.*]] = global i8 0, align 1 + +// GLOB_VAR: @0 = internal global {{.*}} [[VAR]] to i64), {{.*}}, i64 0 }] +// GLOB_VAR_INDICATOR: @0 = internal global {{.*}} [[VAR]] to i64), {{.*}}, i64 ptrtoint (i8* [[ODR]] to i64) }] +// GLOB_ALIAS_INDICATOR: @0 = internal global {{.*}} @1 to i64), {{.*}}, i64 ptrtoint (i8* [[ODR]] to i64) }] + +// ALIAS0-NOT: private alias +// ALIAS1: @1 = private alias {{.*}} [[VAR]] + +// CHECK: call void @__asan_register_globals(i64 ptrtoint ([1 x { i64, i64, i64, i64, i64, i64, i64, i64 }]* @0 to i64), i64 1) +// CHECK: call void @__asan_unregister_globals(i64 ptrtoint ([1 x { i64, i64, i64, i64, i64, i64, i64, i64 }]* @0 to i64), i64 1) Index: clang/test/Driver/fsanitize.c =================================================================== --- clang/test/Driver/fsanitize.c +++ clang/test/Driver/fsanitize.c @@ -248,6 +248,24 @@ // CHECK-ASAN-GLOBALS: -cc1{{.*}}-fsanitize-address-globals-dead-stripping // CHECK-NO-ASAN-GLOBALS-NOT: -cc1{{.*}}-fsanitize-address-globals-dead-stripping +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-use-odr-indicator %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-ODR-INDICATOR +// RUN: %clang_cl --target=x86_64-windows -fsanitize=address -fsanitize-address-use-odr-indicator -### -- %s 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-ODR-INDICATOR +// CHECK-ASAN-ODR-INDICATOR: -cc1{{.*}}-fsanitize-address-use-odr-indicator + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fno-sanitize-address-use-odr-indicator %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-ODR-INDICATOR-OFF +// RUN: %clang_cl --target=x86_64-windows -fsanitize=address -fno-sanitize-address-use-odr-indicator -### -- %s 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-ODR-INDICATOR-OFF +// CHECK-ASAN-ODR-INDICATOR-OFF-NOT: -cc1{{.*}}address-generate-odr-globals + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fno-sanitize-address-use-odr-indicator -fsanitize-address-use-odr-indicator %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-ODR-INDICATOR-BOTH +// RUN: %clang_cl --target=x86_64-windows -fsanitize=address -fno-sanitize-address-use-odr-indicator -fsanitize-address-use-odr-indicator -### -- %s 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-ODR-INDICATOR-BOTH +// CHECK-ASAN-ODR-INDICATOR-BOTH: -cc1{{.*}}-fsanitize-address-use-odr-indicator + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-use-odr-indicator -fno-sanitize-address-use-odr-indicator %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-ODR-INDICATOR-BOTH-OFF +// CHECK-ASAN-ODR-INDICATOR-BOTH-OFF-NOT: -cc1{{.*}}address-generate-odr-globals + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-WITHOUT-ODR-INDICATOR +// CHECK-ASAN-WITHOUT-ODR-INDICATOR-NOT: -cc1{{.*}}address-generate-odr-globals + // RUN: %clang -target x86_64-linux-gnu -fsanitize-memory-track-origins -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ONLY-TRACK-ORIGINS // CHECK-ONLY-TRACK-ORIGINS: warning: argument unused during compilation: '-fsanitize-memory-track-origins' Index: compiler-rt/test/asan/TestCases/Linux/odr-violation.cc =================================================================== --- compiler-rt/test/asan/TestCases/Linux/odr-violation.cc +++ compiler-rt/test/asan/TestCases/Linux/odr-violation.cc @@ -33,6 +33,11 @@ // RUN: %clangxx_asan -mllvm -asan-use-private-alias -mllvm -asan-use-odr-indicator %s %t-ODR-SO.so -Wl,-R. -o %t-ODR-EXE // RUN: %env_asan_opts=fast_unwind_on_malloc=0 not %run %t-ODR-EXE 2>&1 | FileCheck %s +// Same as above but with clang switches. +// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared -fsanitize-address-odr-indicator %s -o %t-ODR-SO.so -DSZ=100 +// RUN: %clangxx_asan -fsanitize-address-odr-indicator %s %t-ODR-SO.so -Wl,-R. -o %t-ODR-EXE +// RUN: %env_asan_opts=fast_unwind_on_malloc=0 not %run %t-ODR-EXE 2>&1 | FileCheck %s + // GNU driver doesn't handle .so files properly. // REQUIRES: Clang Index: llvm/include/llvm/Transforms/Instrumentation.h =================================================================== --- llvm/include/llvm/Transforms/Instrumentation.h +++ llvm/include/llvm/Transforms/Instrumentation.h @@ -149,7 +149,8 @@ bool UseAfterScope = false); ModulePass *createAddressSanitizerModulePass(bool CompileKernel = false, bool Recover = false, - bool UseGlobalsGC = true); + bool UseGlobalsGC = true, + bool UseOdrIndicator = true); // Insert MemorySanitizer instrumentation (detection of uninitialized reads) FunctionPass *createMemorySanitizerPass(int TrackOrigins = 0, Index: llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -735,9 +735,12 @@ explicit AddressSanitizerModule(bool CompileKernel = false, bool Recover = false, - bool UseGlobalsGC = true) - : ModulePass(ID), - UseGlobalsGC(UseGlobalsGC && ClUseGlobalsGC), + bool UseGlobalsGC = true, + bool UseOdrIndicator = false) + : ModulePass(ID), UseGlobalsGC(UseGlobalsGC && ClUseGlobalsGC), + // Enable aliases as they should have no downside with ODR indicators. + UsePrivateAlias(UseOdrIndicator || ClUsePrivateAlias), + UseOdrIndicator(UseOdrIndicator || ClUseOdrIndicator), // Not a typo: ClWithComdat is almost completely pointless without // ClUseGlobalsGC (because then it only works on modules without // globals, which are rare); it is a prerequisite for ClUseGlobalsGC; @@ -746,10 +749,9 @@ // ClWithComdat and ClUseGlobalsGC unless the frontend says it's ok to // do globals-gc. UseCtorComdat(UseGlobalsGC && ClWithComdat) { - this->Recover = ClRecover.getNumOccurrences() > 0 ? - ClRecover : Recover; - this->CompileKernel = ClEnableKasan.getNumOccurrences() > 0 ? - ClEnableKasan : CompileKernel; + this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover; + this->CompileKernel = + ClEnableKasan.getNumOccurrences() > 0 ? ClEnableKasan : CompileKernel; } bool runOnModule(Module &M) override; @@ -794,6 +796,8 @@ bool CompileKernel; bool Recover; bool UseGlobalsGC; + bool UsePrivateAlias; + bool UseOdrIndicator; bool UseCtorComdat; Type *IntptrTy; LLVMContext *C; @@ -1093,9 +1097,11 @@ ModulePass *llvm::createAddressSanitizerModulePass(bool CompileKernel, bool Recover, - bool UseGlobalsGC) { + bool UseGlobalsGC, + bool UseOdrIndicator) { assert(!CompileKernel || Recover); - return new AddressSanitizerModule(CompileKernel, Recover, UseGlobalsGC); + return new AddressSanitizerModule(CompileKernel, Recover, UseGlobalsGC, + UseOdrIndicator); } static size_t TypeSizeToSizeIndex(uint32_t TypeSize) { @@ -2177,14 +2183,14 @@ bool CanUsePrivateAliases = TargetTriple.isOSBinFormatELF() || TargetTriple.isOSBinFormatMachO() || TargetTriple.isOSBinFormatWasm(); - if (CanUsePrivateAliases && ClUsePrivateAlias) { + if (CanUsePrivateAliases && UsePrivateAlias) { // Create local alias for NewGlobal to avoid crash on ODR between // instrumented and non-instrumented libraries. InstrumentedGlobal = GlobalAlias::create(GlobalValue::PrivateLinkage, "", NewGlobal); } - if (ClUseOdrIndicator) { + if (UseOdrIndicator) { // With local aliases, we need to provide another externally visible // symbol __odr_asan_XXX to detect ODR violation. auto *ODRIndicatorSym =