Skip to content

Commit

Permalink
Merge pull request #224 from Unidata/gh221
Browse files Browse the repository at this point in the history
Fix for github issue #221
  • Loading branch information
WardF committed Feb 19, 2016
2 parents 845f3b2 + d5afdff commit e6c2f7a
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 12 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ scan-build
.deps
.libs
*.zip
*.gz
Makefile
.DS_Store
build-par
Expand Down
4 changes: 4 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ Release Notes {#RELEASE_NOTES}

This file contains a high-level description of this package's evolution. Releases are in reverse chronological order (most recent first). Note that, as of netcdf 4.2, the `netcdf-c++` and `netcdf-fortran` libraries have been separated into their own libraries.

## 4.4.1 - TBD

* Addressed an issue where `ncdump` would crash when trying to read a netcdf file containing an empty ragged `VLEN` variable in an unlimited dimension. See [GitHub #221](https://github.com/Unidata/netcdf-c/issues/221) for more information.

## 4.4.0 Released - January 13, 2016

* Bumped SO version to 11.0.0.
Expand Down
Binary file added gh221.nc.gz
Binary file not shown.
9 changes: 8 additions & 1 deletion libsrc4/nc4hdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,7 @@ nc4_get_vara(NC *nc, int ncid, int varid, const size_t *startp,
filldata = (char *)data + real_data_size;
for (i = 0; i < fill_len; i++)
{

if (var->type_info->nc_type_class == NC_STRING)
{
if (*(char **)fillvalue)
Expand All @@ -1157,7 +1158,13 @@ nc4_get_vara(NC *nc, int ncid, int varid, const size_t *startp,
else
*(char **)filldata = NULL;
}
else
else if(var->type_info->nc_type_class == NC_VLEN) {
if(fillvalue) {
memcpy(filldata,fillvalue,file_type_size);
} else {
*(char **)filldata = NULL;
}
} else
memcpy(filldata, fillvalue, file_type_size);
filldata = (char *)filldata + file_type_size;
}
Expand Down
14 changes: 8 additions & 6 deletions nc_test4/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,20 @@ SET(NC4_TESTS tst_dims tst_dims2 tst_dims3 tst_files tst_files4 tst_vars
build_bin_test(renamegroup)
add_sh_test(nc_test4 run_grp_rename)

##
# The shell script, run_empty_vlen_test.sh,
# depends on the 'tst_empty_vlen_unlim' binary.
##
BUILD_BIN_TEST(tst_empty_vlen_unlim)
ADD_SH_TEST(nc_test4 run_empty_vlen_test)


IF(NOT MSVC)
SET(NC4_TESTS ${NC4_TESTS} tst_interops5 tst_camrun)
ENDIF()

# If the v2 API was built, add the test program.
IF(ENABLE_V2_API)

build_bin_test(tst_v2)
ENDIF()

Expand Down Expand Up @@ -82,8 +89,3 @@ IF(TEST_PARALLEL)
build_bin_test(tst_mode)
add_sh_test(nc_test4 run_par_test)
ENDIF()

## Specify files to be distributed by 'make dist'
FILE(GLOB CUR_EXTRA_DIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.c ${CMAKE_CURRENT_SOURCE_DIR}/*.h ${CMAKE_CURRENT_SOURCE_DIR}/*.sh)
SET(CUR_EXTRA_DIST ${CUR_EXTRA_DIST} CMakeLists.txt Makefile.am)
SET(CUR_EXTRA_DIST ${CUR_EXTRA_DIST} ref_chunks1.cdl ref_chunks2.cdl ref_tst_compounds.nc ref_tst_xplatform2_1.nc ref_tst_xplatform2_2.nc ref_tst_dims.nc ref_tst_interops4.nc ref_grp_rename.cdl ref_tst_nvars.nc contig.hdf4 chunked.hdf4)
8 changes: 4 additions & 4 deletions nc_test4/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ t_type cdm_sea_soundings tst_camrun tst_vl tst_atts1 tst_atts2 \
tst_vars2 tst_files5 tst_files6 tst_sync tst_h_strbug tst_h_refs \
tst_h_scalar tst_rename tst_h5_endians tst_atts_string_rewrite

check_PROGRAMS = $(NC4_TESTS) renamegroup
check_PROGRAMS = $(NC4_TESTS) renamegroup tst_empty_vlen_unlim

# Add these if large file tests are turned on.
if LARGE_FILE_TESTS
Expand All @@ -32,7 +32,7 @@ endif

TESTS = $(NC4_TESTS)

TESTS += run_grp_rename.sh
TESTS += run_grp_rename.sh run_empty_vlen_test.sh

# If the v2 API was built, add its test program.
if BUILD_V2
Expand Down Expand Up @@ -123,7 +123,7 @@ ref_tst_interops4.nc run_get_knmi_files.sh CMakeLists.txt \
run_grp_rename.sh tst_formatx_hdf4.sh \
run_chunk_hdf4.sh contiguous.hdf4 chunked.hdf4 \
tst_h5_endians.c tst_h4_lendian.c tst_atts_string_rewrite.c \
tst_put_vars_two_unlim_dim.c
tst_put_vars_two_unlim_dim.c tst_empty_vlen_unlim.c run_empty_vlen_test.sh

CLEANFILES = tst_mpi_parallel.bin cdm_sea_soundings.nc bm_chunking.nc \
bm_radar.nc bm_radar1.nc radar_3d_compression_test.txt \
Expand All @@ -134,7 +134,7 @@ tst_elena_*.cdl tst_simple*.cdl tst_chunks.cdl pr_A1.* tauu_A1.* \
usi_01.* thetau_01.* tst_*.nc tst_*.h5 \
tst_grp_rename.cdl tst_grp_rename.nc tst_grp_rename.dmp ref_grp_rename.cdl \
foo1.nc tst_interops2.h4 tst_h5_endians.nc tst_h4_lendian.h4 test.nc \
tst_atts_string_rewrite.nc
tst_atts_string_rewrite.nc tst_empty_vlen_unlim.nc tst_empty_vlen_lim.nc

if USE_HDF4_FILE_TESTS
DISTCLEANFILES = AMSR_E_L2_Rain_V10_200905312326_A.hdf \
Expand Down
34 changes: 34 additions & 0 deletions nc_test4/run_empty_vlen_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/sh
#
# Front-end for tst_empty_vlen_unlim.c. This test
# ensures that valid netcdf files are generated when
# a ragged VLEN array is defined but not populated.
#
# This script runs tst_empty_vlen_unlim and then
# runs `ncdump` against the two generated files.
#
# See https://github.com/Unidata/netcdf-c/issues/221 for
# full details.
#

set -e

if test "x$srcdir" = x ; then
srcdir=`pwd`
fi

echo ""
echo "* Testing Empty Ragged Arrays (VLEN)"

echo "Generating test netcdf files."
./tst_empty_vlen_unlim

echo "Validating Files with ncdump."
echo "======================================"
../ncdump/ncdump -s tst_empty_vlen_unlim.nc
echo "---------------------------------------"
../ncdump/ncdump -s tst_empty_vlen_lim.nc
echo "======================================"

echo "* Tests Passed."
exit 0
224 changes: 224 additions & 0 deletions nc_test4/tst_empty_vlen_unlim.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
/* This is part of the netCDF package. Copyright 2005 University
Corporation for Atmospheric Research/Unidata See COPYRIGHT file for
conditions of use.
This program excersizes HDF5 variable length array code.
$Id: tst_h_vl2.c,v 1.5 2010/06/01 15:34:52 ed Exp $
*/

/* This test was added to help diagnose the issue described at:
* * https://github.com/Unidata/netcdf-c/issues/221
* This issue was originally reported by the python group at:
* * https://github.com/Unidata/netcdf4-python/issues/527
*/


#include <nc_tests.h>
#include <hdf5.h>
#include <nc_logging.h>

#define FILE_NAME_UNLIM "tst_empty_vlen_unlim.nc"
#define FILE_NAME_LIM "tst_empty_vlen_lim.nc"
#define DIM_LEN_UNLIM NC_UNLIMITED
#define DIM_LEN_LIM 5
#define DIM_NAME "x"
#define VLEN_NAME "vltest"
#define VAR_NAME1 "v"
#define VAR_NAME2 "w"
#define ROW_COUNT 3
#define VLEN0 2
#define VLEN1 3
#define VLEN2 3

int main() {

printf("Testing access to unset entries in VLEN variable, unlimited dimension\n");
{
int ncid, typeid, dimid, varid, varid2;
nc_vlen_t data[ROW_COUNT];
int stat;
float *dat0, *dat1, *dat2;
float *data2;
size_t startp[3] = {0,0,0};
size_t countp[3] = {VLEN0,VLEN1,VLEN2};
size_t startp2[1] = {0};
size_t countp2[1] = {VLEN2};
int i = 0;
/* Create File */
printf("\t* Creating File:\tnc_create()\n");
if (nc_create(FILE_NAME_UNLIM, NC_NETCDF4 | NC_CLOBBER, &ncid)) ERR;

/* Set fill mode */
//printf("\t* Setting fill mode:\tnc_set_fill()\n");
//if(nc_set_fill(ncid,NC_FILL,NULL)) ERR;

/* Create Dimension */
printf("\t* Defining Unlimited Dimension:\tnc_def_dim()\n");
if (nc_def_dim(ncid, DIM_NAME, DIM_LEN_UNLIM, &dimid)) ERR;

/* Create ragged array type. */
printf("\t* Creating Ragged Array type:\tnc_def_vlen().\n");
if (nc_def_vlen(ncid, VLEN_NAME, NC_FLOAT, &typeid)) ERR;

/* Create a variable of typeid. */
printf("\t* Creating Variable using Ragged Arrayt Type:\tnc_def_var().\n");
if (nc_def_var(ncid, VAR_NAME1, typeid, 1, &dimid, &varid)) ERR;

/* Create a variable of type float. */
printf("\t* Creating secondary Variable using NC_FLOAT:\tnc_def_var().\n");
if (nc_def_var(ncid, VAR_NAME2, NC_FLOAT, 1, &dimid, &varid2)) ERR;

/* End define mode. */
printf("\t* Ending define mode:\tnc_enddef().\n");

/* Write out data for w */
printf("\t* Creating float data for secondary variable.\n");
data2 = (float*)malloc(sizeof(float) * VLEN2);
for(i = 0; i < VLEN2; i++) {
data2[i] = (float)i;
}

printf("\t* Puting data in secondary variable:\tnc_put_vara().\n");
if (nc_put_vara(ncid,varid2,&startp2,&countp2,data2)) ERR;

/***********/
/* Actually unnecessary to recreate the issue. */
/***********/


/* Write out varying-length data for v[0] and v[1]. Leave v[2] empty. */

dat0 = (float*)malloc(VLEN0 * sizeof(float));
for(i = 0; i < VLEN0; i++) {
dat0[i] = (float)i;
}
dat1 = (float*)malloc(VLEN1 * sizeof(float));
for(i = 0; i < VLEN1; i++) {
dat1[i] = (float)i;
}
dat2 = (float*)malloc(VLEN2 * sizeof(float));
for(i = 0; i < VLEN2; i++) {
dat2[i] = (float)i;
}

data[0].p = dat0;
data[0].len = VLEN0;

data[1].p = dat1;
data[1].len = VLEN1;

data[2].p = dat2;
data[2].len = VLEN2;

//printf("\t* Puting data in VLEN variable:\tnc_put_vara().\n");
//stat = nc_put_vara(ncid,varid,&startp,&countp,data);
//stat = nc_put_var(ncid,varid,&data);
//if(stat) ERR;



/* Close File. */
printf("\t* Closing file:\tnc_close().\n");
if (stat = nc_close(ncid)) ERR;


}

printf("Testing access to unset entries in VLEN variable, unlimit dimension\n");
{
int ncid, typeid, dimid, varid, varid2;
nc_vlen_t data[ROW_COUNT];
int stat;
float *dat0, *dat1, *dat2;
float *data2;
size_t startp[3] = {0,0,0};
size_t countp[3] = {VLEN0,VLEN1,VLEN2};
size_t startp2[1] = {0};
size_t countp2[1] = {VLEN2};
int i = 0;
/* Create File */
printf("\t* Creating File:\tnc_create()\n");
if (nc_create(FILE_NAME_LIM, NC_NETCDF4 | NC_CLOBBER, &ncid)) ERR;

/* Set fill mode */
//printf("\t* Setting fill mode:\tnc_set_fill()\n");
//if(nc_set_fill(ncid,NC_FILL,NULL)) ERR;

/* Create Dimension */
printf("\t* Defining Unlimited Dimension:\tnc_def_dim()\n");
if (nc_def_dim(ncid, DIM_NAME, DIM_LEN_LIM, &dimid)) ERR;

/* Create ragged array type. */
printf("\t* Creating Ragged Array type:\tnc_def_vlen().\n");
if (nc_def_vlen(ncid, VLEN_NAME, NC_FLOAT, &typeid)) ERR;

/* Create a variable of typeid. */
printf("\t* Creating Variable using Ragged Arrayt Type:\tnc_def_var().\n");
if (nc_def_var(ncid, VAR_NAME1, typeid, 1, &dimid, &varid)) ERR;

/* Create a variable of type float. */
printf("\t* Creating secondary Variable using NC_FLOAT:\tnc_def_var().\n");
if (nc_def_var(ncid, VAR_NAME2, NC_FLOAT, 1, &dimid, &varid2)) ERR;

/* End define mode. */
printf("\t* Ending define mode:\tnc_enddef().\n");

/* Write out data for w */
printf("\t* Creating float data for secondary variable.\n");
data2 = (float*)malloc(sizeof(float) * VLEN2);
for(i = 0; i < VLEN2; i++) {
data2[i] = (float)i;
}

printf("\t* Puting data in secondary variable:\tnc_put_vara().\n");
if (nc_put_vara(ncid,varid2,&startp2,&countp2,data2)) ERR;

/***********/
/* Actually unnecessary to recreate the issue. */
/***********/


/* Write out varying-length data for v[0] and v[1]. Leave v[2] empty. */

dat0 = (float*)malloc(VLEN0 * sizeof(float));
for(i = 0; i < VLEN0; i++) {
dat0[i] = (float)i;
}
dat1 = (float*)malloc(VLEN1 * sizeof(float));
for(i = 0; i < VLEN1; i++) {
dat1[i] = (float)i;
}
dat2 = (float*)malloc(VLEN2 * sizeof(float));
for(i = 0; i < VLEN2; i++) {
dat2[i] = (float)i;
}

data[0].p = dat0;
data[0].len = VLEN0;

data[1].p = dat1;
data[1].len = VLEN1;

data[2].p = dat2;
data[2].len = VLEN2;

//printf("\t* Puting data in VLEN variable:\tnc_put_vara().\n");
//stat = nc_put_vara(ncid,varid,&startp,&countp,data);
//stat = nc_put_var(ncid,varid,&data);
//if(stat) ERR;



/* Close File. */
printf("\t* Closing file:\tnc_close().\n");
if (stat = nc_close(ncid)) ERR;


}


SUMMARIZE_ERR;
FINAL_RESULTS;

}

0 comments on commit e6c2f7a

Please sign in to comment.