test(multitude): drive alignment guards through an injectable cap - #704
Draft
Adomas Bekeras (AdomasBekeras) wants to merge 1 commit into
Draft
test(multitude): drive alignment guards through an injectable cap#704Adomas Bekeras (AdomasBekeras) wants to merge 1 commit into
Adomas Bekeras (AdomasBekeras) wants to merge 1 commit into
Conversation
`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>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #704 +/- ##
========================================
Coverage 100.0% 100.0%
========================================
Files 560 560
Lines 60859 60982 +123
========================================
+ Hits 60859 60982 +123
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
ADO 7707893:
cargo testfails on a clean checkout.The arena refuses allocations whose alignment reaches a cap.
CHUNK_ALIGNis 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 renamedalign_capped_backend), with the flag set by an out-of-tree CI pipeline. Three problems:RUSTFLAGS. SettingRUSTFLAGSwould 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.
Arenagets a#[cfg(test)]alignment cap that the guards read: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:
MAX_SMART_PTR_ALIGNconstants collapse into one accessor. All nine guard sites now route throughrejects_smart_ptr_align/rejects_chunk_align.tests/into#[cfg(test)]modules insrc/(arena/align_guard_tests.rs,bytemuck.rs,zerocopy.rs) so they can reach the knob.align_capped_backendcfg is deleted from the workspaceCargo.toml.Coverage
Nothing was dropped. Two additions beyond parity:
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_aligntofalsefails 39 tests, forcingrejects_chunk_aligntofalsefails 9.Things worth a reviewer's attention
The guards are no longer
const { }. They wereif 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 undercfg(not(test))that accessor returns a literal andalign_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 theconst { }form undercfg(not(test))— happy to add it if you'd rather have the certainty.buffer_freezablestill reads the real cap. It's used insideconst { }on theVechot path, so making it cap-aware would put a runtime branch there. The consequence is that a capped arena is not a faithful model forVec/Stringgrowth and freeze tests — documented oncapped_arena()andset_align_cap(), andset_align_capnow asserts the cap can only be lowered. A new lib test asserts the arena's default caps equalCHUNK_ALIGNandmax_smart_ptr_align(), so the two sources can't drift apart silently.One over-aligned type survives.
non_freezable_overaligned_vec_grows_via_oversized_pathintests/arena.rsstill 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 becausetry_reservenever 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-featurespasses on both the alignment-capped backend and an LLVM-backend toolchain.cargo clippy -p multitude --all-features --all-targets -- -D warningsclean.cargo spellcheckcould 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 --workspaceon the internal toolchain also fails inzeroize1.9.0 (reached viafetch*→rustls→aws-lc-rs) withcodegen not yet implemented for Terminator_InlineAsm. Unrelated to alignment and not fixable in this repo. Worth tracking separately.