From 85e9aaf368a92d152e6294317a9014cf18097728 Mon Sep 17 00:00:00 2001 From: Ward Fisher Date: Fri, 11 Aug 2017 18:18:11 -0600 Subject: [PATCH] Wiring in a large test to check against a regression for the issue described in https://github.com/Unidata/netcdf-c/pull/457 --- nc_test/CMakeLists.txt | 2 +- nc_test/Makefile.am | 5 +- nc_test/tst_large_cdf5.c | 179 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 nc_test/tst_large_cdf5.c diff --git a/nc_test/CMakeLists.txt b/nc_test/CMakeLists.txt index 209bacdd0c..a081aa3199 100644 --- a/nc_test/CMakeLists.txt +++ b/nc_test/CMakeLists.txt @@ -51,7 +51,7 @@ IF(USE_PNETCDF) ENDIF() IF(LARGE_FILE_TESTS) - SET(TESTS ${TESTS} quick_large_files tst_big_var6 tst_big_var2 tst_big_rvar tst_big_var tst_large) + SET(TESTS ${TESTS} quick_large_files tst_big_var6 tst_big_var2 tst_big_rvar tst_big_var tst_large tst_large_cdf5) IF(NOT MSVC) SET(TESTS ${TESTS} large_files) ENDIF() diff --git a/nc_test/Makefile.am b/nc_test/Makefile.am index 8e03ff31f5..87d074e9e1 100644 --- a/nc_test/Makefile.am +++ b/nc_test/Makefile.am @@ -16,7 +16,8 @@ tst_*.nc t_nc.nc large_files.nc quick_large_files.nc \ tst_diskless.nc tst_diskless2.nc \ tst_diskless3.nc tst_diskless3_file.cdl tst_diskless3_memory.cdl \ tst_diskless4.cdl tst_diskless4.nc tst_formatx.nc nc_test_cdf5.nc \ -unlim.nc tst_inq_type.nc tst_elatefill.nc tst_global_fillval.nc +unlim.nc tst_inq_type.nc tst_elatefill.nc tst_global_fillval.nc \ +tst_large_cdf5.nc check_PROGRAMS = @@ -45,7 +46,7 @@ AM_CPPFLAGS += -I$(top_builddir)/liblib -I$(top_builddir)/include -I$(top_srcdir # If the user asked for large file tests, then add them. if LARGE_FILE_TESTS TESTPROGRAMS += quick_large_files tst_big_var6 tst_big_var2 \ -tst_big_rvar tst_big_var tst_large large_files +tst_big_rvar tst_big_var tst_large large_files tst_large_cdf5 endif # LARGE_FILE_TESTS if BUILD_BENCHMARKS diff --git a/nc_test/tst_large_cdf5.c b/nc_test/tst_large_cdf5.c new file mode 100644 index 0000000000..c45e47e29b --- /dev/null +++ b/nc_test/tst_large_cdf5.c @@ -0,0 +1,179 @@ +/* + Copyright 2017, UCAR/Unidata + See COPYRIGHT file for copying and redistribution conditions. + + This program tests the large file bug in netCDF 3.6.2, + creating byte and short variables larger than 4 GiB. + + This program is based on tst_large.c, and tests against + CDF5. + + $Id: tst_large.c,v 1.16 2010/05/18 20:20:01 russ Exp $ +*/ +#include +#include +#include +#include +#include +#include "err_macros.h" +#include + +/* Test with both classic and 64-bit offset files. If netcdf-4 is + * included, test with both netCDF-4 format variants also. */ +#ifdef USE_NETCDF4 +#define NUM_FORMATS (4) +#else +#define NUM_FORMATS (2) +#endif + +#define NUMDIMS 2 /* rank of each variable in tests */ +#define DIM1 2048 +#define DIM2 2097153 /* DIM1*DIM2*sizeof(char) > 2**32 */ +#define DIM3 1024 +#define DIM4 2097153 /* DIM3*DIM4*sizeof(short) > 2**32 */ + +/* + * In netCDF-3.6.2, a divide by zero occurs on 32-bit platforms when + * creating a variable for which the product of dimensions is exactly + * 2**32. Check that this bug has been fixed. + */ +static int +test_big_var(const char *testfile) { + int ncid, varid, dimids[NUMDIMS]; + int cflag = NC_CLOBBER; + nc_type type = NC_BYTE; + size_t index[NUMDIMS]; + signed char nval = 99; + int nval_in; + + /* Define the file with one large variable. */ + if (nc_create(testfile, cflag|NC_64BIT_DATA, &ncid)) ERR; + if (nc_set_fill(ncid, NC_NOFILL, NULL)) ERR; + if (nc_def_dim(ncid, "dim1", DIM1, &dimids[0])) ERR; + if (nc_def_dim(ncid, "dim2", DIM2 - 1, &dimids[1])) ERR; + if (nc_def_var(ncid, "var", type, NUMDIMS, dimids, &varid)) ERR; + if (nc_enddef(ncid)) ERR; + + /* Write one datum, near the end of the variable. */ + index[0] = DIM1 - 1; + index[1] = DIM2 - 2; + if (nc_put_var1_schar(ncid, varid, index, &nval)) ERR; + if (nc_close(ncid)) ERR; + + /* Reopen the file and check that datum. */ + if (nc_open(testfile, NC_NOWRITE, &ncid)) ERR; + if (nc_inq_varid(ncid, "var", &varid)) ERR; + if (nc_get_var1_int(ncid, varid, index, &nval_in)) ERR; + if (nval != nval_in) + ERR; + if (nc_close(ncid)) ERR; + return 0; +} + +static int +test_large_byte_var(const char *testfile) { + int ncid, varid, dimids[NUMDIMS]; + size_t index[NUMDIMS] = {0, 0}; + signed char vals[DIM2]; + signed char char_val_in; + size_t start[NUMDIMS], count[NUMDIMS]; + int j; + + if (nc_create(testfile, NC_CLOBBER|NC_64BIT_DATA, &ncid)) ERR; + if (nc_set_fill(ncid, NC_NOFILL, NULL)) ERR; + if (nc_def_dim(ncid, "dim1", DIM1, &dimids[0])) ERR; + if (nc_def_dim(ncid, "dim2", DIM2, &dimids[1])) ERR; + if (nc_def_var(ncid, "var", NC_BYTE, NUMDIMS, dimids, &varid)) ERR; + if (nc_enddef(ncid)) ERR; + + for (j = 0; j < DIM2; j++) { + vals[j] = 9 * (j + 11); /* note vals[j] is 99 when j==0 */ + } + start[1] = 0; + count[0] = 1; + count[1] = DIM2; + for (start[0] = 0; start[0] < DIM1; start[0]++) { + if (nc_put_vara_schar(ncid, varid, start, count, vals)) + { + ERR; + break; + } + } + + if (nc_close(ncid)) ERR; + if (nc_open(testfile, NC_NOWRITE, &ncid)) ERR; + if (nc_inq_varid(ncid, "var", &varid)) ERR; + if (nc_get_var1_schar(ncid, varid, index, &char_val_in)) ERR; + if (char_val_in != 99) /* see above, the value written when start[0]==0, j==0 */ + ERR; + if (nc_close(ncid)) ERR; + return 0; +} + +static int +test_large_short_var(const char *testfile) { + int ncid, varid, dimids[NUMDIMS]; + int int_val_in, int_val_out = 99; + size_t index[2]; + int cflag = NC_CLOBBER; + + if (nc_create(testfile, cflag|NC_64BIT_DATA, &ncid)) ERR; + if (nc_def_dim(ncid, "dim3", DIM3, &dimids[0])) ERR; + if (nc_def_dim(ncid, "dim4", DIM4, &dimids[1])) ERR; + if (nc_def_var(ncid, "var", NC_SHORT, NUMDIMS, dimids, &varid)) ERR; + if (nc_enddef(ncid)) ERR; + index[0] = 0; + index[1] = 1; + if (nc_put_var1_int(ncid, varid, index, &int_val_out)) ERR; + if (nc_close(ncid)) ERR; + if (nc_open(testfile, NC_NOWRITE, &ncid)) ERR; + if (nc_inq_varid(ncid, "var", &varid)) ERR; + if (nc_get_var1_int(ncid, varid, index, &int_val_in)) ERR; + if (int_val_in != int_val_out) + ERR; +#ifndef NOFILL + index[0] = 1; + index[1] = 2; + if (nc_get_var1_int(ncid, varid, index, &int_val_in)) ERR; + if (int_val_in != NC_FILL_SHORT) + ERR; +#endif + if (nc_close(ncid)) ERR; + return 0; +} + +#define FILE_NAME "tst_large_cdf5.nc" + +int +main(int argc, char **argv) { + int i; + char testfile[NC_MAX_NAME + 1]; + + sprintf(testfile, "%s/%s", TEMP_LARGE, FILE_NAME); + + printf("\n*** Testing fix for 3.6.2 large file bug in %s.\n", + testfile); + /* Go thru formats and run all tests for each of two (for netCDF-3 + * only builds), or 4 (for netCDF-4 builds) different formats. */ + for (i = NC_FORMAT_CLASSIC; i <= NUM_FORMATS; i++) + { + nc_set_default_format(i, NULL); + + printf("*** testing format %d with a variable with 2**32 values...", i); + test_big_var(testfile); + (void) remove(testfile); + SUMMARIZE_ERR; + + printf("*** testing format %d with a byte variable with > 2**32 values...", i); + test_large_byte_var(testfile); + (void) remove(testfile); + SUMMARIZE_ERR; + + printf("*** testing format %d with a short variable with > 2**32 values...", i); + test_large_short_var(testfile); + (void) remove(testfile); + SUMMARIZE_ERR; + } + + FINAL_RESULTS; +}