Add memory leak checks

This commit is contained in:
Ron Pedde 2003-11-23 06:10:25 +00:00
parent 938d54b055
commit 41746a0326
4 changed files with 253 additions and 11 deletions

171
src/err.c
View File

@ -22,15 +22,35 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <errno.h> #include <errno.h>
#include <pthread.h>
#include <syslog.h> #include <syslog.h>
#include <stdlib.h> #include <stdlib.h>
#define __IN_ERR__
#include "err.h" #include "err.h"
typedef struct tag_err_leak {
void *ptr;
char *file;
int line;
int size;
struct tag_err_leak *next;
} ERR_LEAK;
int err_debuglevel=0; int err_debuglevel=0;
int err_logdestination=LOGDEST_STDERR; int err_logdestination=LOGDEST_STDERR;
pthread_mutex_t err_mutex=PTHREAD_MUTEX_INITIALIZER;
ERR_LEAK err_leak = { NULL, NULL, 0, 0, NULL };
/*
* Forwards
*/
int err_lock_mutex(void);
int err_unlock_mutex(void);
/**************************************************** /****************************************************
* log_err * log_err
****************************************************/ ****************************************************/
@ -62,6 +82,7 @@ void log_err(int quit, char *fmt, ...)
****************************************************/ ****************************************************/
void log_setdest(char *app, int destination) { void log_setdest(char *app, int destination) {
switch(destination) { switch(destination) {
case LOGDEST_SYSLOG: case LOGDEST_SYSLOG:
if(err_logdestination != LOGDEST_SYSLOG) { if(err_logdestination != LOGDEST_SYSLOG) {
openlog(app,LOG_PID,LOG_DAEMON); openlog(app,LOG_PID,LOG_DAEMON);
@ -75,3 +96,153 @@ void log_setdest(char *app, int destination) {
break; break;
} }
} }
#ifdef DEBUG
/*
* err_lock
*
* Lock the error mutex
*/
int err_lock_mutex(void) {
int err;
if(err=pthread_mutex_lock(&err_mutex)) {
errno=err;
return -1;
}
return 0;
}
/*
* err_unlock
*
* Unlock the error mutex
*
* returns 0 on success,
* returns -1 on failure, with errno set
*/
int err_unlock_mutex(void) {
int err;
if(err=pthread_mutex_unlock(&err_mutex)) {
errno=err;
return -1;
}
return 0;
}
/*
* err_malloc
*
* safe malloc
*/
void *err_malloc(char *file, int line, size_t size) {
ERR_LEAK *pnew;
DPRINTF(ERR_DEBUG,"Mallocing %d bytes\n",size);
err_leakcheck();
DPRINTF(ERR_DEBUG,"---\n");
pnew=(ERR_LEAK*)malloc(sizeof(pnew));
if(!pnew)
log_err(1,"Error: cannot allocate leak struct\n");
if(err_lock_mutex())
log_err(1,"Error: cannot lock error mutex\n");
pnew->file=file;
pnew->line=line;
pnew->size=size;
pnew->ptr=malloc(size);
pnew->next=err_leak.next;
err_leak.next=pnew;
err_unlock_mutex();
DPRINTF(ERR_DEBUG,"Malloced at %x\n",pnew->ptr);
err_leakcheck();
DPRINTF(ERR_DEBUG,"---\n");
return pnew->ptr;
}
/*
* err_strdup
*
* safe strdup
*/
char *err_strdup(char *file, int line, const char *str) {
void *pnew;
pnew=err_malloc(file,line,strlen(str) + 1);
if(!pnew)
log_err(1,"Cannot malloc enough space for strdup\n");
memcpy(pnew,str,strlen(str)+1);
return pnew;
}
/*
* err_free
*
* safe free
*/
void err_free(char *file, int line, void *ptr) {
ERR_LEAK *current,*last;
DPRINTF(ERR_DEBUG,"Freeing %x\n",ptr);
err_leakcheck();
DPRINTF(ERR_DEBUG,"---\n");
if(err_lock_mutex())
log_err(1,"Error: cannot lock error mutex\n");
last=&err_leak;
current=last->next;
while((current) && (current->ptr != ptr)) {
last=current;
current=current->next;
}
if(!current) {
log_err(0,"Attempt to free unallocated memory: %s, %d\n",file,line);
} else {
free(current->ptr);
last->next=current->next;
free(current);
}
err_unlock_mutex();
DPRINTF(ERR_DEBUG,"Freed\n");
err_leakcheck();
DPRINTF(ERR_DEBUG,"---\n");
}
/*
* void err_leakcheck
*
* Walk through the list of memory
*/
void err_leakcheck(void) {
ERR_LEAK *current;
if(err_lock_mutex())
log_err(1,"Error: cannot lock error mutex\n");
current=err_leak.next;
while(current) {
printf("%s: %d - %d bytes at %x\n",current->file, current->line, current->size,
current->ptr);
current=current->next;
}
err_unlock_mutex();
}
#endif

View File

@ -37,10 +37,25 @@ extern void log_err(int quit, char *fmt, ...);
extern void log_setdest(char *app, int destination); extern void log_setdest(char *app, int destination);
#ifdef DEBUG #ifdef DEBUG
#define DPRINTF(level, fmt, arg...) \ # define DPRINTF(level, fmt, arg...) \
{ if((level) <= err_debuglevel) { log_err(0,"%s: ",__FILE__); log_err(0,fmt,##arg); }} { if((level) <= err_debuglevel) { log_err(0,"%s: ",__FILE__); log_err(0,fmt,##arg); }}
#else #else
#define DPRINTF(level, fmt, arg...) # define DPRINTF(level, fmt, arg...)
#endif /* DEBUG */
#ifdef DEBUG
# ifndef __IN_ERR__
# define malloc(x) err_malloc(__FILE__,__LINE__,x)
# define strdup(x) err_strdup(__FILE__,__LINE__,x)
# define free(x) err_free(__FILE__,__LINE__,x)
# endif /* __IN_ERR__ */
extern void *err_malloc(char *file, int line, size_t size);
extern char *err_strdup(char *file, int line, const char *str);
extern void err_free(char *file, int line, void *ptr);
extern void err_leakcheck(void);
#endif /* DEBUG */ #endif /* DEBUG */
#endif /* __ERR_H__ */ #endif /* __ERR_H__ */

View File

@ -349,9 +349,13 @@ int main(int argc, char *argv[]) {
rend_init(&rendezvous_pid,config.servername, config.port); rend_init(&rendezvous_pid,config.servername, config.port);
while(1) { while(1) {
sleep(20); sleep(100);
} }
#ifdef DEBUG
err_leakcheck();
#endif
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -66,7 +66,10 @@ typedef struct tag_ws_private {
int stop; int stop;
int running; int running;
int threadno; int threadno;
int dispatch_threads;
pthread_t server_tid; pthread_t server_tid;
pthread_cond_t exit_cond;
pthread_mutex_t exit_mutex;
} WS_PRIVATE; } WS_PRIVATE;
/* /*
@ -101,7 +104,8 @@ int ws_testrequestheader(WS_CONNINFO *pwsc, char *header, char *value);
/* /*
* Globals * Globals
*/ */
pthread_mutex_t munsafe=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t ws_unsafe=PTHREAD_MUTEX_INITIALIZER;
char *ws_dow[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; char *ws_dow[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
char *ws_moy[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", char *ws_moy[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
"Aug", "Sep", "Oct", "Nov", "Dec" }; "Aug", "Sep", "Oct", "Nov", "Dec" };
@ -117,7 +121,7 @@ char *ws_moy[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
int ws_lock_unsafe(void) { int ws_lock_unsafe(void) {
int err; int err;
if(err=pthread_mutex_lock(&munsafe)) { if(err=pthread_mutex_lock(&ws_unsafe)) {
errno=err; errno=err;
return -1; return -1;
} }
@ -136,7 +140,7 @@ int ws_lock_unsafe(void) {
int ws_unlock_unsafe(void) { int ws_unlock_unsafe(void) {
int err; int err;
if(err=pthread_mutex_unlock(&munsafe)) { if(err=pthread_mutex_unlock(&ws_unsafe)) {
errno=err; errno=err;
return -1; return -1;
} }
@ -168,8 +172,19 @@ WSHANDLE ws_start(WSCONFIG *config) {
memcpy(&pwsp->wsconfig,config,sizeof(WS_PRIVATE)); memcpy(&pwsp->wsconfig,config,sizeof(WS_PRIVATE));
pwsp->running=0; pwsp->running=0;
pwsp->threadno=0; pwsp->threadno=0;
pwsp->dispatch_threads=0;
pwsp->handlers.next=NULL; pwsp->handlers.next=NULL;
if(err=pthread_cond_init(&pwsp->exit_cond, NULL)) {
errno=err;
return NULL;
}
if(err=pthread_mutex_init(&pwsp->exit_mutex,NULL)) {
errno=err;
return NULL;
}
DPRINTF(ERR_INFO,"Preparing to listen on port %d\n",pwsp->wsconfig.port); DPRINTF(ERR_INFO,"Preparing to listen on port %d\n",pwsp->wsconfig.port);
if((pwsp->server_fd = u_open(pwsp->wsconfig.port)) == -1) { if((pwsp->server_fd = u_open(pwsp->wsconfig.port)) == -1) {
@ -198,10 +213,23 @@ WSHANDLE ws_start(WSCONFIG *config) {
* *
* Stop the web server and all the child threads * Stop the web server and all the child threads
*/ */
int ws_stop(WSHANDLE arg) { extern int ws_stop(WSHANDLE ws) {
WS_PRIVATE *pwsp = (WS_PRIVATE*)arg; WS_PRIVATE *pwsp = (WS_PRIVATE*)ws;
/* free the ws_handlers */ /* free the ws_handlers */
pwsp->stop=1;
/* Wait for all the threads to die */
if(pthread_mutex_lock(&pwsp->exit_mutex))
log_err(1,"Cannot lock condition mutex\n");
/* wait for condition */
while(pwsp->dispatch_threads) {
pthread_cond_wait(&pwsp->exit_cond, &pwsp->exit_mutex);
}
pthread_mutex_unlock(&pwsp->exit_mutex);
return 0; return 0;
} }
@ -257,13 +285,19 @@ void *ws_mainthread(void *arg) {
ws_unlock_unsafe(); ws_unlock_unsafe();
/* now, throw off a dispatch thread */ /* now, throw off a dispatch thread */
if(pthread_mutex_lock(&pwsp->exit_mutex))
log_err(1,"Cannot lock condition mutex\n");
if(err=pthread_create(&tid,NULL,ws_dispatcher,(void*)pwsc)) { if(err=pthread_create(&tid,NULL,ws_dispatcher,(void*)pwsc)) {
pwsc->error=err; pwsc->error=err;
DPRINTF(ERR_WARN,"Could not spawn thread: %s\n",strerror(err)); DPRINTF(ERR_WARN,"Could not spawn thread: %s\n",strerror(err));
pthread_mutex_unlock(&pwsp->exit_mutex);
ws_close(pwsc); ws_close(pwsc);
} else {
pwsp->dispatch_threads++;
pthread_mutex_unlock(&pwsp->exit_mutex);
pthread_detach(tid);
} }
pthread_detach(tid);
} }
} }
@ -280,6 +314,8 @@ void *ws_mainthread(void *arg) {
* allocated memory has been freed * allocated memory has been freed
*/ */
void ws_close(WS_CONNINFO *pwsc) { void ws_close(WS_CONNINFO *pwsc) {
WS_PRIVATE *pwsp = (WS_PRIVATE *)pwsc->pwsp;
DPRINTF(ERR_DEBUG,"Thread %d: Terminating\n",pwsc->threadno); DPRINTF(ERR_DEBUG,"Thread %d: Terminating\n",pwsc->threadno);
DPRINTF(ERR_DEBUG,"Thread %d: Freeing request headers\n",pwsc->threadno); DPRINTF(ERR_DEBUG,"Thread %d: Freeing request headers\n",pwsc->threadno);
ws_freearglist(&pwsc->request_headers); ws_freearglist(&pwsc->request_headers);
@ -292,6 +328,20 @@ void ws_close(WS_CONNINFO *pwsc) {
DPRINTF(ERR_DEBUG,"Thread %d: Closing fd\n",pwsc->threadno); DPRINTF(ERR_DEBUG,"Thread %d: Closing fd\n",pwsc->threadno);
close(pwsc->fd); close(pwsc->fd);
free(pwsc->hostname); free(pwsc->hostname);
/* this thread is done */
if(pthread_mutex_lock(&pwsp->exit_mutex))
log_err(1,"Error: cannot lock condition mutex\n");
if(!pwsp->dispatch_threads) {
log_err(1,"Error: Bad dispatch thread count!\n");
} else {
pwsp->dispatch_threads--;
if(pthread_cond_signal(&pwsp->exit_cond))
log_err(1,"Error: cannot signal condition\n");
}
pthread_mutex_unlock(&pwsp->exit_mutex);
free(pwsc); free(pwsc);
} }
} }
@ -673,8 +723,10 @@ void *ws_dispatcher(void *arg) {
ws_defaulthandler(pwsp,pwsc); ws_defaulthandler(pwsp,pwsc);
} }
if((pwsc->close)||(pwsc->error)) if((pwsc->close) || (pwsc->error) || (pwsp->stop)) {
pwsc->close=1;
connection_done=1; connection_done=1;
}
ws_close(pwsc); ws_close(pwsc);
} }
return NULL; return NULL;