netcdf-c/ncgen/dump.c
Dennis Heimbigner 751300ec59 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-15 10:00:38 -07:00

302 lines
6.5 KiB
C

/*********************************************************************
* Copyright 2009, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/
/* $Id: dump.c,v 1.3 2010/05/24 19:59:57 dmh Exp $ */
/* $Header: /upc/share/CVS/netcdf-3/ncgen/dump.c,v 1.3 2010/05/24 19:59:57 dmh Exp $ */
#include "includes.h"
#include "dump.h"
#define DEBUGSRC
/* Forward */
static void dumpdataprim(NCConstant*,Bytebuffer*);
char*
indentstr(int n)
{
static char indentline[1024];
memset(indentline,' ',n+1);
indentline[n+1] = '\0';
return indentline;
}
void
dumpconstant(NCConstant* con, char* tag)
{
Bytebuffer* buf = bbNew();
Datalist* dl = builddatalist(1);
dlappend(dl,con);
bufdump(dl,buf);
fprintf(stderr,"%s: %s\n",tag,bbContents(buf));
bbFree(buf);
}
void
dumpdatalist(Datalist* list, char* tag)
{
Bytebuffer* buf = bbNew();
bufdump(list,buf);
fprintf(stderr,"%s: %s\n",tag,bbContents(buf));
bbFree(buf);
}
void
bufdump(Datalist* list, Bytebuffer* buf)
{
int i;
NCConstant** dpl;
unsigned int count;
if(list == NULL) {
bbCat(buf,"NULL");
return;
}
count = list->length;
for(dpl=list->data,i=0;i<count;i++,dpl++) {
NCConstant* dp = *dpl;
switch (dp->nctype) {
case NC_COMPOUND:
bbCat(buf,"{");
bufdump(dp->value.compoundv,buf);
bbCat(buf,"}");
break;
case NC_ARRAY:
bbCat(buf,"[");
bufdump(dp->value.compoundv,buf);
bbCat(buf,"]");
break;
case NC_VLEN:
bbCat(buf,"{*");
bufdump(dp->value.compoundv,buf);
bbCat(buf,"}");
break;
default:
if(isprimplus(dp->nctype) || dp->nctype == NC_FILLVALUE) {
bbCat(buf," ");
dumpdataprim(dp,buf);
} else {
char tmp[64];
sprintf(tmp,"?%d? ",dp->nctype);
bbCat(buf,tmp);
} break;
}
}
}
static void
dumpdataprim(NCConstant* ci, Bytebuffer* buf)
{
char tmp[64];
ASSERT(isprimplus(ci->nctype) || ci->nctype == NC_FILLVALUE);
switch (ci->nctype) {
case NC_CHAR: {
bbCat(buf,"'");
escapifychar(ci->value.charv,tmp,'\'');
bbCat(buf,tmp);
bbCat(buf,"'");
} break;
case NC_BYTE:
sprintf(tmp,"%hhd",ci->value.int8v);
bbCat(buf,tmp);
break;
case NC_SHORT:
sprintf(tmp,"%hd",ci->value.int16v);
bbCat(buf,tmp);
break;
case NC_INT:
sprintf(tmp,"%d",ci->value.int32v);
bbCat(buf,tmp);
break;
case NC_FLOAT:
sprintf(tmp,"%g",ci->value.floatv);
bbCat(buf,tmp);
break;
case NC_DOUBLE:
sprintf(tmp,"%lg",ci->value.doublev);
bbCat(buf,tmp);
break;
case NC_UBYTE:
sprintf(tmp,"%hhu",ci->value.int8v);
bbCat(buf,tmp);
break;
case NC_USHORT:
sprintf(tmp,"%hu",ci->value.uint16v);
bbCat(buf,tmp);
break;
case NC_UINT:
sprintf(tmp,"%u",ci->value.uint32v);
bbCat(buf,tmp);
break;
case NC_INT64:
sprintf(tmp,"%lld",ci->value.int64v);
bbCat(buf,tmp);
break;
case NC_UINT64:
sprintf(tmp,"%llu",ci->value.uint64v);
bbCat(buf,tmp);
break;
case NC_ECONST:
sprintf(tmp,"%s",ci->value.enumv->fqn);
bbCat(buf,tmp);
break;
case NC_STRING:
bbCat(buf,"\"");
bbCat(buf,ci->value.stringv.stringv);
bbCat(buf,"\"");
break;
case NC_OPAQUE:
bbCat(buf,"0x");
bbCat(buf,ci->value.opaquev.stringv);
break;
case NC_FILLVALUE:
bbCat(buf,"_");
break;
default: PANIC1("dumpdataprim: bad type code:%d",ci->nctype);
}
}
void
dumpgroup(Symbol* g)
{
if(debug <= 1) return;
fdebug("group %s {\n",(g==NULL?"null":g->name));
if(g != NULL && g->subnodes != NULL) {
int i;
for(i=0;i<listlength(g->subnodes);i++) {
Symbol* sym = (Symbol*)listget(g->subnodes,i);
char* tname;
if(sym->objectclass == NC_PRIM
|| sym->objectclass == NC_TYPE) {
tname = nctypename(sym->subclass);
} else
tname = nctypename(sym->objectclass);
fdebug(" %3d: %s\t%s\t%s\n",
i,
sym->name,
tname,
(sym->ref.is_ref?"ref":"")
);
}
}
fdebug("}\n");
}
void
dumpconstant1(NCConstant* con)
{
switch (con->nctype) {
case NC_COMPOUND: {
Datalist* dl = con->value.compoundv;
Bytebuffer* buf = bbNew();
bufdump(dl,buf);
/* fprintf(stderr,"(0x%lx){",(unsigned long)dl);*/
fprintf(stderr,"{%s}",bbDup(buf));
bbFree(buf);
} break;
case NC_STRING:
if(con->value.stringv.len > 0 && con->value.stringv.stringv != NULL)
fprintf(stderr,"\"%s\"",con->value.stringv.stringv);
else
fprintf(stderr,"\"\"");
break;
case NC_OPAQUE:
if(con->value.opaquev.len > 0 && con->value.opaquev.stringv != NULL)
fprintf(stderr,"0x%s",con->value.opaquev.stringv);
else
fprintf(stderr,"0x--");
break;
case NC_ECONST:
fprintf(stderr,"%s",(con->value.enumv==NULL?"?":con->value.enumv->name));
break;
case NC_FILLVALUE:
fprintf(stderr,"_");
break;
case NC_CHAR:
fprintf(stderr,"'%c'",con->value.charv);
break;
case NC_BYTE:
fprintf(stderr,"%hhd",con->value.int8v);
break;
case NC_UBYTE:
fprintf(stderr,"%hhu",con->value.uint8v);
break;
case NC_SHORT:
fprintf(stderr,"%hd",con->value.int16v);
break;
case NC_USHORT:
fprintf(stderr,"%hu",con->value.uint16v);
break;
case NC_INT:
fprintf(stderr,"%d",con->value.int32v);
break;
case NC_UINT:
fprintf(stderr,"%u",con->value.uint32v);
break;
case NC_INT64:
fprintf(stderr,"%lld",con->value.int64v);
break;
case NC_UINT64:
fprintf(stderr,"%llu",con->value.uint64v);
break;
case NC_FLOAT:
fprintf(stderr,"%g",con->value.floatv);
break;
case NC_DOUBLE:
fprintf(stderr,"%g",con->value.doublev);
break;
default:
fprintf(stderr,"<unknown>");
break;
}
fflush(stderr);
}
#define MAXELEM 8
#define MAXDEPTH 4
#if 0
void
dumpsrc0(Datasrc* src,char* tag)
{
int i, count, index, depth;
depth = MAXDEPTH;
count = src->length;
index = src->index;
if(count > MAXELEM) count = MAXELEM;
if(index > count) index = count;
fprintf(stderr,"%s:: ",(tag?tag:""));
do {
fprintf(stderr,"[%d/%d]",src->index,src->length);
for(i=0;i<index;i++) {
fprintf(stderr," ");
dumpconstant1(src->data[i]);
}
fprintf(stderr,"^");
for(i=index;i<count;i++) {
fprintf(stderr," ");
dumpconstant1(src->data[i]);
}
if(count < src->length) fprintf(stderr,"...");
fprintf(stderr," | ");
src = src->prev;
} while(src != NULL && depth > 0);
if(src != NULL) fprintf(stderr,"---");
fprintf(stderr,"\n");
fflush(stderr);
}
void
dumpsrc(Datasrc* src,char* tag)
{
#ifndef DEBUGSRC
if(debug == 0) return;
#endif
dumpsrc0(src,tag);
}
#endif