Repository navigation
Harden PHF container, add CRC-32, byte-level spec, tests and CI - #1
Merged
Merged
Conversation
Bug fixes - Header flags: the MED bit was never set ((2 << 1) instead of (1 << 1)); RGB files now carry 0x0E and RGBA 0x0F. - phf_decode_memory: `phf_size < 20 + payload_size` could wrap on 32-bit targets (WASM) and let the decoder read past the buffer; rewritten as a subtraction. phf_read_file validates the untrusted header before sizing its allocation, and the PHF header must agree with the NHF3 packet. - Add an optional CRC-32 trailer (flag bit 3) verified before decoding. Corrupted files previously decoded "successfully" ~15% of the time in fuzzing; with the CRC none do. Files without the flag still decode, and older decoders ignore the trailer. - Remove OpenMP data races on shared error flags. - Web viewer: check _malloc results, validate dimensions/channels, map error codes to messages, bump cache-busting version to 1.0.2. - CLI: load libphf on Windows/macOS/Linux (or PHF_LIB), support grayscale, reject 16-bit input instead of corrupting it, `info` now decodes and verifies the CRC, proper exit codes. API - Named PHF_FLAG_*, PHF_ERR_* and limit constants in phf.h; error codes no longer overlap with the internal NHF3 codes. Docs - SPEC.md rewritten byte by byte (NHF3 packet, plane order, prediction borders, code tables, RLE, CRC, limits); validated by an independent decoder written only from the spec. - README/MANIFESTO: drop claims the code does not implement (Package-Merge, AVX2, ESP32), recompute streaming latencies from the measured throughputs, note benchmark conditions, document build/test/bench. - Fix stale comments (fast-table width, table format, ignored `delta`). Tooling - CMakeLists.txt (shared/static, optional OpenMP, sanitizers), tests/test_phf.c (470 checks), bench/bench.py (PHF vs PNG vs WebP-LL, bit-exact checks), GitHub Actions CI for Linux/macOS/Windows. - build.bat locates MSVC via vswhere; WASM builds write to apps/web/; add build_wasm.sh. Stop tracking generated binaries in libphf/. - sample.phf re-encoded with correct flags and CRC (pixels identical). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
libphf
added a commit
that referenced
this pull request
Oct 28, 2026
Harden PHF container, add CRC-32, byte-level spec, tests and CI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the issues found in a full review of libphf: two container bugs (one of them a possible out-of-bounds read on 32-bit/WASM), silent acceptance of corrupted files, OpenMP data races, CLI/web robustness gaps, and documentation that didn't match the code. Adds a byte-level spec, a test suite, a reproducible benchmark and CI.
Bug fixes
(2 << 1)instead of(1 << 1), so RGB files got flags0x040x0E(RGB) /0x0F(RGBA)phf_size < 20 + payload_sizewraps on 32-bit targets (WASM), letting the decoder read past the input bufferphf_read_filealso validates the untrusted header before sizing its allocation, and the PHF header must agree with the inner NHF3 packetomp parallel for_mallocresultsinfoprinted a hardcoded "100% Bit-Exact"PHF_LIB), converts grayscale to RGB, rejects 16-bit input,infoactually decodes and verifies the CRC, returns proper exit codesCompatibility
phf.wasm, read new files fine and just ignore the 4-byte trailer.PHF_ERR_*constants inphf.hand no longer collide with internal NHF3 codes.-1…-6keep their documented meaning (-5truncated,-6stride), and new codes were added (-7corrupt,-8checksum,-9memory,-10I/O). Callers that compared the old overlapping raw numbers should switch to the constants.Documentation
R−G, G, B−G, A), prediction border rules, canonical code tables, the RLE mode, CRC and size limits. To validate it, an independent Python decoder was written only from the spec text; it matches libphf byte for byte (synthetic RGB/RGBA/gray images and a crop of the sample photo)..phfcontainer). Streaming latencies are recomputed from the measured throughputs (1080p at 290 MB/s ≈ 21 ms, not 8 ms). A note says the benchmark conditions weren't recorded and points tobench/bench.py.deltaparameter).Tooling
CMakeLists.txtfor every platform (shared/static, optional OpenMP,PHF_SANITIZE).tests/test_phf.cwith 470 checks: round-trips across sizes and image types (stride 3/4/0), header/limit/error paths, the overflow case, CRC detection, a corruption fuzz, file I/O, and decodingsample.phf.bench/bench.py: PHF vs WebP Lossless vs PNG-6/PNG-1, with a bit-exact check on every decode. While building it we found that WebP Lossless is not bit-exact on RGBA by default: it drops the RGB of fully transparent pixels. The script reports that case separately.build.batfinds MSVC throughvswhere(no hardcoded VS path). The WASM build writes straight toapps/web/, and there is now abuild_wasm.sh.libphf/.sample.phfwas re-encoded with correct flags and a CRC, with identical pixels.Test plan
ctestpasses in Release, Debug + ASan/UBSan, and with OpenMP (macOS arm64, clang): 470/470, zero warnings (including-std=c99 -pedantic)infodetects a flipped payload bytephf-view.jspassesnode --checkapps/web/phf.wasmwithlibphf/build_wasm.sh(Emscripten wasn't available while preparing this PR). Until then, the deployed viewer keeps the old binary without the overflow fix or the CRC checklibphf/build.bat(untested here)🤖 Generated with Claude Code