From cede27fac145f04768cef91d642e6ff70c0c4f42 Mon Sep 17 00:00:00 2001 From: Simon Pinches Date: Tue, 2 Jun 2026 12:04:49 +0200 Subject: [PATCH] Fix OOB read / segfault when reading SHAPE-scalar HDF5 datasets readIntNDFromBuffer and readDoubleNDFromBuffer unconditionally appended a trailing value-dimension index (indices.push_back(0)) whenever rank != dim, then computed a flat offset with indices_to_flat_index. For a *_SHAPE dataset whose rank equals the AOS depth (dim == 0), the index vector already matched the dataset rank, so the extra element pushed the loop one past the dataspace dims array and produced an out-of-range flat offset. The subsequent memcpy(*data, v + index, ...) then read unmapped memory and crashed (SIGSEGV in __intel_avx_rep_memcpy). Guard the push_back with `if (dim != 0)`, mirroring the existing, correct logic in fillFullBuffers() (the buffered write path): when dim == 0 the scalar is addressed directly by current_arrctx_indices with no extra index. Fixes the segfault reported when reading GGD geometry (issue #51), e.g. grid_ggd[0]/space[0]/objects_per_dimension[3]/object[0]/geometry, where the geometry_SHAPE dataset has one fewer dimension than the geometry values. Verified against the reproduction D3D dataset: with the patched libal the previously-crashing empty-geometry read returns an empty array, while non-empty FLT_1D (point coordinates) and INT_1D (nodes) reads remain correct. --- src/hdf5/hdf5_dataset_handler.cpp | 36 ++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/hdf5/hdf5_dataset_handler.cpp b/src/hdf5/hdf5_dataset_handler.cpp index f65c774b..b9139867 100644 --- a/src/hdf5/hdf5_dataset_handler.cpp +++ b/src/hdf5/hdf5_dataset_handler.cpp @@ -1085,11 +1085,21 @@ void HDF5DataSetHandler::readIntNDFromBuffer(HDF5HsSelectionReader & hsSelection *data = (void*) malloc(shape*sizeof(int)); if (rank != dim) { HDF5Utils hdf5_utils; - std::vector < int > indices = current_arrctx_indices; - indices.push_back(0); - int index = hdf5_utils.indices_to_flat_index(indices, hsSelectionReader.getDataSpaceDims()); + int index; + if (dim != 0) { + std::vector < int > indices = current_arrctx_indices; + indices.push_back(0); + index = hdf5_utils.indices_to_flat_index(indices, hsSelectionReader.getDataSpaceDims()); + } + else { + // SHAPE-like datasets store one scalar per AOS cell: the index list + // already matches the dataset rank, so appending the trailing + // value-dimension index over-extends it and reads out of bounds. + // Mirrors the guard in fillFullBuffers(). + index = hdf5_utils.indices_to_flat_index(current_arrctx_indices, hsSelectionReader.getDataSpaceDims()); + } memcpy(*data, v+index, shape*sizeof(int)); - + } else { memcpy(*data, v, shape*sizeof(int)); @@ -1108,11 +1118,21 @@ void HDF5DataSetHandler::readDoubleNDFromBuffer(HDF5HsSelectionReader & hsSelect *data = (void*) malloc(shape*sizeof(double)); if (rank != dim) { HDF5Utils hdf5_utils; - std::vector < int > indices = current_arrctx_indices; - indices.push_back(0); - int index = hdf5_utils.indices_to_flat_index(indices, hsSelectionReader.getDataSpaceDims()); + int index; + if (dim != 0) { + std::vector < int > indices = current_arrctx_indices; + indices.push_back(0); + index = hdf5_utils.indices_to_flat_index(indices, hsSelectionReader.getDataSpaceDims()); + } + else { + // SHAPE-like datasets store one scalar per AOS cell: the index list + // already matches the dataset rank, so appending the trailing + // value-dimension index over-extends it and reads out of bounds. + // Mirrors the guard in fillFullBuffers(). + index = hdf5_utils.indices_to_flat_index(current_arrctx_indices, hsSelectionReader.getDataSpaceDims()); + } memcpy(*data, v+index, shape*sizeof(double)); - } + } else { memcpy(*data, v, shape*sizeof(double)); }