Index: llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -96,7 +96,7 @@ static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init"; static const char *const kAsanInitName = "__asan_init"; static const char *const kAsanVersionCheckName = - "__asan_version_mismatch_check_v6"; + "__asan_version_mismatch_check_v7"; static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp"; static const char *const kAsanPtrSub = "__sanitizer_ptr_sub"; static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return"; @@ -104,6 +104,7 @@ static const char *const kAsanStackMallocNameTemplate = "__asan_stack_malloc_"; static const char *const kAsanStackFreeNameTemplate = "__asan_stack_free_"; static const char *const kAsanGenPrefix = "__asan_gen_"; +static const char *const kODRGenPrefix = "__odr_asan_gen_"; static const char *const kSanCovGenPrefix = "__sancov_gen_"; static const char *const kAsanPoisonStackMemoryName = "__asan_poison_stack_memory"; @@ -229,6 +230,12 @@ cl::desc("Force optimization experiment (for testing)"), cl::Hidden, cl::init(0)); +static cl::opt + ClUsePrivateAliasForGlobals("asan-use-private-alias", + cl::desc("Use private aliases for global" + " variables"), + cl::Hidden, cl::init(false)); + // Debug flags. static cl::opt ClDebug("asan-debug", cl::desc("debug"), cl::Hidden, cl::init(0)); @@ -823,7 +830,8 @@ static bool GlobalWasGeneratedByAsan(GlobalVariable *G) { return G->getName().find(kAsanGenPrefix) == 0 || - G->getName().find(kSanCovGenPrefix) == 0; + G->getName().find(kSanCovGenPrefix) == 0 || + G->getName().find(kODRGenPrefix) == 0; } Value *AddressSanitizer::memToShadow(Value *Shadow, IRBuilder<> &IRB) { @@ -1321,10 +1329,11 @@ // const char *module_name; // size_t has_dynamic_init; // void *source_location; + // size_t odr_indicator; // We initialize an array of such structures and pass it to a run-time call. StructType *GlobalStructTy = StructType::get(IntptrTy, IntptrTy, IntptrTy, IntptrTy, IntptrTy, - IntptrTy, IntptrTy, nullptr); + IntptrTy, IntptrTy, IntptrTy, nullptr); SmallVector Initializers(n); bool HasDynamicallyInitializedGlobals = false; @@ -1340,10 +1349,11 @@ GlobalVariable *G = GlobalsToChange[i]; auto MD = GlobalsMD.get(G); + StringRef NameForGlobal = G->getName(); // Create string holding the global name (use global name from metadata // if it's available, otherwise just write the name of global variable). GlobalVariable *Name = createPrivateGlobalForString( - M, MD.Name.empty() ? G->getName() : MD.Name, + M, MD.Name.empty() ? NameForGlobal : MD.Name, /*AllowMerging*/ true); Type *Ty = G->getValueType(); @@ -1391,13 +1401,41 @@ SourceLoc = ConstantInt::get(IntptrTy, 0); } + Constant *ODRIndicator = ConstantExpr::getNullValue(IRB.getInt8PtrTy()); + GlobalValue *InstrumentedGlobal = NewGlobal; + + bool CanUsePrivateAliases = TargetTriple.isOSBinFormatELF(); + if (CanUsePrivateAliases && ClUsePrivateAliasForGlobals) { + // Create local alias for NewGlobal to avoid crash on ODR between + // instrumented and non-instrumented libraries. + auto *GA = GlobalAlias::create(GlobalValue::InternalLinkage, + NameForGlobal + M.getName(), NewGlobal); + + // With local aliases, we need to provide another externally visible + // symbol __odr_asan_XXX to detect ODR violation. + auto *ODRIndicatorSym = + new GlobalVariable(M, IRB.getInt8Ty(), false, Linkage, + Constant::getNullValue(IRB.getInt8Ty()), + kODRGenPrefix + NameForGlobal, nullptr, + NewGlobal->getThreadLocalMode()); + + // Set meaningful attributes for indicator symbol. + ODRIndicatorSym->setVisibility(NewGlobal->getVisibility()); + ODRIndicatorSym->setDLLStorageClass(NewGlobal->getDLLStorageClass()); + ODRIndicatorSym->setAlignment(1); + ODRIndicator = ODRIndicatorSym; + InstrumentedGlobal = GA; + } + Initializers[i] = ConstantStruct::get( - GlobalStructTy, ConstantExpr::getPointerCast(NewGlobal, IntptrTy), + GlobalStructTy, + ConstantExpr::getPointerCast(InstrumentedGlobal, IntptrTy), ConstantInt::get(IntptrTy, SizeInBytes), ConstantInt::get(IntptrTy, SizeInBytes + RightRedzoneSize), ConstantExpr::getPointerCast(Name, IntptrTy), ConstantExpr::getPointerCast(ModuleName, IntptrTy), - ConstantInt::get(IntptrTy, MD.IsDynInit), SourceLoc, nullptr); + ConstantInt::get(IntptrTy, MD.IsDynInit), SourceLoc, + ConstantExpr::getPointerCast(ODRIndicator, IntptrTy), nullptr); if (ClInitializers && MD.IsDynInit) HasDynamicallyInitializedGlobals = true; Index: llvm/trunk/test/Instrumentation/AddressSanitizer/local_alias.ll =================================================================== --- llvm/trunk/test/Instrumentation/AddressSanitizer/local_alias.ll +++ llvm/trunk/test/Instrumentation/AddressSanitizer/local_alias.ll @@ -0,0 +1,23 @@ +; RUN: opt < %s -asan -asan-module -asan-use-private-alias=1 -S | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@a = internal global [2 x i32] zeroinitializer, align 4 + +; Check that we generate internal alias and odr indicator symbols for global to be protected. +; CHECK: @__odr_asan_gen_a = internal global i8 0, align 1 +; CHECK: @"a" = internal alias { [2 x i32], [56 x i8] }, { [2 x i32], [56 x i8] }* @a + +; Function Attrs: nounwind sanitize_address uwtable +define i32 @foo(i32 %M) #0 { +entry: + %M.addr = alloca i32, align 4 + store i32 %M, i32* %M.addr, align 4 + store volatile i32 6, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @a, i64 2, i64 0), align 4 + %0 = load i32, i32* %M.addr, align 4 + %idxprom = sext i32 %0 to i64 + %arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* @a, i64 0, i64 %idxprom + %1 = load volatile i32, i32* %arrayidx, align 4 + ret i32 %1 +}