From 7cc4447ccfa69e76cb8e3e3cc76984895421dba5 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Wed, 5 Nov 2014 17:21:00 +0000 Subject: [PATCH] [dfsan] Abort at runtime on indirect calls to uninstrumented vararg functions. We currently have no infrastructure to support these correctly. This is accomplished by generating a call to a runtime library function that aborts at runtime in place of the regular wrapper for such functions. Direct calls are rewritten in the usual way during traversal of the caller's IR. We also remove the "split-stack" attribute from such wrappers, as the code generator cannot currently handle split-stack vararg functions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@221360 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Instrumentation/DataFlowSanitizer.cpp | 43 ++++++++++++++----- .../DataFlowSanitizer/abilist.ll | 7 ++- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp index fa8257f3834..c5a4860781b 100644 --- a/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -234,12 +234,14 @@ class DataFlowSanitizer : public ModulePass { FunctionType *DFSanUnimplementedFnTy; FunctionType *DFSanSetLabelFnTy; FunctionType *DFSanNonzeroLabelFnTy; + FunctionType *DFSanVarargWrapperFnTy; Constant *DFSanUnionFn; Constant *DFSanCheckedUnionFn; Constant *DFSanUnionLoadFn; Constant *DFSanUnimplementedFn; Constant *DFSanSetLabelFn; Constant *DFSanNonzeroLabelFn; + Constant *DFSanVarargWrapperFn; MDNode *ColdCallWeights; DFSanABIList ABIList; DenseMap UnwrappedFnMap; @@ -439,6 +441,8 @@ bool DataFlowSanitizer::doInitialization(Module &M) { DFSanSetLabelArgs, /*isVarArg=*/false); DFSanNonzeroLabelFnTy = FunctionType::get( Type::getVoidTy(*Ctx), None, /*isVarArg=*/false); + DFSanVarargWrapperFnTy = FunctionType::get( + Type::getVoidTy(*Ctx), Type::getInt8PtrTy(*Ctx), /*isVarArg=*/false); if (GetArgTLSPtr) { Type *ArgTLSTy = ArrayType::get(ShadowTy, 64); @@ -518,15 +522,26 @@ DataFlowSanitizer::buildWrapperFunction(Function *F, StringRef NewFName, AttributeSet::ReturnIndex)); BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", NewF); - std::vector Args; - unsigned n = FT->getNumParams(); - for (Function::arg_iterator ai = NewF->arg_begin(); n != 0; ++ai, --n) - Args.push_back(&*ai); - CallInst *CI = CallInst::Create(F, Args, "", BB); - if (FT->getReturnType()->isVoidTy()) - ReturnInst::Create(*Ctx, BB); - else - ReturnInst::Create(*Ctx, CI, BB); + if (F->isVarArg()) { + NewF->removeAttributes( + AttributeSet::FunctionIndex, + AttributeSet().addAttribute(*Ctx, AttributeSet::FunctionIndex, + "split-stack")); + CallInst::Create(DFSanVarargWrapperFn, + IRBuilder<>(BB).CreateGlobalStringPtr(F->getName()), "", + BB); + new UnreachableInst(*Ctx, BB); + } else { + std::vector Args; + unsigned n = FT->getNumParams(); + for (Function::arg_iterator ai = NewF->arg_begin(); n != 0; ++ai, --n) + Args.push_back(&*ai); + CallInst *CI = CallInst::Create(F, Args, "", BB); + if (FT->getReturnType()->isVoidTy()) + ReturnInst::Create(*Ctx, BB); + else + ReturnInst::Create(*Ctx, CI, BB); + } return NewF; } @@ -617,6 +632,8 @@ bool DataFlowSanitizer::runOnModule(Module &M) { } DFSanNonzeroLabelFn = Mod->getOrInsertFunction("__dfsan_nonzero_label", DFSanNonzeroLabelFnTy); + DFSanVarargWrapperFn = Mod->getOrInsertFunction("__dfsan_vararg_wrapper", + DFSanVarargWrapperFnTy); std::vector FnsToInstrument; llvm::SmallPtrSet FnsWithNativeABI; @@ -627,7 +644,8 @@ bool DataFlowSanitizer::runOnModule(Module &M) { i != DFSanUnionLoadFn && i != DFSanUnimplementedFn && i != DFSanSetLabelFn && - i != DFSanNonzeroLabelFn) + i != DFSanNonzeroLabelFn && + i != DFSanVarargWrapperFn) FnsToInstrument.push_back(&*i); } @@ -1363,6 +1381,11 @@ void DFSanVisitor::visitCallSite(CallSite CS) { return; } + // Calls to this function are synthesized in wrappers, and we shouldn't + // instrument them. + if (F == DFSF.DFS.DFSanVarargWrapperFn) + return; + assert(!(cast( CS.getCalledValue()->getType()->getPointerElementType())->isVarArg() && dyn_cast(CS.getInstruction()))); diff --git a/test/Instrumentation/DataFlowSanitizer/abilist.ll b/test/Instrumentation/DataFlowSanitizer/abilist.ll index e8cb76d24af..ebf55d9de47 100644 --- a/test/Instrumentation/DataFlowSanitizer/abilist.ll +++ b/test/Instrumentation/DataFlowSanitizer/abilist.ll @@ -29,6 +29,9 @@ declare void @custom1(i32 %a, i32 %b) ; CHECK: ret { i32, i16 } declare i32 @custom2(i32 %a, i32 %b) +; CHECK: define linkonce_odr void @"dfsw$custom3"(i32, i16, i16*, ...) +; CHECK: call void @__dfsan_vararg_wrapper(i8* +; CHECK: unreachable declare void @custom3(i32 %a, ...) declare i32 @custom4(i32 %a, ...) @@ -83,8 +86,6 @@ define i32 (i32, i32)* @g(i32) { ; CHECK: declare void @__dfsw_custom1(i32, i32, i16, i16) ; CHECK: declare i32 @__dfsw_custom2(i32, i32, i16, i16, i16*) -; CHECK: declare void @__dfsw_custom3(i32, i16, i16*, ...) -; CHECK: declare i32 @__dfsw_custom4(i32, i16, i16*, i16*, ...) ; CHECK-LABEL: define linkonce_odr i32 @"dfst0$customcb"(i32 (i32)*, i32, i16, i16*) ; CHECK: %[[BC:.*]] = bitcast i32 (i32)* %0 to { i32, i16 } (i32, i16)* @@ -94,3 +95,5 @@ define i32 (i32, i32)* @g(i32) { ; CHECK: store i16 %[[XVAL1]], i16* %3 ; CHECK: ret i32 %[[XVAL0]] +; CHECK: declare void @__dfsw_custom3(i32, i16, i16*, ...) +; CHECK: declare i32 @__dfsw_custom4(i32, i16, i16*, i16*, ...) -- 2.34.1