From 37499f531725dad82e72491fe2467e48fd852e5f Mon Sep 17 00:00:00 2001 From: Matthew Larson Date: Wed, 29 Nov 2023 13:20:08 -0600 Subject: [PATCH 1/2] Fix segfault with user-defined filter --- src/rest_vol_dataset.c | 81 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 8 deletions(-) diff --git a/src/rest_vol_dataset.c b/src/rest_vol_dataset.c index c62de081..0dd72cad 100644 --- a/src/rest_vol_dataset.c +++ b/src/rest_vol_dataset.c @@ -2274,13 +2274,23 @@ RV_parse_dataset_creation_properties_callback(char *HTTP_response, void *callbac break; } - /* TODO: support for other/user-defined filters */ - default: - /* Push error to stack; but don't fail this function */ + if (strcmp(filter_class, "H5Z_FILTER_USER")) { + /* Push error to stack; but don't fail this function */ + FUNC_DONE_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, + "warning: invalid filter with class '%s' and ID '%lld' on DCPL", + filter_class, filter_ID); + } + + /* Parse user-defined filter from JSON */ FUNC_DONE_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, - "warning: invalid filter with class '%s' and ID '%lld' on DCPL", - filter_class, filter_ID); + "TBD: invalid filter with class '%s' and ID '%lld' on DCPL", + filter_class, filter_ID); + // yajl get array + // iterate through members of array + // if (H5Pset_filter(*DCPL, filter_ID, flags?, cd_nelmts, c_values)) + + } #ifdef RV_CONNECTOR_DEBUG @@ -2444,6 +2454,7 @@ RV_convert_dataset_creation_properties_to_JSON(hid_t dcpl, char **creation_prope void *fill_value = NULL; char *encode_buf_out = NULL; char *fill_value_str = NULL; + char *ud_parameters = NULL; herr_t ret_value = SUCCEED; #ifdef RV_CONNECTOR_DEBUG @@ -3130,7 +3141,12 @@ RV_convert_dataset_creation_properties_to_JSON(hid_t dcpl, char **creation_prope default: /* User-defined filter */ { - char *parameters = NULL; + size_t parameters_size = 0; + size_t parameters_len = 0; + + + // TODO - require HSDS 085 + const char *const fmt_string = "{" "\"class\": \"H5Z_FILTER_USER\"," "\"id\": %d," @@ -3149,8 +3165,54 @@ RV_convert_dataset_creation_properties_to_JSON(hid_t dcpl, char **creation_prope /* Retrieve all of the parameters for the user-defined filter */ + // dcpl, (unsigned)i, &flags, &cd_nelmts, cd_values, + // filter_namelen, filter_name, &filter_config + + /* Start/end brackets and null byte */ + parameters_size += 3; + + for (size_t j = 0; j < cd_nelmts; j++) { + /* N bytes needed to store an N digit number, + * floor(log10) + 1 of an N digit number is >= N, + * plus two bytes for space and comma characters in the list */ + double num_digits = 0; + + if (cd_values[j] == 0) { + num_digits = 1; + } + else { + num_digits = floor(log10((double)cd_values[j])); + } + + parameters_size += (size_t)num_digits + 1 + 2; + } + + if ((ud_parameters = RV_calloc(parameters_size)) == NULL) + FUNC_GOTO_ERROR(H5E_CANTFILTER, H5E_CANTALLOC, FAIL, "can't allocate memory for filter parameters"); + + /* Assemble JSON array for user-defined filter parameters */ + + memset(ud_parameters, '[', 1); + parameters_len += 1; + + for (size_t j = 0; j < cd_nelmts; j++) { + // TODO - better name + int this_param_len = snprintf(ud_parameters + parameters_len, parameters_size - parameters_len, "%d", cd_values[j]); + parameters_len += this_param_len; + + if (j != cd_nelmts - 1) { + strcat(ud_parameters + (size_t) parameters_len, ", "); + parameters_len += 2; + } + } + + memset(ud_parameters + parameters_len, ']', 1); + parameters_len += 1; + memset(ud_parameters + parameters_len, '\0', 1); + parameters_len += 1; + /* Check whether the buffer needs to be grown */ - bytes_to_print = strlen(fmt_string) + MAX_NUM_LENGTH + strlen(parameters) + 1; + bytes_to_print = strlen(fmt_string) + MAX_NUM_LENGTH + strlen(ud_parameters) + 1; buf_ptrdiff = out_string_curr_pos - out_string; if (buf_ptrdiff < 0) @@ -3163,7 +3225,7 @@ RV_convert_dataset_creation_properties_to_JSON(hid_t dcpl, char **creation_prope if ((bytes_printed = snprintf(out_string_curr_pos, out_string_len - (size_t)buf_ptrdiff, - fmt_string, filter_id, parameters)) < 0) + fmt_string, filter_id, ud_parameters)) < 0) FUNC_GOTO_ERROR(H5E_DATASET, H5E_SYSERRSTR, FAIL, "snprintf error"); if ((size_t)bytes_printed >= out_string_len - (size_t)buf_ptrdiff) @@ -3533,6 +3595,9 @@ RV_convert_dataset_creation_properties_to_JSON(hid_t dcpl, char **creation_prope if (fill_value_str) RV_free(fill_value_str); + + if (ud_parameters) + RV_free(ud_parameters); return ret_value; } /* end RV_convert_dataset_creation_properties_to_JSON() */ From 237c2438e23cd6c1743f2c91cc508b52b7d06a52 Mon Sep 17 00:00:00 2001 From: Matthew Larson Date: Wed, 29 Nov 2023 14:44:20 -0600 Subject: [PATCH 2/2] Support opening dataset with UD filter --- src/rest_vol_dataset.c | 100 +++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 39 deletions(-) diff --git a/src/rest_vol_dataset.c b/src/rest_vol_dataset.c index 0dd72cad..46b0c3b0 100644 --- a/src/rest_vol_dataset.c +++ b/src/rest_vol_dataset.c @@ -1776,12 +1776,13 @@ static herr_t RV_parse_dataset_creation_properties_callback(char *HTTP_response, void *callback_data_in, void *callback_data_out) { - yajl_val parse_tree = NULL, creation_properties_obj, key_obj; - hid_t *DCPL = (hid_t *)callback_data_out; - hid_t fill_type = H5I_INVALID_HID; - char *encoded_fill_value = NULL; - char *decoded_fill_value = NULL; - herr_t ret_value = SUCCEED; + yajl_val parse_tree = NULL, creation_properties_obj, key_obj; + hid_t *DCPL = (hid_t *)callback_data_out; + hid_t fill_type = H5I_INVALID_HID; + char *encoded_fill_value = NULL; + char *decoded_fill_value = NULL; + unsigned int *ud_parameters = NULL; + herr_t ret_value = SUCCEED; #ifdef RV_CONNECTOR_DEBUG printf("-> Retrieving dataset's creation properties from server's HTTP response\n\n"); @@ -2283,14 +2284,36 @@ RV_parse_dataset_creation_properties_callback(char *HTTP_response, void *callbac } /* Parse user-defined filter from JSON */ - FUNC_DONE_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, - "TBD: invalid filter with class '%s' and ID '%lld' on DCPL", - filter_class, filter_ID); - // yajl get array - // iterate through members of array - // if (H5Pset_filter(*DCPL, filter_ID, flags?, cd_nelmts, c_values)) + const char *ud_parameter_keys[] = {"parameters", (const char *)0}; + + yajl_val params_array = NULL; + + if (NULL == (params_array = yajl_tree_get(filter_obj, ud_parameter_keys, yajl_t_array))) + FUNC_GOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, + "retrieval of user-defined filter parameters failed"); + + if (NULL == + (ud_parameters = RV_calloc(sizeof(unsigned int) * YAJL_GET_ARRAY(params_array)->len))) + FUNC_GOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, + "can't allocate memory for user-defined filter parameters"); + + for (size_t j = 0; j < YAJL_GET_ARRAY(params_array)->len; j++) { + /* Get each integer parameter */ + long long int val = YAJL_GET_INTEGER(YAJL_GET_ARRAY(params_array)->values[j]); + + if (val < 0) + FUNC_GOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, + "invalid parameter value for user-defined filter"); + + ud_parameters[j] = (unsigned int)val; + } + if (H5Pset_filter(*DCPL, (H5Z_filter_t)filter_ID, H5Z_FLAG_OPTIONAL, + YAJL_GET_ARRAY(params_array)->len, ud_parameters) < 0) + FUNC_GOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, + "can't set user-defined filter on DCPL"); + break; } #ifdef RV_CONNECTOR_DEBUG @@ -2417,7 +2440,11 @@ RV_parse_dataset_creation_properties_callback(char *HTTP_response, void *callbac if (H5Tclose(fill_type) < 0) FUNC_DONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close datatype of fill value"); + if (ud_parameters) + RV_free(ud_parameters); + return ret_value; + } /* end RV_parse_dataset_creation_properties_callback() */ /*------------------------------------------------------------------------- @@ -2454,7 +2481,7 @@ RV_convert_dataset_creation_properties_to_JSON(hid_t dcpl, char **creation_prope void *fill_value = NULL; char *encode_buf_out = NULL; char *fill_value_str = NULL; - char *ud_parameters = NULL; + char *ud_parameters = NULL; herr_t ret_value = SUCCEED; #ifdef RV_CONNECTOR_DEBUG @@ -3141,11 +3168,8 @@ RV_convert_dataset_creation_properties_to_JSON(hid_t dcpl, char **creation_prope default: /* User-defined filter */ { - size_t parameters_size = 0; - size_t parameters_len = 0; - - - // TODO - require HSDS 085 + size_t ud_parameters_size = 0; + size_t ud_parameters_len = 0; const char *const fmt_string = "{" "\"class\": \"H5Z_FILTER_USER\"," @@ -3165,16 +3189,13 @@ RV_convert_dataset_creation_properties_to_JSON(hid_t dcpl, char **creation_prope /* Retrieve all of the parameters for the user-defined filter */ - // dcpl, (unsigned)i, &flags, &cd_nelmts, cd_values, - // filter_namelen, filter_name, &filter_config - /* Start/end brackets and null byte */ - parameters_size += 3; + ud_parameters_size += 3; for (size_t j = 0; j < cd_nelmts; j++) { /* N bytes needed to store an N digit number, - * floor(log10) + 1 of an N digit number is >= N, - * plus two bytes for space and comma characters in the list */ + * floor(log10) + 1 of an N digit number is >= N, + * plus two bytes for space and comma characters in the list */ double num_digits = 0; if (cd_values[j] == 0) { @@ -3184,32 +3205,33 @@ RV_convert_dataset_creation_properties_to_JSON(hid_t dcpl, char **creation_prope num_digits = floor(log10((double)cd_values[j])); } - parameters_size += (size_t)num_digits + 1 + 2; + ud_parameters_size += (size_t)num_digits + 1 + 2; } - if ((ud_parameters = RV_calloc(parameters_size)) == NULL) - FUNC_GOTO_ERROR(H5E_CANTFILTER, H5E_CANTALLOC, FAIL, "can't allocate memory for filter parameters"); + if ((ud_parameters = RV_calloc(ud_parameters_size)) == NULL) + FUNC_GOTO_ERROR(H5E_CANTFILTER, H5E_CANTALLOC, FAIL, + "can't allocate memory for filter parameters"); /* Assemble JSON array for user-defined filter parameters */ - memset(ud_parameters, '[', 1); - parameters_len += 1; + ud_parameters_len += 1; for (size_t j = 0; j < cd_nelmts; j++) { - // TODO - better name - int this_param_len = snprintf(ud_parameters + parameters_len, parameters_size - parameters_len, "%d", cd_values[j]); - parameters_len += this_param_len; + int _param_len = + snprintf(ud_parameters + ud_parameters_len, + ud_parameters_size - ud_parameters_len, "%d", cd_values[j]); + ud_parameters_len += (size_t)_param_len; if (j != cd_nelmts - 1) { - strcat(ud_parameters + (size_t) parameters_len, ", "); - parameters_len += 2; + strcat(ud_parameters + (size_t)ud_parameters_len, ", "); + ud_parameters_len += 2; } } - memset(ud_parameters + parameters_len, ']', 1); - parameters_len += 1; - memset(ud_parameters + parameters_len, '\0', 1); - parameters_len += 1; + memset(ud_parameters + ud_parameters_len, ']', 1); + ud_parameters_len += 1; + memset(ud_parameters + ud_parameters_len, '\0', 1); + ud_parameters_len += 1; /* Check whether the buffer needs to be grown */ bytes_to_print = strlen(fmt_string) + MAX_NUM_LENGTH + strlen(ud_parameters) + 1; @@ -3595,7 +3617,7 @@ RV_convert_dataset_creation_properties_to_JSON(hid_t dcpl, char **creation_prope if (fill_value_str) RV_free(fill_value_str); - + if (ud_parameters) RV_free(ud_parameters);