diff --git a/compiler-rt/test/dfsan/event_callbacks.c b/compiler-rt/test/dfsan/event_callbacks.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/event_callbacks.c @@ -0,0 +1,67 @@ +// RUN: %clang_dfsan -fno-sanitize=dataflow -fPIE -DCALLBACKS -c %s -o %t-callbacks.o +// RUN: %clang_dfsan -mllvm -dfsan-event-callbacks %s %t-callbacks.o -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// Tests that callbacks are inserted for store events when +// -dfsan-event-callbacks is specified. + +#include +#include +#include + +#ifdef CALLBACKS +// Compile this code without DFSan to avoid recursive instrumentation. + +extern dfsan_label LabelI; +extern dfsan_label LabelJ; +extern dfsan_label LabelIJ; + +void __dfsan_store_callback(dfsan_label Label) { + if (!Label) + return; + + static int Count = 0; + switch (Count++) { + case 0: + assert(Label == LabelI); + break; + case 1: + assert(Label == LabelJ); + break; + case 2: + assert(Label == LabelIJ); + break; + default: + assert(0); + } + + // CHECK: Label 1 stored to memory + // CHECK: Label 2 stored to memory + // CHECK: Label 3 stored to memory + fprintf(stderr, "Label %u stored to memory\n", Label); +} + +#else +// Compile this code with DFSan and -dfsan-event-callbacks to insert the +// callbacks. + +dfsan_label LabelI; +dfsan_label LabelJ; +dfsan_label LabelIJ; + +int main(void) { + int I = 1, J = 2; + LabelI = dfsan_create_label("I", 0); + dfsan_set_label(LabelI, &I, sizeof(I)); + LabelJ = dfsan_create_label("J", 0); + dfsan_set_label(LabelJ, &J, sizeof(J)); + LabelIJ = dfsan_union(LabelI, LabelJ); + + volatile int Sink = I; + Sink = J; + Sink += I; + + return 0; +} + +#endif // #ifdef CALLBACKS diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -162,6 +162,17 @@ "load or return with a nonzero label"), cl::Hidden); +// Experimental feature that inserts callbacks for certain data events. +// Currently callbacks are only inserted for stores. +// +// If this flag is set to true, the user must provide definitions for the +// following callback functions: +// void __dfsan_store_callback(dfsan_label Label); +static cl::opt ClEventCallbacks( + "dfsan-event-callbacks", + cl::desc("Insert calls to __dfsan_*_callback functions on data events."), + cl::Hidden, cl::init(false)); + static StringRef GetGlobalTypeString(const GlobalValue &G) { // Types of GlobalVariables are always pointer types. Type *GType = G.getValueType(); @@ -345,6 +356,7 @@ FunctionType *DFSanSetLabelFnTy; FunctionType *DFSanNonzeroLabelFnTy; FunctionType *DFSanVarargWrapperFnTy; + FunctionType *DFSanStoreCallbackFnTy; FunctionCallee DFSanUnionFn; FunctionCallee DFSanCheckedUnionFn; FunctionCallee DFSanUnionLoadFn; @@ -352,6 +364,7 @@ FunctionCallee DFSanSetLabelFn; FunctionCallee DFSanNonzeroLabelFn; FunctionCallee DFSanVarargWrapperFn; + FunctionCallee DFSanStoreCallbackFn; MDNode *ColdCallWeights; DFSanABIList ABIList; DenseMap UnwrappedFnMap; @@ -583,6 +596,8 @@ Type::getVoidTy(*Ctx), None, /*isVarArg=*/false); DFSanVarargWrapperFnTy = FunctionType::get( Type::getVoidTy(*Ctx), Type::getInt8PtrTy(*Ctx), /*isVarArg=*/false); + DFSanStoreCallbackFnTy = + FunctionType::get(Type::getVoidTy(*Ctx), ShadowTy, /*isVarArg=*/false); if (GetArgTLSPtr) { Type *ArgTLSTy = ArrayType::get(ShadowTy, 64); @@ -783,6 +798,9 @@ DFSanVarargWrapperFn = Mod->getOrInsertFunction("__dfsan_vararg_wrapper", DFSanVarargWrapperFnTy); + DFSanStoreCallbackFn = Mod->getOrInsertFunction("__dfsan_store_callback", + DFSanStoreCallbackFnTy); + std::vector FnsToInstrument; SmallPtrSet FnsWithNativeABI; for (Function &i : M) { @@ -793,7 +811,8 @@ &i != DFSanUnimplementedFn.getCallee()->stripPointerCasts() && &i != DFSanSetLabelFn.getCallee()->stripPointerCasts() && &i != DFSanNonzeroLabelFn.getCallee()->stripPointerCasts() && - &i != DFSanVarargWrapperFn.getCallee()->stripPointerCasts()) + &i != DFSanVarargWrapperFn.getCallee()->stripPointerCasts() && + &i != DFSanStoreCallbackFn.getCallee()->stripPointerCasts()) FnsToInstrument.push_back(&i); } @@ -1396,6 +1415,10 @@ Shadow = DFSF.combineShadows(Shadow, PtrShadow, &SI); } DFSF.storeShadow(SI.getPointerOperand(), Size, Alignement, Shadow, &SI); + if (ClEventCallbacks) { + IRBuilder<> IRB(&SI); + IRB.CreateCall(DFSF.DFS.DFSanStoreCallbackFn, Shadow); + } } void DFSanVisitor::visitUnaryOperator(UnaryOperator &UO) {