Skip to content

test(multitude): drive alignment guards through an injectable cap - #704

Merged
Adomas Bekeras (AdomasBekeras) merged 3 commits into
mainfrom
u/abekeras/multitude-align-cap
Sep 3, 2026
Merged

test(multitude): drive alignment guards through an injectable cap#704
Adomas Bekeras (AdomasBekeras) merged 3 commits into
mainfrom
u/abekeras/multitude-align-cap

Conversation

@AdomasBekeras

Copy link
Copy Markdown
Contributor

The bug

ADO 7707893: cargo test fails on a clean checkout.

The arena refuses allocations whose alignment reaches a cap. CHUNK_ALIGN is 64 KiB, and the smart-pointer cap is half of it, 32 KiB, because a smart pointer recovers its chunk header by masking the value pointer's offset within its chunk tile — a value aligned that far can land outside the first tile, where the mask finds a different chunk's header.

To test the rejection, the tests had to instantiate a type aligned at or above the cap. So they declared #[repr(align(32768))], #[repr(align(65536))] and #[repr(align(131072))] types. Some codegen backends cap type alignment at 8192 and refuse to compile such a type at all. The library built fine; three test binaries (arena, audit_repro, pin_support) and one doctest failed codegen.

Why the previous fix didn't hold

#501 gated the tests behind #[cfg(not(utc_backend))] (since renamed align_capped_backend), with the flag set by an out-of-tree CI pipeline. Three problems:

  • Nothing in this repo sets it, so the default build was the broken one. A contributor cloning the repo hits the failure; the gate only helps a build that already knows to opt in.
  • It's all-or-nothing. A backend that sets it loses the guard coverage entirely, on a live memory-safety check.
  • It missed the doctest, because rustdoc ignores RUSTFLAGS. Setting RUSTFLAGS would also have clobbered .cargo/config.toml's -C target-cpu=x86-64-v3.

This change

The test needs the type's alignment and the cap to meet. The old approach raised the alignment to the cap. This one lowers the cap to an alignment every backend compiles.

Arena gets a #[cfg(test)] alignment cap that the guards read:

#[cfg(not(test))]
fn chunk_align_cap(&self) -> usize { CHUNK_ALIGN }

#[cfg(test)]
fn chunk_align_cap(&self) -> usize { self.align_cap.get() }

Tests call capped_arena(), which sets the cap to 8192, and use shared helper types aligned to 4096 and 8192. Both boundaries stay reachable, and the production 2:1 ratio between the chunk cap and the smart-pointer cap is preserved, so each test still exercises the cap its entry point actually consults.

The cfg(test) field and the whole knob disappear from production builds — Arena's layout is unchanged.

Along the way:

  • Three duplicate MAX_SMART_PTR_ALIGN constants collapse into one accessor. All nine guard sites now route through rejects_smart_ptr_align / rejects_chunk_align.
  • ~46 over-alignment tests move from tests/ into #[cfg(test)] modules in src/ (arena/align_guard_tests.rs, bytemuck.rs, zerocopy.rs) so they can reach the knob.
  • The align_capped_backend cfg is deleted from the workspace Cargo.toml.
  • Net −48 lines.

Coverage

Nothing was dropped. Two additions beyond parity:

  • One test asserts the error is specifically is_alignment_too_large(), which nothing outside the deleted doctest checked before.
  • try_alloc_slice_fill_iter's guard had no over-alignment test at all; it does now.

Mutation-checked by hand: forcing rejects_smart_ptr_align to false fails 39 tests, forcing rejects_chunk_align to false fails 9.

Things worth a reviewer's attention

The guards are no longer const { }. They were if const { align_of::<T>() >= MAX_SMART_PTR_ALIGN }, folded at compile time by construction. They are now ordinary comparisons against an #[inline(always)] accessor. In release under cfg(not(test)) that accessor returns a literal and align_of::<T>() is a constant, so LLVM folds it; debug builds pay a compare. The guarantee is gone, the behaviour isn't. Restoring the guarantee would need a macro expanding to the const { } form under cfg(not(test)) — happy to add it if you'd rather have the certainty.

buffer_freezable still reads the real cap. It's used inside const { } on the Vec hot path, so making it cap-aware would put a runtime branch there. The consequence is that a capped arena is not a faithful model for Vec/String growth and freeze tests — documented on capped_arena() and set_align_cap(), and set_align_cap now asserts the cap can only be lowered. A new lib test asserts the arena's default caps equal CHUNK_ALIGN and max_smart_ptr_align(), so the two sources can't drift apart silently.

One over-aligned type survives. non_freezable_overaligned_vec_grows_via_oversized_path in tests/arena.rs still declares #[repr(align(32768))]. It's the one place where the alignment is the subject — it's what makes the element non-freezable — and it compiles because try_reserve never materialises the layout. That's an emergent property, not a guarantee, so there's now a comment naming it as the one fragile declaration left, to make a future failure diagnosable.

Verification

  • cargo test -p multitude --all-features passes on both the alignment-capped backend and an LLVM-backend toolchain.
  • cargo clippy -p multitude --all-features --all-targets -- -D warnings clean.
  • Formatted with the pinned nightly.
  • cargo spellcheck could not be run — the binary is broken in my environment (missing DLL). Please let CI cover it.

Not fixed here

A clean-checkout cargo build --workspace on the internal toolchain also fails in zeroize 1.9.0 (reached via fetch*rustlsaws-lc-rs) with codegen not yet implemented for Terminator_InlineAsm. Unrelated to alignment and not fixable in this repo. Worth tracking separately.

@codecov

codecov Bot commented Aug 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.0%. Comparing base (7fc5cd5) to head (e204649).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff            @@
##             main     #704    +/-   ##
========================================
  Coverage   100.0%   100.0%            
========================================
  Files         587      587            
  Lines       62997    63131   +134     
========================================
+ Hits        62997    63131   +134     
Flag Coverage Δ
linux 88.3% <100.0%> (-11.7%) ⬇️
linux-arm 88.3% <100.0%> (-11.7%) ⬇️
scheduled ?
windows 89.8% <100.0%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown

⚠️ Potential breaking changes detected

cargo semver-checks flagged the following on this PR. This is informational -- breaking changes between commits are expected; the major-version bump happens at release time, not on every PR.

multitude

     Cloning origin/main
    Building multitude v0.9.0 (current)
       Built [   9.868s] (current)
     Parsing multitude v0.9.0 (current)
error: unsupported rustdoc format v60 for file: /home/runner/work/oxidizer/oxidizer/target/semver-checks/local-multitude-0_9_0-default-1502d9aa811debfb/target/doc/multitude.json
(supported formats are v55, v56, v57)

rallocator

     Cloning origin/main
    Building rallocator v0.1.0 (current)
       Built [   3.391s] (current)
     Parsing rallocator v0.1.0 (current)
error: unsupported rustdoc format v60 for file: /home/runner/work/oxidizer/oxidizer/target/semver-checks/local-rallocator-0_1_0-default-f875cd4edfafef03/target/doc/rallocator.json
(supported formats are v55, v56, v57)

@AdomasBekeras
Adomas Bekeras (AdomasBekeras) marked this pull request as ready for review August 31, 2026 09:09
Copilot AI lite review requested due to automatic review settings August 31, 2026 09:09

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.

Pull request overview

This PR fixes multitude’s clean-checkout cargo test failures on codegen backends that cap type alignment (e.g., 8192) by making the arena’s alignment-rejection caps injectable under cfg(test), then rewriting over-alignment tests to exercise the same guard boundaries using smaller, backend-portable alignments.

Changes:

  • Add a test-only alignment cap knob on Arena and route all alignment guards through rejects_smart_ptr_align / rejects_chunk_align.
  • Move/replace over-alignment coverage from crates/multitude/tests/* into unit tests in src/ (including a new arena/align_guard_tests.rs) using capped_arena() and shared aligned helper types.
  • Remove the align_capped_backend cfg wiring from the workspace.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
crates/multitude/tests/zerocopy_integration.rs Removes backend-gated over-alignment integration tests now covered by in-crate unit tests.
crates/multitude/tests/pin_support.rs Removes the over-alignment test that depended on very large repr(align) values.
crates/multitude/tests/bytemuck_integration.rs Removes backend-gated over-alignment integration tests now covered by in-crate unit tests.
crates/multitude/tests/audit_repro.rs Removes backend-gated over-alignment regression coverage now covered by unit tests.
crates/multitude/tests/arena.rs Removes large-alignment test types/cases and documents the one remaining >8192 aligned type.
crates/multitude/src/zerocopy.rs Adds cfg(test) unit tests that drive alignment guards using capped_arena() helpers.
crates/multitude/src/tests_support.rs Adds shared test-only cap constants, capped_arena(), and aligned helper types for guard testing.
crates/multitude/src/error.rs Updates AllocError::is_alignment_too_large docs to avoid non-portable doctest alignment examples.
crates/multitude/src/bytemuck.rs Adds cfg(test) unit tests that drive alignment guards using capped_arena() helpers.
crates/multitude/src/arena/mod.rs Adds test-only alignment cap storage plus shared *_align_cap / rejects_* helpers.
crates/multitude/src/arena/alloc_value.rs Replaces duplicated const caps with arena-based guard helpers for sized smart-pointer paths.
crates/multitude/src/arena/alloc_unsized.rs Routes unsized/DST smart-pointer alignment checks through arena guard helpers.
crates/multitude/src/arena/alloc_slice_ref.rs Routes simple-reference slice alignment checks through arena chunk-cap helper.
crates/multitude/src/arena/alloc_slice_box.rs Routes boxed-slice alignment checks through arena smart-pointer-cap helper.
crates/multitude/src/arena/alloc_slice_arc.rs Routes arc/rc-slice alignment checks through arena smart-pointer-cap helper.
crates/multitude/src/arena/align_guard_tests.rs New unit-test suite asserting each entry point rejects alignments at/above the relevant cap.
crates/multitude/src/allocator_impl.rs Uses arena-derived smart-pointer cap for allocator alignment rejection + test updates.
Cargo.toml Removes align_capped_backend from the workspace check-cfg list.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread crates/multitude/src/tests_support.rs
Comment thread crates/multitude/src/tests_support.rs
Comment thread crates/multitude/src/arena/mod.rs
Comment thread crates/multitude/src/error.rs Outdated
Comment thread crates/multitude/src/zerocopy.rs Outdated
Comment thread crates/multitude/src/tests_support.rs Outdated

@martin-kolinek martin-kolinek left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖: Approved.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[Copilot speaking]

Published 12 findings. One finding follows up on an existing discussion thread.

See diagnostics
Diagnostic Value
Cache Miss

Comment thread crates/multitude/src/tests_support.rs
Comment thread crates/multitude/src/bytemuck.rs
Comment thread crates/multitude/src/bytemuck.rs
Comment thread crates/multitude/src/tests_support.rs
Comment thread crates/multitude/src/arena/align_guard_tests.rs
Comment thread crates/multitude/tests/arena.rs
Comment thread crates/multitude/tests/arena.rs
Comment thread crates/multitude/src/arena/mod.rs
Comment thread crates/multitude/src/arena/align_guard_tests.rs
Comment thread crates/multitude/src/tests_support.rs Outdated
@sandersaares

Copy link
Copy Markdown
Member

Thanks for doing this. I was worried about our previous attempts to solve the problem, good to see a new attempt. Third time is the charm!

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.

🟡 Changes recommended

The new test modules include unqualified align_of usage and a misleading set_align_cap panic message/expectation that should be corrected for clarity and consistency.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (3)

Previously missed (2) — in code that hasn't changed since the last review.

crates/multitude/src/arena/align_guard_tests.rs:32

  • This #[should_panic(expected = ...)] string should match Arena::set_align_cap’s panic message; if that message is updated to describe the cap <= CHUNK_ALIGN constraint, update this expected substring as well.
    crates/multitude/src/arena/mod.rs:597
  • The assertion currently checks cap <= CHUNK_ALIGN, but the panic message says the cap “may only be lowered” and explains a different failure mode. Updating the message to describe the actual constraint (cap must not exceed CHUNK_ALIGN) makes failures easier to diagnose.

crates/multitude/src/tests_support.rs:74

  • These assertions call align_of::<...>() without importing it in this module. Qualify the calls (or add an import within the changed region) so the const check doesn’t depend on an unshown use.
    assert!(align_of::<SmartPtrOverAligned>() == TEST_SMART_PTR_ALIGN);
    assert!(align_of::<SmartPtrOverAlignedDrop>() == TEST_SMART_PTR_ALIGN);
    assert!(align_of::<ChunkOverAligned>() == TEST_CHUNK_ALIGN);
  • Files reviewed: 18/18 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread crates/multitude/src/arena/align_guard_tests.rs
ADOMAS BEKERAS (from Dev Box) and others added 2 commits September 2, 2026 11:23
`cargo test` failed on a clean checkout. The arena rejects allocations
aligned at or above a cap: `CHUNK_ALIGN` is 64 KiB and the smart-pointer
cap is half of it, 32 KiB. Testing those guards meant declaring types with
`#[repr(align(32768))]` and larger, which some codegen backends refuse to
compile at all — the library built fine, but the `arena`, `audit_repro` and
`pin_support` test binaries and one doctest failed codegen.

The previous workaround gated those tests behind a cfg that nothing in-tree
sets, so the default build was the broken one, and it dropped the coverage
wholesale on any backend that set it.

Lower the cap to reach a legal alignment instead of raising a type's
alignment to reach the cap. `Arena` gains a `cfg(test)` alignment cap that
the guards read; tests set it to 8192 and drive both boundaries with 4096-
and 8192-aligned types, which every backend accepts. The affected tests move
in-crate as unit tests so they can reach it.

Also collapses three duplicate `MAX_SMART_PTR_ALIGN` definitions into one
accessor and removes the cfg entirely.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The zerocopy scalar tests used the chunk-cap fixture, but `try_alloc` and
`alloc` route through the smart-pointer guard. They could not detect that
guard loosening from 4 KiB to 8 KiB. Use the smart-pointer fixture, as the
bytemuck tests already did.

Every other fixture sits exactly at its threshold, so narrowing either
predicate from `>=` to `==` left the suite green. Add tests that lower the
cap further and drive the same fixtures from strictly above it, plus the
accepting counterpart below.

`set_align_cap` accepted 1, which makes the derived smart-pointer cap 0 and
rejects every alignment; assert a lower bound.

Also documents both alignment boundaries on `is_alignment_too_large`
instead of only the smart-pointer one, and drops a section marker left
empty by the test migration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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.

🔵 Needs a closer look

There are a couple of concrete correctness issues in the new/updated test modules (unqualified align_of usage and one misleading helper-type doc comment) that should be addressed before merging.

Review details

Suppressed comments (3)

crates/multitude/src/tests_support.rs:75

  • The const assertions use align_of without importing it; qualify these calls with core::mem::align_of (or import align_of) so the assertions are unambiguous.
const _: () = {
    assert!(align_of::<SmartPtrOverAligned>() == TEST_SMART_PTR_ALIGN);
    assert!(align_of::<SmartPtrOverAlignedDrop>() == TEST_SMART_PTR_ALIGN);
    assert!(align_of::<ChunkOverAligned>() == TEST_CHUNK_ALIGN);
};

crates/multitude/src/tests_support.rs:47

  • The doc comment says this type is "accepted by the simple-reference paths", but the scalar &mut T entry points (e.g. try_alloc::<T>()) are described elsewhere as using the smart-pointer cap. Consider clarifying that the "accepted" behavior refers specifically to the simple-reference slice entry points, which use the chunk cap.
/// Aligned exactly at the smart-pointer cap: rejected by every
/// smart-pointer entry point, accepted by the simple-reference paths.

crates/multitude/src/arena/align_guard_tests.rs:19

  • This module uses align_of::<T>() in multiple tests, but doesn’t import or qualify align_of. Add use core::mem::align_of; (or fully qualify each call) to keep the tests self-contained.
use crate::Arena;
use crate::internal::constants::{CHUNK_ALIGN, max_smart_ptr_align};
use crate::tests_support::{ChunkOverAligned, SmartPtrOverAligned, SmartPtrOverAlignedDrop, TEST_CHUNK_ALIGN, capped_arena};
  • Files reviewed: 18/18 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

…ures

The hand-written impls defined only_derive_is_allowed_to_implement_this_trait
and is_bit_valid, which zerocopy reserves for derive-generated code and may
change in a compatible release. Both fixtures are repr(C) wrappers over a u8,
so the derives prove the same contracts through the supported path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 3, 2026 09:40

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.

🟢 Approval recommended

The change keeps production behavior intact while making alignment-guard coverage portable; remaining feedback is limited to a small doc-comment wording nit in test support helpers.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

crates/multitude/src/tests_support.rs:66

  • The doc comment for ChunkOverAligned says “no chunk can satisfy it”, but under capped_arena() this is a test-only lowered cap used to drive the guard; the underlying chunks are still CHUNK_ALIGN-aligned, so the rejection is by design of the guard rather than a hard physical impossibility. Rewording avoids misleading future readers about what the helper is modeling.
  • Files reviewed: 19/19 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@AdomasBekeras
Adomas Bekeras (AdomasBekeras) merged commit e293734 into main Sep 3, 2026
52 checks passed
@AdomasBekeras
Adomas Bekeras (AdomasBekeras) deleted the u/abekeras/multitude-align-cap branch September 3, 2026 13:24
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.

5 participants