Skip to content
1 change: 1 addition & 0 deletions hl/src/H5DS.c
Original file line number Diff line number Diff line change
Expand Up @@ -2292,6 +2292,7 @@ H5DSis_scale(hid_t did)
is_ds = 1;

free(buf);
buf = NULL;

if (H5Tclose(tid) < 0)
goto out;
Expand Down
155 changes: 85 additions & 70 deletions hl/src/H5LT.c
Original file line number Diff line number Diff line change
Expand Up @@ -1889,13 +1889,17 @@ H5LTtext_to_dtype(const char *text, H5LT_lang_t lang_type)

input_len = strlen(text);
myinput = strdup(text);
if (!myinput)
goto out;

if ((type_id = H5LTyyparse()) < 0) {
free(myinput);
myinput = NULL;
goto out;
}

free(myinput);
myinput = NULL;
input_len = 0;

return type_id;
Expand All @@ -1909,7 +1913,20 @@ H5LTtext_to_dtype(const char *text, H5LT_lang_t lang_type)
*
* Purpose: Expand the buffer and append a string to it.
*
* Return: void
* Parameters:
* _no_user_buf: Operating mode flag
* - true: Library-managed buffer (can reallocate)
* - false: User-provided buffer (fixed size, no realloc)
* len: Pointer to current buffer size (updated if reallocated)
* buf: Buffer to append to (must not be NULL)
* str_to_add: String to append (NULL = no append, just ensure space)
*
* Preconditions:
* - buf must be a valid, allocated buffer (never NULL)
* - In library-managed mode: buf was allocated via calloc/malloc
* - In user-provided mode: buf points to user's pre-allocated buffer
*
* Return: Updated buffer pointer on success, NULL on failure
*
*-------------------------------------------------------------------------
*/
Expand All @@ -1918,12 +1935,17 @@ realloc_and_append(bool _no_user_buf, size_t *len, char *buf, const char *str_to
{
size_t size_str_to_add, size_str;

/* Precondition: buf must be allocated (verified in debug builds) */
assert(buf != NULL && "Buffer must not be NULL");

/* Defensive runtime check for production safety (assertions disabled in release builds) */
if (!buf)
goto out;

/* Mode 1: Library-managed buffer - can reallocate as needed */
if (_no_user_buf) {
char *tmp_realloc;

if (!buf)
goto out;

/* If the buffer isn't big enough, reallocate it. Otherwise, go to do strcat. */
if (str_to_add && ((ssize_t)(*len - (strlen(buf) + strlen(str_to_add) + 1)) < LIMIT)) {
*len += ((strlen(buf) + strlen(str_to_add) + 1) / INCREMENT + 1) * INCREMENT;
Expand All @@ -1941,6 +1963,8 @@ realloc_and_append(bool _no_user_buf, size_t *len, char *buf, const char *str_to
else
buf = tmp_realloc;
}
/* Mode 2: User-provided buffer - fixed size, no reallocation
* (else case is implicit - no action needed) */

if (str_to_add) {
/* find the size of the buffer to add */
Expand Down Expand Up @@ -2171,6 +2195,50 @@ H5LTdtype_to_text(hid_t dtype, char *str, H5LT_lang_t lang_type, size_t *len)
return FAIL;
}

/*-------------------------------------------------------------------------
* Function: H5LT_append_dtype_super_text
*
* Purpose: Helper function to get super type text and append it to dt_str.
* This encapsulates the common pattern of: allocate buffer,
* convert dtype to text, append to string, free buffer.
*
* Return: Success: updated dt_str pointer, Failure: NULL
*
*-------------------------------------------------------------------------
*/
static char *
H5LT_append_dtype_super_text(hid_t super, char *dt_str, H5LT_lang_t lang, size_t *slen, bool no_user_buf)
{
size_t super_len;
char *stmp = NULL;

/* Get required buffer size for super type text */
if (H5LTdtype_to_text(super, NULL, lang, &super_len) < 0)
return NULL;

/* Allocate buffer for super type text */
stmp = (char *)calloc(super_len, sizeof(char));
if (!stmp)
return NULL;

/* Convert super type to text */
if (H5LTdtype_to_text(super, stmp, lang, &super_len) < 0) {
free(stmp);
return NULL;
}

/* Append super type text to dt_str */
if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, stmp))) {
free(stmp);
return NULL;
}

/* Clean up */
free(stmp);

return dt_str;
}

/*-------------------------------------------------------------------------
* Function: H5LT_dtype_to_text
*
Expand Down Expand Up @@ -2536,8 +2604,7 @@ H5LT_dtype_to_text(hid_t dtype, char *dt_str, H5LT_lang_t lang, size_t *slen, bo
tag = H5Tget_tag(dtype);
if (tag) {
snprintf(tmp_str, TMP_LEN, "OPQ_TAG \"%s\";\n", tag);
if (tag)
H5free_memory(tag);
H5free_memory(tag);
tag = NULL;
}
else
Expand All @@ -2556,33 +2623,19 @@ H5LT_dtype_to_text(hid_t dtype, char *dt_str, H5LT_lang_t lang, size_t *slen, bo
break;
}
case H5T_ENUM: {
hid_t super;
size_t super_len;
char *stmp = NULL;
hid_t super;

/* Print lead-in */
snprintf(dt_str, *slen, "H5T_ENUM {\n");
indent += COL;
if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen)))
goto out;

/* Get super type and append its text representation */
if ((super = H5Tget_super(dtype)) < 0)
goto out;
if (H5LTdtype_to_text(super, NULL, lang, &super_len) < 0)
goto out;
stmp = (char *)calloc(super_len, sizeof(char));
if (H5LTdtype_to_text(super, stmp, lang, &super_len) < 0) {
free(stmp);
if (!(dt_str = H5LT_append_dtype_super_text(super, dt_str, lang, slen, no_user_buf)))
goto out;
}
if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, stmp))) {
free(stmp);
goto out;
}

if (stmp)
free(stmp);
stmp = NULL;

snprintf(tmp_str, TMP_LEN, ";\n");
if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str)))
Expand All @@ -2603,33 +2656,20 @@ H5LT_dtype_to_text(hid_t dtype, char *dt_str, H5LT_lang_t lang, size_t *slen, bo
break;
}
case H5T_VLEN: {
hid_t super;
size_t super_len;
char *stmp = NULL;
hid_t super;

/* Print lead-in */
snprintf(dt_str, *slen, "H5T_VLEN {\n");
indent += COL;
if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen)))
goto out;

/* Get super type and append its text representation */
if ((super = H5Tget_super(dtype)) < 0)
goto out;
if (H5LTdtype_to_text(super, NULL, lang, &super_len) < 0)
goto out;
stmp = (char *)calloc(super_len, sizeof(char));
if (H5LTdtype_to_text(super, stmp, lang, &super_len) < 0) {
free(stmp);
if (!(dt_str = H5LT_append_dtype_super_text(super, dt_str, lang, slen, no_user_buf)))
goto out;
}
if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, stmp))) {
free(stmp);
goto out;
}

if (stmp)
free(stmp);
stmp = NULL;
snprintf(tmp_str, TMP_LEN, "\n");
if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str)))
goto out;
Expand All @@ -2647,8 +2687,6 @@ H5LT_dtype_to_text(hid_t dtype, char *dt_str, H5LT_lang_t lang, size_t *slen, bo
}
case H5T_ARRAY: {
hid_t super;
size_t super_len;
char *stmp = NULL;
hsize_t dims[H5S_MAX_RANK];
int ndims;

Expand All @@ -2674,22 +2712,12 @@ H5LT_dtype_to_text(hid_t dtype, char *dt_str, H5LT_lang_t lang, size_t *slen, bo
if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str)))
goto out;

/* Get super type and append its text representation */
if ((super = H5Tget_super(dtype)) < 0)
goto out;
if (H5LTdtype_to_text(super, NULL, lang, &super_len) < 0)
goto out;
stmp = (char *)calloc(super_len, sizeof(char));
if (H5LTdtype_to_text(super, stmp, lang, &super_len) < 0) {
free(stmp);
if (!(dt_str = H5LT_append_dtype_super_text(super, dt_str, lang, slen, no_user_buf)))
goto out;
}
if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, stmp))) {
free(stmp);
goto out;
}
if (stmp)
free(stmp);
stmp = NULL;

snprintf(tmp_str, TMP_LEN, "\n");
if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str)))
goto out;
Expand Down Expand Up @@ -2775,33 +2803,20 @@ H5LT_dtype_to_text(hid_t dtype, char *dt_str, H5LT_lang_t lang, size_t *slen, bo
break;
}
case H5T_COMPLEX: {
hid_t super;
size_t super_len;
char *stmp = NULL;
hid_t super;

/* Print lead-in */
snprintf(dt_str, *slen, "H5T_COMPLEX {\n");
indent += COL;
if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen)))
goto out;

/* Get super type and append its text representation */
if ((super = H5Tget_super(dtype)) < 0)
goto out;
if (H5LTdtype_to_text(super, NULL, lang, &super_len) < 0)
goto out;
stmp = (char *)calloc(super_len, sizeof(char));
if (H5LTdtype_to_text(super, stmp, lang, &super_len) < 0) {
free(stmp);
if (!(dt_str = H5LT_append_dtype_super_text(super, dt_str, lang, slen, no_user_buf)))
goto out;
}
if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, stmp))) {
free(stmp);
goto out;
}

if (stmp)
free(stmp);
stmp = NULL;
snprintf(tmp_str, TMP_LEN, "\n");
if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str)))
goto out;
Expand Down
22 changes: 20 additions & 2 deletions hl/src/H5TB.c
Original file line number Diff line number Diff line change
Expand Up @@ -3021,11 +3021,29 @@ H5TBget_field_info(hid_t loc_id, const char *dset_name, char *field_names[], siz
for (i = 0; i < nfields; i++) {
/* get the member name */
if (field_names) {
char *member_name;
char *member_name;
size_t name_len;

if (NULL == (member_name = H5Tget_member_name(tid, (unsigned)i)))
goto out;
strcpy(field_names[i], member_name);

name_len = strlen(member_name);

/* Only enforce HLTB_MAX_FIELD_LEN limit when truncation is necessary.
* This preserves backward compatibility for typical field names while
* preventing unbounded writes for exceptionally long names.
* For names < HLTB_MAX_FIELD_LEN: copies exact length (backward compatible)
* For names >= HLTB_MAX_FIELD_LEN: truncates to HLTB_MAX_FIELD_LEN - 1 chars */
if (name_len >= HLTB_MAX_FIELD_LEN) {
/* Name too long - truncate to fit HLTB_MAX_FIELD_LEN buffer */
memcpy(field_names[i], member_name, HLTB_MAX_FIELD_LEN - 1);
field_names[i][HLTB_MAX_FIELD_LEN - 1] = '\0';
}
else {
/* Name fits - copy entire string including null terminator */
memcpy(field_names[i], member_name, name_len + 1);
}

H5free_memory(member_name);
} /* end if */

Expand Down
5 changes: 2 additions & 3 deletions hl/src/H5TBprivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@
/* public TB prototypes */
#include "H5TBpublic.h"

#define TABLE_CLASS "TABLE"
#define TABLE_VERSION "3.0"
#define HLTB_MAX_FIELD_LEN 255
#define TABLE_CLASS "TABLE"
#define TABLE_VERSION "3.0"

/*-------------------------------------------------------------------------
*
Expand Down
29 changes: 28 additions & 1 deletion hl/src/H5TBpublic.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@
#ifndef H5TBpublic_H
#define H5TBpublic_H

/**
* \brief Maximum length for table field names
*
* \details This constant defines the maximum field name length supported by
* H5TBget_field_info(). Field names exceeding #HLTB_MAX_FIELD_LEN - 1
* characters will be truncated. Callers should allocate buffers sized
* appropriately for their expected field names; only names at or exceeding
* this length require buffers of #HLTB_MAX_FIELD_LEN bytes. Shorter names
* are copied exactly without padding to this length.
*
* \since 2.1.0
*/
#define HLTB_MAX_FIELD_LEN 255

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -457,7 +471,13 @@ H5HL_DLL herr_t H5TBget_table_info(hid_t loc_id, const char *dset_name, hsize_t
*
* \fg_loc_id
* \param[in] dset_name The name of the dataset to read
* \param[out] field_names An array containing the names of the fields
* \param[out] field_names An array containing the names of the fields.
* Each element must be allocated by the caller with sufficient
* space to hold the field name. Field names are copied as-is if
* shorter than #HLTB_MAX_FIELD_LEN. Names longer than
* #HLTB_MAX_FIELD_LEN - 1 characters will be truncated and
* require buffers of at least #HLTB_MAX_FIELD_LEN bytes.
* Pass NULL to skip retrieving field names.
* \param[out] field_sizes An array containing the size of the fields
* \param[out] field_offsets An array containing the offsets of the fields
* \param[out] type_size The size of the HDF5 datatype associated
Expand All @@ -472,6 +492,13 @@ H5HL_DLL herr_t H5TBget_table_info(hid_t loc_id, const char *dset_name, hsize_t
* named \p dset_name attached to the object specified
* by the identifier \p loc_id.
*
* \note When retrieving field names, callers should allocate each field_names[i]
* buffer with sufficient space for the expected field name length.
* For typical field names (< 255 characters), only the actual name length
* plus one byte for null termination is written. Field names exceeding
* #HLTB_MAX_FIELD_LEN - 1 characters will be silently truncated and
* require buffers of at least #HLTB_MAX_FIELD_LEN bytes.
*
*/
H5HL_DLL herr_t H5TBget_field_info(hid_t loc_id, const char *dset_name, char *field_names[],
size_t *field_sizes, size_t *field_offsets, size_t *type_size);
Expand Down
Loading