Skip to content

Add a reproducible MinGW PE EH-frame fixture - #196

Open
zardus wants to merge 1 commit into
masterfrom
feature/pe-eh-frame-function-boundaries
Open

zardus wants to merge 1 commit into
masterfrom
feature/pe-eh-frame-function-boundaries

Conversation

@zardus

@zardus zardus commented Aug 26, 2026 •

Copy link
Copy Markdown
Member

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Problem

The coordinated CLE and angr regressions need a real PE whose wrapper at 0x401006 already owns the bytes of an unnamed six-byte function at 0x40100a. Binaries master has no tests/x86/windows/eh-frame-occupied-start.exe, so that GNU .eh_frame boundary cannot be exercised.

Root cause

Ordinary PE fixtures do not combine an occupied CFG range, no symbol for the inner target, and a GNU FDE that is the only metadata identifying the target as a function.

Fix

Add a source-built i386 MinGW PE together with its complete assembly source, BSD-2-Clause license, and deterministic build recipe. The sole GNU FDE starts at 0x40100a; the committed PE is timestamp-free and stripped of COFF symbols.

Testing

Exact-head readback reports PE32/i386, image base 0x400000, entry RVA 0x1000, zero timestamp, zero COFF symbols, and SHA-256 1cd9ae0b00d1c4cde4cd95579cf9aae14104d9f99031aab77b0116e4e9aa7c8a. Two documented GCC 15.3.0/Binutils 2.46 builds were byte-identical. Validation: #196 (comment)

session: sharpen

@zardus

zardus commented Aug 26, 2026 •

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Validation record for head dc407b8b488e184bb876f0a5f327aa29e26a90b9 against baseline 003e82a2bfa641530924055695b36cec8af483ab.

Re-keyed after this branch was rebased onto binaries master. The head moved and the patch did not: git range-diff reports the commit unchanged (=), and git diff --raw over the merge-base range at the old head ffc011f3de013f23711ded6a05a48df5ea2f726f and at this head is identical — the same four added paths with the same blob OIDs (8fb75cf, 52838a1, d622511, 8ed6234). The figures below therefore describe the same patch on a new base.

  • Exact PR shape: the own-merge-base/head scan verifies the added compiler-produced fixture and its load-bearing format/address shape: PE32 i386 executable; .eh_frame carries an FDE for 0x40100a of size 6.
  • Provenance/reproduction: two fresh GCC 15.3.0 / GNU Binutils 2.46 builds with zero timestamp was rerun twice in separate fresh directories; both outputs byte-compare with each other and with the committed bytes.
  • Input/native identity: committed SHA-256 1cd9ae0b00d1c4cde4cd95579cf9aae14104d9f99031aab77b0116e4e9aa7c8a; angr rustylib mapped from the isolated consumer worktrees on both arms, SHA-256 d02d517eceb3e81de4a96330678444f0faf2c3b065953f0cb8e1813583a0380f; CLE is Python-only here.
  • Real consumer: PE: Separate GNU EH-frame hints from unwind entries cle#789 and CFGFast: Preserve authoritative function starts during reconstruction angr#6948 at baseline cle a4fb8003198229d33c84df6a82f749729232fd31; angr b0feae57a9e401292e03a6f9ffbd4b388d172bf5 and head cle 89ae8c133b4c9c2ba2921429d3504ac2a0624407; angr 1b99ccbe452ed556e79177c41e624093f26ad8ed loaded the committed fixture and produced the complete output linked in this PR's output record.
  • Repeat/order control: A/B/B/A, ASLR disabled and PYTHONHASHSEED=0 for the generated angr text; the CLE hint record is a static structural capture; same-arm output is byte-identical and the cross-arm delta is nonempty.
  • Local scope: this recapture validates fixture bytes, fixture shape, and the actual consumer path only. It does not claim a fresh full-workspace gate.
  • Hosted status: angr/binaries runs no CI of its own — it has no .github/workflows and /commits/dc407b8b488e184bb876f0a5f327aa29e26a90b9/check-runs returns total_count: 0 — so there is nothing to run at this head. The hosted result for this fixture is on the consumer: PE: Separate GNU EH-frame hints from unwind entries cle#789 run 33993326641, which resolves angr/binaries at refs/pull/196/head. On the pre-rebase head that run's Test macos-15 reported 3 failed, 260 passed (all three CLEFileNotFoundError on Mach-O fixtures added to binaries master after this branch was cut); on this head it reports 263 passed, 9 skipped, and Test (Pyodide) and Test windows-2022 are green on the same attempt.

@zardus

zardus commented Aug 28, 2026 •

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Exact fixture-shape and consumer-output record for #196.

  • Fixture comparison: own merge base 003e82a2bfa641530924055695b36cec8af483ab versus exact head dc407b8b488e184bb876f0a5f327aa29e26a90b9. Re-keyed after a rebase onto binaries master: git range-diff reports the commit unchanged (=), and git diff --raw over the merge-base range is identical at the old head ffc011f3de013f23711ded6a05a48df5ea2f726f and at this one — the same four added paths with the same blob OIDs — so the bytes below are the bytes at this head. The target path/shape is absent on the merge base and present on the head. PE32 i386 executable; .eh_frame carries an FDE for 0x40100a of size 6.
  • Fixture identity: SHA-256 1cd9ae0b00d1c4cde4cd95579cf9aae14104d9f99031aab77b0116e4e9aa7c8a; source provenance: the adjacent complete assembly source at this exact binaries head (SHA-256 1b2246525aca4cddbb510b4836116cf4aa78d8d4722ff4cb58caf7e029dbd99b). The complete readelf/objdump scan is retained with the exact script. The recorded recipe (two fresh GCC 15.3.0 / GNU Binutils 2.46 builds with zero timestamp) was rerun twice in fresh directories; both runs are byte-identical to the committed fixture.
  • Actual consumer: PE: Separate GNU EH-frame hints from unwind entries cle#789 and CFGFast: Preserve authoritative function starts during reconstruction angr#6948, exact baseline cle a4fb8003198229d33c84df6a82f749729232fd31; angr b0feae57a9e401292e03a6f9ffbd4b388d172bf5 versus exact head cle 89ae8c133b4c9c2ba2921429d3504ac2a0624407; angr 1b99ccbe452ed556e79177c41e624093f26ad8ed; target CLE function hints and angr function 0x40100a; configuration CLE load plus full / SAILR.
  • Native identity: angr rustylib mapped from the isolated consumer worktrees on both arms, SHA-256 d02d517eceb3e81de4a96330678444f0faf2c3b065953f0cb8e1813583a0380f; CLE is Python-only here.
  • Determinism: fresh A/B/B/A order, ASLR disabled and PYTHONHASHSEED=0 for the generated angr text; the CLE hint record is a static structural capture; each same-arm pair is byte-identical and every base/head comparison below is nonempty. Absolute checkout prefixes in tracebacks are normalized to <workspace> for publication; raw output is retained unchanged.

Before — cle

Exact consumer baseline
sections=['.edata', '.eh_frame', '.idata', '.rdata', '.text']
function_hints=[]

After — cle

Exact consumer head
sections=['.edata', '.eh_frame', '.idata', '.rdata', '.text']
function_hints=[(4198410, 6, '0')]

Before — angr

Exact consumer baseline
Traceback (most recent call last):
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-medium/capture_decompile.py", line 125, in <module>
    function = cfg.functions[int(args.function_address, 0)]
               ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/fixture-output-recapture/consumers/worktrees/6948-base/angr/knowledge_plugins/functions/function_manager.py", line 1175, in __getitem__
    raise KeyError(k)
KeyError: 4198410

After — angr

Exact consumer head
unsigned int sub_40100a(void)
{
    return 42;
}

@zardus
zardus force-pushed the feature/pe-eh-frame-function-boundaries branch 2 times, most recently from ffc011f to c7383da Compare August 29, 2026 19:22
@zardus

zardus commented Aug 30, 2026

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Rebased onto binaries master; git range-diff reports the commit unchanged (=), so this is a base move only.

The reason: angr/cle#789 pins this pull request with a sync: line, and CI resolves a sibling at refs/pull/N/head rather than merged with master. At three commits behind, this tree was missing tests/i386/deep_sp_chain, which tests/analyses/decompiler/test_block_simplifier.py loads. That test is not yet in the angr tree those shards resolve, so the failure was dormant rather than live — it would have appeared the moment the resolved angr tree gained it, on a diff that has nothing to do with it.

session: sharpen

@zardus
zardus force-pushed the feature/pe-eh-frame-function-boundaries branch 2 times, most recently from 1ec1f03 to dc407b8 Compare September 5, 2026 21:43
@zardus
zardus force-pushed the feature/pe-eh-frame-function-boundaries branch from dc407b8 to cc1ff31 Compare September 30, 2026 14:55
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