diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2005-06-18 05:10:22 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2005-06-18 05:10:22 (GMT) |
commit | d6410304369bea0644da9ab594f22af6201fa16e (patch) | |
tree | dbbc72537715fa4c4fb53e153970735dc3003a66 | |
parent | 04e424638ad15f4663f77468f70ec58b7ac8df22 (diff) | |
download | hdf5-d6410304369bea0644da9ab594f22af6201fa16e.zip hdf5-d6410304369bea0644da9ab594f22af6201fa16e.tar.gz hdf5-d6410304369bea0644da9ab594f22af6201fa16e.tar.bz2 |
[svn-r10951] Purpose:
Bug fix
Description:
Hyperslab selections that had a selection offset and were applied to a
chunked dataset could get into an infinite loop or core dump if the same
selection was used multiple times, with different selection offsets.
Solution:
"Normalize" the selection with the selection offset, generate the
selections for the chunks overlapped and then "denormalize" the selection.
Platforms tested:
FreeBSD 4.11 (sleipnir)
Too minor to require h5committest
-rw-r--r-- | release_docs/RELEASE.txt | 5 | ||||
-rw-r--r-- | src/H5Dio.c | 22 | ||||
-rw-r--r-- | src/H5Shyper.c | 78 | ||||
-rw-r--r-- | src/H5Sprivate.h | 3 | ||||
-rw-r--r-- | test/tselect.c | 108 |
5 files changed, 194 insertions, 22 deletions
diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index d99eadf..dd327f6 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -290,6 +290,11 @@ Bug Fixes since HDF5-1.6.0 release Library ------- + - Fixed bug with hyperslab selections that use selection offsets and + operate on chunked datasets going into infinite loop or dumping + core. QAK - 2005/06/17 + - Corrected memory leak and possible corruption when opening a group. + QAK - 2005/06/17 - Added check for opaque datatype tags being too long (check against H5T_OPAQUE_TAG_MAX, currently set to 256). QAK - 2005/06/14 - Fixed various errors in maintaining names for open objects in the diff --git a/src/H5Dio.c b/src/H5Dio.c index b5259a3..f1d12f8 100644 --- a/src/H5Dio.c +++ b/src/H5Dio.c @@ -2358,6 +2358,8 @@ H5D_create_chunk_map(const H5D_t *dataset, const H5T_t *mem_type, const H5S_t *f H5S_t *tmp_mspace=NULL; /* Temporary memory dataspace */ H5S_t *equiv_mspace=NULL; /* Equivalent memory dataspace */ hbool_t equiv_mspace_init=0;/* Equivalent memory dataspace was created */ + hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */ + hbool_t file_space_normalized = FALSE; /* File dataspace was normalized */ hid_t f_tid=(-1); /* Temporary copy of file datatype for iteration */ hbool_t iter_init=0; /* Selection iteration info has been initialized */ unsigned f_ndims; /* The number of dimensions of the file's dataspace */ @@ -2404,6 +2406,16 @@ H5D_create_chunk_map(const H5D_t *dataset, const H5T_t *mem_type, const H5S_t *f if(H5S_get_simple_extent_dims(file_space, fm->f_dims, NULL)<0) HGOTO_ERROR (H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimensionality") + /* Normalize hyperslab selections by adjusting them by the offset */ + /* (It might be worthwhile to normalize both the file and memory dataspaces + * before any (contiguous, chunked, etc) file I/O operation, in order to + * speed up hyperslab calculations by removing the extra checks and/or + * additions involving the offset and the hyperslab selection -QAK) + */ + if(H5S_hyper_normalize_offset(file_space, old_offset)<0) + HGOTO_ERROR (H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") + file_space_normalized = TRUE; + /* Decide the number of chunks in each dimension*/ for(u=0; u<f_ndims; u++) { /* Keep the size of the chunk dimensions as hsize_t for various routines */ @@ -2564,6 +2576,10 @@ done: if(H5I_dec_ref(f_tid)<0) HDONE_ERROR (H5E_DATASET, H5E_CANTFREE, FAIL, "Can't decrement temporary datatype ID") } /* end if */ + if(file_space_normalized) { + if(H5S_hyper_denormalize_offset(file_space, old_offset)<0) + HGOTO_ERROR (H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") + } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_create_chunk_map() */ @@ -2722,12 +2738,6 @@ H5D_create_chunk_file_map_hyper(const fm_map *fm) HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to convert selection to span trees") } /* end if */ - /* Normalize hyperslab selections by adjusting them by the offset */ - if(H5S_hyper_normalize_offset(tmp_fchunk)<0) { - (void)H5S_close(tmp_fchunk); - HGOTO_ERROR (H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") - } /* end if */ - /* "AND" temporary chunk and current chunk */ if(H5S_select_hyperslab(tmp_fchunk,H5S_SELECT_AND,coords,NULL,fm->chunk_dim,NULL)<0) { (void)H5S_close(tmp_fchunk); diff --git a/src/H5Shyper.c b/src/H5Shyper.c index 6f8c1d1..b9f22fb 100644 --- a/src/H5Shyper.c +++ b/src/H5Shyper.c @@ -3671,7 +3671,7 @@ done: REVISION LOG --------------------------------------------------------------------------*/ static htri_t -H5S_hyper_intersect_block_helper (const H5S_hyper_span_info_t *spans, hssize_t *offset, hsize_t *start, hsize_t *end) +H5S_hyper_intersect_block_helper (const H5S_hyper_span_info_t *spans, hsize_t *start, hsize_t *end) { H5S_hyper_span_t *curr; /* Pointer to current span in 1st span tree */ htri_t status; /* Status from recursive call */ @@ -3681,7 +3681,6 @@ H5S_hyper_intersect_block_helper (const H5S_hyper_span_info_t *spans, hssize_t * /* Sanity check */ assert(spans); - assert(offset); assert(start); assert(end); @@ -3691,11 +3690,11 @@ H5S_hyper_intersect_block_helper (const H5S_hyper_span_info_t *spans, hssize_t * /* Iterate over the spans in the tree */ while(curr!=NULL) { /* Check for span entirely before block */ - if(((hssize_t)curr->high+*offset)<(hssize_t)*start) + if(curr->high < *start) /* Advance to next span in this dimension */ curr=curr->next; /* If this span is past the end of the block, then we're done in this dimension */ - else if(((hssize_t)curr->low+*offset)>(hssize_t)*end) + else if(curr->low > *end) HGOTO_DONE(FALSE) /* block & span overlap */ else { @@ -3703,7 +3702,7 @@ H5S_hyper_intersect_block_helper (const H5S_hyper_span_info_t *spans, hssize_t * HGOTO_DONE(TRUE) else { /* Recursively check spans in next dimension down */ - if((status=H5S_hyper_intersect_block_helper(curr->down,offset+1,start+1,end+1))<0) + if((status=H5S_hyper_intersect_block_helper(curr->down,start+1,end+1))<0) HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab intersection check"); /* If there is a span intersection in the down dimensions, the span trees overlap */ @@ -3763,7 +3762,7 @@ H5S_hyper_intersect_block (H5S_t *space, hsize_t *start, hsize_t *end) HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree"); /* Perform the span-by-span intersection check */ - if((ret_value=H5S_hyper_intersect_block_helper(space->select.sel_info.hslab->span_lst,space->select.offset,start,end))<0) + if((ret_value=H5S_hyper_intersect_block_helper(space->select.sel_info.hslab->span_lst,start,end))<0) HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab intersection check"); done: @@ -4106,20 +4105,22 @@ done: "Normalize" a hyperslab selection by adjusting it's coordinates by the amount of the selection offset. USAGE - herr_t H5S_hyper_normalize_offset(space) + herr_t H5S_hyper_normalize_offset(space, old_offset) H5S_t *space; IN/OUT: Pointer to dataspace to move + hssize_t *old_offset; OUT: Pointer to space to store old offset RETURNS Non-negative on success, negative on failure DESCRIPTION - Moves the hyperslab selection by the selection offset and then resets - the selection offset to zeros. + Copies the current selection offset into the array provided, then + inverts the selection offset, subtracts the offset from the hyperslab + selection and resets the offset to zero. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ herr_t -H5S_hyper_normalize_offset(H5S_t *space) +H5S_hyper_normalize_offset(H5S_t *space, hssize_t *old_offset) { unsigned u; /* Local index variable */ herr_t ret_value=SUCCEED; /* Return value */ @@ -4131,17 +4132,18 @@ H5S_hyper_normalize_offset(H5S_t *space) /* Check for 'all' selection, instead of a hyperslab selection */ /* (Technically, this check shouldn't be in the "hyperslab" routines...) */ if(H5S_GET_SELECT_TYPE(space)!=H5S_SEL_ALL) { - /* Invert the selection offset */ - for(u=0; u<space->extent.rank; u++) - space->select.offset[u] =- space->select.offset[u]; + /* Copy & invert the selection offset */ + for(u=0; u<space->extent.rank; u++) { + old_offset[u] = space->select.offset[u]; + space->select.offset[u] = -space->select.offset[u]; + } /* end for */ /* Call the existing 'adjust' routine */ if(H5S_hyper_adjust_s(space, space->select.offset)<0) HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab normalization"); /* Zero out the selection offset */ - for(u=0; u<space->extent.rank; u++) - space->select.offset[u] = 0; + HDmemset(space->select.offset, 0, sizeof(hssize_t) * space->extent.rank); } /* end if */ done: @@ -4151,6 +4153,52 @@ done: /*-------------------------------------------------------------------------- NAME + H5S_hyper_denormalize_offset + PURPOSE + "Denormalize" a hyperslab selection by reverse adjusting it's coordinates + by the amount of the former selection offset. + USAGE + herr_t H5S_hyper_normalize_offset(space, old_offset) + H5S_t *space; IN/OUT: Pointer to dataspace to move + hssize_t *old_offset; IN: Pointer to old offset array + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Subtracts the old offset from the current selection (canceling out the + effect of the "normalize" routine), then restores the old offset into + the dataspace. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5S_hyper_denormalize_offset(H5S_t *space, const hssize_t *old_offset) +{ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5S_hyper_denormalize_offset); + + assert(space); + + /* Check for 'all' selection, instead of a hyperslab selection */ + /* (Technically, this check shouldn't be in the "hyperslab" routines...) */ + if(H5S_GET_SELECT_TYPE(space)!=H5S_SEL_ALL) { + /* Call the existing 'adjust' routine */ + if(H5S_hyper_adjust_s(space, old_offset)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab normalization"); + + /* Copy the selection offset over */ + HDmemcpy(space->select.offset, old_offset, sizeof(hssize_t) * space->extent.rank); + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5S_hyper_denormalize_offset() */ + + +/*-------------------------------------------------------------------------- + NAME H5S_hyper_append_span PURPOSE Create a new span and append to span list diff --git a/src/H5Sprivate.h b/src/H5Sprivate.h index 06c9f02..ac6a297 100644 --- a/src/H5Sprivate.h +++ b/src/H5Sprivate.h @@ -258,7 +258,8 @@ H5_DLL htri_t H5S_hyper_intersect_block (H5S_t *space, hsize_t *start, hsize_t * H5_DLL herr_t H5S_hyper_adjust_u(H5S_t *space, const hsize_t *offset); H5_DLL herr_t H5S_hyper_adjust_s(H5S_t *space, const hssize_t *offset); H5_DLL herr_t H5S_hyper_move(H5S_t *space, const hssize_t *offset); -H5_DLL herr_t H5S_hyper_normalize_offset(H5S_t *space); +H5_DLL herr_t H5S_hyper_normalize_offset(H5S_t *space, hssize_t *old_offset); +H5_DLL herr_t H5S_hyper_denormalize_offset(H5S_t *space, const hssize_t *old_offset); /* Operations on selection iterators */ H5_DLL herr_t H5S_select_iter_init(H5S_sel_iter_t *iter, const H5S_t *space, size_t elmt_size); diff --git a/test/tselect.c b/test/tselect.c index 1801e0c..92e765c 100644 --- a/test/tselect.c +++ b/test/tselect.c @@ -133,6 +133,11 @@ #define SPACE11_DIM2 100 #define SPACE11_NPOINTS 4 +/* Information for offsets w/chunks test #2 */ +#define SPACE12_RANK 1 +#define SPACE12_DIM0 25 +#define SPACE12_CHUNK_DIM0 5 + /* Location comparison function */ int compare_size_t(const void *s1, const void *s2); @@ -6741,6 +6746,108 @@ test_select_hyper_chunk_offset(void) /**************************************************************** ** +** test_select_hyper_chunk_offset2(): Tests selections on dataspace, +** another test to verify that offsets for hyperslab selections are +** working in chunked datasets. +** +****************************************************************/ +static void +test_select_hyper_chunk_offset2(void) +{ + hid_t file, dataset; /* handles */ + hid_t dataspace; + hid_t memspace; + hid_t dcpl; /* Dataset creation property list */ + herr_t status; + unsigned data_out[SPACE12_DIM0]; /* output buffer */ + unsigned data_in[SPACE12_CHUNK_DIM0]; /* input buffer */ + hsize_t dims[SPACE12_RANK]={SPACE12_DIM0}; /* Dimension size */ + hsize_t chunk_dims[SPACE12_RANK]={SPACE12_CHUNK_DIM0}; /* Chunk size */ + hsize_t start[SPACE12_RANK]; /* Start of hyperslab */ + hsize_t count[SPACE12_RANK]; /* Size of hyperslab */ + hssize_t offset[SPACE12_RANK]; /* hyperslab offset in the file */ + unsigned u, v; /* Local index variables */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing more hyperslab selections using offsets in chunked datasets\n")); + + /* Initialize data to write out */ + for (u = 0; u < SPACE12_DIM0; u++) + data_out[u] = u; + + /* Create the file */ + file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* Create dataspace */ + dataspace = H5Screate_simple(SPACE12_RANK, dims, NULL); + CHECK(dataspace, FAIL, "H5Screate_simple"); + + /* Create dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set chunk sizes */ + status = H5Pset_chunk(dcpl, SPACE12_RANK, chunk_dims); + CHECK(status, FAIL, "H5Pset_chunk"); + + /* Create dataset */ + dataset = H5Dcreate(file, DATASETNAME, H5T_NATIVE_UINT, dataspace, dcpl); + CHECK(dataset, FAIL, "H5Dcreate"); + + /* Close DCPL */ + status = H5Pclose(dcpl); + CHECK(status, FAIL, "H5Pclose"); + + /* Write out entire dataset */ + status = H5Dwrite(dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_out); + CHECK(status, FAIL, "H5Dclose"); + + /* Create memory dataspace (same size as a chunk) */ + memspace = H5Screate_simple(SPACE12_RANK, chunk_dims, NULL); + CHECK(dataspace, FAIL, "H5Screate_simple"); + + /* + * Define hyperslab in the file dataspace. + */ + start[0] = 0; + count[0] = SPACE12_CHUNK_DIM0; + status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(status, FAIL, "H5Sselect_hyperslab"); + + /* Loop through retrieving data from file, checking it against data written */ + for(u = 0; u < SPACE12_DIM0; u += SPACE12_CHUNK_DIM0) { + /* Set the offset of the file selection */ + offset[0] = u; + status = H5Soffset_simple(dataspace, offset); + CHECK(status, FAIL, "H5Soffset_simple"); + + /* Read in buffer of data */ + status = H5Dread(dataset, H5T_NATIVE_UINT, memspace, dataspace, + H5P_DEFAULT, data_in); + CHECK(status, FAIL, "H5Dread"); + + /* Check data read in */ + for(v = 0; v < SPACE12_CHUNK_DIM0; v++) + if(data_out[u + v] != data_in[v]) + TestErrPrintf("Error! data_out[%u]=%u, data_in[%u]=%u\n",(unsigned)(u + v), data_out[u + v], v, data_in[v]); + } /* end for */ + + status = H5Dclose(dataset); + CHECK(status, FAIL, "H5Dclose"); + + status = H5Sclose(dataspace); + CHECK(status, FAIL, "H5Sclose"); + + status = H5Sclose(memspace); + CHECK(status, FAIL, "H5Sclose"); + + status = H5Fclose(file); + CHECK(status, FAIL, "H5Fclose"); +} /* test_select_hyper_chunk_offset2() */ + +/**************************************************************** +** ** test_select_bounds(): Tests selection bounds on dataspaces, ** both with and without offsets. ** @@ -7083,6 +7190,7 @@ test_select(void) /* Test using selection offset on hyperslab in chunked dataset */ test_select_hyper_chunk_offset(); + test_select_hyper_chunk_offset2(); /* Test selection bounds with & without offsets */ test_select_bounds(); |