[msan] Precise instrumentation for icmp sgt %x, -1.

Extend signed relational comparison instrumentation with a special
case for comparisons with -1. This fixes an MSan false positive when
such comparison is used as a sign bit test.

https://llvm.org/bugs/show_bug.cgi?id=24561


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@245980 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evgeniy Stepanov 2015-08-25 22:19:11 +00:00
parent 66faa25c3a
commit e49a149453
2 changed files with 96 additions and 25 deletions

View File

@ -1736,25 +1736,30 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
/// \brief Instrument signed relational comparisons. /// \brief Instrument signed relational comparisons.
/// ///
/// Handle (x<0) and (x>=0) comparisons (essentially, sign bit tests) by /// Handle sign bit tests: x<0, x>=0, x<=-1, x>-1 by propagating the highest
/// propagating the highest bit of the shadow. Everything else is delegated /// bit of the shadow. Everything else is delegated to handleShadowOr().
/// to handleShadowOr().
void handleSignedRelationalComparison(ICmpInst &I) { void handleSignedRelationalComparison(ICmpInst &I) {
Constant *constOp0 = dyn_cast<Constant>(I.getOperand(0)); Constant *constOp;
Constant *constOp1 = dyn_cast<Constant>(I.getOperand(1)); Value *op = nullptr;
Value* op = nullptr; CmpInst::Predicate pre;
CmpInst::Predicate pre = I.getPredicate(); if ((constOp = dyn_cast<Constant>(I.getOperand(1)))) {
if (constOp0 && constOp0->isNullValue() &&
(pre == CmpInst::ICMP_SGT || pre == CmpInst::ICMP_SLE)) {
op = I.getOperand(1);
} else if (constOp1 && constOp1->isNullValue() &&
(pre == CmpInst::ICMP_SLT || pre == CmpInst::ICMP_SGE)) {
op = I.getOperand(0); op = I.getOperand(0);
pre = I.getPredicate();
} else if ((constOp = dyn_cast<Constant>(I.getOperand(0)))) {
op = I.getOperand(1);
pre = I.getSwappedPredicate();
} else {
handleShadowOr(I);
return;
} }
if (op) {
if ((constOp->isNullValue() &&
(pre == CmpInst::ICMP_SLT || pre == CmpInst::ICMP_SGE)) ||
(constOp->isAllOnesValue() &&
(pre == CmpInst::ICMP_SGT || pre == CmpInst::ICMP_SLE))) {
IRBuilder<> IRB(&I); IRBuilder<> IRB(&I);
Value* Shadow = Value *Shadow = IRB.CreateICmpSLT(getShadow(op), getCleanShadow(op),
IRB.CreateICmpSLT(getShadow(op), getCleanShadow(op), "_msprop_icmpslt"); "_msprop_icmp_s");
setShadow(&I, Shadow); setShadow(&I, Shadow);
setOrigin(&I, getOrigin(op)); setOrigin(&I, getOrigin(op));
} else { } else {

View File

@ -385,48 +385,99 @@ entry:
; Check that we propagate shadow for x<0, x>=0, etc (i.e. sign bit tests) ; Check that we propagate shadow for x<0, x>=0, etc (i.e. sign bit tests)
define zeroext i1 @ICmpSLT(i32 %x) nounwind uwtable readnone sanitize_memory { define zeroext i1 @ICmpSLTZero(i32 %x) nounwind uwtable readnone sanitize_memory {
%1 = icmp slt i32 %x, 0 %1 = icmp slt i32 %x, 0
ret i1 %1 ret i1 %1
} }
; CHECK-LABEL: @ICmpSLT ; CHECK-LABEL: @ICmpSLTZero
; CHECK: icmp slt ; CHECK: icmp slt
; CHECK-NOT: call void @__msan_warning ; CHECK-NOT: call void @__msan_warning
; CHECK: icmp slt ; CHECK: icmp slt
; CHECK-NOT: call void @__msan_warning ; CHECK-NOT: call void @__msan_warning
; CHECK: ret i1 ; CHECK: ret i1
define zeroext i1 @ICmpSGE(i32 %x) nounwind uwtable readnone sanitize_memory { define zeroext i1 @ICmpSGEZero(i32 %x) nounwind uwtable readnone sanitize_memory {
%1 = icmp sge i32 %x, 0 %1 = icmp sge i32 %x, 0
ret i1 %1 ret i1 %1
} }
; CHECK-LABEL: @ICmpSGE ; CHECK-LABEL: @ICmpSGEZero
; CHECK: icmp slt ; CHECK: icmp slt
; CHECK-NOT: call void @__msan_warning ; CHECK-NOT: call void @__msan_warning
; CHECK: icmp sge ; CHECK: icmp sge
; CHECK-NOT: call void @__msan_warning ; CHECK-NOT: call void @__msan_warning
; CHECK: ret i1 ; CHECK: ret i1
define zeroext i1 @ICmpSGT(i32 %x) nounwind uwtable readnone sanitize_memory { define zeroext i1 @ICmpSGTZero(i32 %x) nounwind uwtable readnone sanitize_memory {
%1 = icmp sgt i32 0, %x %1 = icmp sgt i32 0, %x
ret i1 %1 ret i1 %1
} }
; CHECK-LABEL: @ICmpSGT ; CHECK-LABEL: @ICmpSGTZero
; CHECK: icmp slt ; CHECK: icmp slt
; CHECK-NOT: call void @__msan_warning ; CHECK-NOT: call void @__msan_warning
; CHECK: icmp sgt ; CHECK: icmp sgt
; CHECK-NOT: call void @__msan_warning ; CHECK-NOT: call void @__msan_warning
; CHECK: ret i1 ; CHECK: ret i1
define zeroext i1 @ICmpSLE(i32 %x) nounwind uwtable readnone sanitize_memory { define zeroext i1 @ICmpSLEZero(i32 %x) nounwind uwtable readnone sanitize_memory {
%1 = icmp sle i32 0, %x %1 = icmp sle i32 0, %x
ret i1 %1 ret i1 %1
} }
; CHECK-LABEL: @ICmpSLE ; CHECK-LABEL: @ICmpSLEZero
; CHECK: icmp slt
; CHECK-NOT: call void @__msan_warning
; CHECK: icmp sle
; CHECK-NOT: call void @__msan_warning
; CHECK: ret i1
; Check that we propagate shadow for x<=-1, x>-1, etc (i.e. sign bit tests)
define zeroext i1 @ICmpSLTAllOnes(i32 %x) nounwind uwtable readnone sanitize_memory {
%1 = icmp slt i32 -1, %x
ret i1 %1
}
; CHECK-LABEL: @ICmpSLTAllOnes
; CHECK: icmp slt
; CHECK-NOT: call void @__msan_warning
; CHECK: icmp slt
; CHECK-NOT: call void @__msan_warning
; CHECK: ret i1
define zeroext i1 @ICmpSGEAllOnes(i32 %x) nounwind uwtable readnone sanitize_memory {
%1 = icmp sge i32 -1, %x
ret i1 %1
}
; CHECK-LABEL: @ICmpSGEAllOnes
; CHECK: icmp slt
; CHECK-NOT: call void @__msan_warning
; CHECK: icmp sge
; CHECK-NOT: call void @__msan_warning
; CHECK: ret i1
define zeroext i1 @ICmpSGTAllOnes(i32 %x) nounwind uwtable readnone sanitize_memory {
%1 = icmp sgt i32 %x, -1
ret i1 %1
}
; CHECK-LABEL: @ICmpSGTAllOnes
; CHECK: icmp slt
; CHECK-NOT: call void @__msan_warning
; CHECK: icmp sgt
; CHECK-NOT: call void @__msan_warning
; CHECK: ret i1
define zeroext i1 @ICmpSLEAllOnes(i32 %x) nounwind uwtable readnone sanitize_memory {
%1 = icmp sle i32 %x, -1
ret i1 %1
}
; CHECK-LABEL: @ICmpSLEAllOnes
; CHECK: icmp slt ; CHECK: icmp slt
; CHECK-NOT: call void @__msan_warning ; CHECK-NOT: call void @__msan_warning
; CHECK: icmp sle ; CHECK: icmp sle
@ -437,18 +488,33 @@ define zeroext i1 @ICmpSLE(i32 %x) nounwind uwtable readnone sanitize_memory {
; Check that we propagate shadow for x<0, x>=0, etc (i.e. sign bit tests) ; Check that we propagate shadow for x<0, x>=0, etc (i.e. sign bit tests)
; of the vector arguments. ; of the vector arguments.
define <2 x i1> @ICmpSLT_vector(<2 x i32*> %x) nounwind uwtable readnone sanitize_memory { define <2 x i1> @ICmpSLT_vector_Zero(<2 x i32*> %x) nounwind uwtable readnone sanitize_memory {
%1 = icmp slt <2 x i32*> %x, zeroinitializer %1 = icmp slt <2 x i32*> %x, zeroinitializer
ret <2 x i1> %1 ret <2 x i1> %1
} }
; CHECK-LABEL: @ICmpSLT_vector ; CHECK-LABEL: @ICmpSLT_vector_Zero
; CHECK: icmp slt <2 x i64> ; CHECK: icmp slt <2 x i64>
; CHECK-NOT: call void @__msan_warning ; CHECK-NOT: call void @__msan_warning
; CHECK: icmp slt <2 x i32*> ; CHECK: icmp slt <2 x i32*>
; CHECK-NOT: call void @__msan_warning ; CHECK-NOT: call void @__msan_warning
; CHECK: ret <2 x i1> ; CHECK: ret <2 x i1>
; Check that we propagate shadow for x<=-1, x>0, etc (i.e. sign bit tests)
; of the vector arguments.
define <2 x i1> @ICmpSLT_vector_AllOnes(<2 x i32> %x) nounwind uwtable readnone sanitize_memory {
%1 = icmp slt <2 x i32> <i32 -1, i32 -1>, %x
ret <2 x i1> %1
}
; CHECK-LABEL: @ICmpSLT_vector_AllOnes
; CHECK: icmp slt <2 x i32>
; CHECK-NOT: call void @__msan_warning
; CHECK: icmp slt <2 x i32>
; CHECK-NOT: call void @__msan_warning
; CHECK: ret <2 x i1>
; Check that we propagate shadow for unsigned relational comparisons with ; Check that we propagate shadow for unsigned relational comparisons with
; constants ; constants