Author: Bill Wendling Date: 2026-10-20T18:50:18-07:00 New Revision: 67e2b2852528a8f9c6c63ce570effaefced78ac3
URL: https://github.com/llvm/llvm-project/commit/67e2b2852528a8f9c6c63ce570effaefced78ac3 DIFF: https://github.com/llvm/llvm-project/commit/67e2b2852528a8f9c6c63ce570effaefced78ac3.diff LOG: [Clang][counted_by] Don't re-evaluate the base of a counted_by pointer access for -fsanitize=array-bounds (#232228) When indexing a 'counted_by' pointer field with -fsanitize=array-bounds, EmitCountedByBoundsChecking was handed an invalid address and re-emitted the field's l-value to locate the count. That re-evaluated the struct base, duplicating its side-effects: struct p { int count; int *buf __counted_by(count); }; struct p *q; int f(int i) { return q++->buf[i]; } // 'q' incremented twice int g(int i) { return get()->buf[i]; } // 'get' called twice i.e. enabling the sanitizer changed the program's behavior. Emit the subscript base exactly as before, but have ScalarExprEmitter record the l-value it loads the 'counted_by' field from, and pass that address to the bounds check. The base is emitted the same way with and without the sanitizer, so the load keeps its debug location, ptrauth authentication, 'align_value' assumption, and -fdebug-info-for-profiling pseudo variable. This also covers an intervening cast (e.g. '((char *)get()->buf)[i]'). If the field isn't loaded through the scalar emitter, the field's l-value is re-emitted, which only recomputes its address and so is safe unless the struct base has side-effects; in that case the check is skipped instead of evaluating the base twice. Added: clang/test/CodeGen/attr-counted-by-align-value.c clang/test/CodeGen/attr-counted-by-debug-info.c clang/test/CodeGen/attr-counted-by-ptrauth.c Modified: clang/lib/CodeGen/CGExpr.cpp clang/lib/CodeGen/CGExprScalar.cpp clang/lib/CodeGen/CodeGenFunction.h clang/test/CodeGen/attr-counted-by-base-exprs.c clang/test/CodeGen/attr-counted-by-for-pointers.c clang/test/CodeGen/attr-counted-by-or-null-for-pointers.c clang/test/CodeGen/attr-sized-by-for-pointers.c clang/test/CodeGen/attr-sized-by-or-null-for-pointers.c Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index beebd67116e5f..f6810d84cd235 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -56,6 +56,7 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" +#include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/xxhash.h" #include "llvm/Transforms/Utils/SanitizerStats.h" @@ -5333,9 +5334,43 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, getContext().getTypeSizeInChars(E->getType()).getQuantity(); } } else { - // The base must be a pointer; emit it with an estimate of its alignment. - Address BaseAddr = - EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo); + // Find the load of a 'counted_by' pointer field (e.g. 'p->buf' in + // 'p->buf[i]') whose count bounds this access. + const CastExpr *CountedByLoad = nullptr; + const MemberExpr *CountedByME = nullptr; + if (SanOpts.has(SanitizerKind::ArrayBounds)) { + StructFieldAccess Visitor; + if (const auto *CE = + dyn_cast_if_present<CastExpr>(Visitor.Visit(E->getBase())); + CE && CE->getCastKind() == CK_LValueToRValue) { + const auto *ME = dyn_cast<MemberExpr>(CE->getSubExpr()); + if (ME && ME->getMemberDecl()->getType()->isCountAttributedType()) { + CountedByLoad = CE; + CountedByME = ME; + } + } + } + + // The bounds check locates the count relative to the pointer field's + // address. Record the field's l-value while the base is emitted, so that + // the struct base (which may have side-effects, e.g. 'get()->buf[i]' or + // 'p++->buf[i]') isn't evaluated a second time for the check. The base + // itself is emitted exactly as it is without the sanitizer, so the load + // keeps its debug location, '__ptrauth' authentication, 'align_value' + // assumption, and so on. + LoadedLValueCapture FieldCapture{CountedByME, std::nullopt}; + Address BaseAddr = Address::invalid(); + { + llvm::SaveAndRestore SavedCapture(CurLoadedLValueCapture, + CountedByME ? &FieldCapture : nullptr); + // The base must be a pointer; emit it with an estimate of its alignment. + BaseAddr = + EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo); + } + + Address CountedByFieldAddr = + FieldCapture.LV ? FieldCapture.LV->getAddress() : Address::invalid(); + auto *Idx = EmitIdxAfterBase(/*Promote*/true); QualType ptrType = E->getBase()->getType(); Addr = emitArraySubscriptGEP(*this, BaseAddr, Idx, E->getType(), @@ -5343,16 +5378,16 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, SignedIndices, E->getExprLoc(), &ptrType, E->getBase()); - if (SanOpts.has(SanitizerKind::ArrayBounds)) { - StructFieldAccess Visitor; - const Expr *Base = Visitor.Visit(E->getBase()); - - if (const auto *CE = dyn_cast_if_present<CastExpr>(Base); - CE && CE->getCastKind() == CK_LValueToRValue) - EmitCountedByBoundsChecking(CE, ptrType, Address::invalid(), - E->getIdx()->getType(), Idx, Accessed, - /*FlexibleArray=*/false); - } + // If the field wasn't loaded through ScalarExprEmitter (e.g. it was + // constant folded), EmitCountedByBoundsChecking re-emits the field's + // l-value. That only recomputes the field's address, so it's safe unless + // the struct base has side-effects. In that case skip the check rather + // than evaluating the base twice. + if (CountedByME && (CountedByFieldAddr.isValid() || + !CountedByME->getBase()->HasSideEffects(getContext()))) + EmitCountedByBoundsChecking(CountedByLoad, ptrType, CountedByFieldAddr, + E->getIdx()->getType(), Idx, Accessed, + /*FlexibleArray=*/false); } LValue LV = MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index f1394fc524645..0e2e29f0745d2 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -371,8 +371,11 @@ class ScalarExprEmitter /// value l-value, this method emits the address of the l-value, then loads /// and returns the result. Value *EmitLoadOfLValue(const Expr *E) { - Value *V = EmitLoadOfLValue(EmitCheckedLValue(E, CodeGenFunction::TCK_Load), - E->getExprLoc()); + LValue LV = EmitCheckedLValue(E, CodeGenFunction::TCK_Load); + if (CGF.CurLoadedLValueCapture && CGF.CurLoadedLValueCapture->E == E) + CGF.CurLoadedLValueCapture->LV = LV; + + Value *V = EmitLoadOfLValue(LV, E->getExprLoc()); EmitLValueAlignmentAssumption(E, V); return V; diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 733d9ab310aff..421bf33088dd7 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -651,6 +651,22 @@ class CodeGenFunction : public CodeGenTypeCache { // applies to. nullptr if there is no 'musttail' on the current statement. const CallExpr *MustTailCall = nullptr; + /// Records the l-value that ScalarExprEmitter loads from when it emits a + /// specific expression. EmitArraySubscriptExpr sets this while emitting the + /// base of a 'counted_by' pointer subscript, so that the bounds check can + /// locate the count from the pointer field's address without re-emitting + /// (and so re-evaluating) the base. Capturing the l-value, instead of + /// emitting the load separately, keeps everything else the scalar load path + /// does (debug locations, 'align_value' assumptions, pseudo variables for + /// -fdebug-info-for-profiling, etc.). + struct LoadedLValueCapture { + /// The expression whose l-value is recorded. + const Expr *E; + /// The recorded l-value, set if \c E was loaded by ScalarExprEmitter. + std::optional<LValue> LV; + }; + LoadedLValueCapture *CurLoadedLValueCapture = nullptr; + /// Returns true if a function must make progress, which means the /// mustprogress attribute can be added. bool checkIfFunctionMustProgress() { diff --git a/clang/test/CodeGen/attr-counted-by-align-value.c b/clang/test/CodeGen/attr-counted-by-align-value.c new file mode 100644 index 0000000000000..056cbfbb7135f --- /dev/null +++ b/clang/test/CodeGen/attr-counted-by-align-value.c @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -disable-llvm-passes -o - %s | FileCheck --check-prefixes=CHECK,NOSAN %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=array-bounds -emit-llvm -disable-llvm-passes -o - %s | FileCheck --check-prefixes=CHECK,BOUNDS %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=array-bounds,alignment -emit-llvm -disable-llvm-passes -o - %s | FileCheck --check-prefixes=CHECK,BOUNDS,ALIGN %s + +// With -fsanitize=array-bounds, a subscript of a 'counted_by' pointer field +// loads the pointer itself rather than going through the scalar emitter, so +// that it can reuse the field's address for the bounds check. Make sure the +// 'align_value' assumption on the field's type (and its +// -fsanitize=alignment check) is still emitted on that path. + +typedef int *__attribute__((align_value(64))) aligned_int_ptr; + +struct s { + int n; + aligned_int_ptr buf __attribute__((counted_by(n))); +}; + +// CHECK-LABEL: define {{.*}} @f( +// CHECK: [[FIELD:%.*]] = getelementptr inbounds nuw %struct.s, ptr {{%.*}}, i32 0, i32 1 +// CHECK: [[BUF:%.*]] = load ptr, ptr [[FIELD]] +// ALIGN: call void @__ubsan_handle_alignment_assumption +// CHECK: call void @llvm.assume(i1 true) [ "align"(ptr [[BUF]], i64 64) ] +// CHECK: getelementptr inbounds i32, ptr [[BUF]] +// BOUNDS: getelementptr inbounds i8, ptr [[FIELD]], i32 -8 +// BOUNDS: call void @__ubsan_handle_out_of_bounds +// NOSAN-NOT: __ubsan_handle +int f(struct s *p, int i) { return p->buf[i]; } diff --git a/clang/test/CodeGen/attr-counted-by-base-exprs.c b/clang/test/CodeGen/attr-counted-by-base-exprs.c index 403b9de7a0b3a..27913b6fb1051 100644 --- a/clang/test/CodeGen/attr-counted-by-base-exprs.c +++ b/clang/test/CodeGen/attr-counted-by-base-exprs.c @@ -20,6 +20,11 @@ struct s { int array[] __attribute__((counted_by(count))); }; +struct p { + int count; + int *buf __attribute__((counted_by(count))); +}; + struct wrap { long tag; struct s *s; @@ -33,6 +38,7 @@ struct e { }; struct s *get_s(void); +struct p *get_p(void); // A call has side-effects, so __bdos can't use it to load the count. // CHECK-LABEL: define dso_local noundef i64 @test_bdos_call_base( @@ -48,14 +54,14 @@ unsigned long test_bdos_call_base(void) { // CHECK-LABEL: define dso_local i32 @test_index_call_base( // CHECK-SAME: i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[CALL:%.*]] = tail call ptr @get_s() #[[ATTR8:[0-9]+]] +// CHECK-NEXT: [[CALL:%.*]] = tail call ptr @get_s() #[[ATTR9:[0-9]+]] // CHECK-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[CALL]], align 4 // CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[I]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6:![0-9]+]] // CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]] // CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]] // CHECK-NEXT: br i1 [[TMP2]], label %[[CONT:.*]], label %[[TRAP:.*]], !prof [[PROF7:![0-9]+]], !nosanitize [[META6]] // CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR9:[0-9]+]], !nosanitize [[META6]] +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR10:[0-9]+]], !nosanitize [[META6]] // CHECK-NEXT: unreachable, !nosanitize [[META6]] // CHECK: [[CONT]]: // CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 4 @@ -68,6 +74,113 @@ int test_index_call_base(int i) { return get_s()->array[i]; } +// +// For a 'counted_by' pointer, the bounds check must not re-evaluate the base +// to find the count: 'get_p' must be called only once, and 'pp' incremented +// only once. +// CHECK-LABEL: define dso_local i32 @test_index_call_base_ptr( +// CHECK-SAME: i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR1]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[CALL:%.*]] = tail call ptr @get_p() #[[ATTR9]] +// CHECK-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[CALL]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[I]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]] +// CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]] +// CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]] +// CHECK-NEXT: br i1 [[TMP2]], label %[[CONT:.*]], label %[[TRAP:.*]], !prof [[PROF7]], !nosanitize [[META6]] +// CHECK: [[TRAP]]: +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR10]], !nosanitize [[META6]] +// CHECK-NEXT: unreachable, !nosanitize [[META6]] +// CHECK: [[CONT]]: +// CHECK-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 8 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[INTPTR_TBAA9:![0-9]+]] +// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i8], ptr [[TMP3]], i64 [[IDXPROM]] +// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[INT_TBAA8]] +// CHECK-NEXT: ret i32 [[TMP4]] +// +int test_index_call_base_ptr(int i) { + return get_p()->buf[i]; +} + +// CHECK-LABEL: define dso_local i32 @test_index_side_effect_base_ptr( +// CHECK-SAME: ptr nofree noundef readonly captures(none) [[PP:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PP]], align 8, !tbaa [[_ZTS1PPTR_TBAA13:![0-9]+]] +// CHECK-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[TMP0]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[I]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]] +// CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]] +// CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]], !nosanitize [[META6]] +// CHECK-NEXT: br i1 [[TMP3]], label %[[CONT:.*]], label %[[TRAP:.*]], !prof [[PROF7]], !nosanitize [[META6]] +// CHECK: [[TRAP]]: +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR10]], !nosanitize [[META6]] +// CHECK-NEXT: unreachable, !nosanitize [[META6]] +// CHECK: [[CONT]]: +// CHECK-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 8 +// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[INTPTR_TBAA9]] +// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i8], ptr [[TMP4]], i64 [[IDXPROM]] +// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[INT_TBAA8]] +// CHECK-NEXT: ret i32 [[TMP5]] +// +int test_index_side_effect_base_ptr(struct p **pp, int i) { + return (*pp++)->buf[i]; +} + +struct p *global_p; + +// CHECK-LABEL: define dso_local i32 @test_index_post_inc_base_ptr( +// CHECK-SAME: i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @global_p, align 8, !tbaa [[_ZTS1PPTR_TBAA13]] +// CHECK-NEXT: [[INCDEC_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16 +// CHECK-NEXT: store ptr [[INCDEC_PTR]], ptr @global_p, align 8, !tbaa [[_ZTS1PPTR_TBAA13]] +// CHECK-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[TMP0]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[I]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]] +// CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]] +// CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]], !nosanitize [[META6]] +// CHECK-NEXT: br i1 [[TMP3]], label %[[CONT:.*]], label %[[TRAP:.*]], !prof [[PROF7]], !nosanitize [[META6]] +// CHECK: [[TRAP]]: +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR10]], !nosanitize [[META6]] +// CHECK-NEXT: unreachable, !nosanitize [[META6]] +// CHECK: [[CONT]]: +// CHECK-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 8 +// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[INTPTR_TBAA9]] +// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [4 x i8], ptr [[TMP4]], i64 [[IDXPROM]] +// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[INT_TBAA8]] +// CHECK-NEXT: ret i32 [[TMP5]] +// +int test_index_post_inc_base_ptr(int i) { + return global_p++->buf[i]; +} + +// A cast in between doesn't stop the check from reusing the base: it's still +// checked, and 'get_p()' is still only called once. +// CHECK-LABEL: define dso_local range(i32 -128, 128) i32 @test_index_side_effect_base_ptr_through_cast( +// CHECK-SAME: i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR1]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[CALL:%.*]] = tail call ptr @get_p() #[[ATTR9]] +// CHECK-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[CALL]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[I]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]] +// CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]] +// CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]] +// CHECK-NEXT: br i1 [[TMP2]], label %[[CONT:.*]], label %[[TRAP:.*]], !prof [[PROF7]], !nosanitize [[META6]] +// CHECK: [[TRAP]]: +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR10]], !nosanitize [[META6]] +// CHECK-NEXT: unreachable, !nosanitize [[META6]] +// CHECK: [[CONT]]: +// CHECK-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 8 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[INTPTR_TBAA9]] +// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64 +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[TMP3]], i64 [[IDXPROM]] +// CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[CHAR_TBAA15:![0-9]+]] +// CHECK-NEXT: [[CONV:%.*]] = sext i8 [[TMP4]] to i32 +// CHECK-NEXT: ret i32 [[CONV]] +// +int test_index_side_effect_base_ptr_through_cast(int i) { + return ((char *)get_p()->buf)[i]; +} + // CHECK-LABEL: define dso_local noundef i64 @test_bdos_side_effect_base( // CHECK-SAME: ptr nofree noundef readnone captures(none) [[PP:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] @@ -78,16 +191,16 @@ unsigned long test_bdos_side_effect_base(struct s **pp) { } // CHECK-LABEL: define dso_local i32 @test_index_side_effect_base( -// CHECK-SAME: ptr nofree noundef readonly captures(none) [[PP:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] { +// CHECK-SAME: ptr nofree noundef readonly captures(none) [[PP:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR4]] { // CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PP]], align 8, !tbaa [[_ZTS1SPTR_TBAA9:![0-9]+]] +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PP]], align 8, !tbaa [[_ZTS1SPTR_TBAA16:![0-9]+]] // CHECK-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[TMP0]], align 4 // CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[I]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]] // CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]] // CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]], !nosanitize [[META6]] // CHECK-NEXT: br i1 [[TMP3]], label %[[CONT:.*]], label %[[TRAP:.*]], !prof [[PROF7]], !nosanitize [[META6]] // CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR9]], !nosanitize [[META6]] +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR10]], !nosanitize [[META6]] // CHECK-NEXT: unreachable, !nosanitize [[META6]] // CHECK: [[CONT]]: // CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 4 @@ -101,11 +214,11 @@ int test_index_side_effect_base(struct s **pp, int i) { } // CHECK-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test_bdos_array_of_ptrs( -// CHECK-SAME: ptr nofree noundef readonly captures(none) [[PP:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] { +// CHECK-SAME: ptr nofree noundef readonly captures(none) [[PP:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR6:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64 // CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [8 x i8], ptr [[PP]], i64 [[IDXPROM]] -// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[_ZTS1SPTR_TBAA9]] +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[_ZTS1SPTR_TBAA16]] // CHECK-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[TMP0]], align 4 // CHECK-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64 // CHECK-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2 @@ -118,10 +231,10 @@ unsigned long test_bdos_array_of_ptrs(struct s **pp, int i) { } // CHECK-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test_bdos_through_ptr_member( -// CHECK-SAME: ptr nofree noundef readonly captures(none) [[W:%.*]]) local_unnamed_addr #[[ATTR5]] { +// CHECK-SAME: ptr nofree noundef readonly captures(none) [[W:%.*]]) local_unnamed_addr #[[ATTR6]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[S:%.*]] = getelementptr inbounds nuw i8, ptr [[W]], i64 8 -// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S]], align 8, !tbaa [[_ZTS1SPTR_TBAA12:![0-9]+]] +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S]], align 8, !tbaa [[_ZTS1SPTR_TBAA18:![0-9]+]] // CHECK-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[TMP0]], align 4 // CHECK-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64 // CHECK-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2 @@ -137,14 +250,14 @@ unsigned long test_bdos_through_ptr_member(struct wrap *w) { // CHECK-SAME: ptr nofree noundef readonly captures(none) [[W:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR4]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[S:%.*]] = getelementptr inbounds nuw i8, ptr [[W]], i64 8 -// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S]], align 8, !tbaa [[_ZTS1SPTR_TBAA12]] +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S]], align 8, !tbaa [[_ZTS1SPTR_TBAA18]] // CHECK-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[TMP0]], align 4 // CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[I]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]] // CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]] // CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]], !nosanitize [[META6]] // CHECK-NEXT: br i1 [[TMP3]], label %[[CONT:.*]], label %[[TRAP:.*]], !prof [[PROF7]], !nosanitize [[META6]] // CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR9]], !nosanitize [[META6]] +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR10]], !nosanitize [[META6]] // CHECK-NEXT: unreachable, !nosanitize [[META6]] // CHECK: [[CONT]]: // CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 4 @@ -158,7 +271,7 @@ int test_index_through_ptr_member(struct wrap *w, int i) { } // CHECK-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test_bdos_explicit_deref( -// CHECK-SAME: ptr nofree noundef readonly captures(none) [[A:%.*]]) local_unnamed_addr #[[ATTR6:[0-9]+]] { +// CHECK-SAME: ptr nofree noundef readonly captures(none) [[A:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[A]], align 4 // CHECK-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64 @@ -191,7 +304,7 @@ unsigned long test_bdos_conditional_base(struct s *a, struct s *b, int c) { // CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]] // CHECK-NEXT: br i1 [[TMP2]], label %[[CONT:.*]], label %[[TRAP:.*]], !prof [[PROF7]], !nosanitize [[META6]] // CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR9]], !nosanitize [[META6]] +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR10]], !nosanitize [[META6]] // CHECK-NEXT: unreachable, !nosanitize [[META6]] // CHECK: [[CONT]]: // CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[COND]], i64 4 @@ -214,7 +327,7 @@ unsigned long test_bdos_negative_const_index(struct s *a) { } // CHECK-LABEL: define dso_local range(i64 0, 17179869181) i64 @test_bdos_enum_count( -// CHECK-SAME: ptr nofree noundef readonly captures(none) [[A:%.*]]) local_unnamed_addr #[[ATTR6]] { +// CHECK-SAME: ptr nofree noundef readonly captures(none) [[A:%.*]]) local_unnamed_addr #[[ATTR7]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[A]], align 4 // CHECK-NEXT: [[COUNT:%.*]] = zext i32 [[COUNTED_BY_LOAD]] to i64 @@ -226,13 +339,13 @@ unsigned long test_bdos_enum_count(struct e *a) { } // CHECK-LABEL: define dso_local i32 @test_index_enum_count( -// CHECK-SAME: ptr nofree noundef readonly captures(none) [[A:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] { +// CHECK-SAME: ptr nofree noundef readonly captures(none) [[A:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR8:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[A]], align 4 // CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[I]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]] // CHECK-NEXT: br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !prof [[PROF7]], !nosanitize [[META6]] // CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR9]], !nosanitize [[META6]] +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR10]], !nosanitize [[META6]] // CHECK-NEXT: unreachable, !nosanitize [[META6]] // CHECK: [[CONT]]: // CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 4 @@ -247,7 +360,7 @@ int test_index_enum_count(struct e *a, int i) { // Index types narrower and wider than the count. // CHECK-LABEL: define dso_local i32 @test_index_char( -// CHECK-SAME: ptr nofree noundef readonly captures(none) [[A:%.*]], i8 noundef signext [[I:%.*]]) local_unnamed_addr #[[ATTR7]] { +// CHECK-SAME: ptr nofree noundef readonly captures(none) [[A:%.*]], i8 noundef signext [[I:%.*]]) local_unnamed_addr #[[ATTR8]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[A]], align 4 // CHECK-NEXT: [[TMP0:%.*]] = sext i8 [[I]] to i32 @@ -256,7 +369,7 @@ int test_index_enum_count(struct e *a, int i) { // CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]], !nosanitize [[META6]] // CHECK-NEXT: br i1 [[TMP3]], label %[[CONT:.*]], label %[[TRAP:.*]], !prof [[PROF7]], !nosanitize [[META6]] // CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR9]], !nosanitize [[META6]] +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR10]], !nosanitize [[META6]] // CHECK-NEXT: unreachable, !nosanitize [[META6]] // CHECK: [[CONT]]: // CHECK-NEXT: [[IDXPROM:%.*]] = sext i8 [[I]] to i64 @@ -270,7 +383,7 @@ int test_index_char(struct s *a, signed char i) { } // CHECK-LABEL: define dso_local i32 @test_index_unsigned_long( -// CHECK-SAME: ptr nofree noundef readonly captures(none) [[A:%.*]], i64 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR7]] { +// CHECK-SAME: ptr nofree noundef readonly captures(none) [[A:%.*]], i64 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR8]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[A]], align 4 // CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META6]] @@ -279,7 +392,7 @@ int test_index_char(struct s *a, signed char i) { // CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]], !nosanitize [[META6]] // CHECK-NEXT: br i1 [[TMP3]], label %[[CONT:.*]], label %[[TRAP:.*]], !prof [[PROF7]], !nosanitize [[META6]] // CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR9]], !nosanitize [[META6]] +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 18) #[[ATTR10]], !nosanitize [[META6]] // CHECK-NEXT: unreachable, !nosanitize [[META6]] // CHECK: [[CONT]]: // CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 4 @@ -297,10 +410,16 @@ int test_index_unsigned_long(struct s *a, unsigned long i) { // CHECK: [[META6]] = !{} // CHECK: [[PROF7]] = !{!"branch_weights", i32 1048575, i32 1} // CHECK: [[INT_TBAA8]] = !{[[META3]], [[META3]], i64 0} -// CHECK: [[_ZTS1SPTR_TBAA9]] = !{[[META10:![0-9]+]], [[META10]], i64 0} -// CHECK: [[META10]] = !{!"p1 _ZTS1s", [[META11:![0-9]+]], i64 0} -// CHECK: [[META11]] = !{!"any pointer", [[META4]], i64 0} -// CHECK: [[_ZTS1SPTR_TBAA12]] = !{[[META13:![0-9]+]], [[META10]], i64 8} -// CHECK: [[META13]] = !{!"wrap", [[META14:![0-9]+]], i64 0, [[META10]], i64 8} -// CHECK: [[META14]] = !{!"long", [[META4]], i64 0} +// CHECK: [[INTPTR_TBAA9]] = !{[[META10:![0-9]+]], [[META11:![0-9]+]], i64 8} +// CHECK: [[META10]] = !{!"p", [[META3]], i64 0, [[META11]], i64 8} +// CHECK: [[META11]] = !{!"p1 int", [[META12:![0-9]+]], i64 0} +// CHECK: [[META12]] = !{!"any pointer", [[META4]], i64 0} +// CHECK: [[_ZTS1PPTR_TBAA13]] = !{[[META14:![0-9]+]], [[META14]], i64 0} +// CHECK: [[META14]] = !{!"p1 _ZTS1p", [[META12]], i64 0} +// CHECK: [[CHAR_TBAA15]] = !{[[META4]], [[META4]], i64 0} +// CHECK: [[_ZTS1SPTR_TBAA16]] = !{[[META17:![0-9]+]], [[META17]], i64 0} +// CHECK: [[META17]] = !{!"p1 _ZTS1s", [[META12]], i64 0} +// CHECK: [[_ZTS1SPTR_TBAA18]] = !{[[META19:![0-9]+]], [[META17]], i64 8} +// CHECK: [[META19]] = !{!"wrap", [[META20:![0-9]+]], i64 0, [[META17]], i64 8} +// CHECK: [[META20]] = !{!"long", [[META4]], i64 0} //. diff --git a/clang/test/CodeGen/attr-counted-by-debug-info.c b/clang/test/CodeGen/attr-counted-by-debug-info.c new file mode 100644 index 0000000000000..205af3d68f3c5 --- /dev/null +++ b/clang/test/CodeGen/attr-counted-by-debug-info.c @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -disable-llvm-passes -debug-info-kind=limited -fdebug-info-for-profiling -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -disable-llvm-passes -debug-info-kind=limited -fdebug-info-for-profiling -fsanitize=array-bounds -o - %s | FileCheck %s + +// With -fsanitize=array-bounds, the bounds check for a subscript of a +// 'counted_by' pointer field reuses the field's address from the load of the +// base. Make sure that the load itself is emitted the same way with and +// without the sanitizer: it keeps the member's debug location, and the +// -fdebug-info-for-profiling pseudo variable for the struct base pointer. +// Both RUN lines share the same CHECK lines. + +struct s { + int n; + int *buf __attribute__((counted_by(n))); +}; + +struct o { + struct s *in; +}; + +struct s *get(void); + +// CHECK-LABEL: define {{.*}} @nested( +// CHECK: [[IN_FIELD:%.*]] = getelementptr inbounds nuw %struct.o, ptr {{%.*}}, i32 0, i32 0 +// CHECK-NEXT: [[IN:%.*]] = load ptr, ptr [[IN_FIELD]], align 8, !dbg [[NESTED_IN_LOC:![0-9]+]] +// CHECK-NEXT: #dbg_value(ptr [[IN]], [[NESTED_PSEUDO:![0-9]+]], !DIExpression(), [[NESTED_IN_LOC]]) +// CHECK-NEXT: [[FIELD:%.*]] = getelementptr inbounds nuw %struct.s, ptr [[IN]], i32 0, i32 1, !dbg [[NESTED_LOC:![0-9]+]] +// CHECK-NEXT: load ptr, ptr [[FIELD]], align 8, !dbg [[NESTED_LOC]] +int nested(struct o *q, int i) { + return q->in->buf[i]; +} + +// CHECK-LABEL: define {{.*}} @call( +// CHECK: [[CALL:%.*]] = call ptr @get(), !dbg [[CALL_GET_LOC:![0-9]+]] +// CHECK-NEXT: #dbg_value(ptr [[CALL]], [[CALL_PSEUDO:![0-9]+]], !DIExpression(), [[CALL_GET_LOC]]) +// CHECK-NEXT: [[FIELD:%.*]] = getelementptr inbounds nuw %struct.s, ptr [[CALL]], i32 0, i32 1, !dbg [[CALL_LOC:![0-9]+]] +// CHECK-NEXT: load ptr, ptr [[FIELD]], align 8, !dbg [[CALL_LOC]] +int call(int i) { + return get()->buf[i]; +} + +// CHECK-LABEL: define {{.*}} @compound( +// CHECK: [[IN_FIELD:%.*]] = getelementptr inbounds nuw %struct.o, ptr {{%.*}}, i32 0, i32 0 +// CHECK-NEXT: [[IN:%.*]] = load ptr, ptr [[IN_FIELD]], align 8, !dbg [[COMPOUND_IN_LOC:![0-9]+]] +// CHECK-NEXT: #dbg_value(ptr [[IN]], [[COMPOUND_PSEUDO:![0-9]+]], !DIExpression(), [[COMPOUND_IN_LOC]]) +// CHECK-NEXT: [[FIELD:%.*]] = getelementptr inbounds nuw %struct.s, ptr [[IN]], i32 0, i32 1, !dbg [[COMPOUND_LOC:![0-9]+]] +// CHECK-NEXT: load ptr, ptr [[FIELD]], align 8, !dbg [[COMPOUND_LOC]] +void compound(struct o *q, int i, int v) { + q->in->buf[i] += v; +} + +// The field load is located at the 'buf' member token in each function. +// CHECK-DAG: [[NESTED_PSEUDO]] = !DILocalVariable(scope: {{.*}}, flags: DIFlagArtificial) +// CHECK-DAG: [[NESTED_LOC]] = !DILocation(line: 29, column: 17, +// CHECK-DAG: [[CALL_PSEUDO]] = !DILocalVariable(scope: {{.*}}, flags: DIFlagArtificial) +// CHECK-DAG: [[CALL_LOC]] = !DILocation(line: 38, column: 17, +// CHECK-DAG: [[COMPOUND_PSEUDO]] = !DILocalVariable(scope: {{.*}}, flags: DIFlagArtificial) +// CHECK-DAG: [[COMPOUND_LOC]] = !DILocation(line: 48, column: 10, diff --git a/clang/test/CodeGen/attr-counted-by-for-pointers.c b/clang/test/CodeGen/attr-counted-by-for-pointers.c index ef0f3ac23a67f..5aa7dfbc6b76a 100644 --- a/clang/test/CodeGen/attr-counted-by-for-pointers.c +++ b/clang/test/CodeGen/attr-counted-by-for-pointers.c @@ -33,12 +33,12 @@ struct annotated_ptr { // SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ult i32 [[INDEX]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6:![0-9]+]] // SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7:![0-9]+]], !nosanitize [[META6]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT5:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7:![0-9]+]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 [[TMP3]]) #[[ATTR4:[0-9]+]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]] -// SANITIZE-WITH-ATTR: [[CONT10]]: +// SANITIZE-WITH-ATTR: [[CONT5]]: // SANITIZE-WITH-ATTR-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8 // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA8:![0-9]+]] // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 @@ -143,12 +143,12 @@ void test_store_subscript_through_cast(struct annotated_ptr *p, int index, struc // SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ule i32 [[INDEX]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT5:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 [[TMP3]]) #[[ATTR4]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]] -// SANITIZE-WITH-ATTR: [[CONT10]]: +// SANITIZE-WITH-ATTR: [[CONT5]]: // SANITIZE-WITH-ATTR-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8 // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA8]] // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 @@ -270,12 +270,12 @@ size_t test_bdos_of_pointer_through_cast(struct annotated_ptr *p, int index) { // SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ule i32 [[INDEX]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT8:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT3:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[TMP3]]) #[[ATTR4]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]] -// SANITIZE-WITH-ATTR: [[CONT8]]: +// SANITIZE-WITH-ATTR: [[CONT3]]: // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = zext nneg i32 [[DOTCOUNTED_BY_LOAD]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = sub nuw nsw i64 [[COUNT]], [[IDXPROM]] diff --git a/clang/test/CodeGen/attr-counted-by-or-null-for-pointers.c b/clang/test/CodeGen/attr-counted-by-or-null-for-pointers.c index f7de00e62d4b2..185937acfec28 100644 --- a/clang/test/CodeGen/attr-counted-by-or-null-for-pointers.c +++ b/clang/test/CodeGen/attr-counted-by-or-null-for-pointers.c @@ -43,12 +43,12 @@ struct annotated_ptr { // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp ult i32 [[INDEX]], [[TMP2]], !nosanitize [[META12:![0-9]+]] // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[TMP2]], 0, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = and i1 [[TMP4]], [[TMP3]], !nosanitize [[META12]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP5]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13:![0-9]+]], !nosanitize [[META12]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP5]], label %[[CONT5:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13:![0-9]+]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 [[TMP6]]) #[[ATTR5:[0-9]+]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META12]] -// SANITIZE-WITH-ATTR: [[CONT10]]: +// SANITIZE-WITH-ATTR: [[CONT5]]: // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [8 x i8], ptr [[TMP0]], i64 [[IDXPROM]] // SANITIZE-WITH-ATTR-NEXT: store ptr [[VALUE]], ptr [[ARRAYIDX]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA14:![0-9]+]] @@ -157,12 +157,12 @@ void test_store_subscript_through_cast(struct annotated_ptr *p, int index, struc // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp ule i32 [[INDEX]], [[TMP2]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[TMP2]], 0, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = and i1 [[TMP4]], [[TMP3]], !nosanitize [[META12]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP5]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP5]], label %[[CONT5:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 [[TMP6]]) #[[ATTR5]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META12]] -// SANITIZE-WITH-ATTR: [[CONT10]]: +// SANITIZE-WITH-ATTR: [[CONT5]]: // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [8 x i8], ptr [[TMP0]], i64 [[IDXPROM]] // SANITIZE-WITH-ATTR-NEXT: store ptr [[VALUE]], ptr [[ARRAYIDX]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA14]] @@ -298,12 +298,12 @@ size_t test_bdos_of_pointer_through_cast(struct annotated_ptr *p, int index) { // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp ule i32 [[INDEX]], [[TMP2]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[TMP2]], 0, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = and i1 [[TMP4]], [[TMP3]], !nosanitize [[META12]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP5]], label %[[CONT8:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP5]], label %[[CONT3:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[TMP6]]) #[[ATTR5]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META12]] -// SANITIZE-WITH-ATTR: [[CONT8]]: +// SANITIZE-WITH-ATTR: [[CONT3]]: // SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[DOTCOUNTED_BY_LOAD]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = shl nsw i64 [[COUNT]], 3 diff --git a/clang/test/CodeGen/attr-counted-by-ptrauth.c b/clang/test/CodeGen/attr-counted-by-ptrauth.c new file mode 100644 index 0000000000000..5d4eaddf67dbf --- /dev/null +++ b/clang/test/CodeGen/attr-counted-by-ptrauth.c @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-intrinsics -fsanitize=array-bounds -fsanitize-trap=array-bounds -emit-llvm -o - %s | FileCheck %s + +// A '__ptrauth'-qualified 'counted_by' pointer must still be authenticated +// before it's indexed when -fsanitize=array-bounds shares the field's l-value +// with the bounds check. + +struct pa { + int count; + int *__ptrauth(1, 1, 42) buf __attribute__((counted_by(count))); +}; + +// CHECK-LABEL: define {{.*}} @test_index( +// CHECK: [[BUF:%.*]] = getelementptr inbounds nuw %struct.pa, ptr {{%.*}}, i32 0, i32 1 +// CHECK: [[SIGNED:%.*]] = load ptr, ptr [[BUF]] +// CHECK: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 42) +// CHECK: [[INT:%.*]] = ptrtoint ptr [[SIGNED]] to i64 +// CHECK: [[AUTH:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[INT]], i32 1, i64 [[DISC]]) +// CHECK: [[PTR:%.*]] = inttoptr i64 [[AUTH]] to ptr +// CHECK: [[PHI:%.*]] = phi ptr [ null, {{.*}} ], [ [[PTR]], {{.*}} ] +// CHECK: getelementptr inbounds i32, ptr [[PHI]], i64 +// CHECK: call void @llvm.ubsantrap( +int test_index(struct pa *p, int i) { + return p->buf[i]; +} diff --git a/clang/test/CodeGen/attr-sized-by-for-pointers.c b/clang/test/CodeGen/attr-sized-by-for-pointers.c index dabe3163571a5..b7eb0d1f244e0 100644 --- a/clang/test/CodeGen/attr-sized-by-for-pointers.c +++ b/clang/test/CodeGen/attr-sized-by-for-pointers.c @@ -34,12 +34,12 @@ struct annotated_ptr { // SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i32 [[INDEX]], [[TMP0]], !nosanitize [[META6:![0-9]+]] // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 7 // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]], !nosanitize [[META6]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP3]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7:![0-9]+]], !nosanitize [[META6]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP3]], label %[[CONT5:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7:![0-9]+]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 [[TMP4]]) #[[ATTR6:[0-9]+]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]] -// SANITIZE-WITH-ATTR: [[CONT10]]: +// SANITIZE-WITH-ATTR: [[CONT5]]: // SANITIZE-WITH-ATTR-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8 // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA8:![0-9]+]] // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 @@ -146,12 +146,12 @@ void test_store_subscript_through_cast(struct annotated_ptr *p, int index, struc // SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ule i32 [[INDEX]], [[TMP0]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 7 // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]], !nosanitize [[META6]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP3]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP3]], label %[[CONT5:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 [[TMP4]]) #[[ATTR6]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]] -// SANITIZE-WITH-ATTR: [[CONT10]]: +// SANITIZE-WITH-ATTR: [[CONT5]]: // SANITIZE-WITH-ATTR-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8 // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA8]] // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 @@ -217,12 +217,12 @@ struct annotated_sized_ptr_odd_pointee { // SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 8 // SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = udiv i32 [[DOTCOUNTED_BY_LOAD]], 3 // SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i32 [[INDEX]], [[TMP0]], !nosanitize [[META6]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label %[[CONT15:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB7:[0-9]+]], i64 [[TMP2]]) #[[ATTR6]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]] -// SANITIZE-WITH-ATTR: [[CONT15]]: +// SANITIZE-WITH-ATTR: [[CONT10]]: // SANITIZE-WITH-ATTR-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8 // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[_ZTS18THREE_BYTE_POINTEEPTR_TBAA16:![0-9]+]] // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 @@ -281,12 +281,12 @@ struct annotated_sized_ptr_pow2_unsigned_count { // SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 8 // SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = lshr i32 [[DOTCOUNTED_BY_LOAD]], 3 // SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i32 [[INDEX]], [[TMP0]], !nosanitize [[META6]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label %[[CONT5:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB9:[0-9]+]], i64 [[TMP2]]) #[[ATTR6]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]] -// SANITIZE-WITH-ATTR: [[CONT10]]: +// SANITIZE-WITH-ATTR: [[CONT5]]: // SANITIZE-WITH-ATTR-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8 // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA20:![0-9]+]] // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 @@ -472,12 +472,12 @@ size_t test_bdos_of_pointer(struct annotated_sized_ptr *p) { // SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ule i32 [[INDEX]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT8:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT3:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB15:[0-9]+]], i64 [[TMP3]]) #[[ATTR6]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]] -// SANITIZE-WITH-ATTR: [[CONT8]]: +// SANITIZE-WITH-ATTR: [[CONT3]]: // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = zext nneg i32 [[DOTCOUNTED_BY_LOAD]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[RESULT:%.*]] = sub nuw nsw i64 [[COUNT]], [[IDXPROM]] @@ -598,12 +598,12 @@ size_t test_bdos_of_pointer_multibyte_pointee(struct annotated_sized_ptr_non_byt // SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ule i32 [[INDEX]], [[TMP0]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 7 // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]], !nosanitize [[META6]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP3]], label %[[CONT8:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP3]], label %[[CONT3:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB18:[0-9]+]], i64 [[TMP4]]) #[[ATTR6]], !nosanitize [[META6]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]] -// SANITIZE-WITH-ATTR: [[CONT8]]: +// SANITIZE-WITH-ATTR: [[CONT3]]: // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = zext nneg i32 [[DOTCOUNTED_BY_LOAD]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[INDEX_SIZE:%.*]] = shl nsw i64 [[IDXPROM]], 3 diff --git a/clang/test/CodeGen/attr-sized-by-or-null-for-pointers.c b/clang/test/CodeGen/attr-sized-by-or-null-for-pointers.c index 05f3c57d86149..06452acfc03fb 100644 --- a/clang/test/CodeGen/attr-sized-by-or-null-for-pointers.c +++ b/clang/test/CodeGen/attr-sized-by-or-null-for-pointers.c @@ -44,12 +44,12 @@ struct annotated_ptr { // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp ult i32 [[INDEX]], [[TMP3]], !nosanitize [[META12:![0-9]+]] // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = icmp sgt i32 [[TMP3]], 0, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = and i1 [[TMP5]], [[TMP4]], !nosanitize [[META12]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP6]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13:![0-9]+]], !nosanitize [[META12]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP6]], label %[[CONT5:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13:![0-9]+]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 [[TMP7]]) #[[ATTR6:[0-9]+]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META12]] -// SANITIZE-WITH-ATTR: [[CONT10]]: +// SANITIZE-WITH-ATTR: [[CONT5]]: // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [8 x i8], ptr [[TMP0]], i64 [[IDXPROM]] // SANITIZE-WITH-ATTR-NEXT: store ptr [[VALUE]], ptr [[ARRAYIDX]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA14:![0-9]+]] @@ -160,12 +160,12 @@ void test_store_subscript_through_cast(struct annotated_ptr *p, int index, struc // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp ule i32 [[INDEX]], [[TMP3]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = icmp sgt i32 [[TMP3]], 0, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = and i1 [[TMP5]], [[TMP4]], !nosanitize [[META12]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP6]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP6]], label %[[CONT5:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 [[TMP7]]) #[[ATTR6]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META12]] -// SANITIZE-WITH-ATTR: [[CONT10]]: +// SANITIZE-WITH-ATTR: [[CONT5]]: // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [8 x i8], ptr [[TMP0]], i64 [[IDXPROM]] // SANITIZE-WITH-ATTR-NEXT: store ptr [[VALUE]], ptr [[ARRAYIDX]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA14]] @@ -233,12 +233,12 @@ struct annotated_sized_ptr_odd_pointee { // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = udiv i32 [[DOTCOUNTED_BY_LOAD]], 3 // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp ugt i32 [[TMP2]], [[INDEX]] // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], i1 [[TMP3]], i1 false -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP4]], label %[[CONT15:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP4]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB7:[0-9]+]], i64 [[TMP5]]) #[[ATTR6]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META12]] -// SANITIZE-WITH-ATTR: [[CONT15]]: +// SANITIZE-WITH-ATTR: [[CONT10]]: // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x i8], ptr [[TMP0]], i64 [[IDXPROM]] // SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[CHAR_TBAA19:![0-9]+]] @@ -299,12 +299,12 @@ struct annotated_sized_ptr_pow2_unsigned_count { // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = lshr i32 [[DOTCOUNTED_BY_LOAD]], 3 // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp ugt i32 [[TMP2]], [[INDEX]] // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], i1 [[TMP3]], i1 false -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP4]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP4]], label %[[CONT5:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB9:[0-9]+]], i64 [[TMP5]]) #[[ATTR6]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META12]] -// SANITIZE-WITH-ATTR: [[CONT10]]: +// SANITIZE-WITH-ATTR: [[CONT5]]: // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [8 x i8], ptr [[TMP0]], i64 [[IDXPROM]] // SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA14]] @@ -500,12 +500,12 @@ size_t test_bdos_of_pointer(struct annotated_sized_ptr *p) { // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp ule i32 [[INDEX]], [[TMP2]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[TMP2]], 0, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = and i1 [[TMP4]], [[TMP3]], !nosanitize [[META12]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP5]], label %[[CONT8:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP5]], label %[[CONT3:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB15:[0-9]+]], i64 [[TMP6]]) #[[ATTR6]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META12]] -// SANITIZE-WITH-ATTR: [[CONT8]]: +// SANITIZE-WITH-ATTR: [[CONT3]]: // SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[DOTCOUNTED_BY_LOAD]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[COUNT_OR_NULL:%.*]] = select i1 [[TMP1]], i64 0, i64 [[COUNT]] @@ -649,12 +649,12 @@ size_t test_bdos_of_pointer_multibyte_pointee(struct annotated_sized_ptr_non_byt // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp ule i32 [[INDEX]], [[TMP3]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = icmp sgt i32 [[TMP3]], 0, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = and i1 [[TMP5]], [[TMP4]], !nosanitize [[META12]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP6]], label %[[CONT8:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP6]], label %[[CONT3:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF13]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]: // SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB18:[0-9]+]], i64 [[TMP7]]) #[[ATTR6]], !nosanitize [[META12]] // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META12]] -// SANITIZE-WITH-ATTR: [[CONT8]]: +// SANITIZE-WITH-ATTR: [[CONT3]]: // SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[DOTCOUNTED_BY_LOAD]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITH-ATTR-NEXT: [[COUNT_OR_NULL:%.*]] = select i1 [[TMP1]], i64 0, i64 [[COUNT]] _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
