diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 562cf12bf576c..1c9b34489cc5d 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -1978,6 +1978,10 @@ void AggExprEmitter::EmitCheckedBoundPointerArithmetic( LValue BaseLV = CGF.EmitAggExprToLValue(Base); EmitBoundPointerArithmetic(DestLV, BaseLV, Idx, IsSigned, IsSub); + if (IsSub) { + Idx = Builder.CreateNeg(Idx, "idx.neg"); + } + if (CGF.SanOpts.has(SanitizerKind::ArrayBounds)) CGF.EmitBoundsCheck(E, Base, Idx, IdxType, /*Accessed*/ false); diff --git a/clang/test/BoundsSafety/CodeGen/ubsan/ptr-overflow-subtraction.c b/clang/test/BoundsSafety/CodeGen/ubsan/ptr-overflow-subtraction.c new file mode 100644 index 0000000000000..491987afed861 --- /dev/null +++ b/clang/test/BoundsSafety/CodeGen/ubsan/ptr-overflow-subtraction.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -O0 -fbounds-safety -fsanitize=pointer-overflow -fsanitize-trap=pointer-overflow -emit-llvm %s -o - | FileCheck %s + +#include + +// Regression test for pointer subtraction generating a false-positive +// UBSan pointer overflow check when -fbounds-safety is enabled. +// The check must use the negated index so that (base - offset) ule base +// is checked, not (base + offset) ule base which is unconditionally false. +void ptr_sub(unsigned char * __bidi_indexable ptr, unsigned int offset) { + unsigned char * __bidi_indexable ptr2 = ptr - offset; + (void)ptr2; +} + +// CHECK: %[[OFFSET:[a-z0-9]+]] = load i32 +// CHECK: %[[NEG:[a-z0-9.]+]] = sub i32 0, %[[OFFSET]] +// CHECK: getelementptr{{.*}} %[[NEG]] +// CHECK: %[[EXT:[a-z0-9.]+]] = sext i32 %[[NEG]] to i64 +// CHECK: call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 %[[EXT]])