Skip to content

feat(interpreter): give memory blocks with a physical address space - #1454

Closed
tobiasgrosser wants to merge 1 commit into
mainfrom
tobias/memory_model_blocks
Closed

tobiasgrosser wants to merge 1 commit into
mainfrom
tobias/memory_model_blocks

Conversation

@tobiasgrosser

@tobiasgrosser tobiasgrosser commented Sep 12, 2026 •

Copy link
Copy Markdown
Collaborator

Memory was one flat byte array, so a pointer could walk from one allocation into its neighbour and nothing distinguished allocations. Memory is now an array of objects, one per allocation, and a pointer is an object index with a 64-bit offset. Loads and stores are checked against their own object by MemoryState.checkAccess, the one place where every later condition on an access is added, so leaving the object is UB.

Every object has a base address assigned by a bump allocator that honours the allocation's declared alignment, leaves a guard byte between objects, and starts past a 64 KiB arena that machine code may address directly. A pointer converts to an integer as base plus offset, and an integer converts back by binary search over the bases, so bitcasts, unrealized casts to registers and pointers stored in memory keep their meaning. RISC-V accesses decode the register value the same way and grow the object they land in up to the next object's base, which keeps machine code that addresses memory freely working.

Memory refinement lifts from the flat array to the objects: the same number of objects, each at the same address and refined bytewise.

@tobiasgrosser
tobiasgrosser force-pushed the tobias/memory_model_blocks branch 2 times, most recently from 1d1a673 to 58218c3 Compare September 17, 2026 05:23
@tobiasgrosser
tobiasgrosser marked this pull request as draft September 17, 2026 05:23
Memory was one flat byte array, so a pointer could walk from one
allocation into its neighbour and nothing distinguished allocations.
Memory is now an array of objects, one per allocation, and a pointer
is an object index with a 64-bit offset. Loads and stores are checked
against their own object by `MemoryState.checkAccess`, which is the
one place every later condition on an access is added.

Every object has a base address, assigned by a bump allocator that
honours the alignment its allocation declares, leaves a guard byte
between objects, and starts past a 64 KiB arena that machine code may
address directly. A pointer converts to an integer as base plus
offset, and an integer converts back by binary search over the bases,
so bitcasts, unrealized casts to registers and pointers stored in
memory keep their meaning. RISC-V accesses decode the register value
the same way and grow the object they land in up to the next object's
base, which keeps machine code that addresses memory freely working.

Memory refinement lifts from the flat array to the objects: the same
number of objects, each at the same address and refined bytewise.

The fuzzing harness gains the null-dereference knob this makes correct.
Deliberately undefined accesses stay off until the next change adds
alignment, since before it the two tools would disagree on misaligned
accesses for a reason unrelated to bounds.
@tobiasgrosser
tobiasgrosser force-pushed the tobias/memory_model_blocks branch from 58218c3 to 9d71151 Compare September 17, 2026 05:46
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