[llvm-branch-commits] [clang] [Clang][counted_by] Don't re-evaluate the base of a counted_by pointer access for -fsanitize=array-bounds (PR #232228)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Oct 15 01:37:41 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-codegen

Author: Bill Wendling (isanbard)

<details>
<summary>Changes</summary>

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.

When the subscript base is exactly the field load, emit the field's l-value once,
load the pointer from it (as the default case of EmitPointerWithAlignment does,
through EmitLoadOfLValue so that a '__ptrauth'-qualified field is still authenticated),
and pass the field's address to the bounds check. When there's an intervening cast
(e.g. '((char *)p->buf)[i]') the base can't be shared, so the field's l-value is still re-emitted,
which only recomputes its address and so is safe unless the struct base has side-effects.
In that case the check is now skipped instead of evaluating the base twice.


---

Patch is 50.95 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/232228.diff


7 Files Affected:

- (modified) clang/lib/CodeGen/CGExpr.cpp (+50-13) 
- (modified) clang/test/CodeGen/attr-counted-by-base-exprs.c (+136-26) 
- (modified) clang/test/CodeGen/attr-counted-by-for-pointers.c (+6-6) 
- (modified) clang/test/CodeGen/attr-counted-by-or-null-for-pointers.c (+6-6) 
- (added) clang/test/CodeGen/attr-counted-by-ptrauth.c (+24) 
- (modified) clang/test/CodeGen/attr-sized-by-for-pointers.c (+12-12) 
- (modified) clang/test/CodeGen/attr-sized-by-or-null-for-pointers.c (+12-12) 


``````````diff
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 927652c460922..9cfcfc0aa68aa 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -5379,9 +5379,46 @@ 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. When the base is exactly the field load, emit the field's
+    // l-value once and load the pointer from it, 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. This mirrors the default
+    // case of EmitPointerWithAlignment. The load goes through EmitLoadOfLValue,
+    // not EmitLoadOfScalar, so that a '__ptrauth'-qualified field is
+    // authenticated before it's used.
+    Address CountedByFieldAddr = Address::invalid();
+    Address BaseAddr = Address::invalid();
+    if (CountedByME && E->getBase()->IgnoreParens() == CountedByLoad) {
+      LValue FieldLV = EmitCheckedLValue(CountedByME, TCK_Load);
+      CountedByFieldAddr = FieldLV.getAddress();
+      BaseAddr = makeNaturalAddressForPointer(
+          EmitLoadOfLValue(FieldLV, CountedByME->getExprLoc()).getScalarVal(),
+          E->getBase()->getType()->getPointeeType(), CharUnits(),
+          /*ForPointeeType=*/true, &EltBaseInfo, &EltTBAAInfo);
+    } else {
+      // The base must be a pointer; emit it with an estimate of its alignment.
+      BaseAddr =
+          EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
+    }
+
     auto *Idx = EmitIdxAfterBase(/*Promote*/true);
     QualType ptrType = E->getBase()->getType();
     Addr = emitArraySubscriptGEP(*this, BaseAddr, Idx, E->getType(),
@@ -5389,16 +5426,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);
-    }
+    // Without the field's address (e.g. '((char *)p->buf)[i]'),
+    // 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/test/CodeGen/attr-counted-by-base-exprs.c b/clang/test/CodeGen/attr-counted-by-base-exprs.c
index 403b9de7a0b3a..7f8aa45545c07 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,104 @@ 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];
+}
+
+// When there's a cast in between, the base can't be shared with the check, so
+// the check is skipped instead of evaluating the base twice.
+// 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:    [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[INTPTR_TBAA9]]
+// CHECK-NEXT:    [[IDXPROM:%.*]] = sext i32 [[I]] to i64
+// CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 [[IDXPROM]]
+// CHECK-NEXT:    [[TMP1:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[CHAR_TBAA15:![0-9]+]]
+// CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[TMP1]] 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 +182,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 +205,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 +222,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 +241,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 +262,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 +295,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 +318,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 +330,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 +351,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 r...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/232228


More information about the llvm-branch-commits mailing list