netcdf-c/ncdump/tst_fillbug.c

204 lines
6.2 KiB
C

/*
This is part of the netCDF package. Copyright 2018 University
Corporation for Atmospheric Research/Unidata. See COPYRIGHT file for
conditions of use. See www.unidata.ucar.edu for more info.
*/
#include <nc_tests.h>
#include "err_macros.h"
#include <stdio.h>
#include <stdlib.h>
#include <netcdf.h>
#define FILENAME "tst_fillbug.nc"
static int count_udtypes(int ncid);
int
main(int argc, char **argv)
{/* create file that caused seg fault in ncdump */
int ncid; /* netCDF id */
/* dimension ids */
int Time_dim;
int X_dim;
int Y_dim;
/* dimension lengths */
size_t Time_len = NC_UNLIMITED;
size_t X_len = 4;
size_t Y_len = 3;
/* variable ids */
int Time_id;
int P_id;
/* rank (number of dimensions) for each variable */
# define RANK_Time 1
# define RANK_P 3
/* variable shapes */
int Time_dims[RANK_Time];
int P_dims[RANK_P];
printf("\n*** Testing preparation of fillbug test.\n");
printf("*** creating fillbug test file %s...", FILENAME);
/* enter define mode */
if (nc_create(FILENAME, NC_CLOBBER|NC_NETCDF4, &ncid)) ERR;
/* define dimensions */
if (nc_def_dim(ncid, "Time", Time_len, &Time_dim)) ERR;
if (nc_def_dim(ncid, "X", X_len, &X_dim)) ERR;
if (nc_def_dim(ncid, "Y", Y_len, &Y_dim)) ERR;
/* define variables */
Time_dims[0] = Time_dim;
if (nc_def_var(ncid, "Time", NC_DOUBLE, RANK_Time, Time_dims, &Time_id)) ERR;
P_dims[0] = Time_dim;
P_dims[1] = Y_dim;
P_dims[2] = X_dim;
if (nc_def_var(ncid, "P", NC_FLOAT, RANK_P, P_dims, &P_id)) ERR;
/* leave define mode */
if (nc_enddef (ncid)) ERR;
{/* assign variable data */
static double Time_data[1]={3.14159};
static size_t Time_startset[1] = {0};
static size_t Time_countset[1] = {1};
if (nc_put_vara(ncid, Time_id, Time_startset, Time_countset, Time_data)) ERR;
}
if (nc_close(ncid)) ERR;
/* Try to duplicate segfault ncdump gets by making the same calls
* to the netCDF-4 library, in the same order. This doesn't
* result in the same segfault, so either we have missed a call
* made by ncdump, or an earlier ncdump bug masks the real problem
* until a call is made into the netCDF-4 library ... */
if (nc_open(FILENAME, NC_NOWRITE, &ncid)) ERR;
{
/* We declare local arrays with small constant sizes to avoid
* all the mallocs and frees used in ncdump. For the example
* above, the fixed-size arrays are ample. */
int format, ndims, nvars, ngatts, xdimid, ndims_grp, dimids_grp[3],
unlimids[1], d_grp, nunlim, nvars_grp, varids_grp[3], v_grp,
varid, varndims, vardims[3], varnatts, vartype, dimids[3], is_recvar,
id, ntypes, numgrps;
size_t dimsize, len;
char dimname[20], varname[20];
if ( nc_inq_format(ncid, &format)) ERR;
ntypes = count_udtypes(ncid);
if ( nc_inq_typeids(ncid, &ntypes, NULL) ) ERR;
if ( nc_inq_format(ncid, &format)) ERR;
if ( nc_inq_grps(ncid, &numgrps, NULL) ) ERR;
if ( nc_inq_typeids(ncid, &ntypes, NULL) ) ERR;
if ( nc_inq(ncid, &ndims, &nvars, &ngatts, &xdimid) ) ERR;
if ( nc_inq_ndims(ncid, &ndims_grp) ) ERR;
if ( nc_inq_dimids(ncid, 0, dimids_grp, 0) ) ERR;
if ( nc_inq_unlimdims(ncid, &nunlim, NULL) ) ERR;
if ( nc_inq_unlimdims(ncid, &nunlim, unlimids) ) ERR;
for (d_grp = 0; d_grp < ndims_grp; d_grp++) {
int dimid = dimids_grp[d_grp];
if ( nc_inq_dim(ncid, dimid, dimname, &dimsize) ) ERR;
}
if ( nc_inq_format(ncid, &format) ) ERR;
if ( nc_inq_varids(ncid, &nvars_grp, varids_grp) ) ERR;
for (v_grp = 0; v_grp < nvars_grp; v_grp++) {
varid = varids_grp[v_grp];
if ( nc_inq_varndims(ncid, varid, &varndims) ) ERR;
if ( nc_inq_var(ncid, varid, varname, &vartype, 0, vardims,
&varnatts) ) ERR;
for (id = 0; id < varndims; id++) {
if ( nc_inq_dimname(ncid, vardims[id], dimname) ) ERR;
}
}
for (v_grp = 0; v_grp < nvars_grp; v_grp++) {
varid = varids_grp[v_grp];
if( nc_inq_varndims(ncid, varid, &varndims) ) ERR;
if( nc_inq_var(ncid, varid, varname, &vartype, 0, vardims,
&varnatts) ) ERR;
{
is_recvar = 0;
if ( nc_inq_varndims(ncid, varid, &ndims) ) ERR;
if (ndims > 0) {
int nunlimdims;
int recdimids[3];
int dim, recdim;
if ( nc_inq_vardimid(ncid, varid, dimids) ) ERR;
if ( nc_inq_unlimdims(ncid, &nunlimdims, NULL) ) ERR;
if ( nc_inq_unlimdims(ncid, NULL, recdimids) ) ERR;
for (dim = 0; dim < ndims && is_recvar == 0; dim++) {
for(recdim = 0; recdim < nunlimdims; recdim++) {
if(dimids[dim] == recdimids[recdim]) {
is_recvar = 1;
break;
}
}
}
}
}
for (id = 0; id < varndims; id++) {
if( nc_inq_dimlen(ncid, vardims[id], &len) ) ERR;
}
if (varid == 0) {
/* read Time variable */
static double Time_data;
static size_t cor[RANK_Time] = {0};
static size_t edg[RANK_Time] = {1};
if (nc_get_vara(ncid, varid, cor, edg, &Time_data)) ERR;
} else {
/* read data slices from P variable, should get fill values */
static float P_data[4];
static size_t cor[RANK_P] = {0, 0, 0};
static size_t edg[RANK_P] = {1, 1, 4};
/* first slice retrieved OK */
if (nc_get_vara(ncid, varid, cor, edg, P_data)) ERR;
/* In ncdump, reading second slice gets seg fault in
* nc4_open_var_grp(), but this attempt to do all the
* same netCDF calls as ncdump can't duplicate the
* error, which would seem to implicate ncdump rather
* than HDF5 or netCDF-4 library ... */
cor[1] = 1;
if (nc_get_vara(ncid, varid, cor, edg, P_data)) ERR;
}
}
}
if (nc_close(ncid)) ERR;
SUMMARIZE_ERR;
FINAL_RESULTS;
}
/* return number of user-defined types in a group and all its subgroups */
static int
count_udtypes(int ncid) {
int ntypes = 0;
int numgrps;
int *ncids;
int i;
int format;
if( nc_inq_format(ncid, &format) ) ERR;
if (format == NC_FORMAT_NETCDF4) {
/* Get number of types in this group */
if( nc_inq_typeids(ncid, &ntypes, NULL) ) ERR;
if( nc_inq_grps(ncid, &numgrps, NULL) ) ERR;
ncids = (int *) malloc(sizeof(int) * numgrps);
if( nc_inq_grps(ncid, NULL, ncids) ) ERR;
/* Add number of types in each subgroup, if any */
for (i=0; i < numgrps; i++) {
ntypes += count_udtypes(ncids[i]);
}
free(ncids);
}
return ntypes;
}