Skip to content

Cover object placement in an address space narrower than a granule - #717

Open
zardus wants to merge 1 commit into
masterfrom
feature/pcode-narrow
Open

Cover object placement in an address space narrower than a granule#717
zardus wants to merge 1 commit into
masterfrom
feature/pcode-narrow

Conversation

@zardus

@zardus zardus commented Aug 9, 2026

Copy link
Copy Markdown
Member

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

This PR no longer changes cle/loader.py. #735 fixed the bug it was opened for; only the coverage is left.

A 16-bit p-code architecture has a 64 KiB address space, smaller than the default 1 MiB rebase granularity, so Loader._find_safe_rebase_addr aligned the extern object past the end of memory and loading a z80 blob failed with Ran out of room in address space. The original fix here was to use a one-byte alignment below 32 bits.

#735 has since landed and fixes that generally: placement searches the free space, and the granularity gives way to 0x1000 and then to one byte when a gap is too tight for it. A narrow address space is just the extreme case of the gap that PR is about, so its ladder already covers this one and the one-byte special case for arch.bits < 32 would only change which working address gets picked. It is dropped rather than rebased.

What is missing is a guard. Nothing in the suite loads an architecture narrower than 32 bits, and every test #735 added still passes when the one-byte step is removed from the ladder, so the step that makes narrow architectures work is untested. Two tests in tests/test_rebase.py cover it:

  • test_address_space_narrower_than_the_granularity loads a z80 blob and checks that the extern object lands behind it, inside the address space, and is readable through Loader.memory. This is the original reproducer.
  • test_narrow_address_space_holds_more_objects_than_granules then loads 24 more objects into the same 64 KiB, which is fewer than one granule wide. It fails with Ran out of room in address space if the ladder stops at 0x1000.

Validation: #717 (comment)

Related: angr/archinfo#363, angr/angr#6793. angr/angr#6793 passes rebase_granularity=0x100 to load a 16-bit shellcode; with #735 in place the default granularity works, so that workaround can go.

@zardus

zardus commented Aug 9, 2026

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Validation record for head 27f641b0045cde23890bc27679d461de753c7e19 against baseline 45c6509c753d07f740099035cd41f7f473dc6f31, which is master with #735 in it. This replaces the record for 8a792e9; the rebase changed what there is to validate.

Rebase: the conflict was in Loader._find_safe_rebase_addr, which #735 rewrote whole. Resolved by keeping master's implementation and dropping this branch's alignment = 1 if arch.bits < 32 hack, because master's alignment ladder already ends at one byte and so already places every object this branch was placing. What survives is the coverage.

  • Reproducer: cle.Loader(io.BytesIO(b"\0" * 0x1500), main_opts={"backend": "blob", "base_addr": 0, "entry_point": 0, "arch": archinfo.ArchPcode("z80:LE:16:default")})CLEOperationError: Ran out of room in address space on b58ea02, this branch's old base. On 45c6509 it loads, with the extern object at 0x2000.
  • Regression against the old base: both new tests fail on b58ea02 with CLEOperationError: Ran out of room in address space.
  • Regression against the current base: there is no production change left to withhold, so the tests were checked against the merged code they guard instead. Removing the one-byte step from the ladder in cle/loader.py (alignments += [a for a in (0x1000,) if a < self._rebase_granularity]) fails test_narrow_address_space_holds_more_objects_than_granules with the same error, while every test Place rebased objects in the free space, not one granule at a time #735 added still passes — that step has no other guard. Cutting the ladder back to the granularity alone fails all five tests in tests/test_rebase.py.
  • Focused suites: python -m pytest tests/test_rebase.py tests/test_blob.py tests/test_extern.py tests/test_elfcore.py tests/test_overlap.py tests/test_preload.py — 12 passed
  • Full suite: python -m pytest tests — 227 passed, 9 skipped
  • Lint/type: pylint and pyright, scored per changed file against merge base 45c6509 the way the hosted Lint and Typecheck jobs score them — tests/test_rebase.py 10.00 -> 10.00 and badness 0.0 -> 0.0
  • Hooks: pre-commit run --all-files — every hook passes and leaves the tree unchanged
  • Test inputs: check-test-inputs.py --repository cle passes. The blob is raw zero bytes with no header, not an assembled container.
  • Downstream: Support narrow p-code pointer widths angr#6793 loads a 16-bit shellcode with rebase_granularity=0x100 because the default did not fit. On master the default works — the extern object lands at 0x1000 — so that argument can be dropped there.
  • Environment: Python 3.12.13, pytest 9.1.1, pypcode 4.0.1

Caveats: the tests need pypcode, which is in cle's testing dependency group, and skip without it. The z80 blob only exercises a 16-bit address space; 24-bit p-code architectures share the code path but are not covered here.

@angr-bot

angr-bot commented Aug 9, 2026

Copy link
Copy Markdown
Member

Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/cle_717

A 16-bit p-code architecture has an address space of 64 KiB, smaller than the
default 1 MiB rebase granularity. Placing an object by aligning up to the
granularity therefore jumped past the end of memory, and loading a z80 blob
failed with "Ran out of room in address space" as soon as the extern object
needed an address.

Searching the free space instead, and treating the granularity as a preference
that gives way to a finer alignment, already fixes this, but nothing in the
suite loads an architecture narrower than 32 bits, so the rule that makes it
work is unguarded. Load a z80 blob and check that the extern object lands
inside the address space and is reachable, then fill that space with more
objects than it has granules.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@zardus
zardus force-pushed the feature/pcode-narrow branch from 8a792e9 to 27f641b Compare August 11, 2026 00:20
@zardus zardus changed the title Pack extern objects on narrow p-code architectures Cover object placement in an address space narrower than a granule Aug 11, 2026
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.

2 participants