// RUN: %clang_dfsan -fno-sanitize=dataflow -O2 -fPIE -DCALLBACKS -c %s -o %t-callbacks.o
// RUN: %clang_dfsan -O2 -mllvm -dfsan-event-callbacks %s %t-callbacks.o -o %t
-// RUN: %run %t 2>&1 | FileCheck %s
+// RUN: %run %t FooBarBaz 2>&1 | FileCheck %s
// Tests that callbacks are inserted for store events when
// -dfsan-event-callbacks is specified.
#include <assert.h>
#include <sanitizer/dfsan_interface.h>
#include <stdio.h>
+#include <string.h>
#ifdef CALLBACKS
// Compile this code without DFSan to avoid recursive instrumentation.
extern dfsan_label LabelI;
extern dfsan_label LabelJ;
extern dfsan_label LabelIJ;
+extern dfsan_label LabelArgv;
+extern size_t LenArgv;
void __dfsan_store_callback(dfsan_label Label) {
if (!Label)
fprintf(stderr, "Label %u loaded from memory\n", Label);
}
+void __dfsan_mem_transfer_callback(dfsan_label *Start, size_t Len) {
+ assert(Len == LenArgv);
+ for (int I = 0; I < Len; ++I) {
+ assert(Start[I] == LabelArgv);
+ }
+
+ fprintf(stderr, "Label %u copied to memory\n", Start[0]);
+}
+
#else
// Compile this code with DFSan and -dfsan-event-callbacks to insert the
// callbacks.
dfsan_label LabelI;
dfsan_label LabelJ;
dfsan_label LabelIJ;
+dfsan_label LabelArgv;
+
+size_t LenArgv;
+
+int main(int Argc, char *Argv[]) {
+ assert(Argc == 2);
-int main(void) {
int I = 1, J = 2;
LabelI = dfsan_create_label("I", 0);
dfsan_set_label(LabelI, &I, sizeof(I));
// CHECK: Label 3 loaded from memory
assert(Sink == 3);
+ LenArgv = strlen(Argv[1]);
+ LabelArgv = dfsan_create_label("Argv", 0);
+ dfsan_set_label(LabelArgv, Argv[1], LenArgv);
+
+ char SinkBuf[64];
+ assert(LenArgv < sizeof(SinkBuf) - 1);
+
+ // CHECK: Label 4 copied to memory
+ memcpy(SinkBuf, Argv[1], LenArgv);
+
+ // CHECK: Label 4 copied to memory
+ memmove(&SinkBuf[1], SinkBuf, LenArgv);
+
return 0;
}
cl::Hidden);
// Experimental feature that inserts callbacks for certain data events.
-// Currently callbacks are only inserted for loads and stores.
+// Currently callbacks are only inserted for loads, stores, and memory transfers
+// (i.e. memcpy and memmove).
//
// If this flag is set to true, the user must provide definitions for the
// following callback functions:
// void __dfsan_load_callback(dfsan_label Label);
// void __dfsan_store_callback(dfsan_label Label);
+// void __dfsan_mem_transfer_callback(dfsan_label *Start, size_t Len);
static cl::opt<bool> ClEventCallbacks(
"dfsan-event-callbacks",
cl::desc("Insert calls to __dfsan_*_callback functions on data events."),
FunctionType *DFSanNonzeroLabelFnTy;
FunctionType *DFSanVarargWrapperFnTy;
FunctionType *DFSanLoadStoreCallbackFnTy;
+ FunctionType *DFSanMemTransferCallbackFnTy;
FunctionCallee DFSanUnionFn;
FunctionCallee DFSanCheckedUnionFn;
FunctionCallee DFSanUnionLoadFn;
FunctionCallee DFSanVarargWrapperFn;
FunctionCallee DFSanLoadCallbackFn;
FunctionCallee DFSanStoreCallbackFn;
+ FunctionCallee DFSanMemTransferCallbackFn;
MDNode *ColdCallWeights;
DFSanABIList ABIList;
DenseMap<Value *, Function *> UnwrappedFnMap;
Type::getVoidTy(*Ctx), Type::getInt8PtrTy(*Ctx), /*isVarArg=*/false);
DFSanLoadStoreCallbackFnTy =
FunctionType::get(Type::getVoidTy(*Ctx), ShadowTy, /*isVarArg=*/false);
+ Type *DFSanMemTransferCallbackArgs[2] = {ShadowPtrTy, IntptrTy};
+ DFSanMemTransferCallbackFnTy =
+ FunctionType::get(Type::getVoidTy(*Ctx), DFSanMemTransferCallbackArgs,
+ /*isVarArg=*/false);
if (GetArgTLSPtr) {
Type *ArgTLSTy = ArrayType::get(ShadowTy, 64);
DFSanLoadStoreCallbackFnTy);
DFSanStoreCallbackFn = Mod->getOrInsertFunction("__dfsan_store_callback",
DFSanLoadStoreCallbackFnTy);
+ DFSanMemTransferCallbackFn = Mod->getOrInsertFunction(
+ "__dfsan_mem_transfer_callback", DFSanMemTransferCallbackFnTy);
std::vector<Function *> FnsToInstrument;
SmallPtrSet<Function *, 2> FnsWithNativeABI;
&i != DFSanNonzeroLabelFn.getCallee()->stripPointerCasts() &&
&i != DFSanVarargWrapperFn.getCallee()->stripPointerCasts() &&
&i != DFSanLoadCallbackFn.getCallee()->stripPointerCasts() &&
- &i != DFSanStoreCallbackFn.getCallee()->stripPointerCasts())
+ &i != DFSanStoreCallbackFn.getCallee()->stripPointerCasts() &&
+ &i != DFSanMemTransferCallbackFn.getCallee()->stripPointerCasts())
FnsToInstrument.push_back(&i);
}
void DFSanVisitor::visitMemTransferInst(MemTransferInst &I) {
IRBuilder<> IRB(&I);
- Value *DestShadow = DFSF.DFS.getShadowAddress(I.getDest(), &I);
+ Value *RawDestShadow = DFSF.DFS.getShadowAddress(I.getDest(), &I);
Value *SrcShadow = DFSF.DFS.getShadowAddress(I.getSource(), &I);
Value *LenShadow = IRB.CreateMul(
I.getLength(),
ConstantInt::get(I.getLength()->getType(), DFSF.DFS.ShadowWidth / 8));
Type *Int8Ptr = Type::getInt8PtrTy(*DFSF.DFS.Ctx);
- DestShadow = IRB.CreateBitCast(DestShadow, Int8Ptr);
+ Value *DestShadow = IRB.CreateBitCast(RawDestShadow, Int8Ptr);
SrcShadow = IRB.CreateBitCast(SrcShadow, Int8Ptr);
auto *MTI = cast<MemTransferInst>(
IRB.CreateCall(I.getFunctionType(), I.getCalledValue(),
MTI->setDestAlignment(DFSF.DFS.ShadowWidth / 8);
MTI->setSourceAlignment(DFSF.DFS.ShadowWidth / 8);
}
+ if (ClEventCallbacks) {
+ IRB.CreateCall(DFSF.DFS.DFSanMemTransferCallbackFn,
+ {RawDestShadow, I.getLength()});
+ }
}
void DFSanVisitor::visitReturnInst(ReturnInst &RI) {