Skip to content

Prevent byte relocation of non-trivial VLA elements - #217

Merged
thirtytwobits merged 7 commits into
codex/issue-37-vla-partial-constructionfrom
codex/issue-213-vla-safe-reallocation
Oct 6, 2026
Merged

thirtytwobits merged 7 commits into
codex/issue-37-vla-partial-constructionfrom
codex/issue-213-vla-safe-reallocation

Conversation

@thirtytwobits

@thirtytwobits thirtytwobits commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

reserve() and shrink_to_fit() could pass live non-trivially-copyable elements to an allocator's reallocate, which may move the block by copying bytes. Address-sensitive elements then retained pointers into released storage, and element constructors/destructors were bypassed.

Gate the shared reallocation helper on std::is_trivially_copyable<value_type>. Other elements use the existing allocator-aware relocation and rollback from #215. Trivial storage and packed bool retain reallocation support. Non-trivial elements now require replacement storage for capacity changes, including when the underlying resource could resize in place; the public documentation explains reserving capacity up front for single-allocation resources.

Stacked on #215 (codex/issue-37-vla-partial-construction, base commit 38027ab). The implementation remains self-contained.

Tests were written, run against the unchanged implementation, and committed before the fix:

  • 59fbcab: deterministic moving-resource regressions for reserve, shrink, implicit growth, address-sensitive elements, move-only/copy-fallback lifetimes, allocation and construction failures, trivial storage, packed bool, and allocators without reallocate.
  • 90ed933: single-allocation resource behavior, plus explicit capacity setup in existing copy-assignment and fill-resize tests that previously relied on non-trivial in-place growth.
  • dc8e9c4: production gate and documentation.

The reallocation suite centralizes numeric scenario inputs and derives sizes, payloads, packed capacities, and lifetime expectations from them. Static assertions protect the relocation, failure-position, bit-pattern, and numeric-range requirements; implicit resize derives its target from the capacity obtained after append.

Validation:

  • Unchanged Fix VLA rollback after partial construction #215: 14 of 22 new tests failed with GCC C++14 Debug and Clang C++17 Debug; 10 of 18 failed with GCC C++14 ReleaseEP. The eight control cases passed. The additional single-allocation regression also failed against an isolated copy of the unchanged header.
  • Fixed implementation: all 22 new tests pass with exceptions; all 18 applicable tests pass without exceptions.
  • All 10 VLA suites passed GCC/Clang × C++14/17 × Debug/ReleaseEP (8 configurations). Reallocation and exception-safety suites passed GCC/Clang × C++14/17/20/23 × Debug/Release/DebugEP/ReleaseEP (32 configurations).
  • Reallocation and exception-safety suites passed ASan/UBSan with leak detection in C++14 and C++17.
  • Constant refactor: the focused suite passed GCC/Clang × C++14/17 × Debug/ReleaseEP. Two alternate constant configurations passed with and without exceptions, and 12 invalid configurations were rejected by their intended static assertions.
  • Changed-code clang-format checks and git diff --check passed. Doxygen completed with the same 13 pre-existing warnings in type_traits_ext.hpp and unbounded_variant.hpp.

Closes #213 after this stack is merged into the default branch.

Cover reserve, shrink, implicit growth, trivial storage, packed bool, and relocation rollback before fixing issue #213. The unchanged implementation fails 14 of 22 tests with exceptions and 10 of 18 tests without exceptions.
Reserve setup storage in the assignment and fill-resize tests. Add a regression proving that safe relocation retains the original array when replacement storage is unavailable; verified failing against the issue #37 header.
Use the issue #37 allocation and construction rollback path for non-trivial elements during reserve and shrink_to_fit. Preserve byte-storage optimization and document the replacement-storage requirement. Fixes #213 after the stack reaches main. #verification #docs
@thirtytwobits
thirtytwobits marked this pull request as ready for review October 6, 2026 18:44
@thirtytwobits
thirtytwobits requested a balanced review from Copilot October 6, 2026 18:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The focused safety fix is consistent with allocator behavior and is covered across relevant element types and failure paths.

Review effort: Balanced
Findings: None

What changed in this PR

Prevents unsafe byte relocation of non-trivial VLA elements while retaining optimized reallocation for trivial and packed-bool storage.

Changes:

  • Gates allocator reallocation on trivial copyability.
  • Documents capacity behavior for single-allocation resources.
  • Adds comprehensive relocation, failure, and lifetime tests.
File Description
include/​cetl/​variable_length_array.hpp Adds the safe reallocation gate and documentation.
cetlvast/​suites/​unittest/​test_variable_length_array_reallocation.cpp Tests relocation safety and failure handling.
cetlvast/​suites/​unittest/​test_variable_length_array_general_allocation.cpp Updates fixed-buffer tests and covers replacement-storage limits.
cetlvast/​suites/​unittest/​CMakeLists.txt Registers the new test suite.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Centralize scenario capacities, element counts, payloads, packed-bit patterns, and sentinels. Derive loop bounds and expectations, and assert the relationships required for relocation and failure coverage. Validate alternate numeric configurations and compile-time rejection of invalid ones. #verification
Keep resource and lifetime recorders non-copyable and non-movable. Explicitly default or delete the remaining special members on relocation elements while retaining their tested lifetime and copy/move traits. #verification
Record targeted suppressions for intentional raw allocation and the test-only exception sentinel, clarify packed-count grouping, and make saved pointer declarations explicit. #verification
@thirtytwobits
thirtytwobits added this pull request to stack #216 October 6, 2026 20:24
@thirtytwobits
thirtytwobits merged commit ea85a83 into main Oct 6, 2026
36 checks passed
@thirtytwobits
thirtytwobits deleted the codex/issue-213-vla-safe-reallocation branch October 6, 2026 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

VLA reserve()/shrink_to_fit() byte-relocate non-trivially-copyable elements via allocator reallocate (UB)

3 participants