From 993214723e6842aea43362ada12ee4cd85fce32a Mon Sep 17 00:00:00 2001 From: osobh Date: Sat, 26 Sep 2026 01:32:00 -0500 Subject: [PATCH] test: a v2 header message running into the checksum is refused, as in libhdf5 The review read libhdf5's H5O__chunk_deserialize as accepting a v2 message that runs up to 4 bytes into the chunk's checksum, since it bounds message bodies by the whole chunk buffer. It does not accept it: the message loop stops at the checksum, and the checksum read that follows starts past it and overruns the chunk ("ran off end of input buffer while decoding"). h5py refuses such files whether the message runs 1, 4 or 5 bytes in, and so does clawhdf5, with its own error text. No code change; the test pins the agreement and a comment records why. Co-Authored-By: Claude Opus 5.5 (1M context) --- crates/clawhdf5-format/src/object_header.rs | 7 +++ .../tests/header_validation_interop.rs | 48 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/crates/clawhdf5-format/src/object_header.rs b/crates/clawhdf5-format/src/object_header.rs index b28fdad..2c3c819 100644 --- a/crates/clawhdf5-format/src/object_header.rs +++ b/crates/clawhdf5-format/src/object_header.rs @@ -421,6 +421,13 @@ impl ObjectHeader { }; pos += msg_header_size; + // `end` is where the messages stop and the checksum starts. + // libhdf5 bounds a message by the chunk including its checksum, + // but a message that runs into the checksum still fails there: + // its loop stops at the checksum, and reading the checksum from + // past its start overruns the chunk ("ran off end of input + // buffer while decoding"). Both refuse it; only the text + // differs. if msg_data_size > end - pos { return Err(FormatError::InvalidObjectHeader( "message size exceeds buffer end", diff --git a/crates/clawhdf5/tests/header_validation_interop.rs b/crates/clawhdf5/tests/header_validation_interop.rs index 7cdd4b4..2f52d27 100644 --- a/crates/clawhdf5/tests/header_validation_interop.rs +++ b/crates/clawhdf5/tests/header_validation_interop.rs @@ -252,6 +252,54 @@ for libver in ("earliest", "latest"): } } +/// A v2 object header message whose size runs past the messages into the +/// chunk's checksum is refused by libhdf5 whether it runs 1 byte or more +/// into the checksum (its loop stops at the checksum, and then the checksum +/// read and the size check fail), so it is refused here too. +#[test] +fn v2_header_message_running_into_the_checksum_is_refused() { + skip_if_no_python!(); + let dir = tempfile::tempdir().unwrap(); + let body = format!( + "{FIX_OHDR_PY}{}", + r#" +good = os.path.join(d, "good.h5") +with h5py.File(good, "w", libver="latest") as f: + f.create_dataset("d", data=np.arange(4, dtype="