netcdf-c/ncgen/list.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

221 lines
4.3 KiB
C

/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
See the COPYRIGHT file for more information. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "includes.h"
int listnull(void* e) {return e == NULL;}
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define DEFAULTALLOC 16
#define ALLOCINCR 16
List* listnew(void)
{
List* l;
/*
if(!initialized) {
memset((void*)&DATANULL,0,sizeof(void*));
initialized = 1;
}
*/
l = (List*)emalloc(sizeof(List));
if(l) {
l->alloc=0;
l->length=0;
l->content=NULL;
}
return l;
}
int
listfree(List* l)
{
if(l) {
l->alloc = 0;
if(l->content != NULL) {efree(l->content); l->content = NULL;}
efree(l);
}
return TRUE;
}
int
listsetalloc(List* l, unsigned long sz)
{
void** newcontent = NULL;
if(l == NULL) return FALSE;
if(sz <= 0) {sz = (l->length?2*l->length:DEFAULTALLOC);}
if(l->alloc >= sz) {return TRUE;}
newcontent=(void**)ecalloc(sz*sizeof(void*));
if(newcontent != NULL && l->alloc > 0 && l->length > 0 && l->content != NULL) {
memcpy((void*)newcontent,(void*)l->content,sizeof(void*)*l->length);
}
if(l->content != NULL) efree(l->content);
l->content=newcontent;
l->alloc=sz;
return TRUE;
}
int
listsetlength(List* l, unsigned long sz)
{
if(l == NULL) return FALSE;
if(sz > l->alloc && !listsetalloc(l,sz)) return FALSE;
l->length = sz;
return TRUE;
}
void*
listget(List* l, unsigned long index)
{
if(l == NULL || l->length == 0) return NULL;
if(index >= l->length) return NULL;
return l->content[index];
}
int
listset(List* l, unsigned long index, void* elem)
{
if(l == NULL) return FALSE;
if(index >= l->length) return FALSE;
l->content[index] = elem;
return TRUE;
}
/* Insert at position i of l; will push up elements i..|seq|. */
int
listinsert(List* l, unsigned long index, void* elem)
{
int i; /* do not make unsigned */
if(l == NULL) return FALSE;
if(index > l->length) return FALSE;
listsetalloc(l,0);
for(i=(int)l->length;i>index;i--) l->content[i] = l->content[i-1];
l->content[index] = elem;
l->length++;
return TRUE;
}
int
listpush(List* l, void* elem)
{
if(l == NULL) return FALSE;
if(l->length >= l->alloc) listsetalloc(l,0);
l->content[l->length] = elem;
l->length++;
return TRUE;
}
void*
listpop(List* l)
{
if(l == NULL || l->length == 0) return NULL;
l->length--;
return l->content[l->length];
}
void*
listtop(List* l)
{
if(l == NULL || l->length == 0) return NULL;
return l->content[l->length - 1];
}
void*
listremove(List* l, unsigned long i)
{
unsigned long len;
void* elem;
if(l == NULL || (len=l->length) == 0) return NULL;
if(i >= len) return NULL;
elem = l->content[i];
for(i+=1;i<len;i++) l->content[i-1] = l->content[i];
l->length--;
return elem;
}
/* Duplicate and return the content (null terminate) */
void**
listdup(List* l)
{
void** result = (void**)emalloc(sizeof(void*)*(l->length+1));
memcpy((void*)result,(void*)l->content,sizeof(void*)*l->length);
result[l->length] = (void*)0;
return result;
}
int
listcontains(List* l, void* elem)
{
unsigned long i;
for(i=0;i<listlength(l);i++) {
if(elem == listget(l,i)) return 1;
}
return 0;
}
/* Remove element by value; only removes first encountered */
int
listelemremove(List* l, void* elem)
{
unsigned long len;
unsigned long i;
int found = 0;
if(l == NULL || (len=l->length) == 0) return 0;
for(i=0;i<listlength(l);i++) {
void* candidate = l->content[i];
if(elem == candidate) {
for(i+=1;i<len;i++) l->content[i-1] = l->content[i];
l->length--;
found = 1;
break;
}
}
return found;
}
/* Extends list to include a unique operator
which remove duplicate values; NULL values removed
return value is always 1.
*/
int
listunique(List* l)
{
unsigned long i,j,k,len;
void** content;
if(l == NULL || l->length == 0) return 1;
len = l->length;
content = l->content;
for(i=0;i<len;i++) {
for(j=i+1;j<len;j++) {
if(content[i] == content[j]) {
/* compress out jth element */
for(k=j+1;k<len;k++) content[k-1] = content[k];
len--;
}
}
}
l->length = len;
return 1;
}
List*
listclone(List* l)
{
List* clone = listnew();
*clone = *l;
clone->content = listdup(l);
return clone;
}