https://github.com/nataliakokoromyti updated https://github.com/llvm/llvm-project/pull/175512
>From 6c3d7bd99351e52a3b72212d9f2b6074e6bd2305 Mon Sep 17 00:00:00 2001 From: Natalia Kokoromyti <[email protected]> Date: Mon, 12 Jan 2026 02:12:16 -0800 Subject: [PATCH 1/3] [clang][bytecode] Add test case for issue #175432 Add test case for assertion crash with GlobalInlineDescriptor when checking initialization of constexpr pointer arrays. --- clang/test/AST/ByteCode/arrays.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clang/test/AST/ByteCode/arrays.cpp b/clang/test/AST/ByteCode/arrays.cpp index d83ae97fc8213..f9b4f7b55332a 100644 --- a/clang/test/AST/ByteCode/arrays.cpp +++ b/clang/test/AST/ByteCode/arrays.cpp @@ -835,3 +835,12 @@ namespace MultiDimConstructExpr { constexpr b d; static_assert(d.m[2][1].p == &d.m[2][1]); } + +// Test for issue #175432 - assertion crash with GlobalInlineDescriptor +// Previously crashed with: Assertion `BS.Base != sizeof(GlobalInlineDescriptor)` failed +namespace gh175432 { + constexpr const int *arr[][2] = {{nullptr, nullptr}}; + static_assert(arr[0][0] == nullptr, ""); + static_assert(arr[0][1] == nullptr, ""); +} + >From d8b43055ce6d783d24ab2f6867c56f1c2669efa0 Mon Sep 17 00:00:00 2001 From: Natalia Kokoromyti <[email protected]> Date: Mon, 12 Jan 2026 02:24:44 -0800 Subject: [PATCH 2/3] [clang][bytecode] Fix assertion in Pointer::isInitialized() for GlobalInlineDescriptor The function was calling getFieldDesc() which internally calls getInlineDesc(), triggering an assertion when BS.Base == sizeof(GlobalInlineDescriptor). The existing check at the start of the function handles the case where isRoot() && Offset == BS.Base, but doesn't cover cases where BS.Base == sizeof(GlobalInlineDescriptor) but Offset != BS.Base. Added a safety check before calling getFieldDesc() to return true for these cases, avoiding the crash while preserving existing behavior for the normal isRoot() path. Fixes #175432 --- clang/docs/ReleaseNotes.rst | 2 ++ clang/lib/AST/ByteCode/Pointer.cpp | 6 ++++++ clang/test/AST/ByteCode/arrays.cpp | 13 ++++++------- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index cc04deb45bb53..eecab591508ff 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -127,6 +127,8 @@ Bug Fixes to C++ Support Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ +- Fixed assertion crash in bytecode interpreter when checking initialization of + constexpr pointer arrays with GlobalInlineDescriptor. (#GH175432) Miscellaneous Bug Fixes ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index c5e0fd83021d7..1d9b5a36390cc 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -454,6 +454,12 @@ bool Pointer::isInitialized() const { return GD.InitState == GlobalInitState::Initialized; } + // Safety check: if BS.Base == sizeof(GlobalInlineDescriptor) but we're not + // in the isRoot() case above, we still cannot call getInlineDesc(). + // This can happen when Offset != BS.Base. Return true to avoid crash. + if (BS.Base == sizeof(GlobalInlineDescriptor)) + return true; + assert(BS.Pointee && "Cannot check if null pointer was initialized"); const Descriptor *Desc = getFieldDesc(); assert(Desc); diff --git a/clang/test/AST/ByteCode/arrays.cpp b/clang/test/AST/ByteCode/arrays.cpp index f9b4f7b55332a..255bfb99783b9 100644 --- a/clang/test/AST/ByteCode/arrays.cpp +++ b/clang/test/AST/ByteCode/arrays.cpp @@ -834,13 +834,12 @@ namespace MultiDimConstructExpr { }; constexpr b d; static_assert(d.m[2][1].p == &d.m[2][1]); -} -// Test for issue #175432 - assertion crash with GlobalInlineDescriptor -// Previously crashed with: Assertion `BS.Base != sizeof(GlobalInlineDescriptor)` failed -namespace gh175432 { - constexpr const int *arr[][2] = {{nullptr, nullptr}}; - static_assert(arr[0][0] == nullptr, ""); - static_assert(arr[0][1] == nullptr, ""); } +namespace GH175432 { + constexpr const int *foo[][2] = { + {nullptr, int}, // both-error {{expected '(' for function-style cast or type construction}} + }; + static_assert(foo[0][0] == nullptr, ""); // both-error {{not an integral constant expression}} +} >From 9a9baa1d340f42a2d2c6a3bd3fdef8134ba50afc Mon Sep 17 00:00:00 2001 From: Natalia <[email protected]> Date: Tue, 13 Jan 2026 19:12:27 -0800 Subject: [PATCH 3/3] Fix initialization check to return false for edge case Changes return value from true to false when BS.Base == sizeof(GlobalInlineDescriptor) but isRoot() conditions are not met. Returning true was too permissive and caused test failures. Returning false is more conservative and prevents the crash while maintaining correct behavior for valid code. Also updated test expectations to use expected-error instead of both-error since this issue only affects the new constant evaluator. --- clang/lib/AST/ByteCode/Pointer.cpp | 12 +++++++----- clang/test/AST/ByteCode/arrays.cpp | 11 ++++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 1d9b5a36390cc..8f623a3cb7890 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -454,13 +454,15 @@ bool Pointer::isInitialized() const { return GD.InitState == GlobalInitState::Initialized; } - // Safety check: if BS.Base == sizeof(GlobalInlineDescriptor) but we're not - // in the isRoot() case above, we still cannot call getInlineDesc(). - // This can happen when Offset != BS.Base. Return true to avoid crash. + assert(BS.Pointee && "Cannot check if null pointer was initialized"); + + // Handle the case where BS.Base == sizeof(GlobalInlineDescriptor) but + // the pointer is not a proper root. This can happen with invalid code. + // We cannot call getFieldDesc() or getInlineDesc() in this case as they + // would trigger assertions. Conservatively return false. if (BS.Base == sizeof(GlobalInlineDescriptor)) - return true; + return false; - assert(BS.Pointee && "Cannot check if null pointer was initialized"); const Descriptor *Desc = getFieldDesc(); assert(Desc); if (Desc->isPrimitiveArray()) diff --git a/clang/test/AST/ByteCode/arrays.cpp b/clang/test/AST/ByteCode/arrays.cpp index 255bfb99783b9..b18f8e50c1e59 100644 --- a/clang/test/AST/ByteCode/arrays.cpp +++ b/clang/test/AST/ByteCode/arrays.cpp @@ -838,8 +838,13 @@ namespace MultiDimConstructExpr { } namespace GH175432 { - constexpr const int *foo[][2] = { - {nullptr, int}, // both-error {{expected '(' for function-style cast or type construction}} + // Test that we don't crash when checking initialization of + // pointer arrays with invalid initializers + constexpr const int *foo[][2] = { // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{declared here}} + {nullptr, int}, // expected-error {{expected '(' for function-style cast or type construction}} }; - static_assert(foo[0][0] == nullptr, ""); // both-error {{not an integral constant expression}} + + static_assert(foo[0][0] == nullptr, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{initializer of 'foo' is unknown}} } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
