Skip to content

bugc: give each memory-homed scalar its own word, stop byte-packing#272

Merged
gnidan merged 1 commit into
mainfrom
compiler-subword-unpack
Jul 18, 2026
Merged

bugc: give each memory-homed scalar its own word, stop byte-packing#272
gnidan merged 1 commit into
mainfrom
compiler-subword-unpack

Conversation

@gnidan

@gnidan gnidan commented Jul 16, 2026

Copy link
Copy Markdown
Member

The frame/static memory allocator byte-packed several sub-word scalars (address, bool, intN/uintN, bytesN) into one 32-byte word. But a memory-homed value is read and written with full-word MLOAD/MSTORE, so two sub-word scalars sharing a word clobber each other: storing one writes the whole word and overwrites the other's bytes.

This is a real runtime corruption, not just a debug-info artifact. Confirmed with an execution trace: for f(ad: address, flag: bool, …) where ad and flag byte-pack into one word, at a live-frame step ad reads back 0x000…000 instead of its argument 0xaA — the bool's full-word MSTORE overwrote the address's low bytes. A program that read the address after the bool store would observe zero.

Fix

Allocate one full 32-byte word per memory-homed value instead of byte-packing sub-word scalars. A word is the EVM's natural load/store granularity and memory is not scarce at O0, so the only cost is a slightly larger frame. Each scalar now solely occupies its word, so its full-word store cannot touch a neighbor.

Test

Adds a memory-planning test asserting that several sub-word scalars (address, bool, uint8, bytes4) each receive a distinct, word-aligned slot. It fails against the old packing (all four collapse into one word) and passes with the fix.

The frame/static memory allocator byte-packed several sub-word scalars
(address, bool, intN/uintN, bytesN) into one 32-byte word. But a
memory-homed value is read and written with full-word MLOAD/MSTORE, so
two sub-word scalars sharing a word clobber each other: storing one
writes the whole word and overwrites the other's bytes. This is a real
runtime corruption — e.g. an address packed with a bool reads back zero
once the bool is stored, because the bool's full-word store overwrites
the address's low bytes.

Allocate one full 32-byte word per memory-homed value instead. A word is
the EVM's natural load/store granularity and memory is not scarce at O0,
so the only cost is a slightly larger frame. Each scalar now solely
occupies its word, so its full-word store cannot touch a neighbor.

Adds a memory-planning test asserting that several sub-word scalars each
receive a distinct, word-aligned slot (it fails against the old packing,
where all four collapsed into one word).
@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-07-18 02:53 UTC

@gnidan
gnidan merged commit 8a8f988 into main Jul 18, 2026
4 of 6 checks passed
@gnidan
gnidan deleted the compiler-subword-unpack branch July 18, 2026 02:48
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.

1 participant