netcdf-c/nc_test/tst_diskless4.c

189 lines
4.7 KiB
C
Raw Normal View History

/*
2018-12-07 05:56:42 +08:00
Copyright 2018, 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.
$Id: tst_big_var.c,v 1.9 2010/05/15 00:50:10 russ Exp $
*/
#include <nc_tests.h>
#include "err_macros.h"
#include <netcdf.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#undef XFAIL
#define FILE_NAME "tst_diskless4.nc"
#define CHUNKSIZE 4096
#define DATASIZE (CHUNKSIZE/sizeof(int))
Fix more memory leaks in netcdf-c library This is a follow up to PR https://github.com/Unidata/netcdf-c/pull/1173 Sorry that it is so big, but leak suppression can be complex. This PR fixes all remaining memory leaks -- as determined by -fsanitize=address, and with the exceptions noted below. Unfortunately. there remains a significant leak that I cannot solve. It involves vlens, and it is unclear if the leak is occurring in the netcdf-c library or the HDF5 library. I have added a check_PROGRAM to the ncdump directory to show the problem. The program is called tst_vlen_demo.c To exercise it, build the netcdf library with -fsanitize=address enabled. Then go into ncdump and do a "make clean check". This should build tst_vlen_demo without actually executing it. Then do the command "./tst_vlen_demo" to see the output of the memory checker. Note the the lost malloc is deep in the HDF5 library (in H5Tvlen.c). I am temporarily working around this error in the following way. 1. I modified several test scripts to not execute known vlen tests that fail as described above. 2. Added an environment variable called NC_VLEN_NOTEST. If set, then those specific tests are suppressed. This should mean that the --disable-utilities option to ./configure should not need to be set to get a memory leak clean build. This should allow for detection of any new leaks. Note: I used an environment variable rather than a ./configure option to control the vlen tests. This is because it is temporary (I hope) and because it is a bit tricky for shell scripts to access ./configure options. Finally, as before, this only been tested with netcdf-4 and hdf5 support.
2018-11-16 01:00:38 +08:00
#define DIMMAX 500000000L
typedef enum Tag {Create,CreateDiskless,Open,OpenDiskless} Tag;
#define REPORT err_report(status,__FILE__,__LINE__)
static void
err_report(int status, char* file, int line)
{
printf("***FAIL: %s: line=%d status=%d %s\n",file,line,status,nc_strerror(status));
#ifdef XFAIL
exit(0);
#else
exit(1);
#endif
}
int
main(int argc, char **argv)
{
int status = NC_NOERR;
int i,j,iv;
unsigned int data[DATASIZE];
size_t start[1];
size_t count[1];
Tag tag = Create;
int cmode = 0;
int ncid;
int dimids[1];
void* memory;
int nvars;
int varids[4096];
size_t varsize;
size_t filesize;
/* Get the specified var/file size */
if(argc > 1) {
filesize = atol(argv[1]);
} else
filesize = 1000000000L;
/* Test that we can malloc that much space */
memory = malloc(filesize);
if(memory == NULL) {
fprintf(stderr,"Cannot malloc %lu bytes\n",(unsigned long)filesize);
fprintf(stderr,"This may mean your machine does not have enough RAM. If this is the case, it is safe to ignore this error.\n");
exit(1);
}
free(memory);
if(argc > 2) {
if(strcmp(argv[2],"create")==0) tag = Create;
else if(strcmp(argv[2],"creatediskless")==0) tag = CreateDiskless;
else if(strcmp(argv[2],"open")==0) tag = Open;
else if(strcmp(argv[2],"opendiskless")==0) tag = OpenDiskless;
else {
fprintf(stderr,"illegal tag: %s",argv[2]);
exit(1);
}
} else
tag = Create; /* default */
switch (tag) {
case Create: printf("\n*** Create file\n"); break;
case CreateDiskless: printf("\n*** Create file diskless\n"); break;
case Open: printf("\n*** Open file\n"); break;
case OpenDiskless: printf("\n*** Open file diskless\n"); break;
}
switch (tag) {
case Create: cmode = NC_CLOBBER; break;
case CreateDiskless: cmode = NC_CLOBBER|NC_DISKLESS|NC_PERSIST|NC_WRITE; break;
case Open: cmode = 0; break;
case OpenDiskless: cmode = NC_DISKLESS; break;
}
switch (tag) {
case Create:
case CreateDiskless:
/* Try to alloc as much as possible initially */
if((status=nc__create(FILE_NAME, cmode, filesize, NULL, &ncid)))
REPORT;
if((status=nc_set_fill(ncid, NC_NOFILL, NULL)))
REPORT;
/* Only need 1 dimension */
if((status=nc_def_dim(ncid, "dim", DIMMAX, &dimids[0])))
REPORT;
break;
case Open:
case OpenDiskless:
if((status=nc_open(FILE_NAME, cmode, &ncid)))
REPORT;
if((status=nc_inq_dimid(ncid, "dim", &dimids[0])))
REPORT;
break;
}
varsize = DIMMAX;
nvars = filesize / varsize;
assert((filesize % DIMMAX) == 0);
assert(nvars < 4096);
for(iv=0;iv<nvars;iv++) {
char varname[32];
sprintf(varname,"var%d",iv);
switch (tag) {
case Create:
case CreateDiskless:
if((status=nc_def_var(ncid, varname, NC_BYTE, 1, &dimids[0], &varids[iv])))
REPORT;
break;
case Open:
case OpenDiskless:
if((status=nc_inq_varid(ncid, varname, &varids[iv])))
REPORT;
break;
}
}
if(tag == Create || tag == CreateDiskless) {
if((status=nc_enddef(ncid)))
REPORT;
}
for(iv=0;iv<nvars;iv++) {
size_t pieces = varsize/CHUNKSIZE;
switch (tag) {
case Create:
case CreateDiskless:
/* Fill and put as integers */
for(i=0;i<pieces;i++) {
start[0] = i*CHUNKSIZE;
count[0] = CHUNKSIZE;
for(j=0;j<DATASIZE;j++) data[j] = iv*((i*CHUNKSIZE)+j);
if((status=nc_put_vara(ncid,varids[iv],start,count,(void*)data)))
REPORT;
}
break;
case Open:
case OpenDiskless:
/* Read the var contents and validate */
for(i=0;i<pieces;i++) {
start[0] = i*CHUNKSIZE;
count[0] = CHUNKSIZE;
if((status=nc_get_vara(ncid,varids[iv],start,count,(void*)data)))
REPORT;
for(j=0;j<DATASIZE;j++) {
unsigned int expected = iv*((i*CHUNKSIZE)+j);
if(data[j] != expected) {
printf("mismatch: iv=%d i=%u j=%u data=%u; should be %u\n",
iv, i,j,data[j],expected);
err++;
}
}
}
break;
}
}
if((status=nc_close(ncid)))
REPORT;
SUMMARIZE_ERR;
exit(0);
return 0;
}