Repository navigation
Conversation
Review ChecklistThis PR touches the following areas. Each needs a sign-off
|
| *------------------------------------------------------------------------- | ||
| */ | ||
| const H5Z_class2_t * | ||
| H5Z__scaleoffset_class(void) |
There was a problem hiding this comment.
Just as a design suggestion, these functions could alternatively self-register the filter so that they don't return a pointer to internal details from a function that is exposed
There was a problem hiding this comment.
I agree, I was going to make the same suggestion, create H5Z__deflate_register(), etc. analogous to H5FD__sec2_register(). These functions would then call H5Z_register with their private class structs. While the way it is now works, it is slightly strange (if legal) to pass the address of a static variable outside the scope of that variable. I think it would be more straightforward to use e.g. H5Z__deflate_register(), and it would be more in line with the rest of the library.
There was a problem hiding this comment.
Done in c621bc5. Each filter file now has H5Z__<filter>_register(), like H5FD__sec2_register(), and the szip encoder check moved into H5Z__szip_register(). The structs never leave their files now; test/dsets.c gets the szip class through H5Z_find().
c621bc5 to
fd765b0
Compare
The class structs of the built-in filters (H5Z_DEFLATE, H5Z_SHUFFLE, H5Z_FLETCHER32, H5Z_NBIT, H5Z_SCALEOFFSET, H5Z_SZIP) were exported from libhdf5. Filter plugins built from a copy of HDF5's filter source, such as netCDF-C's deflate, shuffle and fletcher32 plugins, define globals with the same names, and on ELF platforms the plugin's references to its own struct bound to libhdf5's copy instead. Make the structs static, as the VFD and native VOL class structs already are, and reach them through package accessors. Add a test that checks none of the names is exported.
Replace the H5Z__<filter>_class() accessors with H5Z__<filter>_register() functions that call H5Z_register() on the file's static class struct, as H5FD__sec2_register() and the other VFDs do, so no pointer to the internal struct leaves its file. The szip encoder check moves into H5Z__szip_register(), and test/dsets.c looks the szip class up with H5Z_find().
fd765b0 to
4c55ae5
Compare
|
|
||
| #if defined(H5_HAVE_DLFCN_H) && defined(RTLD_DEFAULT) | ||
| for (u = 0; u < NELMTS(names); u++) | ||
| if (dlsym(RTLD_DEFAULT, names[u]) != NULL) { |
There was a problem hiding this comment.
This is maybe fine as a quick hack but consider that projects already appear to be exporting these symbols publicly as well, so if HDF5 is being built as a sub-project and this test is run, it has the potential to fail for reasons unrelated to what this is testing for.
There was a problem hiding this comment.
Good point, fixed in 4b7e5a6. The test now looks the names up in libhdf5's own shared object (found with dladdr() on H5open, opened with RTLD_NOLOAD) and only fails if the symbol found is inside libhdf5, so a definition elsewhere in the process doesn't count. It's skipped for static builds.
I checked it by preloading a library that exports its own H5Z_DEFLATE: the test passes against this PR's library and still fails when libhdf5 exports the structs. Incidentally, with that preload the unfixed libhdf5 itself breaks: its own references to H5Z_DEFLATE bind to the foreign definition, and dsets segfaults in the filter tests. This PR fixes that too.
There was a problem hiding this comment.
Do you think we need a test for this, in general, or should I remove it?
There was a problem hiding this comment.
Generally speaking I would avoid testing for specific symbol names at all since it can be hard to predict what is going to be exported at any given time, especially when dlopen() is involved (let's say the library dlopens a filter like blosc which may in turn dlopen its own copy of an H5Z_SZIP).
…lass structs) # Conflicts: # release_docs/CHANGELOG.md
dlsym(RTLD_DEFAULT, ...) searches the whole process, so the test failed when another object, such as a project that builds HDF5 as a sub-project, defines one of these names. Look the names up in the library's own shared object instead and only count a symbol found inside it. Skip the test when the library is not a shared object.
|
|
||
| The class structs of the built-in filters (H5Z_DEFLATE, H5Z_SHUFFLE, H5Z_FLETCHER32, | ||
| H5Z_NBIT, H5Z_SCALEOFFSET and H5Z_SZIP) were exported from the shared library. Filter | ||
| plugins built from a copy of HDF5's filter source, such as netCDF-C's deflate, shuffle |
| The class structs of the built-in filters (H5Z_DEFLATE, H5Z_SHUFFLE, H5Z_FLETCHER32, | ||
| H5Z_NBIT, H5Z_SCALEOFFSET and H5Z_SZIP) were exported from the shared library. Filter | ||
| plugins built from a copy of HDF5's filter source, such as netCDF-C's deflate, shuffle | ||
| and fletcher32 plugins, define globals with the same names, and on ELF platforms the |
There was a problem hiding this comment.
ELF platforms the -> ELF platforms where the
There was a problem hiding this comment.
Good catch: "bound" was meant as the verb, and it is easy to misread. "Where" would leave the clause without a verb, though, so I reworded it instead: "...on ELF platforms the plugin's references to its own struct were resolved to the library's copy instead." (02a95af). Does that read clearly now?
| ### Stopped exporting the built-in filter class structs | ||
|
|
||
| The class structs of the built-in filters (H5Z_DEFLATE, H5Z_SHUFFLE, H5Z_FLETCHER32, | ||
| H5Z_NBIT, H5Z_SCALEOFFSET and H5Z_SZIP) were exported from the shared library. Filter |
There was a problem hiding this comment.
H5Z_SCALEOFFSET and H5Z_SZIP -> `H5Z_SCALEOFFSET, and H5Z_SZIP
There was a problem hiding this comment.
Thanks, applied in 02a95af. The CHANGELOG uses the serial comma elsewhere, so this is more consistent.
Address review: add the serial commas the rest of the CHANGELOG uses, and replace "references ... bound to the library's copy", which read as a noun phrase, with "were resolved to the library's copy".
|
Thanks for the careful read, @hyoklee. All three are addressed in 02a95af. One small request for future wording nits: could you post them as suggestion blocks (the "Insert a suggestion" button in the review comment box)? Then I can apply them straight from the PR in one batch commit instead of editing each one by hand. Thanks! |
Testing for specific exported symbol names is fragile: what a process exports depends on what else is loaded, including filter plugins that dlopen their own copies of these names.
|
Removed. Whether a given name is exported depends on what else is loaded, so the test was checking the environment as much as the fix. |
|
🎉 All checklist items are signed off — @brtnfld, this PR is ready to merge. |
Describe your changes
libhdf5 exported the class structs of its built-in filters (
H5Z_DEFLATE,H5Z_SHUFFLE,H5Z_FLETCHER32,H5Z_NBIT,H5Z_SCALEOFFSET,H5Z_SZIP). They are declared in the privateH5Zpkg.h, butH5_DLLVARand default symbol visibility put them in the shared library's exported symbols.Filter plugins built from a copy of HDF5's filter source define globals with the same names; netCDF-C's deflate, shuffle and fletcher32 plugins do. On Linux, when such a plugin is loaded into a process that already has libhdf5, the plugin's reference to its own struct binds to libhdf5's copy, so
H5PLget_plugin_info()returns libhdf5's struct and filter function. This has been silent because the structs matched. #6710 changes the built-in structs toH5Z_class3_twith version 3; netCDF-C's NCZarr loader then rejects the plugins (libnczarr/zplugins.c:413) and the netCDF CI job fails.This makes the six structs
static, the same way the VFD and native VOL class structs already are. Each filter file now registers its own filter throughH5Z__<filter>_register()(likeH5FD__sec2_register()), so no pointer to the struct leaves its file; the szip encoder check moved intoH5Z__szip_register(). Internal linkage keeps them out of the export table with any compiler, without visibility attributes.test/dsets.c: newtest_filter_class_symbols()checks withdlsym(RTLD_DEFAULT, ...)that none of the six names is exported. It fails on develop and passes with this change, and is skipped whereRTLD_DEFAULTis not available.nczarr_testpasses 34/34 locally (23 fail without it).Once #6710 merges, this needs a rebase onto the
H5Z_class3_tstructs; the change itself is the same.Issue ticket number (GitHub or JIRA)
Related to #6710 (netCDF CI failure).