Summary
The Rust core was cross-validated on Linux (glibc + musl), Windows (mingw cross-link), macOS (cargo check, both arches), and wasm. Compilation and linking are clean on every target. Running the test suite on wasm (wasm32-wasip1-threads under wasmtime v24 with -S threads) surfaced two runtime failures — 101/103 pass:
1. Display-list parser allocates before validating (aborts on wasm, memory-DoS vector on native)
raster::tests::malformed_buffer_is_rejected_not_panicked aborts the wasm module with:
memory allocation of 1212696648 bytes failed
Reader::pts (src/raster.rs:1360) does Vec::with_capacity(n) where n is an untrusted u32 from the command buffer, before checking that 8*n bytes are actually present. A 5-byte buffer claiming ~151M points reserves ~1.2 GB up front.
- On 64-bit native this "passes" only via OS overcommit: the reserve succeeds, the parse hits end-of-buffer, returns
None, memory is freed untouched.
- On wasm32 (no overcommit, 4 GB linear-memory ceiling) the allocation fails and Rust aborts — allocation failure is not catchable.
- Same allocate-before-validate pattern for the gradient stop count (
src/raster.rs:~1915) and both dash counts (~1933, ~2378).
This contradicts the "malformed op is rejected, not faked/panicked" contract, and is a hostile-input memory-DoS vector on native too (a display list can force multi-GB transient reserves).
Proposed fix: clamp every count-driven reserve to what the remaining buffer can encode, e.g. a Reader::bounded(count, item_size) helper returning count.min(remaining / item_size); parse loops already bail correctly on truncation. (Fix was prototyped and passes both native 103/103 and the wasm raster test; withheld pending this issue.)
2. ffi_guard panic backstop does not exist on wasm
tests::ffi_guard_maps_panic_to_sentinel aborts: ffi_guard (src/lib.rs:48) relies on std::panic::catch_unwind, but wasm32 targets have panic=abort semantics — there is no unwinding to catch, so the deliberate test panic kills the module.
- Platform property, not a code bug.
- Test should be gated
#[cfg(panic = "unwind")].
- Worth recording in the dossier: on any future wasm build (e.g. Pyodide/JupyterLite), an internal panic aborts the wasm instance — the C-ABI sentinel backstop only exists on unwinding platforms.
3. (minor) fuzz_parallel_matches_serial on threadless wasm
On plain wasm32-wasip1 (no threads) this test force-drives threads = 2/3/5 into the impls and aborts on thread::scope spawn. Production is unaffected (par_threads → available_parallelism → 1 → serial path). Passes fine on wasm32-wasip1-threads. Only relevant if threadless wasm ever becomes a tested config; would need a cfg gate.
Cross-platform validation matrix (2026-07-22)
| Target |
Method |
Result |
| x86_64-unknown-linux-gnu |
host + clean rust:1-slim Docker, build + tests |
✅ 103/103 |
| x86_64-unknown-linux-musl |
rust:alpine Docker, build + tests |
✅ 103/103 (cdylib needs -C target-feature=-crt-static) |
| x86_64-pc-windows-gnu |
Docker + mingw-w64 full cdylib link |
✅ xy_core.dll links |
| x86_64-pc-windows-msvc |
cargo check |
✅ |
| x86_64 / aarch64-apple-darwin |
cargo check (no Apple SDK in Docker) |
✅ |
| wasm32-unknown-unknown |
full build |
✅ |
| wasm32-wasip1-threads |
wasmtime v24 -S threads, full test run |
⚠️ 101/103 (items 1–2 above) |
Repro for the wasm test run:
rustup target add wasm32-wasip1-threads
curl -sSf https://wasmtime.dev/install.sh | bash -s -- --version v24.0.0 # newer wasmtime removed -S threads
CARGO_TARGET_WASM32_WASIP1_THREADS_RUNNER='wasmtime run -S threads' \
cargo test --release --target wasm32-wasip1-threads
Summary
The Rust core was cross-validated on Linux (glibc + musl), Windows (mingw cross-link), macOS (
cargo check, both arches), and wasm. Compilation and linking are clean on every target. Running the test suite on wasm (wasm32-wasip1-threadsunder wasmtime v24 with-S threads) surfaced two runtime failures — 101/103 pass:1. Display-list parser allocates before validating (aborts on wasm, memory-DoS vector on native)
raster::tests::malformed_buffer_is_rejected_not_panickedaborts the wasm module with:Reader::pts(src/raster.rs:1360) doesVec::with_capacity(n)wherenis an untrustedu32from the command buffer, before checking that8*nbytes are actually present. A 5-byte buffer claiming ~151M points reserves ~1.2 GB up front.None, memory is freed untouched.src/raster.rs:~1915) and both dash counts (~1933,~2378).This contradicts the "malformed op is rejected, not faked/panicked" contract, and is a hostile-input memory-DoS vector on native too (a display list can force multi-GB transient reserves).
Proposed fix: clamp every count-driven reserve to what the remaining buffer can encode, e.g. a
Reader::bounded(count, item_size)helper returningcount.min(remaining / item_size); parse loops already bail correctly on truncation. (Fix was prototyped and passes both native 103/103 and the wasm raster test; withheld pending this issue.)2.
ffi_guardpanic backstop does not exist on wasmtests::ffi_guard_maps_panic_to_sentinelaborts:ffi_guard(src/lib.rs:48) relies onstd::panic::catch_unwind, but wasm32 targets have panic=abort semantics — there is no unwinding to catch, so the deliberate test panic kills the module.#[cfg(panic = "unwind")].3. (minor)
fuzz_parallel_matches_serialon threadless wasmOn plain
wasm32-wasip1(no threads) this test force-drivesthreads = 2/3/5into the impls and aborts onthread::scopespawn. Production is unaffected (par_threads→available_parallelism→ 1 → serial path). Passes fine onwasm32-wasip1-threads. Only relevant if threadless wasm ever becomes a tested config; would need a cfg gate.Cross-platform validation matrix (2026-07-22)
rust:1-slimDocker, build + testsrust:alpineDocker, build + tests-C target-feature=-crt-static)xy_core.dlllinkscargo checkcargo check(no Apple SDK in Docker)-S threads, full test runRepro for the wasm test run: