Skip to content

Load minidumps whose writer left out a stream - #725

Open
zardus wants to merge 1 commit into
masterfrom
feature/fix-cle-minidump-streams
Open

Load minidumps whose writer left out a stream#725
zardus wants to merge 1 commit into
masterfrom
feature/fix-cle-minidump-streams

Conversation

@zardus

@zardus zardus commented Aug 10, 2026

Copy link
Copy Markdown
Member

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

A minidump's directory lists only the streams its writer emitted. The backend reads
four of them and could not cope when one was absent: a dump with no memory list was
rejected outright, and one with no module or thread list raised an AttributeError
from inside a loop.

Those lists now read as empty when the stream is absent, so such a dump loads with
no memory, no sections or no threads. MinidumpMissingStreamError, which a missing
SystemInfoStream still raises, derives from CLEError and passes its explanation to
the base class rather than stashing it on an attribute that str() never reached.

The regression tests take a real dump and strike a stream out of its directory. One
of the two dumps they use is a 64-bit Windows minidump added by angr/binaries#176,
so the checks here stay red until that merges. A module whose image the dump did not
capture is still rejected a few lines below; #715 reworks the same function for that,
so whichever of the two lands second needs a rebase.

Validation: #725 (comment)

@zardus

zardus commented Aug 10, 2026

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Validation record for head 9f414421bcfb9c3a7d738514635748857e672371 against baseline b58ea02a446106647cdaae32bdf91b7062404cc1. Python 3.12.13, minidump 0.0.24, commands run from the cle checkout with angr/binaries#176 checked out.

  • Regression: python -m pytest tests/test_minidump.py with only cle/backends/minidump/__init__.py reverted to the baseline — 4 failed, 1 passed; with it restored, 5 passed. test_minidump_without_module_list and test_minidump_without_captured_memory fail with AttributeError: 'NoneType' object has no attribute 'modules' at cle/backends/minidump/__init__.py:41, the wow64 lookup on the architecture path; test_minidump_without_thread_list fails with AttributeError: 'NoneType' object has no attribute 'threads' at line 78; test_minidump_without_system_info fails because the MinidumpMissingStreamError raised at line 38 is not a CLEError and pytest.raises(cle.CLEError) does not match it.
  • Focused: python -m pytest tests/test_minidump.py — 5 passed, 0 skipped.
  • Full suite: python -m pytest tests/ — 206 passed, 9 skipped.
  • Lint/type: every configured pre-commit hook passes and rewrites nothing; pylint per changed file 9.81 -> 9.90 for cle/backends/minidump/__init__.py and 10.00 -> 10.00 for tests/test_minidump.py; pyright badness 0.1596 -> 0.1508 and 0.0 -> 0.0, both against the baseline.

The tests get a dump with a missing stream by reading a real one and marking that stream's directory entry UnusedStream, which is what a writer that reserved an entry for a stream it did not collect leaves behind. The 32-bit case uses the existing jusched_x86.dmp; the 64-bit case, needed because the module list is what decides between AMD64 and WoW64 x86, uses the Breakpad minidump tiny-exe-with-cet-xsave.dmp added by angr/binaries#176. The checks on this PR stay red until that merges, since CI checks out binaries master.

Origin of the change: a corpus sweep loaded 5,250 minidumps through cle.Loader. Of the 250 labelled real-world, 18 failed and 16 of those failed inside Minidump.__init__ — 8 with no memory list (smallest sha256 e198aef56fbc85f9ddfb91fe360e1aea109e80d18f58558afbf0162ebff47d38, 912 bytes, x86, carrying SystemInfo, ThreadList, ModuleList and Exception streams), and among the rest 6 with mdf.modules is None and 3 with mdf.threads is None.

Caveats:

  • Most of those 8 dumps read as authored rather than captured: one module timestamp across every module, sequential thread ids, a header TimeDateStamp of 2. The case rests on the file format and on the backend already handling absent data elsewhere, not on the count.
  • Those 8 still fail on this branch, at the module loop Load partial-memory minidumps #715 replaces, so no single file among them can stand as the regression test.
  • The sweep itself was run on cle 638301bbf02865e53394e6643e1eb6e66083ee94, not on the head above; the failure modes were re-confirmed against the baseline with the tests in this PR.
  • The 9 skips are pre-existing TODO skips in tests/test_macho_bindinghelper.py. No minidump test is skipped.

@angr-bot

Copy link
Copy Markdown
Member

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

A minidump's stream directory lists only the streams its writer chose to emit;
the header and the directory are the only mandatory parts of the file. The
backend read four of them and handled a missing one three different ways: the
memory list was required, the module and thread lists were dereferenced
unguarded and produced an AttributeError from the middle of a loop, and only the
system information stream raised a considered error.

A dump with no memory list now loads with no memory, and one with no module or
thread list loads with no sections or with no threads. The module list is read on
the architecture path as well, where a 64-bit dump without one failed before any
of that.

MinidumpMissingStreamError, which the missing system information stream still
raises when no architecture was passed either, now derives from CLEError and
hands its explanation to the base class. It was invisible to except CLEError, and
str() on it was empty because the explanation only ever reached an attribute.

A module whose image the dump did not capture is still rejected twenty lines
further down; #715 covers that half.
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