const ConstantArrayType *ArrayTy =
Context.getAsConstantArrayType(BaseExpr->getType());
- if (!ArrayTy)
- return;
-
- const Type *BaseType = ArrayTy->getElementType().getTypePtr();
- if (EffectiveType->isDependentType() || BaseType->isDependentType())
+ const Type *BaseType =
+ ArrayTy == nullptr ? nullptr : ArrayTy->getElementType().getTypePtr();
+ bool IsUnboundedArray = (BaseType == nullptr);
+ if (EffectiveType->isDependentType() ||
+ (!IsUnboundedArray && BaseType->isDependentType()))
return;
Expr::EvalResult Result;
return;
llvm::APSInt index = Result.Val.getInt();
- if (IndexNegated)
+ if (IndexNegated) {
+ index.setIsUnsigned(false);
index = -index;
+ }
const NamedDecl *ND = nullptr;
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr))
ND = ME->getMemberDecl();
+ if (IsUnboundedArray) {
+ if (index.isUnsigned() || !index.isNegative()) {
+ const auto &ASTC = getASTContext();
+ unsigned AddrBits =
+ ASTC.getTargetInfo().getPointerWidth(ASTC.getTargetAddressSpace(
+ EffectiveType->getCanonicalTypeInternal()));
+ if (index.getBitWidth() < AddrBits)
+ index = index.zext(AddrBits);
+ CharUnits ElemCharUnits = ASTC.getTypeSizeInChars(EffectiveType);
+ llvm::APInt ElemBytes(index.getBitWidth(), ElemCharUnits.getQuantity());
+ // If index has more active bits than address space, we already know
+ // we have a bounds violation to warn about. Otherwise, compute
+ // address of (index + 1)th element, and warn about bounds violation
+ // only if that address exceeds address space.
+ if (index.getActiveBits() <= AddrBits) {
+ bool Overflow;
+ llvm::APInt Product(index);
+ Product += 1;
+ Product = Product.umul_ov(ElemBytes, Overflow);
+ if (!Overflow && Product.getActiveBits() <= AddrBits)
+ return;
+ }
+
+ // Need to compute max possible elements in address space, since that
+ // is included in diag message.
+ llvm::APInt MaxElems = llvm::APInt::getMaxValue(AddrBits);
+ MaxElems = MaxElems.zext(std::max(AddrBits + 1, ElemBytes.getBitWidth()));
+ MaxElems += 1;
+ ElemBytes = ElemBytes.zextOrTrunc(MaxElems.getBitWidth());
+ MaxElems = MaxElems.udiv(ElemBytes);
+
+ unsigned DiagID =
+ ASE ? diag::warn_array_index_exceeds_max_addressable_bounds
+ : diag::warn_ptr_arith_exceeds_max_addressable_bounds;
+
+ // Diag message shows element size in bits and in "bytes" (platform-
+ // dependent CharUnits)
+ DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr,
+ PDiag(DiagID)
+ << index.toString(10, true) << AddrBits
+ << (unsigned)ASTC.toBits(ElemCharUnits)
+ << ElemBytes.toString(10, false)
+ << MaxElems.toString(10, false)
+ << (unsigned)MaxElems.getLimitedValue(~0U)
+ << IndexExpr->getSourceRange());
+
+ if (!ND) {
+ // Try harder to find a NamedDecl to point at in the note.
+ while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
+ BaseExpr = ASE->getBase()->IgnoreParenCasts();
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
+ ND = DRE->getDecl();
+ if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
+ ND = ME->getMemberDecl();
+ }
+
+ if (ND)
+ DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr,
+ PDiag(diag::note_array_declared_here) << ND);
+ }
+ return;
+ }
+
if (index.isUnsigned() || !index.isNegative()) {
// It is possible that the type of the base expression after
// IgnoreParenCasts is incomplete, even though the type of the base
}
}
- unsigned DiagID = diag::warn_ptr_arith_exceeds_bounds;
- if (ASE)
- DiagID = diag::warn_array_index_exceeds_bounds;
+ unsigned DiagID = ASE ? diag::warn_array_index_exceeds_bounds
+ : diag::warn_ptr_arith_exceeds_bounds;
DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr,
PDiag(DiagID) << toString(index, 10, true)
if (!ND) {
// Try harder to find a NamedDecl to point at in the note.
- while (const ArraySubscriptExpr *ASE =
- dyn_cast<ArraySubscriptExpr>(BaseExpr))
+ while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
BaseExpr = ASE->getBase()->IgnoreParenCasts();
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
ND = DRE->getDecl();
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr))
+ if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
ND = ME->getMemberDecl();
}
--- /dev/null
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-X86-ADDR64 %s \
+// RUN: --implicit-check-not 'past the last possible element'
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-I386-ADDR32 %s \
+// RUN: --implicit-check-not 'past the last possible element'
+// RUN: %clang_cc1 -triple avr-pc-linux-gnu -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-AVR-ADDR16 %s \
+// RUN: --implicit-check-not 'past the last possible element'
+
+struct S {
+ long long a;
+ char b;
+ long long c;
+ short d;
+};
+
+struct S s[];
+
+void f1() {
+ ++s[3].a;
+ ++s[7073650413200313099].b;
+ // CHECK-X86-ADDR64: :[[@LINE-1]]:5: warning: array index 7073650413200313099 refers past the last possible element for an array in 64-bit address space containing 256-bit (32-byte) elements (max possible 576460752303423488 elements)
+ // CHECK-I386-ADDR32: :[[@LINE-2]]:5: warning: {{.*}} past the last possible element {{.*}} in 32-bit {{.*}} (max possible 178956970 elements)
+ // CHECK-AVR-ADDR16: :[[@LINE-3]]:5: warning: {{.*}} past the last possible element {{.*}} in 16-bit {{.*}} (max possible 3276 elements)
+ ++s[7073650].c;
+ // CHECK-AVR-ADDR16: :[[@LINE-1]]:5: warning: {{.*}} past the last possible element {{.*}} in 16-bit {{.*}} (max possible 3276 elements)
+}
+
+long long ll[];
+
+void f2() {
+ ++ll[3];
+ ++ll[2705843009213693952];
+ // CHECK-X86-ADDR64: :[[@LINE-1]]:5: warning: {{.*}} past the last possible element {{.*}} in 64-bit {{.*}} (max possible 2305843009213693952 elements)
+ // CHECK-I386-ADDR32: :[[@LINE-2]]:5: warning: {{.*}} past the last possible element {{.*}} in 32-bit {{.*}} (max possible 536870912 elements)
+ // CHECK-AVR-ADDR16: :[[@LINE-3]]:5: warning: {{.*}} past the last possible element {{.*}} in 16-bit {{.*}} (max possible 8192 elements)
+ ++ll[847073650];
+ // CHECK-I386-ADDR32: :[[@LINE-1]]:5: warning: {{.*}} past the last possible element {{.*}} in 32-bit {{.*}} (max possible 536870912 elements)
+ // CHECK-AVR-ADDR16: :[[@LINE-2]]:5: warning: {{.*}} past the last possible element {{.*}} in 16-bit {{.*}} (max possible 8192 elements)
+}
+
+void f3(struct S p[]) {
+ ++p[3].a;
+ ++p[7073650413200313099].b;
+ // CHECK-X86-ADDR64: :[[@LINE-1]]:5: warning: {{.*}} past the last possible element {{.*}} in 64-bit {{.*}} (max possible 576460752303423488 elements)
+ // CHECK-I386-ADDR32: :[[@LINE-2]]:5: warning: {{.*}} past the last possible element {{.*}} in 32-bit {{.*}} (max possible 178956970 elements)
+ // CHECK-AVR-ADDR16: :[[@LINE-3]]:5: warning: {{.*}} past the last possible element {{.*}} in 16-bit {{.*}} (max possible 3276 elements)
+ ++p[7073650].c;
+ // CHECK-AVR-ADDR16: :[[@LINE-1]]:5: warning: {{.*}} past the last possible element {{.*}} in 16-bit {{.*}} (max possible 3276 elements)
+}
+
+void f4(struct S *p) {
+ p += 3;
+ p += 7073650413200313099;
+ // CHECK-X86-ADDR64: :[[@LINE-1]]:3: warning: the pointer incremented by 7073650413200313099 refers past the last possible element for an array in 64-bit address space containing 256-bit (32-byte) elements (max possible 576460752303423488 elements)
+ // CHECK-I386-ADDR32: :[[@LINE-2]]:3: warning: {{.*}} past the last possible element {{.*}} in 32-bit {{.*}} (max possible 178956970 elements)
+ // CHECK-AVR-ADDR16: :[[@LINE-3]]:3: warning: {{.*}} past the last possible element {{.*}} in 16-bit {{.*}} (max possible 3276 elements)
+ p += 7073650;
+ // CHECK-AVR-ADDR16: :[[@LINE-1]]:3: warning: {{.*}} past the last possible element {{.*}} in 16-bit {{.*}} (max possible 3276 elements)
+}
+
+struct BQ {
+ struct S bigblock[3276];
+};
+
+struct BQ bq[];
+
+void f5() {
+ ++bq[0].bigblock[0].a;
+ ++bq[1].bigblock[0].a;
+ // CHECK-AVR-ADDR16: :[[@LINE-1]]:5: warning: {{.*}} past the last possible element {{.*}} in 16-bit {{.*}} (max possible 1 element)
+}
+
+void f6() {
+ int ints[] = {1, 3, 5, 7, 8, 6, 4, 5, 9};
+ int const n_ints = sizeof(ints) / sizeof(int);
+ unsigned long long const N = 3;
+
+ int *middle = &ints[0] + n_ints / 2;
+ // Should NOT produce a warning.
+ *(middle + 5 - N) = 22;
+}