Index: lib/Transforms/Instrumentation/SanitizerCoverage.cpp =================================================================== --- lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -46,6 +46,14 @@ static const char *const SanCovTraceCmp2 = "__sanitizer_cov_trace_cmp2"; static const char *const SanCovTraceCmp4 = "__sanitizer_cov_trace_cmp4"; static const char *const SanCovTraceCmp8 = "__sanitizer_cov_trace_cmp8"; +static const char *const SanCovTraceConstCmp1 = + "__sanitizer_cov_trace_const_cmp1"; +static const char *const SanCovTraceConstCmp2 = + "__sanitizer_cov_trace_const_cmp2"; +static const char *const SanCovTraceConstCmp4 = + "__sanitizer_cov_trace_const_cmp4"; +static const char *const SanCovTraceConstCmp8 = + "__sanitizer_cov_trace_const_cmp8"; static const char *const SanCovTraceDiv4 = "__sanitizer_cov_trace_div4"; static const char *const SanCovTraceDiv8 = "__sanitizer_cov_trace_div8"; static const char *const SanCovTraceGep = "__sanitizer_cov_trace_gep"; @@ -204,12 +212,13 @@ Function *SanCovTracePCIndir; Function *SanCovTracePC, *SanCovTracePCGuard; Function *SanCovTraceCmpFunction[4]; + Function *SanCovTraceConstCmpFunction[4]; Function *SanCovTraceDivFunction[2]; Function *SanCovTraceGepFunction; Function *SanCovTraceSwitchFunction; InlineAsm *EmptyAsm; Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy, - *Int8Ty, *Int8PtrTy; + *Int16Ty, *Int8Ty, *Int8PtrTy; Module *CurModule; Triple TargetTriple; LLVMContext *C; @@ -281,6 +290,7 @@ Int8PtrTy = PointerType::getUnqual(IRB.getInt8Ty()); Int64Ty = IRB.getInt64Ty(); Int32Ty = IRB.getInt32Ty(); + Int16Ty = IRB.getInt16Ty(); Int8Ty = IRB.getInt8Ty(); SanCovTracePCIndir = checkSanitizerInterfaceFunction( @@ -298,6 +308,19 @@ checkSanitizerInterfaceFunction(M.getOrInsertFunction( SanCovTraceCmp8, VoidTy, Int64Ty, Int64Ty)); + SanCovTraceConstCmpFunction[0] = + checkSanitizerInterfaceFunction(M.getOrInsertFunction( + SanCovTraceConstCmp1, VoidTy, Int8Ty, Int8Ty)); + SanCovTraceConstCmpFunction[1] = + checkSanitizerInterfaceFunction(M.getOrInsertFunction( + SanCovTraceConstCmp2, VoidTy, Int16Ty, Int16Ty)); + SanCovTraceConstCmpFunction[2] = + checkSanitizerInterfaceFunction(M.getOrInsertFunction( + SanCovTraceConstCmp4, VoidTy, Int32Ty, Int32Ty)); + SanCovTraceConstCmpFunction[3] = + checkSanitizerInterfaceFunction(M.getOrInsertFunction( + SanCovTraceConstCmp8, VoidTy, Int64Ty, Int64Ty)); + SanCovTraceDivFunction[0] = checkSanitizerInterfaceFunction(M.getOrInsertFunction( SanCovTraceDiv4, VoidTy, IRB.getInt32Ty())); @@ -316,6 +339,8 @@ for (int i = 0; i < 3; i++) { SanCovTraceCmpFunction[i]->addParamAttr(0, Attribute::ZExt); SanCovTraceCmpFunction[i]->addParamAttr(1, Attribute::ZExt); + SanCovTraceConstCmpFunction[i]->addParamAttr(0, Attribute::ZExt); + SanCovTraceConstCmpFunction[i]->addParamAttr(1, Attribute::ZExt); } SanCovTraceDivFunction[0]->addParamAttr(0, Attribute::ZExt); } @@ -644,10 +669,21 @@ TypeSize == 64 ? 3 : -1; if (CallbackIdx < 0) continue; // __sanitizer_cov_trace_cmp((type_size << 32) | predicate, A0, A1); + auto CallbackFunc = SanCovTraceCmpFunction[CallbackIdx]; + bool FirstIsConst = isa(A0); + bool SecondIsConst = isa(A1); + // If both are const, then we don't need such a comparison. + if (FirstIsConst && SecondIsConst) continue; + // If only one is const, then make it the first callback argument. + if (FirstIsConst || SecondIsConst) { + CallbackFunc = SanCovTraceConstCmpFunction[CallbackIdx]; + if (SecondIsConst) + std::swap(A0, A1); + } + auto Ty = Type::getIntNTy(*C, TypeSize); - IRB.CreateCall( - SanCovTraceCmpFunction[CallbackIdx], - {IRB.CreateIntCast(A0, Ty, true), IRB.CreateIntCast(A1, Ty, true)}); + IRB.CreateCall(CallbackFunc, {IRB.CreateIntCast(A0, Ty, true), + IRB.CreateIntCast(A1, Ty, true)}); } } } Index: test/Instrumentation/SanitizerCoverage/const-cmp-tracing.ll =================================================================== --- test/Instrumentation/SanitizerCoverage/const-cmp-tracing.ll +++ test/Instrumentation/SanitizerCoverage/const-cmp-tracing.ll @@ -0,0 +1,64 @@ +; Test -sanitizer-coverage-trace-compares=1 +; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-trace-compares=1 -S | FileCheck %s + +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" +target triple = "x86_64-unknown-linux-gnu" +define i32 @foo(i32 %a, i32 %b) #0 { +entry: + +; compare (non-const, non-const) + %cmp = icmp slt i32 %a, %b +; CHECK: call void @__sanitizer_cov_trace_cmp4 +; CHECK-NEXT: icmp slt i32 %a, %b + +; compare (const, non-const) + icmp slt i32 %a, 1 +; CHECK: call void @__sanitizer_cov_trace_const_cmp4(i32 1, i32 %a) +; CHECK-NEXT: icmp slt i32 %a, 1 + +; compare (non-const, const) + icmp slt i32 1, %a +; CHECK: call void @__sanitizer_cov_trace_const_cmp4(i32 1, i32 %a) +; CHECK-NEXT: icmp slt i32 1, %a + +; compare (const, const) - should not be instrumented + icmp slt i32 1, 0 +; CHECK-NOT: call void @__sanitizer_cov_trace +; CHECK icmp slt i32 1, 0 + +; compare variables of byte size + %x = trunc i32 %a to i8 + + icmp slt i8 %x, 1 +; CHECK: call void @__sanitizer_cov_trace_const_cmp1(i8 1, i8 %x) +; CHECK-NEXT: icmp slt i8 %x, 1 + + icmp slt i8 1, %x +; CHECK: call void @__sanitizer_cov_trace_const_cmp1(i8 1, i8 %x) +; CHECK-NEXT: icmp slt i8 1, %x + +; compare variables of word size + %y = trunc i32 %a to i16 + + icmp slt i16 %y, 1 +; CHECK: call void @__sanitizer_cov_trace_const_cmp2(i16 1, i16 %y) +; CHECK-NEXT: icmp slt i16 %y, 1 + + icmp slt i16 1, %y +; CHECK: call void @__sanitizer_cov_trace_const_cmp2(i16 1, i16 %y) +; CHECK-NEXT: icmp slt i16 1, %y + +; compare variables of qword size + %z = zext i32 %a to i64 + + icmp slt i64 %z, 1 +; CHECK: call void @__sanitizer_cov_trace_const_cmp8(i64 1, i64 %z) +; CHECK-NEXT: icmp slt i64 %z, 1 + + icmp slt i64 1, %z +; CHECK: call void @__sanitizer_cov_trace_const_cmp8(i64 1, i64 %z) +; CHECK-NEXT: icmp slt i64 1, %z + + %conv = zext i1 %cmp to i32 + ret i32 %conv +} Index: tools/clang/docs/SanitizerCoverage.rst =================================================================== --- tools/clang/docs/SanitizerCoverage.rst +++ tools/clang/docs/SanitizerCoverage.rst @@ -211,6 +211,14 @@ void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2); void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2); + // Called before a comparison instruction if exactly one of the arguments is constant. + // Arg1 and Arg2 are arguments of the comparison, Arg1 is a compile-time constant. + // These callbacks are emitted by -fsanitize-coverage=trace-cmp since 2017-08-11 + void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2); + void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2); + void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2); + void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2); + // Called before a switch statement. // Val is the switch operand. // Cases[0] is the number of case constants. @@ -227,7 +235,6 @@ // for every non-constant array index. void __sanitizer_cov_trace_gep(uintptr_t Idx); - This interface is a subject to change. Default implementation