Skip to content

Add error checking to zstd hdf5 plugin - #280

Open
pimlu wants to merge 4 commits into
HDFGroup:masterfrom
pimlu:geipel/zstd-check-errors
Open

Add error checking to zstd hdf5 plugin#280
pimlu wants to merge 4 commits into
HDFGroup:masterfrom
pimlu:geipel/zstd-check-errors

Conversation

@pimlu

@pimlu pimlu commented Jul 30, 2026

Copy link
Copy Markdown

This PR adds error checking to the zstd hdf5 plugin. Previously it would return uninitialized memory from malloc when any zstd error occurred.

It also prevents proceeding with the result of malloc(0) in the abnormal case where decompSize == 0.

@pimlu
pimlu requested review from mkitti and nhz2 as code owners July 30, 2026 18:40
Comment thread ZSTD/src/H5Zzstd.c Outdated
@@ -66,10 +66,16 @@ H5Z_filter_zstd(unsigned int flags, size_t cd_nelmts, const unsigned int cd_valu
if (flags & H5Z_FLAG_REVERSE) {
/* We're decompressing */
size_t decompSize = ZSTD_getFrameContentSize(*buf, origSize);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically decompSize should be an unsigned long long but on 64-bit systems the outcome is the same. Let me know if I should update this in the same PR.

@mkitti mkitti Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix that here.

Below, an unknown content size should not be treated as an error. That is a perfectly valid situation for Zstandard compressed data.

We may need to use the streaming API to complete decompression, however.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that to support if some other program compressed hdf5 data via the streaming API? Since currently ZSTD_CONTENTSIZE_UNKNOWN is unreachable right, at least if hdf5_plugins is doing the compression. ZSTD_compress will always set the decompressed size

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you have seen, there are multiple implementations of the HDF5 Zstandard plugin. We cannot guarantee that the streaming API will not be used.

I've added support for streaming decompression in the past in a couple of libraries:
https://github.com/zarr-developers/numcodecs/blob/82c36354abf7f1c1999bc1c3cd11571215a6f364/src/numcodecs/zstd.pyx#L228
https://github.com/zarr-developers/numcodecs/blob/82c36354abf7f1c1999bc1c3cd11571215a6f364/src/numcodecs/zstd.pyx#L279-L369
https://github.com/manzt/numcodecs.js/blob/main/codecs/zstd/zstd_codec.cpp#L56

If you do not want to do right now, that's fine. However, the "error message" should be appropriate. The stream is not corrupt, but streaming decompression is not enabled here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, the "error message" should be appropriate.

Oh whoah, we can report error messages now (since HDFGroup/hdf5#6539, two weeks ago)?
We would love to report error messages (in general, not just for streaming decompression). My original PR used H5Epush2 until I found that errors didn't bubble up to python because of the H5E_PAUSE_ERRORS. Is it okay if I call H5Epush2(H5E_DEFAULT, ...) for every error case with a message?

@jhendersonHDF

Copy link
Copy Markdown
Contributor

Hi @pimlu,

could you also rebase this branch off of the current master? The CI workflows needed a couple fixes to make testing work again after changes in HDF5.

pimlu added 2 commits August 17, 2026 14:04
This PR adds error checking to the zstd hdf5 plugin.  Previously it would return uninitialized memory from malloc when any zstd error occurred.

It also prevents proceeding with the result of malloc(0) in the abnormal case where decompSize == 0.
This also changes the return type of ZSTD_getFrameContentSize to
unsigned long long.
@pimlu
pimlu force-pushed the geipel/zstd-check-errors branch from 5c3b7c5 to aad7cdd Compare August 17, 2026 18:06
pimlu added 2 commits August 17, 2026 14:14
The rest of the repo shies away from it
@pimlu

pimlu commented Aug 17, 2026

Copy link
Copy Markdown
Author

I made a few changes:

  • Rebased this branch
  • Added error checking/pushing with H5Epush
    • When the file was compressed with the zstd streaming API, it reports that too
  • Properly use unsigned long long for return type of ZSTD_getFrameContentSize

In actual python code, the error shows up as:

OSError: Can't synchronously read data (zstd frame missing decompressed size; data was likely compressed with the zstd streaming API, which is not supported)

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request improves the robustness of the ZSTD HDF5 filter by adding explicit error handling for Zstandard compression/decompression failures and guarding against invalid/unsupported frame metadata, preventing propagation of invalid buffers to HDF5.

Changes:

  • Add checks for invalid/unknown/zero decompressed size when parsing ZSTD frame content size.
  • Add explicit error handling for ZSTD_decompress / ZSTD_compress error returns with descriptive HDF5 error stack entries.
  • Improve malloc failure handling for compression/decompression buffers.
Suppressed comments (1)

ZSTD/src/H5Zzstd.c:140

  • compSize is a size_t, but the debug log uses %ld, which is undefined/wrong on platforms where size_t is not long. Use %zu for size_t.
        fprintf(stderr, "    compressing nbytes: %ld\n", compSize);

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread ZSTD/src/H5Zzstd.c
}

#ifdef ZSTD_DEBUG
fprintf(stderr, " decompressing nbytes: %ld\n", decompSize);
Comment thread ZSTD/src/H5Zzstd.c
Comment on lines +86 to 90
if (NULL == (outbuf = malloc((size_t)contentSize))) {
PUSH_ERR("H5Z_filter_zstd", H5E_CALLBACK, "Can't allocate zstd decompression buffer");
goto error;
}

@mkitti

mkitti commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

A further to do item would be to add some test files with a corrupt ZSTD header or an unknown decompressed size in order to exercise this error detection.

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.

4 participants