Skip to content

Verify the hunk CRC32 that v3/v4 map entries carry - #187

Merged
rtissera merged 1 commit into
masterfrom
legacy-hunk-crc
Sep 10, 2026
Merged

Verify the hunk CRC32 that v3/v4 map entries carry#187
rtissera merged 1 commit into
masterfrom
legacy-hunk-crc

Conversation

@rtissera

@rtissera rtissera commented Sep 9, 2026

Copy link
Copy Markdown
Owner

CHDv3/v4 map entries hold a CRC32 of the decoded hunk plus a flag to opt out of it. map_extract() has always parsed the field into entry->crc, and nothing ever read it, so on the pre-v5 path a hunk that decompressed cleanly to the wrong bytes was handed back as valid data. The v5 path has checked its CRC16 all along. MAME rejects the same files with a decompression error.

The gap also undercut the reasoning behind DR_FLAC_NO_CRC: dr_flac's own frame CRC is dropped because the hunk CRC is said to cover the same data, and CHDCOMPRESSION_AV on a v3/v4 file routes through the same libchdr_flac.c with no hunk CRC being checked at all.

The check mirrors MAME: COMPRESSED, UNCOMPRESSED and MINI entries, the 0x10 opt-out honoured, self- and parent-referenced entries covered when the hunk they point at is read. v1/v2 entries have no room for a CRC and map_extract_old() already sets the opt-out flag for them.

Testing

tests/corpus/mklegacy.py builds the v3/v4 layouts directly, since chdman only writes v5. It emits an intact pair, two files whose stored hunk no longer matches the CRC the map advertises, and one that sets the opt-out flag on that same hunk. All ten cases agree with MAME 0.264 — the intact and opt-out files verify, the other two are refused. tests/legacy_decode.c asserts that, and fails on master with four got "no error", want "decompression error".

Also checked against three real CHDv4 images (76, 75 and 1817 hunks), which decode identically to chdman extractraw, and against the v5 corpus plus a large real disc, whose output is unchanged. Built and run under the default configuration, CHDR_LOWRAM_TARGET=ON, WITH_SYSTEM_ZLIB=ON and CHDR_VERIFY_BLOCK_CRC=OFF.

The fixtures need only a Python interpreter, unlike the CHDv5 corpus, so the CMake job builds them; the test skips itself where they are absent, as parent-decode does.

Not covered: no v3/v4 AVHuff fixture. The check sits after decompress() regardless of codec, so AV is covered by construction, but nothing exercises it.

Cost

About 1.1 KB of text on RV32 at -Os, nearly all of it mz_crc32's table. Nothing extra against a shared system zlib, and nothing when VERIFY_BLOCK_CRC is off. mz_crc32 joins the ESP ROM rename list, since libchdr's own sources now name it.

🤖 Generated with Claude Code

Those entries hold a CRC32 of the decoded hunk and a flag to opt out of it.
libchdr parsed the field and never used it, so on the pre-v5 path a hunk that
decompressed cleanly to the wrong bytes was returned as valid data - the v5
path has checked its CRC16 all along. MAME rejects the same files with a
decompression error.

That gap also undercut the reasoning behind DR_FLAC_NO_CRC: dr_flac's own
frame CRC is dropped because the hunk CRC is said to cover the same data, and
on a v3/v4 AV hunk no hunk CRC was being checked at all.

Covered by tests/legacy_decode.c against fixtures from tests/corpus/mklegacy.py,
which builds the older layouts directly because chdman only writes v5. Every
fixture agrees with MAME 0.264: the intact pair verifies, the two whose stored
hunk no longer matches the advertised CRC are refused, and the one setting the
opt-out flag reads again. Checked against real CHDv4 images too. The fixtures
need only a Python interpreter, so the CMake job builds them; the test skips
itself where they are absent, as parent-decode does.

Costs about 1.1 KB of text on RV32 with bundled miniz, nearly all of it
mz_crc32's table; nothing extra against a shared system zlib, and nothing when
VERIFY_BLOCK_CRC is off.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rtissera
rtissera merged commit 799938e into master Sep 10, 2026
37 checks passed
@rtissera
rtissera deleted the legacy-hunk-crc branch September 10, 2026 20:43
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