Author: Timm Baeder Date: 2026-05-11T13:36:07+02:00 New Revision: 5c8c7bae4045d49869c6ee2a979419ad112e9964
URL: https://github.com/llvm/llvm-project/commit/5c8c7bae4045d49869c6ee2a979419ad112e9964 DIFF: https://github.com/llvm/llvm-project/commit/5c8c7bae4045d49869c6ee2a979419ad112e9964.diff LOG: [clang][bytecode] Check destination size when initializing from an array initlist (#196916) Added: Modified: clang/lib/AST/ByteCode/Compiler.cpp clang/lib/AST/ByteCode/Interp.h clang/lib/AST/ByteCode/Opcodes.td clang/test/AST/ByteCode/new-delete.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index faad6e0b4a230..beaeed09005b9 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -2205,16 +2205,16 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, } if (QT->isArrayType()) { - if (Inits.size() == 1 && QT == Inits[0]->getType()) - return this->delegate(Inits[0]); - const ConstantArrayType *CAT = Ctx.getASTContext().getAsConstantArrayType(QT); uint64_t NumElems = CAT->getZExtSize(); - if (!this->emitCheckArraySize(NumElems, E)) + if (Initializing && !this->emitCheckArrayDestSize(NumElems, E)) return false; + if (Inits.size() == 1 && QT == Inits[0]->getType()) + return this->delegate(Inits[0]); + OptPrimType InitT = classify(CAT->getElementType()); unsigned ElementIndex = 0; for (const Expr *Init : Inits) { diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index fe2d99901d367..b620d1cce9010 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -3753,6 +3753,22 @@ inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) { return true; } +/// Check if the destination array we're initializing can hold the \p NumElems +/// elements. +inline bool CheckArrayDestSize(InterpState &S, CodePtr OpPC, size_t NumElems) { + if (!CheckArraySize(S, OpPC, NumElems)) + return false; + + const Pointer &Ptr = S.Stk.peek<Pointer>(); + if (!Ptr.isUnknownSizeArray() && NumElems > Ptr.getNumElems()) { + S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_too_small) + << Ptr.getNumElems() << NumElems; + return false; + } + + return true; +} + inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { assert(Desc); diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 57ed71fb6f16b..0838263a53ede 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -458,6 +458,7 @@ def CheckLiteralType : Opcode { } def CheckArraySize : Opcode { let Args = [ArgUint64]; } +def CheckArrayDestSize : Opcode { let Args = [ArgUint64]; } def CheckFunctionDecl : Opcode { let Args = [ArgFunctionDecl]; } def CheckBitCast : Opcode { let Args = [ArgTypePtr, ArgBool]; } diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp index ac2c2ff4a73c6..b6e6d333a4bcb 100644 --- a/clang/test/AST/ByteCode/new-delete.cpp +++ b/clang/test/AST/ByteCode/new-delete.cpp @@ -1197,6 +1197,26 @@ namespace vdtor { static_assert(vdtor_3(3) == 3); } +namespace ArrayDestSize { + template<typename T> + constexpr T dynarray(int elems, int i) { + T *p; + if constexpr (sizeof(T) == 1) + p = new T[elems]{"fox"}; // both-note {{evaluated array bound 3 is too small to hold 4 explicitly initialized elements}} + else + p = new T[elems]{1, 2, 3}; // both-note {{evaluated array bound 2 is too small to hold 3 explicitly initialized elements}} + T n = p[i]; // both-note 4{{past-the-end}} + delete [] p; + return n; + } + static_assert(dynarray<int>(4, 4) == 0); // both-error {{constant expression}} both-note {{in call}} + static_assert(dynarray<int>(3, 3) == 0); // both-error {{constant expression}} both-note {{in call}} + static_assert(dynarray<int>(2, 1) == 0); // both-error {{constant expression}} both-note {{in call}} + static_assert(dynarray<char>(5, 5) == 0); // both-error {{constant expression}} both-note {{in call}} + static_assert(dynarray<char>(4, 4) == 0); // both-error {{constant expression}} both-note {{in call}} + static_assert(dynarray<char>(3, 2) == 'x'); // both-error {{constant expression}} both-note {{in call}} +} + #else /// Make sure we reject this prior to C++20 constexpr int a() { // both-error {{never produces a constant expression}} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
