[ My employer, Celo Communications, has kindly allowed me to let this
added feature get out to this list to be included i OpenSSL ]
I'm currently using the memory debugging routines from crypto/mem.c.
They show really nicely who allocated what (if used as intended).
However, there are times when you'd actually like to see some kind of
call stack, to determine what was really originating the memory
allocation.
I've implemented that by giving the library user the ability to add
(and later on remove) information to be stored with every hash entry.
The added information is a file name, a line number and a string with
whatever more info the developer wants to show.
The added information is atored in another hash table, key'd with the
thread ID, thereby giving threaded programs an appropriate tool.
Here's the diff:
------------------------------ SOD ------------------------------
Index: crypto/crypto.h
===================================================================
RCS file: /src/SourceRepository/OpenSSL/crypto/crypto.h,v
retrieving revision 1.14
diff -u -r1.14 crypto.h
--- crypto/crypto.h 1999/09/22 21:50:34 1.14
+++ crypto/crypto.h 1999/11/09 08:27:59
@@ -302,6 +302,9 @@
void *CRYPTO_realloc(void *addr,int num);
void *CRYPTO_remalloc(void *addr,int num);
+int CRYPTO_add_info(const char *file, int line, const char *info);
+int CRYPTO_remove_info();
+
void *CRYPTO_dbg_malloc(int num,const char *file,int line);
void *CRYPTO_dbg_realloc(void *addr,int num,const char *file,int line);
void CRYPTO_dbg_free(void *);
Index: crypto/mem.c
===================================================================
RCS file: /src/SourceRepository/OpenSSL/crypto/mem.c,v
retrieving revision 1.1.1.10
diff -u -r1.1.1.10 mem.c
--- crypto/mem.c 1999/07/26 15:40:48 1.1.1.10
+++ crypto/mem.c 1999/11/09 08:28:04
@@ -84,6 +84,19 @@
static unsigned long order=0;
+static LHASH *amih=NULL;
+
+typedef struct app_mem_info_st
+ {
+ unsigned long thread;
+ const char *file;
+ int line;
+ const char *info;
+ struct app_mem_info_st *next;
+ int references;
+ int in_hash;
+ } APP_INFO;
+
static LHASH *mh=NULL;
typedef struct mem_st
@@ -99,6 +112,7 @@
#ifdef CRYPTO_MDEBUG_TIME
time_t time;
#endif
+ APP_INFO *app_info;
} MEM;
int CRYPTO_mem_ctrl(int mode)
@@ -147,6 +161,120 @@
return(ret);
}
+static int app_info_cmp(APP_INFO *a, APP_INFO *b)
+ {
+ return(a->thread - b->thread);
+ }
+
+static unsigned long app_info_hash(APP_INFO *a)
+ {
+ unsigned long ret;
+
+ ret=(unsigned long)a->thread;
+
+ ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
+ return(ret);
+ }
+
+static APP_INFO *free_info(APP_INFO *app_info)
+ {
+ APP_INFO *next;
+
+ if (app_info == NULL)
+ return NULL;
+
+ if (--(app_info->references) > 0 || app_info->in_hash)
+ return app_info;
+
+ app_info->references = 0;
+
+ next = app_info->next;
+ Free(app_info);
+ return free_info(next);
+ }
+
+static APP_INFO *remove_info()
+ {
+ APP_INFO tmp;
+ APP_INFO *ret = NULL;
+
+ if (amih != NULL)
+ {
+ tmp.thread=CRYPTO_thread_id();
+ if ((ret=(APP_INFO *)lh_delete(amih,(char *)&tmp)) != NULL)
+ {
+ APP_INFO *next=ret->next;
+ ret->in_hash=0;
+ if (next != NULL)
+ {
+ lh_insert(amih,(char *)next);
+ next->in_hash=1;
+ }
+ free_info(ret);
+ }
+ }
+ return(ret);
+ }
+
+int CRYPTO_add_info(const char *file, int line, const char *info)
+ {
+ APP_INFO *ami, *amim;
+ int ret=0;
+
+ if (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
+ {
+ MemCheck_off();
+ CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
+
+ if ((ami = (APP_INFO *)Malloc(sizeof(APP_INFO))) == NULL)
+ {
+ ret=0;
+ goto err;
+ }
+ if (amih == NULL)
+ {
+ if ((amih=lh_new(app_info_hash,app_info_cmp)) == NULL)
+ {
+ Free(ami);
+ ret=0;
+ goto err;
+ }
+ }
+
+ ami->thread=CRYPTO_thread_id();
+ ami->file=file;
+ ami->line=line;
+ ami->info=info;
+ ami->references=0;
+ ami->in_hash=1;
+ ami->next=NULL;
+
+ if ((amim=(APP_INFO *)lh_insert(amih,(char *)ami)) != NULL)
+ {
+ ami->next=amim;
+ amim->in_hash=0;
+ }
+ err:
+ CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
+ MemCheck_on();
+ }
+ return(ret);
+ }
+
+int CRYPTO_remove_info()
+ {
+ int ret=0;
+ if (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
+ {
+ MemCheck_off();
+ CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
+ ret=(remove_info() != NULL);
+ CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
+ MemCheck_on();
+ }
+ return(ret);
+ }
+
static char *(*malloc_locked_func)()=(char *(*)())malloc;
static void (*free_locked_func)()=(void (*)())free;
static char *(*malloc_func)()= (char *(*)())malloc;
@@ -213,6 +341,7 @@
{
char *ret;
MEM *m,*mm;
+ APP_INFO tmp,*amim;
if ((ret=malloc_func(num)) == NULL)
return(NULL);
@@ -254,9 +383,22 @@
#ifdef CRYPTO_MDEBUG_TIME
m->time=time(NULL);
#endif
+
+ tmp.thread=CRYPTO_thread_id();
+ m->app_info=NULL;
+ if ((amim=(APP_INFO *)lh_retrieve(amih,(char *)&tmp)) != NULL)
+ {
+ m->app_info = amim;
+ amim->references++;
+ }
+
if ((mm=(MEM *)lh_insert(mh,(char *)m)) != NULL)
{
/* Not good, but don't sweat it */
+ if (mm->app_info != NULL)
+ {
+ mm->app_info->references--;
+ }
Free(mm);
}
err:
@@ -277,7 +419,13 @@
m.addr=addr;
mp=(MEM *)lh_delete(mh,(char *)&m);
if (mp != NULL)
+ {
+ if (mp->app_info != NULL)
+ {
+ mp->app_info->references--;
+ }
Free(mp);
+ }
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
MemCheck_on();
}
@@ -335,6 +483,8 @@
static void print_leak(MEM *m, MEM_LEAK *l)
{
char buf[128];
+ APP_INFO *amip;
+ int ami_cnt;
#ifdef CRYPTO_MDEBUG_TIME
struct tm *lcl;
#endif
@@ -365,8 +515,40 @@
m->num,(unsigned long)m->addr);
BIO_puts(l->bio,buf);
+
l->chunks++;
l->bytes+=m->num;
+
+ amip=m->app_info;
+ ami_cnt=0;
+ while(amip)
+ {
+ int buf_len;
+ int info_len;
+
+ ami_cnt++;
+ memset(buf,'>',ami_cnt);
+ sprintf(buf + ami_cnt,
+ "file=%s, line=%d, info=\"",
+ amip->file, amip->line);
+ buf_len=strlen(buf);
+ info_len=strlen(amip->info);
+ if (128 - buf_len - 3 < info_len)
+ {
+ memcpy(buf + buf_len, amip->info, 128 - buf_len - 3);
+ buf_len = 128 - 3;
+ }
+ else
+ {
+ strcpy(buf + buf_len, amip->info);
+ buf_len = strlen(buf);
+ }
+ sprintf(buf + buf_len, "\"\n");
+
+ BIO_puts(l->bio,buf);
+
+ amip = amip->next;
+ }
}
void CRYPTO_mem_leaks(BIO *b)
------------------------------ EOD ------------------------------
I tested it with the following program:
------------------------------ SOP ------------------------------
#include <stdio.h>
#define CRYPTO_MDEBUG_ALL 1
#include <openssl/crypto.h>
void *foo(int i)
{
void *bar = NULL;
if (i < 3)
{
CRYPTO_add_info(__FILE__,__LINE__,"foo 666");
bar = (void *)Malloc(100);
foo(i+1);
Free(bar);
CRYPTO_remove_info();
}
else
{
CRYPTO_mem_leaks_fp(stdout);
}
return NULL;
}
main()
{
MemCheck_start();
foo(0);
MemCheck_stop();
}
------------------------------ EOP ------------------------------
Running it gave the following output:
------------------------------ SOO ------------------------------
1 file=test-OSSL-debug-mem.c, line=13, number=100, address=0804FD60
>file=test-OSSL-debug-mem.c, line=12, info="foo 666"
>>file=test-OSSL-debug-mem.c, line=12, info="foo 666"
0 file=test-OSSL-debug-mem.c, line=13, number=100, address=0804FBF8
>file=test-OSSL-debug-mem.c, line=12, info="foo 666"
2 file=test-OSSL-debug-mem.c, line=13, number=100, address=0804FE18
>file=test-OSSL-debug-mem.c, line=12, info="foo 666"
>>file=test-OSSL-debug-mem.c, line=12, info="foo 666"
>>>file=test-OSSL-debug-mem.c, line=12, info="foo 666"
300 bytes leaked in 3 chunks
------------------------------ EOO ------------------------------
I know, it's not very elegant, but it's pretty easily parsable with a
perl script fo further analysis.
--
Richard Levitte \ Spannv�gen 38, II \ [EMAIL PROTECTED]
Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47
\ SWEDEN \ or +46-708-26 53 44
Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED]
Unsolicited commercial email is subject to an archival fee of $400.
See <http://www.stacken.kth.se/~levitte/mail/> for more info.
______________________________________________________________________
OpenSSL Project http://www.openssl.org
Development Mailing List [EMAIL PROTECTED]
Automated List Manager [EMAIL PROTECTED]
Added feature to memory debugging routines
Richard Levitte - VMS Whacker Tue, 9 Nov 1999 01:11:19 -0800
