Author: Timm Baeder Date: 2025-08-21T13:01:45+02:00 New Revision: 21bd3a7fa809eea64bdf73dd467c582f68981b07
URL: https://github.com/llvm/llvm-project/commit/21bd3a7fa809eea64bdf73dd467c582f68981b07 DIFF: https://github.com/llvm/llvm-project/commit/21bd3a7fa809eea64bdf73dd467c582f68981b07.diff LOG: [clang][bytecode] Check for unknown size array pointers in InitField* (#154689) This can happen when the base pointer is an unknown size array, where !isOnePastEnd(), but isPastEnd(). Fixes #153990 Added: Modified: clang/lib/AST/ByteCode/Interp.h clang/test/AST/ByteCode/arrays.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 149ce3b1042db..86fca7f652a47 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -1640,6 +1640,9 @@ bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { const Pointer &Ptr = S.Stk.peek<Pointer>(); if (!CheckRange(S, OpPC, Ptr, CSK_Field)) return false; + if (!CheckArray(S, OpPC, Ptr)) + return false; + const Pointer &Field = Ptr.atField(I); Field.deref<T>() = Value; Field.initialize(); @@ -1652,6 +1655,9 @@ bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) { const Pointer &Ptr = S.Stk.peek<Pointer>(); if (!CheckRange(S, OpPC, Ptr, CSK_Field)) return false; + if (!CheckArray(S, OpPC, Ptr)) + return false; + const Pointer &Field = Ptr.atField(I); Field.deref<T>() = Value; Field.activate(); @@ -1663,7 +1669,13 @@ template <PrimType Name, class T = typename PrimConv<Name>::T> bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { assert(F->isBitField()); const T &Value = S.Stk.pop<T>(); - const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset); + const Pointer &Ptr = S.Stk.peek<Pointer>(); + if (!CheckRange(S, OpPC, Ptr, CSK_Field)) + return false; + if (!CheckArray(S, OpPC, Ptr)) + return false; + + const Pointer &Field = Ptr.atField(F->Offset); if constexpr (needsAlloc<T>()) { T Result = S.allocAP<T>(Value.bitWidth()); @@ -1689,7 +1701,13 @@ bool InitBitFieldActivate(InterpState &S, CodePtr OpPC, const Record::Field *F) { assert(F->isBitField()); const T &Value = S.Stk.pop<T>(); - const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset); + const Pointer &Ptr = S.Stk.peek<Pointer>(); + if (!CheckRange(S, OpPC, Ptr, CSK_Field)) + return false; + if (!CheckArray(S, OpPC, Ptr)) + return false; + + const Pointer &Field = Ptr.atField(F->Offset); if constexpr (needsAlloc<T>()) { T Result = S.allocAP<T>(Value.bitWidth()); diff --git a/clang/test/AST/ByteCode/arrays.cpp b/clang/test/AST/ByteCode/arrays.cpp index 68102b42f3820..22a4b41041eb3 100644 --- a/clang/test/AST/ByteCode/arrays.cpp +++ b/clang/test/AST/ByteCode/arrays.cpp @@ -800,3 +800,23 @@ namespace ZeroSizeArrayRead { static_assert(s[0] == '0', ""); // both-error {{not an integral constant expression}} \ // both-note {{read of dereferenced one-past-the-end pointer}} } + +namespace FAM { + char *strchr(const char *, int); + + struct A { + char n, a[2]; + }; + struct B { + int n; + struct A a[]; // both-note {{here}} + }; + + const struct B b = {0, {{1, {2, 3}}, {4, {5, 6}}}}; + void foo(void) { int sch = 0 != strchr(b.a[1].a, '\0'); } + + int foo2() { + struct B b = {0, {{1, {2, 3}}, {4, {5, 6}}}}; // both-error {{initialization of flexible array member is not allowed}} + return 1; + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits