Skip to content

Fix several undefined behavior issues noted by UBsan#6319

Open
jhendersonHDF wants to merge 2 commits intoHDFGroup:developfrom
jhendersonHDF:fix_undefined_issues
Open

Fix several undefined behavior issues noted by UBsan#6319
jhendersonHDF wants to merge 2 commits intoHDFGroup:developfrom
jhendersonHDF:fix_undefined_issues

Conversation

@jhendersonHDF
Copy link
Collaborator

Disable float16 support for undefined sanitizer workflow for now as it causes a crash in UBSan

Disable float16 support for undefined sanitizer workflow for now as it
causes a crash in UBSan
@jhendersonHDF jhendersonHDF added Component - C Library Core C library issues (usually in the src directory) Component - Testing Code in test or testpar directories, GitHub workflows labels Mar 25, 2026
@github-project-automation github-project-automation bot moved this to To be triaged in HDF5 - TRIAGE & TRACK Mar 25, 2026
/********************/

static herr_t H5A__close_cb(H5VL_object_t *attr_vol_obj, void **request);
static herr_t H5A__close_cb(void *attr_vol_obj, void **request);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There were several instances in the library where an H5I_free_t callback was declared with some type parameter instead of void * and then casted to H5I_free_t, causing UBSan to complain. The typing is lost for these callbacks, but several other H5I_free_t callbacks in the library already use the correct void * parameter anyway.

((const uint8_t *)write_bufs[i] - (const uint8_t *)io_info->tconv_buf));
void *tmp_write_buf;

if (io_info->sel_pieces[i]->in_place_tconv) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@fortnern do these changes look correct? UBSan was complaining because in this particular case (where modifying of write buffers is enabled), the type conversion buffer wasn't allocated, so the previous logic was adding a non-zero offset to a NULL pointer. I'm not entirely certain how the testing passes currently given that, but it was definitely wrong. In the in_place_tconv case, it seemed like the logic above in the first loop already set each write_bufs[i] to point to the correct location in the write buffer. In fact, it also looks like each write_bufs[i] gets set to the correct place in io_info->tconv_buf above as well, so both cases might be able to be simplified to just the two lines below without needing all the casting in the in_place_tconv == false case.

set (ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DHDF5_BUILD_JAVA:BOOL=OFF")
set (ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DHDF5_BUILD_CPP_LIB:BOOL=ON")
set (ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DHDF5_BUILD_FORTRAN:BOOL=OFF")
set (ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DHDF5_ENABLE_NONSTANDARD_FEATURE_FLOAT16:BOOL=OFF")
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The _Float16 type currently crashes UBSan, preventing further analysis in dt_arith.c.

*thing = iblock;
*thing_elmt_buf = (uint8_t *)iblock->elmts;
*thing_elmt_idx = idx;
*thing_unprot_func = (H5EA__unprotect_func_t)H5EA__iblock_unprotect;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Similar to H5I_free_t, these callbacks were declaring in an incompatible way with H5EA__unprotect_func_t and then casted into it, causing UBSan to complain.

{
bool skip;
H5T_t *dt = NULL;
const uint8_t *p_end = p + p_size - 1;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There were a handful of cases in the library where this type of calculation was performed when p_size is SIZE_MAX (the case where we can't know how big the buffer is for checking during decoding). This would cause p to overflow and cause UBSan to complain. Not really an issue, but easy to fix by checking p_size before doing the addition.

{
H5F_t *src_f = NULL;
hid_t file_id = H5I_INVALID_HID;
H5R_ref_priv_t *dst_ref = (H5R_ref_priv_t *)dst_buf;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This casting can form an unaligned pointer which could potentially be problematic and which UBSan complains about. As the only place it is actually used is in a memcpy() from a temporary, aligned local reference object, just memcpy() directly into dst_buf instead of trying to go through dst_ref.

assert(src_size);
assert(dst_buf);
assert(dst_size == H5T_REF_MEM_SIZE);
HDcompile_assert(sizeof(*dst_ref) == sizeof(tmp_ref));
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This assertion isn't really needed because *dst_ref would always be H5R_ref_priv_t in the previous logic, and tmp_ref is a H5R_ref_priv_t, making this trivially true. For catching future size issues, using dst_size would probably be more appropriate, but that was a bit outside the scope of this fix.

@brtnfld
Copy link
Collaborator

brtnfld commented Mar 26, 2026

Not part of PR, but minor observation:

At H5T.c:2502, the error line reads:

HGOTO_ERROR(H5E_ATTR, H5E_CANTDEC, FAIL, "unable to free VOL object");
This should be H5E_DATATYPE , every other HGOTO_ERROR in that function uses H5E_DATATYPE.

brtnfld
brtnfld previously approved these changes Mar 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component - C Library Core C library issues (usually in the src directory) Component - Testing Code in test or testpar directories, GitHub workflows

Projects

Status: To be triaged

Development

Successfully merging this pull request may close these issues.

6 participants