From ffba4c7e69cd0d0ef346e9845b918a030ca51ae8 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Tue, 27 Aug 2013 22:09:06 +0000 Subject: [PATCH] DataFlowSanitizer: Implement trampolines for function pointers passed to custom functions. Differential Revision: http://llvm-reviews.chandlerc.com/D1503 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189408 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Instrumentation/DataFlowSanitizer.cpp | 80 ++++++++++++++++++- .../DataFlowSanitizer/Inputs/abilist.txt | 7 +- .../DataFlowSanitizer/abilist.ll | 15 ++++ 3 files changed, 94 insertions(+), 8 deletions(-) diff --git a/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp index 2fa33834f1f..8ee5482ceaf 100644 --- a/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -48,6 +48,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/IRBuilder.h" @@ -182,6 +183,7 @@ class DataFlowSanitizer : public ModulePass { bool isInstrumented(const Function *F); bool isInstrumented(const GlobalAlias *GA); FunctionType *getArgsFunctionType(FunctionType *T); + FunctionType *getTrampolineFunctionType(FunctionType *T); FunctionType *getCustomFunctionType(FunctionType *T); InstrumentedABI getInstrumentedABI(); WrapperKind getWrapperKind(Function *F); @@ -189,6 +191,7 @@ class DataFlowSanitizer : public ModulePass { Function *buildWrapperFunction(Function *F, StringRef NewFName, GlobalValue::LinkageTypes NewFLink, FunctionType *NewFT); + Constant *getOrBuildTrampolineFunction(FunctionType *FT, StringRef FName); public: DataFlowSanitizer(StringRef ABIListFile = StringRef(), @@ -288,10 +291,32 @@ FunctionType *DataFlowSanitizer::getArgsFunctionType(FunctionType *T) { return FunctionType::get(RetType, ArgTypes, T->isVarArg()); } +FunctionType *DataFlowSanitizer::getTrampolineFunctionType(FunctionType *T) { + assert(!T->isVarArg()); + llvm::SmallVector ArgTypes; + ArgTypes.push_back(T->getPointerTo()); + std::copy(T->param_begin(), T->param_end(), std::back_inserter(ArgTypes)); + for (unsigned i = 0, e = T->getNumParams(); i != e; ++i) + ArgTypes.push_back(ShadowTy); + Type *RetType = T->getReturnType(); + if (!RetType->isVoidTy()) + ArgTypes.push_back(ShadowPtrTy); + return FunctionType::get(T->getReturnType(), ArgTypes, false); +} + FunctionType *DataFlowSanitizer::getCustomFunctionType(FunctionType *T) { assert(!T->isVarArg()); llvm::SmallVector ArgTypes; - std::copy(T->param_begin(), T->param_end(), std::back_inserter(ArgTypes)); + for (FunctionType::param_iterator i = T->param_begin(), e = T->param_end(); i != e; ++i) { + FunctionType *FT; + if (isa(*i) && + (FT = dyn_cast(cast(*i)->getElementType()))) { + ArgTypes.push_back(getTrampolineFunctionType(FT)->getPointerTo()); + ArgTypes.push_back(Type::getInt8PtrTy(*Ctx)); + } else { + ArgTypes.push_back(*i); + } + } for (unsigned i = 0, e = T->getNumParams(); i != e; ++i) ArgTypes.push_back(ShadowTy); Type *RetType = T->getReturnType(); @@ -417,6 +442,39 @@ DataFlowSanitizer::buildWrapperFunction(Function *F, StringRef NewFName, return NewF; } +Constant *DataFlowSanitizer::getOrBuildTrampolineFunction(FunctionType *FT, + StringRef FName) { + FunctionType *FTT = getTrampolineFunctionType(FT); + Constant *C = Mod->getOrInsertFunction(FName, FTT); + Function *F = dyn_cast(C); + if (F && F->isDeclaration()) { + F->setLinkage(GlobalValue::LinkOnceODRLinkage); + BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); + std::vector Args; + Function::arg_iterator AI = F->arg_begin(); ++AI; + for (unsigned N = FT->getNumParams(); N != 0; ++AI, --N) + Args.push_back(&*AI); + CallInst *CI = + CallInst::Create(&F->getArgumentList().front(), Args, "", BB); + ReturnInst *RI; + if (FT->getReturnType()->isVoidTy()) + RI = ReturnInst::Create(*Ctx, BB); + else + RI = ReturnInst::Create(*Ctx, CI, BB); + + DFSanFunction DFSF(*this, F, /*IsNativeABI=*/true); + Function::arg_iterator ValAI = F->arg_begin(), ShadowAI = AI; ++ValAI; + for (unsigned N = FT->getNumParams(); N != 0; ++ValAI, ++ShadowAI, --N) + DFSF.ValShadowMap[ValAI] = ShadowAI; + DFSanVisitor(DFSF).visitCallInst(*CI); + if (!FT->getReturnType()->isVoidTy()) + new StoreInst(DFSF.getShadow(RI->getReturnValue()), + &F->getArgumentList().back(), RI); + } + + return C; +} + bool DataFlowSanitizer::runOnModule(Module &M) { if (!DL) return false; @@ -1181,8 +1239,24 @@ void DFSanVisitor::visitCallSite(CallSite CS) { std::vector Args; CallSite::arg_iterator i = CS.arg_begin(); - for (unsigned n = FT->getNumParams(); n != 0; ++i, --n) - Args.push_back(*i); + for (unsigned n = FT->getNumParams(); n != 0; ++i, --n) { + Type *T = (*i)->getType(); + FunctionType *ParamFT; + if (isa(T) && + (ParamFT = dyn_cast( + cast(T)->getElementType()))) { + std::string TName = "dfst"; + TName += utostr(FT->getNumParams() - n); + TName += "$"; + TName += F->getName(); + Constant *T = DFSF.DFS.getOrBuildTrampolineFunction(ParamFT, TName); + Args.push_back(T); + Args.push_back( + IRB.CreateBitCast(*i, Type::getInt8PtrTy(*DFSF.DFS.Ctx))); + } else { + Args.push_back(*i); + } + } i = CS.arg_begin(); for (unsigned n = FT->getNumParams(); n != 0; ++i, --n) diff --git a/test/Instrumentation/DataFlowSanitizer/Inputs/abilist.txt b/test/Instrumentation/DataFlowSanitizer/Inputs/abilist.txt index 42e34e44d8b..97ce5e60a54 100644 --- a/test/Instrumentation/DataFlowSanitizer/Inputs/abilist.txt +++ b/test/Instrumentation/DataFlowSanitizer/Inputs/abilist.txt @@ -4,8 +4,5 @@ fun:discard*=discard fun:functional=uninstrumented fun:functional=functional -fun:custom1=uninstrumented -fun:custom1=custom - -fun:custom2=uninstrumented -fun:custom2=custom +fun:custom*=uninstrumented +fun:custom*=custom diff --git a/test/Instrumentation/DataFlowSanitizer/abilist.ll b/test/Instrumentation/DataFlowSanitizer/abilist.ll index 4e23bf1e700..66ddc140a08 100644 --- a/test/Instrumentation/DataFlowSanitizer/abilist.ll +++ b/test/Instrumentation/DataFlowSanitizer/abilist.ll @@ -16,6 +16,10 @@ declare void @custom1(i32 %a, i32 %b) declare i32 @custom2(i32 %a, i32 %b) +declare void @customcb(i32 (i32)* %cb) + +declare i32 @cb(i32) + ; CHECK: @"dfs$f" define void @f() { ; CHECK: %[[LABELRETURN:.*]] = alloca i16 @@ -26,6 +30,9 @@ define void @f() { ; CHECK: call i32 @__dfsw_custom2(i32 1, i32 2, i16 0, i16 0, i16* %[[LABELRETURN]]) call i32 @custom2(i32 1, i32 2) + ; CHECK: call void @__dfsw_customcb({{.*}} @"dfst0$customcb", i8* bitcast ({{.*}} @"dfs$cb" to i8*), i16 0) + call void @customcb(i32 (i32)* @cb) + ret void } @@ -58,3 +65,11 @@ 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-LABEL: define linkonce_odr i32 @"dfst0$customcb"(i32 (i32)*, i32, i16, i16*) +; CHECK: %[[BC:.*]] = bitcast i32 (i32)* %0 to { i32, i16 } (i32, i16)* +; CHECK: %[[CALL:.*]] = call { i32, i16 } %[[BC]](i32 %1, i16 %2) +; CHECK: %[[XVAL0:.*]] = extractvalue { i32, i16 } %[[CALL]], 0 +; CHECK: %[[XVAL1:.*]] = extractvalue { i32, i16 } %[[CALL]], 1 +; CHECK: store i16 %[[XVAL1]], i16* %3 +; CHECK: ret i32 %[[XVAL0]]