1 /*
2   Copyright 2018, UCAR/Unidata
3   See COPYRIGHT file for copying and redistribution conditions.
4 
5   This program tests the fix for a large file bug in versions previous
6   to netCDF-4.1.2 for 32-bit platforms, writing to a variable with
7   more than 1 dimension and more than 2**32 values, where the write
8   starts after the first 2**32 elements.
9 
10   Russ Rew
11 */
12 
13 #include <nc_tests.h>
14 #include "err_macros.h"
15 #include <netcdf.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 
20 #define FILE_NAME "tst_big_var6.nc"
21 
22 /* Test with both classic and 64-bit offset files. If netcdf-4 is
23  * included, test with both netCDF-4 format variants also. */
24 #ifdef USE_NETCDF4
25 #define NUM_FORMATS (4)
26 #else
27 #define NUM_FORMATS (2)
28 #endif
29 
30 #define NUMDIMS 4	      /* rank of variable in tests */
31 #define DIM0 1
32 #define DIM1 2
33 #define DIM2 5000
34 #define DIM3 1000000		/* DIM2*DIM3 > 2**32 */
35 #define FIRST_VAL   65
36 #define SECOND_VAL  90
37 /*
38  * This program tests the fix for a large file bug in versions
39  * previous to netCDF-4.1.2 for 32-bit platforms, writing to a
40  * variable with more than 1 dimension and more than 2**32 values,
41  * where the write starts after the first 2**32 elements.  The bug
42  * applies to record variables with more than 2**32 values per record
43  * as well, but that's not tested here.
44  */
45 static int
test_big_var(const char * testfile)46 test_big_var(const char *testfile)
47 {
48     int ncid, varid, dimids[NUMDIMS];
49     size_t start[NUMDIMS] = {0, 0, 0, 0};
50     size_t count[NUMDIMS] = {1, 1, 1, DIM3};
51     short data[DIM3];
52     int j;
53     int nerrs = 0;
54 
55     /* Create a file with one big 4D variable. */
56     if (nc_create(testfile, NC_CLOBBER, &ncid)) ERR;
57     if (nc_set_fill(ncid, NC_NOFILL, NULL)) ERR;
58     if (nc_def_dim(ncid, "dim0", DIM0, &dimids[0])) ERR;
59     if (nc_def_dim(ncid, "dim1", DIM1, &dimids[1])) ERR;
60     if (nc_def_dim(ncid, "dim2", DIM2, &dimids[2])) ERR;
61     if (nc_def_dim(ncid, "dim3", DIM3, &dimids[3])) ERR;
62     if (nc_def_var(ncid, "var", NC_SHORT, NUMDIMS, dimids, &varid)) ERR;
63     if (nc_enddef(ncid)) ERR;
64 
65     /* write var(0,0,4294,*) as all FIRST_VAL */
66     start[0] = 0;
67     start[1] = 0;
68     start[2] = 4294;
69     for (j = 0; j < DIM3; j++)
70 	data[j] = FIRST_VAL;
71     if (nc_put_vara_short(ncid, varid, start, count, &data[0])) ERR;
72 
73     /* write var(0,1,0,*) as all 8588 */
74     start[0] = 0;
75     start[1] = 1;
76     start[2] = 0;
77     for (j = 0; j < DIM3; j++)
78 	data[j] = SECOND_VAL;
79     if (nc_put_vara_short(ncid, varid, start, count, &data[0])) ERR;
80 
81     /* Read and check var(0,0,4294,*) */
82     start[0] = 0;
83     start[1] = 0;
84     start[2] = 4294;
85     if (nc_get_vara_short(ncid, varid, start, count, &data[0])) ERR;
86     for (j = 0; j < DIM3; j++) {
87 	if (data[j] != FIRST_VAL ) {
88 	    printf("error on start[0..2]: %ld,%ld,%ld  j: %d, expected %d got %d\n",
89 		   start[0], start[1], start[2], j, FIRST_VAL, data[j]);
90 	    ERR;
91 	    if(nerrs++ > 1)
92 	      return nerrs;
93 	}
94     }
95     if (nc_close(ncid)) ERR;
96     return NC_NOERR;
97 }
98 
99 int
main(int argc,char ** argv)100 main(int argc, char **argv) {
101     int i;
102     char testfile[NC_MAX_NAME + 1];
103 
104     printf("\n*** Testing multidimensional variable with more than 2**32 values\n");
105     sprintf(testfile, "%s/%s", TEMP_LARGE, FILE_NAME);
106     for (i = NC_FORMAT_CLASSIC; i <= NUM_FORMATS; i++)
107     {
108        printf("*** testing format %d file with short variable with > 2**32 values...", i);
109        nc_set_default_format(i, NULL);
110        if (test_big_var(testfile)) ERR_RET;
111        (void) remove(testfile);
112        SUMMARIZE_ERR;
113    }
114 
115     FINAL_RESULTS;
116 }
117