From: ian Date: Tue, 2 Nov 1999 23:40:14 +0000 (+0000) Subject: + * Many memory leaks fixed. X-Git-Tag: privaterel-1999-11-02-fanf~1 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=commitdiff_plain;h=914a5ff5342e43d8a2378b1f0f65057ef084fe20 + * Many memory leaks fixed. @@ -4,14 +4,15 @@ * Do not fail assertion if _qf_owner, _qf_search, domain ends in `.'. * Avoid infinite timeouts, causing lockup, when they should be zero ! * TCP handling revamped (avoids recursive-invocation problems). - * Two memory leaks (one in all queries, one in cancelled ones) fixed. + * Many memory leaks fixed. Test and client program bug and portability fixes: * Dynamic library building works properly. * adnshost prints somewhat better messages about some wrong usages. * Include and in adnshost.h. * adnslogres: parsing and error checking improved (Tony Finch). - * Regresion tests can cope with zero-length reads. + * Regression tests can cope with zero-length reads. + * Regression tests check for memory leaks. General improvements * New adns_if_logpid option (functionality suggested by Tony Finch). --- diff --git a/changelog b/changelog index 2f292b1..2981a07 100644 --- a/changelog +++ b/changelog @@ -4,14 +4,15 @@ adns (0.6) unstable; urgency=high * Do not fail assertion if _qf_owner, _qf_search, domain ends in `.'. * Avoid infinite timeouts, causing lockup, when they should be zero ! * TCP handling revamped (avoids recursive-invocation problems). - * Two memory leaks (one in all queries, one in cancelled ones) fixed. + * Many memory leaks fixed. Test and client program bug and portability fixes: * Dynamic library building works properly. * adnshost prints somewhat better messages about some wrong usages. * Include and in adnshost.h. * adnslogres: parsing and error checking improved (Tony Finch). - * Regresion tests can cope with zero-length reads. + * Regression tests can cope with zero-length reads. + * Regression tests check for memory leaks. General improvements * New adns_if_logpid option (functionality suggested by Tony Finch). diff --git a/client/adnstest.c b/client/adnstest.c index 4abd4ff..2460dbf 100644 --- a/client/adnstest.c +++ b/client/adnstest.c @@ -41,11 +41,30 @@ # define OUTPUTSTREAM stdout #endif +struct myctx { + adns_query qu; + int doneyet, found; + const char *fdom; +}; + +static struct myctx *mcs; +static adns_state ads; +static adns_rrtype *types_a; + +static void quitnow(int rc) NONRETURNING; +static void quitnow(int rc) { + free(mcs); + free(types_a); + if (ads) adns_finish(ads); + + exit(rc); +} + #ifndef HAVE_POLL #undef poll int poll(struct pollfd *ufds, int nfds, int timeout) { fputs("poll(2) not supported on this system\n",stderr); - exit(5); + quitnow(5); } #define adns_beforepoll(a,b,c,d,e) 0 #define adns_afterpoll(a,b,c,d) 0 @@ -54,13 +73,13 @@ int poll(struct pollfd *ufds, int nfds, int timeout) { static void failure_status(const char *what, adns_status st) NONRETURNING; static void failure_status(const char *what, adns_status st) { fprintf(stderr,"adns failure: %s: %s\n",what,adns_strerror(st)); - exit(2); + quitnow(2); } static void failure_errno(const char *what, int errnoval) NONRETURNING; static void failure_errno(const char *what, int errnoval) { fprintf(stderr,"adns failure: %s: errno=%d\n",what,errnoval); - exit(2); + quitnow(2); } static void usageerr(const char *why) NONRETURNING; @@ -80,7 +99,7 @@ static void usageerr(const char *why) { " 4 usage error\n" " 5 operation not supported on this system\n", why); - exit(4); + quitnow(4); } static const adns_rrtype defaulttypes[]= { @@ -120,7 +139,7 @@ static void fdom_split(const char *fdom, const char **dom_r, int *qf_r, if (*ep == ',' && strchr(ep,'/')) { ep++; while (*ep != '/') { - if (--ownflags_l <= 0) { fputs("too many flags\n",stderr); exit(3); } + if (--ownflags_l <= 0) { fputs("too many flags\n",stderr); quitnow(3); } *ownflags++= *ep++; } } @@ -134,15 +153,8 @@ static int consistsof(const char *string, const char *accept) { } int main(int argc, char *const *argv) { - struct myctx { - adns_query qu; - int doneyet, found; - const char *fdom; - }; - - adns_state ads; adns_query qu; - struct myctx *mcs, *mc, *mcw; + struct myctx *mc, *mcw; void *mcr; adns_answer *ans; const char *initstring, *rrtn, *fmtn; @@ -153,7 +165,6 @@ int main(int argc, char *const *argv) { int r; const adns_rrtype *types; struct timeval now; - adns_rrtype *types_a; char ownflags[10]; char *ep; const char *initflags, *owninitflags; @@ -185,7 +196,7 @@ int main(int argc, char *const *argv) { for (cp= argv[1]+1, tc=1; (ch= *cp); cp++) if (ch==',') tc++; types_a= malloc(sizeof(*types_a)*(tc+1)); - if (!types_a) { perror("malloc types"); exit(3); } + if (!types_a) { perror("malloc types"); quitnow(3); } for (cp= argv[1]+1, ti=0; tifdom,&domain,&qflags,ownflags,sizeof(ownflags)); - if (gettimeofday(&now,0)) { perror("gettimeofday"); exit(3); } + if (gettimeofday(&now,0)) { perror("gettimeofday"); quitnow(3); } ri= adns_rr_info(ans->type, &rrtn,&fmtn,&len, 0,0); fprintf(stdout, "%s flags %d type ",domain,qflags); @@ -321,8 +333,5 @@ int main(int argc, char *const *argv) { mc->doneyet= 1; } - free(mcs); - adns_finish(ads); - - exit(0); + quitnow(0); } diff --git a/regress/Makefile.in b/regress/Makefile.in index 3ed85f1..2945c8b 100644 --- a/regress/Makefile.in +++ b/regress/Makefile.in @@ -35,6 +35,7 @@ HCPPFLAGS:= $(foreach F, \ gettimeofday select poll \ socket fcntl connect close \ sendto recvfrom read write writev \ + malloc realloc free exit \ , -D$F=H$F) HARNLOBJS= $(addsuffix _d.o, $(basename $(LIBOBJS))) diff --git a/regress/case-flags10.sys b/regress/case-flags10.sys index 550bc22..c535edd 100644 --- a/regress/case-flags10.sys +++ b/regress/case-flags10.sys @@ -10,3 +10,6 @@ default fcntl fd=4 cmd=F_SETFL O_NONBLOCK|... fcntl=OK +0.000061 + close fd=4 + close=OK + +0.000001 diff --git a/regress/harness.h.m4 b/regress/harness.h.m4 index 12ecc3e..35efa18 100644 --- a/regress/harness.h.m4 +++ b/regress/harness.h.m4 @@ -48,6 +48,11 @@ m4_include(`hsyscalls.i4') int Hwritev(int fd, const struct iovec *vector, size_t count); int Hgettimeofday(struct timeval *tv, struct timezone *tz); +void *Hmalloc(size_t sz); +void Hfree(void *ptr); +void *Hrealloc(void *op, size_t nsz); +void Hexit(int rv); + /* There is a Q function (Q for Question) for each such syscall; * it constructs a string representing the call, and calls Q_str * on it, or constructs it in vb and calls Q_vb; @@ -59,6 +64,8 @@ m4_include(`hsyscalls.i4') void Q_vb(void); +extern void Tshutdown(void); + /* General help functions */ void Tfailed(const char *why); diff --git a/regress/hcommon.c.m4 b/regress/hcommon.c.m4 index 59d97ed..311087e 100644 --- a/regress/hcommon.c.m4 +++ b/regress/hcommon.c.m4 @@ -28,6 +28,7 @@ m4_include(hmacros.i4) #include #include #include +#include #include #include @@ -228,3 +229,80 @@ void Tnomem(void) { void Toutputerr(void) { Tfailed("write error on test harness output"); } + +struct malloced { + struct malloced *next, *back; + size_t sz; + unsigned long count; + struct { double d; long ul; void *p; void (*fp)(void); } data; +}; + +static unsigned long malloccount, mallocfailat; +static struct { struct malloced *head, *tail; } mallocedlist; + +#define MALLOCHSZ ((char*)&mallocedlist.head->data - (char*)mallocedlist.head) + +void *Hmalloc(size_t sz) { + struct malloced *newnode; + const char *mfavar; + char *ep; + + assert(sz); + + newnode= malloc(MALLOCHSZ + sz); if (!newnode) Tnomem(); + + LIST_LINK_TAIL(mallocedlist,newnode); + newnode->sz= sz; + newnode->count= ++malloccount; + if (!mallocfailat) { + mfavar= getenv("ADNS_REGRESS_MALLOCFAILAT"); + if (mfavar) { + mallocfailat= strtoul(mfavar,&ep,10); + if (!mallocfailat || *ep) Tfailed("ADNS_REGRESS_MALLOCFAILAT bad value"); + } else { + mallocfailat= ~0UL; + } + } + assert(newnode->count != mallocfailat); + memset(&newnode->data,0xc7,sz); + return &newnode->data; +} + +void Hfree(void *ptr) { + struct malloced *oldnode; + + if (!ptr) return; + + oldnode= (void*)((char*)ptr - MALLOCHSZ); + LIST_UNLINK(mallocedlist,oldnode); + memset(&oldnode->data,0x38,oldnode->sz); + free(oldnode); +} + +void *Hrealloc(void *op, size_t nsz) { + struct malloced *oldnode; + void *np; + size_t osz; + + if (op) { oldnode= (void*)((char*)op - MALLOCHSZ); osz= oldnode->sz; } else { osz= 0; } + np= Hmalloc(nsz); + memcpy(np,op, osz>nsz ? nsz : osz); + Hfree(op); + return np; +} + +void Hexit(int rv) { + struct malloced *loopnode; + + Tshutdown(); + adns__vbuf_free(&vb); + adns__vbuf_free(&vbw); + if (mallocedlist.head) { + fprintf(stderr,"adns test harness: memory leaked:"); + for (loopnode=mallocedlist.head; loopnode; loopnode=loopnode->next) + fprintf(stderr," %lu(%lu)",loopnode->count,(unsigned long)loopnode->sz); + putc('\n',stderr); + if (ferror(stderr)) exit(-1); + } + exit(rv); +} diff --git a/regress/hplayback.c.m4 b/regress/hplayback.c.m4 index d7b383a..97e951a 100644 --- a/regress/hplayback.c.m4 +++ b/regress/hplayback.c.m4 @@ -40,6 +40,10 @@ m4_include(hmacros.i4) static FILE *Tinputfile, *Treportfile; static vbuf vb2; +extern void Tshutdown(void) { + adns__vbuf_free(&vb2); +} + static void Tensurereportfile(void) { const char *fdstr; int fd; diff --git a/regress/hrecord.c.m4 b/regress/hrecord.c.m4 index 1e98c82..c6417ca 100644 --- a/regress/hrecord.c.m4 +++ b/regress/hrecord.c.m4 @@ -35,6 +35,9 @@ m4_include(hmacros.i4) static FILE *Toutputfile; +void Tshutdown(void) { +} + static void R_recordtime(void) { int r; struct timeval tv, tvrel; diff --git a/src/general.c b/src/general.c index 0168a4a..8793762 100644 --- a/src/general.c +++ b/src/general.c @@ -68,6 +68,7 @@ void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent, if (qu->typei && qu->typei->fmtname) fprintf(ads->diagfile,"(%s)",qu->typei->fmtname); bef=", "; aft=")\n"; + adns__vbuf_free(&vb); } if (serv>=0) { diff --git a/src/query.c b/src/query.c index e6bc7a0..37306d1 100644 --- a/src/query.c +++ b/src/query.c @@ -91,7 +91,7 @@ static void query_submit(adns_state ads, adns_query qu, const typeinfo *typei, vbuf *qumsg_vb, int id, adns_queryflags flags, struct timeval now) { /* Fills in the query message in for a previously-allocated query, - * and submits it. Cannot fail. + * and submits it. Cannot fail. Takes over the memory for qumsg_vb. */ qu->vb= *qumsg_vb; @@ -131,7 +131,7 @@ static void query_simple(adns_state ads, adns_query qu, int id; adns_status stat; - adns__vbuf_init(&vb); + vb= qu->vb; stat= adns__mkquery(ads,&vb,&id, owner,ol, typei,flags); if (stat) { adns__query_fail(qu,stat); return; } @@ -390,6 +390,7 @@ static void free_query_allocs(adns_query qu) { for (an= qu->allocations.head; an; an= ann) { ann= an->next; free(an); } LIST_INIT(qu->allocations); adns__vbuf_free(&qu->vb); + adns__vbuf_free(&qu->search_vb); free(qu->query_dgram); } diff --git a/src/setup.c b/src/setup.c index dca8a19..e19a705 100644 --- a/src/setup.c +++ b/src/setup.c @@ -62,6 +62,11 @@ static void addserver(adns_state ads, struct in_addr addr) { ads->nservers++; } +static void freesearchlist(adns_state ads) { + if (ads->nsearchlist) free(*ads->searchlist); + free(ads->searchlist); +} + static void saveerr(adns_state ads, int en) { if (!ads->configerrno) ads->configerrno= en; } @@ -133,7 +138,7 @@ static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) *newchars++ = 0; } - free(ads->searchlist); + freesearchlist(ads); ads->nsearchlist= count; ads->searchlist= newptrs; } @@ -591,6 +596,7 @@ void adns_finish(adns_state ads) { if (ads->tcpsocket >= 0) close(ads->tcpsocket); adns__vbuf_free(&ads->tcpsend); adns__vbuf_free(&ads->tcprecv); + freesearchlist(ads); free(ads); } diff --git a/src/transmit.c b/src/transmit.c index edb79c3..c5ae9dc 100644 --- a/src/transmit.c +++ b/src/transmit.c @@ -81,7 +81,7 @@ adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r, const char *p, *pe; adns_status st; - st= mkquery_header(ads,vb,id_r,strlen(owner)+2); if (st) return st; + st= mkquery_header(ads,vb,id_r,ol+2); if (st) return st; MKQUERY_START(vb);