[netcdfgroup] Bug in netcdf-4.2.1.1 using NC_FILL_xx values

Using netcdf-4.2.1.1 on Windows or Mac OS X.

 

The following documentation page discusses the merit of data conversion:

http://www.unidata.ucar.edu/software/netcdf/docs/type_conversion.html

 

We utilize data conversion for various reasons.  For example, our older
formats used 4-byte integers while our newer formats will write 8-byte
integers.  Our Apps need to be flexible and process both without worrying
about how the data was stored.

 

We use NC_FILL_xx to test for missing data.  Unfortunately, netcdf-4.2.1.1
uses the NC_FILL type of the stored variable, rather than the target data
type.  This leads to unexpected behavior depending on whether you are
up-casting or down-casting.  If the variable is defined as a record variable
with UNLIMITED dimension and you are down-casting, the array element
immediately following the targeted value is corrupted.  The corruption
occurs when the following line is executed:

 

nc4hdf.c - line 1143:

  memcpy(filldata, fillvalue, file_type_size);

 

I wrote a small test program that reads and writes integer data in various
combinations.  The error messages can lead you to which combinations are
problematic.  The ones that report corruptions are the worst cases.

 

One could argue that returning an error when the NC_FILL value cannot fit
the targeted data is reasonable.  I hope instead you would consider
returning the NC_FILL value of the corresponding target data type.  This
would allow missing values within a slab of data so we could read what's
available.

 

Roy Dennington

Semichem, Inc.

/* #RDD Test file
Read a simple file, with some of the features of netCDF-4.

This is part of the netCDF package. Copyright 2006-2011 University
Corporation for Atmospheric Research/Unidata. See COPYRIGHT file for
conditions of use. Full documentation of the netCDF can be found at
http://www.unidata.ucar.edu/software/netcdf/docs.
*/
#include <stdlib.h>
#include <stdio.h>
#include <netcdf.h>
/* This is the name of the data file we will create. */
#define FILE_NAME "roy_nc4.nc"

#define NDIMS 2
#define NVARS 8

/* Handle errors by printing an error message and exiting with a
 * non-zero status. */
#define ERRCODE 2
#define ERR(e) {printf("Error: %s\n", nc_strerror(e)); exit(ERRCODE);}

int write_netcdf_file()
{
   int ncid, varid[NVARS], dimids[NDIMS], one_dimid, rec_dimid, retval;
   size_t start[2] = {0, 0};
   size_t edge[2] = {1, 1};
   long long int64_data_out = 42LL;
   int int_data_out = 42;

   if ((retval = nc_create(FILE_NAME, NC_NETCDF4|NC_CLOBBER, &ncid)))
      ERR(retval);

   if ((retval = nc_def_dim(ncid, "one", 1, &one_dimid)))
      ERR(retval);

   if ((retval = nc_def_dim(ncid, "records", NC_UNLIMITED, &rec_dimid)))
      ERR(retval);

   dimids[0] = rec_dimid;
   dimids[1] = one_dimid;
   if ((retval = nc_def_var(ncid, "data_int64_rec_set", NC_INT64, 2, 
                            dimids, &varid[0])))
      ERR(retval);

   if ((retval = nc_def_var(ncid, "data_int64_rec_unset", NC_INT64, 2, 
                            dimids, &varid[1])))
      ERR(retval);

   if ((retval = nc_def_var(ncid, "data_int64_set", NC_INT64, 1, 
                            &one_dimid, &varid[2])))
      ERR(retval);

   if ((retval = nc_def_var(ncid, "data_int64_unset", NC_INT64, 1, 
                            &one_dimid, &varid[3])))
      ERR(retval);

   if ((retval = nc_def_var(ncid, "data_int_rec_set", NC_INT, 2, 
                            dimids, &varid[4])))
      ERR(retval);

   if ((retval = nc_def_var(ncid, "data_int_rec_unset", NC_INT, 2, 
                            dimids, &varid[5])))
      ERR(retval);

   if ((retval = nc_def_var(ncid, "data_int_set", NC_INT, 1, 
                            &one_dimid, &varid[6])))
      ERR(retval);

   if ((retval = nc_def_var(ncid, "data_int_unset", NC_INT, 1, 
                            &one_dimid, &varid[7])))
      ERR(retval);

   if ((retval = nc_put_vara_longlong(ncid, varid[0], start, edge, 
&int64_data_out)))
      ERR(retval);

   if ((retval = nc_put_var_longlong(ncid, varid[2], &int64_data_out)))
      ERR(retval);

   if ((retval = nc_put_vara_int(ncid, varid[4], start, edge, &int_data_out)))
      ERR(retval);

   if ((retval = nc_put_var_int(ncid, varid[6], &int_data_out)))
      ERR(retval);

   /* Close the file. */
   if ((retval = nc_close(ncid)))
      ERR(retval);

   printf("*** SUCCESS writing example file roy_nc4.nc!\n");
   return 0;
}

void CheckReadLongLong(int ncid, int varid, long long value)
{
  int retval;
  size_t start[2] = {0, 0};
  size_t edge[2] = {1, 1};
  long long data_in_longlong[2] = {0LL, 0LL};

  data_in_longlong[0] = data_in_longlong[1] = 0LL;
  if ((retval = nc_get_var1_longlong(ncid, varid, start, &data_in_longlong[0])))
    printf("  Error: %s\n", nc_strerror(retval));

  if (data_in_longlong[0] != value)
    printf("  data_in_longlong[0]=%lld does not match %lld!\n", 
data_in_longlong[0], value);

  if (data_in_longlong[1] != 0LL)
    printf("  data_in_longlong[1]=%lld corruption!\n", data_in_longlong[1]);

  data_in_longlong[0] = data_in_longlong[1] = 0LL;
  if ((retval = nc_get_var_longlong(ncid, varid, &data_in_longlong[0])))
    printf("  Error: %s\n", nc_strerror(retval));

  if (data_in_longlong[0] != value)
     printf("  data_in_longlong[0]=%lld does not match %lld!\n", 
data_in_longlong[0], value);

  if (data_in_longlong[1] != 0LL)
    printf("  data_in_longlong[1]=%lld corruption!\n", data_in_longlong[1]);

  data_in_longlong[0] = data_in_longlong[1] = 0LL;
  if ((retval = nc_get_vara_longlong(ncid, varid, start, edge, 
&data_in_longlong[0])))
    printf("  Error: %s\n", nc_strerror(retval));

  if (data_in_longlong[0] != value)
     printf("  data_in_longlong[0]=%lld does not match %lld!\n", 
data_in_longlong[0], value);

  if (data_in_longlong[1] != 0LL)
    printf("  data_in_longlong[1]=%lld corruption!\n", data_in_longlong[1]);
}

void CheckReadInt(int ncid, int varid, int value)
{
  int retval;
  size_t start[2] = {0, 0};
  size_t edge[2] = {1, 1};
  int data_in_int[2] = {0, 0};

  data_in_int[0] = data_in_int[1] = 0;
  if ((retval = nc_get_var1_int(ncid, varid, start, &data_in_int[0])))
    printf("  Error: %s\n", nc_strerror(retval));

  if (data_in_int[0] != value)
    printf("  data_in_int[0]=%d does not match %d!\n", data_in_int[0], value);

  if (data_in_int[1] != 0)
    printf("  data_in_int[1]=%d corruption!\n", data_in_int[1]);

  data_in_int[0] = data_in_int[1] = 0;
  if ((retval = nc_get_var_int(ncid, varid, &data_in_int[0])))
    printf("  Error: %s\n", nc_strerror(retval));

  if (data_in_int[0] != value)
     printf("  data_in_int[0]=%d does not match %d!\n", data_in_int[0], value);

  if (data_in_int[1] != 0)
    printf("  data_in_int[1]=%d corruption!\n", data_in_int[1]);

  data_in_int[0] = data_in_int[1] = 0;
  if ((retval = nc_get_vara_int(ncid, varid, start, edge, &data_in_int[0])))
    printf("  Error: %s\n", nc_strerror(retval));

  if (data_in_int[0] != value)
     printf("  data_in_int[0]=%d does not match %d!\n", data_in_int[0], value);

  if (data_in_int[1] != 0)
    printf("  data_in_int[1]=%d corruption!\n", data_in_int[1]);
}

int read_netcdf_file()
{
   int ncid, varid[NVARS], retval;

   if ((retval = nc_open(FILE_NAME, NC_NOWRITE, &ncid)))
      ERR(retval);

   if ((retval = nc_inq_varid(ncid, "data_int64_set", &varid[0]))) 
      ERR(retval);

   if ((retval = nc_inq_varid(ncid, "data_int64_unset", &varid[1]))) 
      ERR(retval);

   if ((retval = nc_inq_varid(ncid, "data_int64_rec_set", &varid[2]))) 
      ERR(retval);

   if ((retval = nc_inq_varid(ncid, "data_int64_rec_unset", &varid[3]))) 
      ERR(retval);

   if ((retval = nc_inq_varid(ncid, "data_int_set", &varid[4]))) 
      ERR(retval);

   if ((retval = nc_inq_varid(ncid, "data_int_unset", &varid[5]))) 
      ERR(retval);

   if ((retval = nc_inq_varid(ncid, "data_int_rec_set", &varid[6]))) 
      ERR(retval);

   if ((retval = nc_inq_varid(ncid, "data_int_rec_unset", &varid[7]))) 
      ERR(retval);

   printf("*** Reading INT64 set variable into long long (matched)\n");
   CheckReadLongLong(ncid, varid[0], 42LL);  // data_int64_set

   printf("*** Reading INT64 set variable into int (downsizing)\n");
   CheckReadInt(ncid, varid[0], 42);        // data_int64_set

   printf("*** Reading INT64 unset variable into long long (matched)\n");
   CheckReadLongLong(ncid, varid[1], NC_FILL_INT64);  // data_int64_unset

   printf("*** Reading INT64 unset variable into int (downsizing)\n");
   CheckReadInt(ncid, varid[1], NC_FILL_INT);         // data_int64_unset

   printf("*** Reading INT64 rec set variable into long long (matched)\n");
   CheckReadLongLong(ncid, varid[2], 42LL);  // data_int64_rec_set

   printf("*** Reading INT64 rec set variable into int (downsizing)\n");
   CheckReadInt(ncid, varid[2], 42);        // data_int64_rec_set

   printf("*** Reading INT64 unset rec variable into long long (matched)\n");
   CheckReadLongLong(ncid, varid[3], NC_FILL_INT64);  // data_int64_rec_unset

   printf("*** Reading INT64 unset rec variable into int (downsizing)\n");
   CheckReadInt(ncid, varid[3], NC_FILL_INT);         // data_int64_rec_unset

   printf("*** Reading INT set variable into long long (upsizing)\n");
   CheckReadLongLong(ncid, varid[4], 42LL);  // data_int_set

   printf("*** Reading INT set variable into int (matched)\n");
   CheckReadInt(ncid, varid[4], 42);        // data_int_set

   printf("*** Reading INT unset variable into long long (upsizing)\n");
   CheckReadLongLong(ncid, varid[5], NC_FILL_INT64);  // data_int_unset

   printf("*** Reading INT unset variable into int (matched)\n");
   CheckReadInt(ncid, varid[5], NC_FILL_INT);         // data_int_unset

   printf("*** Reading INT set rec variable into long long (upsizing)\n");
   CheckReadLongLong(ncid, varid[6], 42LL);  // data_int_rec_set

   printf("*** Reading INT set rec variable into int (matched)\n");
   CheckReadInt(ncid, varid[6], 42);        // data_int_rec_set

   printf("*** Reading INT unset rec variable into long long (upsizing)\n");
   CheckReadLongLong(ncid, varid[7], NC_FILL_INT64);  // data_int_rec_unset

   printf("*** Reading INT unset rec variable into int (matched)\n");
   CheckReadInt(ncid, varid[7], NC_FILL_INT);         // data_int_rec_unset

   /* Close the file, freeing all resources. */
   if ((retval = nc_close(ncid)))
      ERR(retval);

   printf("*** SUCCESS reading example file %s!\n", FILE_NAME);
   return 0;
}

int main()
{
  int status = 0;
  status = write_netcdf_file();
  status = read_netcdf_file();
  return (status);
}

  • 2013 messages navigation, sorted by:
    1. Thread
    2. Subject
    3. Author
    4. Date
    5. ↑ Table Of Contents
  • Search the netcdfgroup archives: