llvm.org GIT mirror llvm / 34432ae
[msan] Fast path optimization for wrap-indirect-calls feature of MemorySanitizer. Indirect call wrapping helps MSanDR (dynamic instrumentation companion tool for MSan) to catch all cases where execution leaves a compiler-instrumented module by allowing the tool to rewrite targets of indirect calls. This change is an optimization that skips wrapping for calls when target is inside the current module. This relies on the linker providing symbols at the begin and end of the module code (or code + data, does not really matter). Gold linker provides such symbols by default. GNU (BFD) linker needs a link flag: -Wl,--defsym=__executable_start=0. More info: https://code.google.com/p/memory-sanitizer/wiki/MSanDR#Native_exec git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194697 91177308-0d34-0410-b5e6-96231b3b80d8 Evgeniy Stepanov 7 years ago
2 changed file(s) with 80 addition(s) and 14 deletion(s). Raw diff Collapse all Expand all
189189 cl::desc("Wrap indirect calls with a given function"),
190190 cl::Hidden);
191191
192 static cl::opt ClWrapIndirectCallsFast("msan-wrap-indirect-calls-fast",
193 cl::desc("Do not wrap indirect calls with target in the same module"),
194 cl::Hidden, cl::init(true));
195
192196 namespace {
193197
194198 /// \brief An instrumentation pass implementing detection of uninitialized
239243 /// function.
240244 GlobalVariable *OriginTLS;
241245
246 GlobalVariable *MsandrModuleStart;
247 GlobalVariable *MsandrModuleEnd;
248
242249 /// \brief The run-time callback to print a warning.
243250 Value *WarningFn;
244251 /// \brief Run-time helper that copies origin info for a memory range.
373380 PointerType::getUnqual(FunctionType::get(IRB.getVoidTy(), false));
374381 IndirectCallWrapperFn = M.getOrInsertFunction(
375382 ClWrapIndirectCalls, AnyFunctionPtrTy, AnyFunctionPtrTy, NULL);
383 }
384
385 if (ClWrapIndirectCallsFast) {
386 MsandrModuleStart = new GlobalVariable(
387 M, IRB.getInt32Ty(), false, GlobalValue::ExternalLinkage,
388 0, "__executable_start");
389 MsandrModuleStart->setVisibility(GlobalVariable::HiddenVisibility);
390 MsandrModuleEnd = new GlobalVariable(
391 M, IRB.getInt32Ty(), false, GlobalValue::ExternalLinkage,
392 0, "_end");
393 MsandrModuleEnd->setVisibility(GlobalVariable::HiddenVisibility);
376394 }
377395 }
378396
488506 };
489507 SmallVector InstrumentationList;
490508 SmallVector StoreList;
509 SmallVector IndirectCallList;
491510
492511 MemorySanitizerVisitor(Function &F, MemorySanitizer &MS)
493512 : F(F), MS(MS), VAHelper(CreateVarArgHelper(F, MS, *this)) {
587606 DEBUG(dbgs() << "DONE:\n" << F);
588607 }
589608
609 void materializeIndirectCalls() {
610 for (size_t i = 0, n = IndirectCallList.size(); i < n; i++) {
611 CallSite CS = IndirectCallList[i];
612 Instruction *I = CS.getInstruction();
613 BasicBlock *B = I->getParent();
614 IRBuilder<> IRB(I);
615 Value *Fn0 = CS.getCalledValue();
616 Value *Fn = IRB.CreateBitCast(Fn0, MS.AnyFunctionPtrTy);
617
618 if (ClWrapIndirectCallsFast) {
619 // Check that call target is inside this module limits.
620 Value *Start =
621 IRB.CreateBitCast(MS.MsandrModuleStart, MS.AnyFunctionPtrTy);
622 Value *End = IRB.CreateBitCast(MS.MsandrModuleEnd, MS.AnyFunctionPtrTy);
623
624 Value *NotInThisModule = IRB.CreateOr(IRB.CreateICmpULT(Fn, Start),
625 IRB.CreateICmpUGE(Fn, End));
626
627 PHINode *NewFnPhi =
628 IRB.CreatePHI(Fn0->getType(), 2, "msandr.indirect_target");
629
630 Instruction *CheckTerm = SplitBlockAndInsertIfThen(
631 cast(NotInThisModule),
632 /* Unreachable */ false, MS.ColdCallWeights);
633
634 IRB.SetInsertPoint(CheckTerm);
635 // Slow path: call wrapper function to possibly transform the call
636 // target.
637 Value *NewFn = IRB.CreateBitCast(
638 IRB.CreateCall(MS.IndirectCallWrapperFn, Fn), Fn0->getType());
639
640 NewFnPhi->addIncoming(Fn0, B);
641 NewFnPhi->addIncoming(NewFn, dyn_cast(NewFn)->getParent());
642 CS.setCalledFunction(NewFnPhi);
643 } else {
644 Value *NewFn = IRB.CreateBitCast(
645 IRB.CreateCall(MS.IndirectCallWrapperFn, Fn), Fn0->getType());
646 CS.setCalledFunction(NewFn);
647 }
648 }
649 }
650
590651 /// \brief Add MemorySanitizer instrumentation to a function.
591652 bool runOnFunction() {
592653 MS.initializeCallbacks(*F.getParent());
628689
629690 // Insert shadow value checks.
630691 materializeChecks();
692
693 // Wrap indirect calls.
694 materializeIndirectCalls();
631695
632696 return true;
633697 }
18081872 }
18091873 }
18101874
1811 // Replace call to (*Fn) with a call to (*IndirectCallWrapperFn(Fn)).
1812 void wrapIndirectCall(IRBuilder<> &IRB, CallSite CS) {
1813 Value *Fn = CS.getCalledValue();
1814 Value *NewFn = IRB.CreateBitCast(
1815 IRB.CreateCall(MS.IndirectCallWrapperFn,
1816 IRB.CreateBitCast(Fn, MS.AnyFunctionPtrTy)),
1817 Fn->getType());
1818 setShadow(NewFn, getShadow(Fn));
1819 CS.setCalledFunction(NewFn);
1820 }
1821
18221875 void visitCallSite(CallSite CS) {
18231876 Instruction &I = *CS.getInstruction();
18241877 assert((CS.isCall() || CS.isInvoke()) && "Unknown type of CallSite");
18591912 IRBuilder<> IRB(&I);
18601913
18611914 if (MS.WrapIndirectCalls && !CS.getCalledFunction())
1862 wrapIndirectCall(IRB, CS);
1915 IndirectCallList.push_back(CS);
18631916
18641917 unsigned ArgOffset = 0;
18651918 DEBUG(dbgs() << " CallSite: " << I << "\n");
None ; RUN: opt < %s -msan -msan-check-access-address=0 -msan-wrap-indirect-calls=zzz -S | FileCheck %s
0 ; RUN: opt < %s -msan -msan-check-access-address=0 -msan-wrap-indirect-calls=zzz -msan-wrap-indirect-calls-fast=0 -S | FileCheck %s
1 ; RUN: opt < %s -msan -msan-check-access-address=0 -msan-wrap-indirect-calls=zzz -msan-wrap-indirect-calls-fast=1 -S | FileCheck -check-prefix=CHECK-FAST %s
12 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
23 target triple = "x86_64-unknown-linux-gnu"
34
1516 ; CHECK: @func
1617 ; CHECK: bitcast i32 (i32, i32)* %f to void ()*
1718 ; CHECK: call void ()* (void ()*)* @zzz(void ()*
18 ; CHECK: [[A:%[01-9a-z]+]] = bitcast void ()* {{.*}} to i32 (i32, i32)*
19 ; CHECK: [[A:%[01-9a-z_.]+]] = bitcast void ()* {{.*}} to i32 (i32, i32)*
1920 ; CHECK: call i32 {{.*}}[[A]](i32 {{.*}}, i32 {{.*}})
2021 ; CHECK: ret i32
22
23 ; CHECK-FAST: @func
24 ; CHECK-FAST: bitcast i32 (i32, i32)* %f to void ()*
25 ; CHECK-FAST: icmp ult void ()* {{.*}}, bitcast (i32* @__executable_start to void ()*)
26 ; CHECK-FAST: icmp uge void ()* {{.*}}, bitcast (i32* @_end to void ()*)
27 ; CHECK-FAST: or i1
28 ; CHECK-FAST: br i1
29 ; CHECK-FAST: call void ()* (void ()*)* @zzz(void ()*
30 ; CHECK-FAST: br label
31 ; CHECK-FAST: [[A:%[01-9a-z_.]+]] = phi i32 (i32, i32)* [ %f, %entry ], [ {{.*}} ]
32 ; CHECK-FAST: call i32 {{.*}}[[A]](i32 {{.*}}, i32 {{.*}})
33 ; CHECK-FAST: ret i32