[asan] Introduce new hidden -asan-use-private-alias option.

As discussed in https://github.com/google/sanitizers/issues/398, with current
implementation of poisoning globals we can have some CHECK failures or false
positives in case of mixing instrumented and non-instrumented code due to ASan
poisons innocent globals from non-sanitized binary/library. We can use private
aliases to avoid such errors. In addition, to preserve ODR violation detection,
we introduce new __odr_asan_gen_XXX symbol for each instrumented global that
indicates if this global was already registered. To detect ODR violation in
runtime, we should only check the value of indicator and report an error if it
isn't equal to zero.

Differential Revision: http://reviews.llvm.org/D15642

llvm-svn: 260075
This commit is contained in:
Maxim Ostapenko 2016-02-08 08:30:57 +00:00
parent 33dc7c1040
commit fce986a506
2 changed files with 67 additions and 6 deletions

View File

@ -96,7 +96,7 @@ static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init";
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 int kMaxAsanStackMallocSizeClass = 10;
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 @@ static cl::opt<uint32_t> ClForceExperiment(
cl::desc("Force optimization experiment (for testing)"), cl::Hidden,
cl::init(0));
static cl::opt<bool>
ClUsePrivateAliasForGlobals("asan-use-private-alias",
cl::desc("Use private aliases for global"
" variables"),
cl::Hidden, cl::init(false));
// Debug flags.
static cl::opt<int> ClDebug("asan-debug", cl::desc("debug"), cl::Hidden,
cl::init(0));
@ -823,7 +830,8 @@ static GlobalVariable *createPrivateGlobalForSourceLoc(Module &M,
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 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
// 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<Constant *, 16> Initializers(n);
bool HasDynamicallyInitializedGlobals = false;
@ -1340,10 +1349,11 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
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 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
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;

View File

@ -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<stdin>" = 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
}