@@ -4589,8 +4589,25 @@ void CodeGenFunction::EmitCountedByBoundsChecking(
45894589// / array subscripts are within bounds, enabling better optimization without
45904590// / duplicating side effects from the subscript expression. The IndexVal
45914591// / parameter should be the already-emitted index value to avoid re-evaluation.
4592+ // /
4593+ // / Code that intentionally accesses out-of-bounds (UB) may break with
4594+ // / optimizations. Only applies to constant-size arrays (not pointers, VLAs, or
4595+ // / flexible arrays.) Disabled when -fsanitize=array-bounds is active.
4596+ // /
45924597void CodeGenFunction::EmitArrayBoundsConstraints (const ArraySubscriptExpr *E,
45934598 llvm::Value *IndexVal) {
4599+ // Disable with -fno-assume-array-bounds.
4600+ if (!CGM.getCodeGenOpts ().AssumeArrayBounds )
4601+ return ;
4602+
4603+ // Disable at -O0.
4604+ if (CGM.getCodeGenOpts ().OptimizationLevel == 0 )
4605+ return ;
4606+
4607+ // Disable with array-bounds sanitizer.
4608+ if (SanOpts.has (SanitizerKind::ArrayBounds))
4609+ return ;
4610+
45944611 const Expr *Base = E->getBase ();
45954612 const Expr *Idx = E->getIdx ();
45964613 QualType BaseType = Base->getType ();
@@ -4610,6 +4627,26 @@ void CodeGenFunction::EmitArrayBoundsConstraints(const ArraySubscriptExpr *E,
46104627 if (ArraySize == 0 )
46114628 return ;
46124629
4630+ // Don't generate assumes for flexible array member pattern.
4631+ // Arrays of size 1 in structs are often used as placeholders for
4632+ // variable-length data (pre-C99 flexible array member idiom.)
4633+ if (ArraySize == 1 ) {
4634+ if (const auto *ME = dyn_cast<MemberExpr>(Base->IgnoreParenImpCasts ())) {
4635+ if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl ())) {
4636+ const RecordDecl *RD = FD->getParent ();
4637+ // Check if this field is the last field in the record.
4638+ // Only the last field can be a flexible array member.
4639+ const FieldDecl *LastField = nullptr ;
4640+ for (const auto *Field : RD->fields ())
4641+ LastField = Field;
4642+ if (LastField == FD)
4643+ // This is a size-1 array as the last field in a struct.
4644+ // Likely a flexible array member pattern - skip assumes.
4645+ return ;
4646+ }
4647+ }
4648+ }
4649+
46134650 QualType IdxType = Idx->getType ();
46144651 llvm::Type *IndexType = ConvertType (IdxType);
46154652 llvm::Value *Zero = llvm::ConstantInt::get (IndexType, 0 );
@@ -4633,21 +4670,21 @@ void CodeGenFunction::EmitArrayBoundsConstraints(const ArraySubscriptExpr *E,
46334670 // This enforces the C18 standard requirement that array subscripts
46344671 // must be "greater than or equal to zero and less than the size of the
46354672 // array."
4636- llvm::Value *LowerBound, *UpperBound;
46374673 if (IdxType->isSignedIntegerOrEnumerationType ()) {
46384674 // For signed indices: index >= 0 && index < size.
4639- LowerBound = Builder.CreateICmpSGE (IndexVal, Zero, " idx.ge.zero" );
4640- UpperBound = Builder.CreateICmpSLT (IndexVal, ArraySizeVal, " idx.lt.size" );
4675+ llvm::Value *LowerBound =
4676+ Builder.CreateICmpSGE (IndexVal, Zero, " idx.ge.zero" );
4677+ llvm::Value *UpperBound =
4678+ Builder.CreateICmpSLT (IndexVal, ArraySizeVal, " idx.lt.size" );
4679+ llvm::Value *BoundsConstraint =
4680+ Builder.CreateAnd (LowerBound, UpperBound, " bounds.constraint" );
4681+ Builder.CreateAssumption (BoundsConstraint);
46414682 } else {
4642- // For unsigned indices: index < size (>= 0 is implicit).
4643- LowerBound = Builder.getTrue ();
4644- UpperBound = Builder.CreateICmpULT (IndexVal, ArraySizeVal, " idx.lt.size" );
4683+ // For unsigned indices: index < size (>= 0 is implicit.)
4684+ llvm::Value *UpperBound =
4685+ Builder.CreateICmpULT (IndexVal, ArraySizeVal, " idx.lt.size" );
4686+ Builder.CreateAssumption (UpperBound);
46454687 }
4646-
4647- llvm::Value *BoundsConstraint =
4648- Builder.CreateAnd (LowerBound, UpperBound, " bounds.constraint" );
4649- llvm::Function *AssumeIntrinsic = CGM.getIntrinsic (llvm::Intrinsic::assume);
4650- Builder.CreateCall (AssumeIntrinsic, BoundsConstraint);
46514688}
46524689
46534690LValue CodeGenFunction::EmitArraySubscriptExpr (const ArraySubscriptExpr *E,
0 commit comments