[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
This commit is contained in:
Quincey Koziol 2005-06-18 00:10:22 -05:00
parent 04e424638a
commit d641030436
5 changed files with 194 additions and 22 deletions

View File

@ -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

View File

@ -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);

View File

@ -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,23 +4132,70 @@ 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:
FUNC_LEAVE_NOAPI(ret_value);
} /* H5S_hyper_normalize_offset() */
/*--------------------------------------------------------------------------
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

View File

@ -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);

View File

@ -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);
@ -6739,6 +6744,108 @@ test_select_hyper_chunk_offset(void)
HDfree(rbuf);
} /* test_select_hyper_chunk_offset() */
/****************************************************************
**
** 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,
@ -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();