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 <stdarg.h>
#include <errno.h>
#include <pthread.h>
#include <syslog.h>
#include <stdlib.h>
#define __IN_ERR__
#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_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
****************************************************/
@ -62,6 +82,7 @@ void log_err(int quit, char *fmt, ...)
****************************************************/
void log_setdest(char *app, int destination) {
switch(destination) {
case LOGDEST_SYSLOG:
if(err_logdestination != LOGDEST_SYSLOG) {
openlog(app,LOG_PID,LOG_DAEMON);
@ -75,3 +96,153 @@ void log_setdest(char *app, int destination) {
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);
#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); }}
#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 /* __ERR_H__ */

View File

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

View File

@ -66,7 +66,10 @@ typedef struct tag_ws_private {
int stop;
int running;
int threadno;
int dispatch_threads;
pthread_t server_tid;
pthread_cond_t exit_cond;
pthread_mutex_t exit_mutex;
} WS_PRIVATE;
/*
@ -101,7 +104,8 @@ int ws_testrequestheader(WS_CONNINFO *pwsc, char *header, char *value);
/*
* 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_moy[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
"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 err;
if(err=pthread_mutex_lock(&munsafe)) {
if(err=pthread_mutex_lock(&ws_unsafe)) {
errno=err;
return -1;
}
@ -136,7 +140,7 @@ int ws_lock_unsafe(void) {
int ws_unlock_unsafe(void) {
int err;
if(err=pthread_mutex_unlock(&munsafe)) {
if(err=pthread_mutex_unlock(&ws_unsafe)) {
errno=err;
return -1;
}
@ -168,8 +172,19 @@ WSHANDLE ws_start(WSCONFIG *config) {
memcpy(&pwsp->wsconfig,config,sizeof(WS_PRIVATE));
pwsp->running=0;
pwsp->threadno=0;
pwsp->dispatch_threads=0;
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);
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
*/
int ws_stop(WSHANDLE arg) {
WS_PRIVATE *pwsp = (WS_PRIVATE*)arg;
extern int ws_stop(WSHANDLE ws) {
WS_PRIVATE *pwsp = (WS_PRIVATE*)ws;
/* 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;
}
@ -257,13 +285,19 @@ void *ws_mainthread(void *arg) {
ws_unlock_unsafe();
/* 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)) {
pwsc->error=err;
DPRINTF(ERR_WARN,"Could not spawn thread: %s\n",strerror(err));
pthread_mutex_unlock(&pwsp->exit_mutex);
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
*/
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: Freeing request headers\n",pwsc->threadno);
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);
close(pwsc->fd);
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);
}
}
@ -673,8 +723,10 @@ void *ws_dispatcher(void *arg) {
ws_defaulthandler(pwsp,pwsc);
}
if((pwsc->close)||(pwsc->error))
if((pwsc->close) || (pwsc->error) || (pwsp->stop)) {
pwsc->close=1;
connection_done=1;
}
ws_close(pwsc);
}
return NULL;