[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 20040312:bug found in ncdump utility delivered with netCDF V3.5.0



>To: address@hidden
>From: address@hidden
>Subject: BOUNCE address@hidden: Non-member submission from 
[Philippe Poilbarbe <address@hidden>]
>Organization: UCAR/Unidata
>Keywords: 200403120804.i2C840hS019881

Hi Philippe,

> Here is a bug found in ncdump utility delivered with netCDF V3.5.0.
> 
> The bug appears when attributes have a zero length. In this case, it
> tries to show them as 0 length string but the way it is implemented
> is buggy.  The value shown depends on the non empty preceding
> attribute. If it is a string, the first letter of this string is
> repeated as the value of all empty following attributes (due to a
> reuse of allocated data not initialized)
> 
> Below is an exemple (the last 3 attributes have 0 values):
> 
>        :Data_provider = "Data provider" ;
>        :Experiment_name = "D" ;
>        :Project_name = "D" ;
>        :Experiment_description = "D" ;
> 
> You can find joined a patch which can be used to correct this
> problem and another (incorrect writing of control characters).

Thanks for reporting this and providing a patch.  It may be already fixed in 
netCDF 3.5.1, because I cannot reproduce the problem.  I have attached a test 
program that creates several variable and global attributes with 0 values, but 
the output of ncdump on the resulting netCDF file has all of these displayed 
as an empty string on my Solaris SPARC platform.  If you still see the bug 
using this test program, could you tell me what operating system and platform 
you are using?  Or send me a complete program that demonstrates the problem?  
Thanks!

> On an another way here is a question: does it take any sense to have
> an attribute with no value ? IMHO, if there is no value the attribute has
> not to be created.

We explicitly permit attributes to be defined with no value, because
we want to provide a way to declare that a variable has a particular
characteristic, for example whether it is georeferenced (associated
with a latitude/longitude location on earth).  The characteristic has
a name, and the variable either has the characteristic or doesn't, so
a Boolean attribute might be used, as in:

  georeferenced = True   or  georeferenced = False

But it seems more elegant to just attach the attribute, without
values, to variables for which the characteristic is true, and
variables for which the characteristic is false or does not apply do
not have the attribute.

This is analogous to the use of C preprocessor macros, which may have
a value, but are often used just to test whether they are defined or
not, without regard for any value.  For example, if you include

  -DHAS_PROPERTY_X

on your compile line, it defines the macro "HAS_PROPERTY_X" without a
value, and it can be tested by the C preprocessor using

#ifdef HAS_PROPERTY_X

--Russ

netcdf bug5 {
variables:
        int x ;
                x:Data_provider = "Data provider" ;
                x:HasProperty = "" ;
                x:Experiment_name = "" ;
                x:Project_name = "" ;
                x:Experiment_description = "" ;

// global attributes:
                :History = "Generated for testing" ;
                :HasProperty = "" ;
                :source = "" ;
                :provinence = "" ;
data:

 x = 0 ;
}
#include <stdio.h>
#include <stdlib.h>
#include <netcdf.h>

void
check_err(const int stat, const int line, const char *file) {
    if (stat != NC_NOERR) {
           (void) fprintf(stderr, "line %d of %s: %s\n", line, file, 
nc_strerror(stat));
        exit(1);
    }
}

int
main() {                        /* create bug5.nc */

   int  ncid;                   /* netCDF id */

   /* variable ids */
   int x_id;

   /* rank (number of dimensions) for each variable */
#  define RANK_x 0

   /* enter define mode */
   int stat = nc_create("bug5.nc", NC_CLOBBER, &ncid);
   check_err(stat,__LINE__,__FILE__);

   /* define variables */

   stat = nc_def_var(ncid, "x", NC_INT, RANK_x, 0, &x_id);
   check_err(stat,__LINE__,__FILE__);

   /* assign attributes */
   stat = nc_put_att_text(ncid, x_id, "Data_provider", 13, "Data provider");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_int(ncid, x_id, "HasProperty", NC_INT, 0, (void *)0);
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, x_id, "Experiment_name", 0, "");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, x_id, "Project_name", 0, "");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, x_id, "Experiment_description", 0, "");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, NC_GLOBAL, "History", 21, "Generated for 
testing");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_int(ncid, NC_GLOBAL, "HasProperty", NC_INT, 0, (void *)0);
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, NC_GLOBAL, "source", 0, "");
   check_err(stat,__LINE__,__FILE__);
   stat = nc_put_att_text(ncid, NC_GLOBAL, "provinence", 0, "");
   check_err(stat,__LINE__,__FILE__);

   /* leave define mode */
   stat = nc_enddef (ncid);
   check_err(stat,__LINE__,__FILE__);

   {                    /* store x */
    static int x = 0;
    stat = nc_put_var_int(ncid, x_id, &x);
    check_err(stat,__LINE__,__FILE__);
   }
   stat = nc_close(ncid);
   check_err(stat,__LINE__,__FILE__);
   return 0;
}