diff options
-rw-r--r-- | lib/Transforms/Instrumentation/AddressSanitizer.cpp | 38 | ||||
-rw-r--r-- | test/Instrumentation/AddressSanitizer/test64.ll | 22 |
2 files changed, 52 insertions, 8 deletions
diff --git a/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 5f03d35..a9d08db 100644 --- a/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -79,6 +79,9 @@ static cl::opt<bool> ClInstrumentReads("asan-instrument-reads", cl::desc("instrument read instructions"), cl::Hidden, cl::init(true)); static cl::opt<bool> ClInstrumentWrites("asan-instrument-writes", cl::desc("instrument write instructions"), cl::Hidden, cl::init(true)); +static cl::opt<bool> ClInstrumentAtomics("asan-instrument-atomics", + cl::desc("instrument atomic instructions (rmw, cmpxchg)"), + cl::Hidden, cl::init(true)); // This flag may need to be replaced with -f[no]asan-stack. static cl::opt<bool> ClStack("asan-stack", cl::desc("Handle stack memory"), cl::Hidden, cl::init(true)); @@ -290,16 +293,36 @@ bool AddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) { return true; } -static Value *getLDSTOperand(Instruction *I) { +// If I is an interesting memory access, return the PointerOperand +// and set IsWrite. Otherwise return NULL. +static Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite) { if (LoadInst *LI = dyn_cast<LoadInst>(I)) { + if (!ClInstrumentReads) return NULL; + *IsWrite = false; return LI->getPointerOperand(); } - return cast<StoreInst>(*I).getPointerOperand(); + if (StoreInst *SI = dyn_cast<StoreInst>(I)) { + if (!ClInstrumentWrites) return NULL; + *IsWrite = true; + return SI->getPointerOperand(); + } + if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) { + if (!ClInstrumentAtomics) return NULL; + *IsWrite = true; + return RMW->getPointerOperand(); + } + if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) { + if (!ClInstrumentAtomics) return NULL; + *IsWrite = true; + return XCHG->getPointerOperand(); + } + return NULL; } void AddressSanitizer::instrumentMop(Instruction *I) { - int IsWrite = isa<StoreInst>(*I); - Value *Addr = getLDSTOperand(I); + bool IsWrite; + Value *Addr = isInterestingMemoryAccess(I, &IsWrite); + assert(Addr); if (ClOpt && ClOptGlobals && isa<GlobalVariable>(Addr)) { // We are accessing a global scalar variable. Nothing to catch here. return; @@ -660,6 +683,7 @@ bool AddressSanitizer::handleFunction(Module &M, Function &F) { SmallSet<Value*, 16> TempsToInstrument; SmallVector<Instruction*, 16> ToInstrument; SmallVector<Instruction*, 8> NoReturnCalls; + bool IsWrite; // Fill the set of memory operations to instrument. for (Function::iterator FI = F.begin(), FE = F.end(); @@ -668,9 +692,7 @@ bool AddressSanitizer::handleFunction(Module &M, Function &F) { for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) { if (LooksLikeCodeInBug11395(BI)) return false; - if ((isa<LoadInst>(BI) && ClInstrumentReads) || - (isa<StoreInst>(BI) && ClInstrumentWrites)) { - Value *Addr = getLDSTOperand(BI); + if (Value *Addr = isInterestingMemoryAccess(BI, &IsWrite)) { if (ClOpt && ClOptSameTemp) { if (!TempsToInstrument.insert(Addr)) continue; // We've seen this temp in the current BB. @@ -697,7 +719,7 @@ bool AddressSanitizer::handleFunction(Module &M, Function &F) { Instruction *Inst = ToInstrument[i]; if (ClDebugMin < 0 || ClDebugMax < 0 || (NumInstrumented >= ClDebugMin && NumInstrumented <= ClDebugMax)) { - if (isa<StoreInst>(Inst) || isa<LoadInst>(Inst)) + if (isInterestingMemoryAccess(Inst, &IsWrite)) instrumentMop(Inst); else instrumentMemIntrinsic(cast<MemIntrinsic>(Inst)); diff --git a/test/Instrumentation/AddressSanitizer/test64.ll b/test/Instrumentation/AddressSanitizer/test64.ll index fc27de9..d544d77 100644 --- a/test/Instrumentation/AddressSanitizer/test64.ll +++ b/test/Instrumentation/AddressSanitizer/test64.ll @@ -12,3 +12,25 @@ entry: ; Check for ASAN's Offset for 64-bit (2^44) ; CHECK-NEXT: 17592186044416 ; CHECK: ret + +define void @example_atomicrmw(i64* %ptr) nounwind uwtable address_safety { +entry: + %0 = atomicrmw add i64* %ptr, i64 1 seq_cst + ret void +} + +; CHECK: @example_atomicrmw +; CHECK: lshr {{.*}} 3 +; CHECK: atomicrmw +; CHECK: ret + +define void @example_cmpxchg(i64* %ptr, i64 %compare_to, i64 %new_value) nounwind uwtable address_safety { +entry: + %0 = cmpxchg i64* %ptr, i64 %compare_to, i64 %new_value seq_cst + ret void +} + +; CHECK: @example_cmpxchg +; CHECK: lshr {{.*}} 3 +; CHECK: cmpxchg +; CHECK: ret |