* 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 <stdlib.h> and <sys/types.h> 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).
# 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
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;
" 4 usage error\n"
" 5 operation not supported on this system\n",
why);
- exit(4);
+ quitnow(4);
}
static const adns_rrtype defaulttypes[]= {
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++;
}
}
}
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;
int r;
const adns_rrtype *types;
struct timeval now;
- adns_rrtype *types_a;
char ownflags[10];
char *ep;
const char *initflags, *owninitflags;
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; ti<tc; ti++) {
types_a[ti]= strtoul(cp,&cp,10);
if ((ch= *cp)) {
cp++;
}
}
- *cp++= adns_r_none;
+ types_a[ti]= adns_r_none;
types= types_a;
argv++;
} else {
+ types_a= 0;
types= defaulttypes;
}
for (qc=0; fdomlist[qc]; qc++);
for (tc=0; types[tc] != adns_r_none; tc++);
- mcs= malloc(sizeof(*mcs)*qc*tc);
- if (!mcs) { perror("malloc mcs"); exit(3); }
+ mcs= malloc(tc ? sizeof(*mcs)*qc*tc : 1);
+ if (!mcs) { perror("malloc mcs"); quitnow(3); }
if (initstring) {
r= adns_init_strcfg(&ads,
fdom_split(mc->fdom,&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);
mc->doneyet= 1;
}
- free(mcs);
- adns_finish(ads);
-
- exit(0);
+ quitnow(0);
}
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)))
fcntl fd=4 cmd=F_SETFL O_NONBLOCK|...
fcntl=OK
+0.000061
+ close fd=4
+ close=OK
+ +0.000001
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;
void Q_vb(void);
+extern void Tshutdown(void);
+
/* General help functions */
void Tfailed(const char *why);
#include <fcntl.h>
#include <string.h>
#include <errno.h>
+#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
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);
+}
static FILE *Tinputfile, *Treportfile;
static vbuf vb2;
+extern void Tshutdown(void) {
+ adns__vbuf_free(&vb2);
+}
+
static void Tensurereportfile(void) {
const char *fdstr;
int fd;
static FILE *Toutputfile;
+void Tshutdown(void) {
+}
+
static void R_recordtime(void) {
int r;
struct timeval tv, tvrel;
if (qu->typei && qu->typei->fmtname)
fprintf(ads->diagfile,"(%s)",qu->typei->fmtname);
bef=", "; aft=")\n";
+ adns__vbuf_free(&vb);
}
if (serv>=0) {
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;
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; }
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);
}
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;
}
*newchars++ = 0;
}
- free(ads->searchlist);
+ freesearchlist(ads);
ads->nsearchlist= count;
ads->searchlist= newptrs;
}
if (ads->tcpsocket >= 0) close(ads->tcpsocket);
adns__vbuf_free(&ads->tcpsend);
adns__vbuf_free(&ads->tcprecv);
+ freesearchlist(ads);
free(ads);
}
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);