@@ -4608,6 +4608,11 @@ void CodeGenFunction::EmitArrayBoundsConstraints(const ArraySubscriptExpr *E,
46084608 if (SanOpts.has (SanitizerKind::ArrayBounds))
46094609 return ;
46104610
4611+ // Use the provided IndexVal to avoid duplicating side effects.
4612+ // The caller has already emitted the index expression once.
4613+ if (!IndexVal)
4614+ return ;
4615+
46114616 const Expr *Base = E->getBase ();
46124617 const Expr *Idx = E->getIdx ();
46134618 QualType BaseType = Base->getType ();
@@ -4618,19 +4623,28 @@ void CodeGenFunction::EmitArrayBoundsConstraints(const ArraySubscriptExpr *E,
46184623 }
46194624 }
46204625
4621- // For now: only handle constant array types.
4626+ // Handle both constant arrays and VLAs (variable-length arrays.)
46224627 const ConstantArrayType *CAT = getContext ().getAsConstantArrayType (BaseType);
4623- if (!CAT)
4624- return ;
4628+ llvm::Value *VLASize = nullptr ;
46254629
4626- llvm::APInt ArraySize = CAT->getSize ();
4630+ if (!CAT) {
4631+ if (const VariableArrayType *VAT =
4632+ getContext ().getAsVariableArrayType (BaseType))
4633+ VLASize = getVLASize (VAT).NumElts ;
4634+ else
4635+ return ; // Not a constant or VLA.
4636+ }
4637+
4638+ llvm::APInt ArraySize;
4639+ if (CAT)
4640+ ArraySize = CAT->getSize ();
46274641
46284642 // Don't generate assumes for flexible array member pattern.
46294643 // Size-1 arrays: "struct { int len; char data[1]; }" (pre-C99 idiom.)
46304644 // Zero-length arrays: "struct { int len; char data[0]; }" (GCC extension
46314645 // https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html)
46324646 // Both patterns use arrays as placeholders for variable-length data.
4633- if (ArraySize == 0 || ArraySize == 1 ) {
4647+ if (CAT && ( ArraySize == 0 || ArraySize == 1 ) ) {
46344648 if (const auto *ME = dyn_cast<MemberExpr>(Base->IgnoreParenImpCasts ())) {
46354649 if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl ())) {
46364650 const RecordDecl *RD = FD->getParent ();
@@ -4649,15 +4663,18 @@ void CodeGenFunction::EmitArrayBoundsConstraints(const ArraySubscriptExpr *E,
46494663
46504664 QualType IdxType = Idx->getType ();
46514665 llvm::Type *IndexType = ConvertType (IdxType);
4652- llvm::Value *Zero = llvm::ConstantInt::get (IndexType, 0 );
4653-
4654- uint64_t ArraySizeValue = ArraySize.getLimitedValue ();
4655- llvm::Value *ArraySizeVal = llvm::ConstantInt::get (IndexType, ArraySizeValue);
4666+ llvm::Value *ArraySizeVal;
46564667
4657- // Use the provided IndexVal to avoid duplicating side effects.
4658- // The caller has already emitted the index expression once.
4659- if (!IndexVal)
4660- return ;
4668+ if (CAT)
4669+ // Constant array: use compile-time size.
4670+ ArraySizeVal =
4671+ llvm::ConstantInt::get (IndexType, ArraySize.getLimitedValue ());
4672+ else
4673+ // VLA: use runtime size.
4674+ ArraySizeVal =
4675+ VLASize->getType () == IndexType
4676+ ? VLASize
4677+ : Builder.CreateIntCast (VLASize, IndexType, false , " vla.size.cast" );
46614678
46624679 // Ensure index value has the same type as our constants.
46634680 if (IndexVal->getType () != IndexType) {
@@ -4672,6 +4689,7 @@ void CodeGenFunction::EmitArrayBoundsConstraints(const ArraySubscriptExpr *E,
46724689 // array."
46734690 if (IdxType->isSignedIntegerOrEnumerationType ()) {
46744691 // For signed indices: index >= 0 && index < size.
4692+ llvm::Value *Zero = llvm::ConstantInt::get (IndexType, 0 );
46754693 llvm::Value *LowerBound =
46764694 Builder.CreateICmpSGE (IndexVal, Zero, " idx.ge.zero" );
46774695 llvm::Value *UpperBound =
0 commit comments