1 /*
2   Copyright 2008, UCAR/Unidata
3   See COPYRIGHT file for copying and redistribution conditions.
4 
5   This program tests the large file bug in netCDF 3.6.2,
6   creating byte and short variables larger than 4 GiB.
7 
8   $Id: tst_large.c,v 1.16 2010/05/18 20:20:01 russ Exp $
9 */
10 #include <config.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <nc_tests.h>
15 #include "err_macros.h"
16 #include <netcdf.h>
17 
18 /* Test with both classic and 64-bit offset files. If netcdf-4 is
19  * included, test with both netCDF-4 format variants also. */
20 #ifdef USE_NETCDF4
21 #define NUM_FORMATS (4)
22 #else
23 #define NUM_FORMATS (2)
24 #endif
25 
26 #define NUMDIMS 2		/* rank of each variable in tests */
27 #define DIM1 2048
28 #define DIM2 2097153		/* DIM1*DIM2*sizeof(char)   > 2**32 */
29 #define DIM3 1024
30 #define DIM4 2097153		/* DIM3*DIM4*sizeof(short)  > 2**32  */
31 
32 /*
33  * In netCDF-3.6.2, a divide by zero occurs on 32-bit platforms when
34  * creating a variable for which the product of dimensions is exactly
35  * 2**32.  Check that this bug has been fixed.
36  */
37 static int
test_big_var(const char * testfile)38 test_big_var(const char *testfile) {
39     int ncid, varid, dimids[NUMDIMS];
40     int cflag = NC_CLOBBER;
41     nc_type type = NC_BYTE;
42     size_t index[NUMDIMS];
43     signed char nval = 99;
44     int nval_in;
45 
46     /* Define the file with one large variable. */
47     if (nc_create(testfile, cflag, &ncid)) ERR;
48     if (nc_set_fill(ncid, NC_NOFILL, NULL)) ERR;
49     if (nc_def_dim(ncid, "dim1", DIM1, &dimids[0])) ERR;
50     if (nc_def_dim(ncid, "dim2", DIM2 - 1, &dimids[1])) ERR;
51     if (nc_def_var(ncid, "var", type, NUMDIMS, dimids, &varid)) ERR;
52     if (nc_enddef(ncid)) ERR;
53 
54     /* Write one datum, near the end of the variable. */
55     index[0] = DIM1 - 1;
56     index[1] = DIM2 - 2;
57     if (nc_put_var1_schar(ncid, varid, index, &nval)) ERR;
58     if (nc_close(ncid)) ERR;
59 
60     /* Reopen the file and check that datum. */
61     if (nc_open(testfile, NC_NOWRITE, &ncid)) ERR;
62     if (nc_inq_varid(ncid, "var", &varid)) ERR;
63     if (nc_get_var1_int(ncid, varid, index, &nval_in)) ERR;
64     if (nval != nval_in)
65 	ERR;
66     if (nc_close(ncid)) ERR;
67     return 0;
68 }
69 
70 static int
test_large_byte_var(const char * testfile)71 test_large_byte_var(const char *testfile) {
72     int ncid, varid, dimids[NUMDIMS];
73     size_t index[NUMDIMS] = {0, 0};
74     signed char vals[DIM2];
75     signed char char_val_in;
76     size_t start[NUMDIMS], count[NUMDIMS];
77     int j;
78 
79     if (nc_create(testfile, NC_CLOBBER, &ncid)) ERR;
80     if (nc_set_fill(ncid, NC_NOFILL, NULL)) ERR;
81     if (nc_def_dim(ncid, "dim1", DIM1, &dimids[0])) ERR;
82     if (nc_def_dim(ncid, "dim2", DIM2, &dimids[1])) ERR;
83     if (nc_def_var(ncid, "var", NC_BYTE, NUMDIMS, dimids, &varid)) ERR;
84     if (nc_enddef(ncid)) ERR;
85 
86     for (j = 0; j < DIM2; j++) {
87        vals[j] = 9 * (j + 11); /* note vals[j] is 99 when j==0 */
88     }
89     start[1] = 0;
90     count[0] = 1;
91     count[1] = DIM2;
92     for (start[0] = 0; start[0] < DIM1; start[0]++) {
93 	if (nc_put_vara_schar(ncid, varid, start, count, vals))
94 	{
95 	    ERR;
96 	    break;
97 	}
98     }
99 
100     if (nc_close(ncid)) ERR;
101     if (nc_open(testfile, NC_NOWRITE, &ncid)) ERR;
102     if (nc_inq_varid(ncid, "var", &varid)) ERR;
103     if (nc_get_var1_schar(ncid, varid, index, &char_val_in)) ERR;
104     if (char_val_in != 99)	/* see above, the value written when start[0]==0, j==0 */
105 	ERR;
106     if (nc_close(ncid)) ERR;
107     return 0;
108 }
109 
110 static int
test_large_short_var(const char * testfile)111 test_large_short_var(const char *testfile) {
112     int ncid, varid, dimids[NUMDIMS];
113     int int_val_in, int_val_out = 99;
114     size_t index[2];
115     int cflag = NC_CLOBBER;
116 
117     if (nc_create(testfile, cflag, &ncid)) ERR;
118     if (nc_def_dim(ncid, "dim3", DIM3, &dimids[0])) ERR;
119     if (nc_def_dim(ncid, "dim4", DIM4, &dimids[1])) ERR;
120     if (nc_def_var(ncid, "var", NC_SHORT, NUMDIMS, dimids, &varid)) ERR;
121     if (nc_enddef(ncid)) ERR;
122     index[0] = 0;
123     index[1] = 1;
124     if (nc_put_var1_int(ncid, varid, index, &int_val_out)) ERR;
125     if (nc_close(ncid)) ERR;
126     if (nc_open(testfile, NC_NOWRITE, &ncid)) ERR;
127     if (nc_inq_varid(ncid, "var", &varid)) ERR;
128     if (nc_get_var1_int(ncid, varid, index, &int_val_in)) ERR;
129     if (int_val_in != int_val_out)
130 	ERR;
131 #ifndef NOFILL
132     index[0] = 1;
133     index[1] = 2;
134     if (nc_get_var1_int(ncid, varid, index, &int_val_in)) ERR;
135     if (int_val_in != NC_FILL_SHORT)
136 	ERR;
137 #endif
138     if (nc_close(ncid)) ERR;
139     return 0;
140 }
141 
142 #define FILE_NAME "tst_large.nc"
143 
144 int
main(int argc,char ** argv)145 main(int argc, char **argv) {
146     int i;
147     char testfile[NC_MAX_NAME + 1];
148 
149     sprintf(testfile, "%s/%s", TEMP_LARGE, FILE_NAME);
150 
151     printf("\n*** Testing fix for 3.6.2 large file bug in %s.\n",
152 	   testfile);
153    /* Go thru formats and run all tests for each of two (for netCDF-3
154     * only builds), or 4 (for netCDF-4 builds) different formats. */
155     for (i = NC_FORMAT_CLASSIC; i <= NUM_FORMATS; i++)
156     {
157        nc_set_default_format(i, NULL);
158 
159        printf("*** testing format %d with a variable with 2**32 values...", i);
160        test_big_var(testfile);
161        (void) remove(testfile);
162        SUMMARIZE_ERR;
163 
164        printf("*** testing format %d with a byte variable with > 2**32 values...", i);
165        test_large_byte_var(testfile);
166        (void) remove(testfile);
167        SUMMARIZE_ERR;
168 
169        printf("*** testing format %d with a short variable with > 2**32 values...", i);
170        test_large_short_var(testfile);
171        (void) remove(testfile);
172        SUMMARIZE_ERR;
173     }
174 
175     FINAL_RESULTS;
176 }
177