diff --git a/compiler-rt/test/dfsan/gep.c b/compiler-rt/test/dfsan/gep.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/gep.c @@ -0,0 +1,22 @@ +// RUN: %clang_dfsan %s -mllvm -dfsan-combine-offset-labels-on-gep=false -o %t && %run %t +// RUN: %clang_dfsan %s -DPROP_OFFSET_LABELS -o %t && %run %t +// +// REQUIRES: x86_64-target-arch + +// Tests that labels are propagated through GEP. + +#include +#include + +int main(void) { + int i = 1; + int *p = &i; + dfsan_set_label(1, &i, sizeof(i)); + p = p + i; +#ifdef PROP_OFFSET_LABELS + assert(dfsan_get_label(p) == 1); +#else + assert(dfsan_get_label(p) == 0); +#endif + return 0; +} 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 @@ -201,6 +201,14 @@ "storing in memory."), cl::Hidden, cl::init(false)); +// Controls whether the pass propagates labels of offsets in GEP instructions. +static cl::opt ClCombineOffsetLabelsOnGEP( + "dfsan-combine-offset-labels-on-gep", + cl::desc( + "Combine the label of the offset with the label of the pointer when " + "doing pointer arithmetic."), + cl::Hidden, cl::init(true)); + static cl::opt ClDebugNonzeroLabels( "dfsan-debug-nonzero-labels", cl::desc("Insert calls to __dfsan_nonzero_label on observing a parameter, " @@ -2778,7 +2786,14 @@ } void DFSanVisitor::visitGetElementPtrInst(GetElementPtrInst &GEPI) { - visitInstOperands(GEPI); + if (ClCombineOffsetLabelsOnGEP) { + visitInstOperands(GEPI); + return; + } + + DFSF.setShadow(&GEPI, DFSF.getShadow(GEPI.getOperand(0))); + if (DFSF.DFS.shouldTrackOrigins()) + DFSF.setOrigin(&GEPI, DFSF.getOrigin(GEPI.getOperand(0))); } void DFSanVisitor::visitExtractElementInst(ExtractElementInst &I) { diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/dont_combine_offset_labels_on_gep.ll b/llvm/test/Instrumentation/DataFlowSanitizer/dont_combine_offset_labels_on_gep.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/DataFlowSanitizer/dont_combine_offset_labels_on_gep.ll @@ -0,0 +1,22 @@ +; RUN: opt < %s -dfsan -dfsan-track-origins=1 -dfsan-combine-offset-labels-on-gep=false -dfsan-fast-8-labels=true -S | FileCheck %s --check-prefixes=CHECK,CHECK_ORIGIN +; RUN: opt < %s -dfsan -dfsan-combine-offset-labels-on-gep=false -dfsan-fast-8-labels=true -S | FileCheck %s --check-prefixes=CHECK +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" +target triple = "x86_64-unknown-linux-gnu" + +; CHECK: @__dfsan_arg_tls = external thread_local(initialexec) global [[TLS_ARR:\[100 x i64\]]] +; CHECK: @__dfsan_retval_tls = external thread_local(initialexec) global [[TLS_ARR]] +; CHECK: @__dfsan_shadow_width_bits = weak_odr constant i32 [[#SBITS:]] +; CHECK: @__dfsan_shadow_width_bytes = weak_odr constant i32 [[#SBYTES:]] + +define i32* @gepop([10 x [20 x i32]]* %p, i32 %a, i32 %b, i32 %c) { + ; CHECK: @"dfs$gepop" + ; CHECK_ORIGIN: [[PO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align [[ALIGN_O:4]] + ; CHECK: [[PS:%.*]] = load i[[#SBITS]], i[[#SBITS]]* bitcast ([100 x i64]* @__dfsan_arg_tls to i[[#SBITS]]*), align [[ALIGN_S:2]] + ; CHECK: %e = getelementptr [10 x [20 x i32]], [10 x [20 x i32]]* %p, i32 %a, i32 %b, i32 %c + ; CHECK: store i[[#SBITS]] [[PS]], i[[#SBITS]]* bitcast ([100 x i64]* @__dfsan_retval_tls to i[[#SBITS]]*), align [[ALIGN_S]] + ; CHECK_ORIGIN: store i32 [[PO]], i32* @__dfsan_retval_origin_tls, align [[ALIGN_O]] + + %e = getelementptr [10 x [20 x i32]], [10 x [20 x i32]]* %p, i32 %a, i32 %b, i32 %c + ret i32* %e +} +