提交 9ac42ed8 编写于 作者: R Richard Levitte

Rebuild of the OpenSSL memory allocation and deallocation routines.

With this change, the following is provided and present at all times
(meaning CRYPTO_MDEBUG is no longer required to get this functionality):

  - hooks to provide your own allocation and deallocation routines.
    They have to have the same interface as malloc(), realloc() and
    free().  They are registered by calling CRYPTO_set_mem_functions()
    with the function pointers.

  - hooks to provide your own memory debugging routines.  The have to
    have the same interface as as the CRYPTO_dbg_*() routines.  They
    are registered by calling CRYPTO_set_mem_debug_functions() with
    the function pointers.

I moved everything that was already built into OpenSSL and did memory
debugging to a separate file (mem_dbg.c), to make it clear what is
what.

With this, the relevance of the CRYPTO_MDEBUG has changed.  The only
thing in crypto/crypto.h that it affects is the definition of the
MemCheck_start and MemCheck_stop macros.
上级 1ad9bdf2
......@@ -4,6 +4,16 @@
Changes between 0.9.4 and 0.9.5 [xx XXX 1999]
*) Rebuild of the memory allocation routines used by OpenSSL code and
possibly others as well. The purpose is to make an interface that
provide hooks so anyone can build a separate set of allocation and
deallocation routines to be used by OpenSSL, for example if memory
pool implementations, or something else. The same is provided for
memory debugging code. OpenSSL already comes with code that finds
memory leaks, but this gives people a chance to debug other memory
problems.
[Richard Levitte]
*) Some S/MIME fixes. The OID for SMIMECapabilities was wrong, the
ordering of SMIMECapabilities wasn't in "strength order" and there
was a missing NULL in the AlgorithmIdentifier for the SHA1 signature
......
......@@ -34,8 +34,8 @@ SDIRS= md2 md5 sha mdc2 hmac ripemd \
GENERAL=Makefile README crypto-lib.com install.com
LIB= $(TOP)/libcrypto.a
LIBSRC= cryptlib.c mem.c cversion.c ex_data.c tmdiff.c cpt_err.c
LIBOBJ= cryptlib.o mem.o cversion.o ex_data.o tmdiff.o cpt_err.o
LIBSRC= cryptlib.c mem.c mem_dbg.c cversion.c ex_data.c tmdiff.c cpt_err.c
LIBOBJ= cryptlib.o mem.o mem_dbg.o cversion.o ex_data.o tmdiff.o cpt_err.o
SRC= $(LIBSRC)
......@@ -174,8 +174,13 @@ ex_data.o: ../include/openssl/opensslv.h ../include/openssl/stack.h cryptlib.h
mem.o: ../include/openssl/bio.h ../include/openssl/buffer.h
mem.o: ../include/openssl/crypto.h ../include/openssl/e_os.h
mem.o: ../include/openssl/e_os2.h ../include/openssl/err.h
mem.o: ../include/openssl/lhash.h ../include/openssl/opensslconf.h
mem.o: ../include/openssl/opensslv.h ../include/openssl/stack.h cryptlib.h
mem.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
mem.o: ../include/openssl/stack.h cryptlib.h
mem_dbg.o: ../include/openssl/bio.h ../include/openssl/buffer.h
mem_dbg.o: ../include/openssl/crypto.h ../include/openssl/e_os.h
mem_dbg.o: ../include/openssl/e_os2.h ../include/openssl/err.h
mem_dbg.o: ../include/openssl/lhash.h ../include/openssl/opensslconf.h
mem_dbg.o: ../include/openssl/opensslv.h ../include/openssl/stack.h cryptlib.h
tmdiff.o: ../include/openssl/bio.h ../include/openssl/buffer.h
tmdiff.o: ../include/openssl/crypto.h ../include/openssl/e_os.h
tmdiff.o: ../include/openssl/e_os2.h ../include/openssl/err.h
......
......@@ -174,7 +174,7 @@ $!
$ APPS_DES = "DES/DES,CBC3_ENC"
$ APPS_PKCS7 = "ENC/ENC;DEC/DEC;SIGN/SIGN;VERIFY/VERIFY,EXAMPLE"
$
$ LIB_ = "cryptlib,mem,cversion,ex_data,tmdiff,cpt_err"
$ LIB_ = "cryptlib,mem,mem_dbg,cversion,ex_data,tmdiff,cpt_err"
$ LIB_MD2 = "md2_dgst,md2_one"
$ LIB_MD5 = "md5_dgst,md5_one"
$ LIB_SHA = "sha_dgst,sha1dgst,sha_one,sha1_one"
......
......@@ -196,12 +196,14 @@ typedef struct crypto_ex_data_func_st
#define CRYPTO_EX_INDEX_X509_STORE 4
#define CRYPTO_EX_INDEX_X509_STORE_CTX 5
/* Use this for win32 DLL's */
/* This is the default callbacks, but we can have others as well */
#define CRYPTO_malloc_init() CRYPTO_set_mem_functions(\
(char *(*)())malloc,\
(char *(*)())realloc,\
(void (*)())free)
#ifdef CRYPTO_MDEBUG_ALL
# ifndef CRYPTO_MDEBUG_TIME
# define CRYPTO_MDEBUG_TIME
......@@ -211,6 +213,28 @@ typedef struct crypto_ex_data_func_st
# endif
#endif
/* Magic to make sure we get correct values */
#ifdef CRYPTO_MDEBUG_TIME
#define V_CRYPTO_MDEBUG_TIME 1
#else
#define V_CRYPTO_MDEBUG_TIME 0
#endif
#ifdef CRYPTO_MDEBUG_THREAD
#define V_CRYPTO_MDEBUG_THREAD 2
#else
#define V_CRYPTO_MDEBUG_THREAD 0
#endif
#define CRYPTO_malloc_debug_init() do {\
CRYPTO_set_mem_debug_functions(\
(void (*)())CRYPTO_dbg_malloc,\
(void (*)())CRYPTO_dbg_realloc,\
(void (*)())CRYPTO_dbg_free,\
(void (*)())CRYPTO_dbg_set_options,\
(void (*)())CRYPTO_dbg_get_options);\
CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_TIME|V_CRYPTO_MDEBUG_THREAD);\
} while(0);
#if defined CRYPTO_MDEBUG_TIME || defined CRYPTO_MDEBUG_THREAD
# ifndef CRYPTO_MDEBUG /* avoid duplicate #define */
# define CRYPTO_MDEBUG
......@@ -220,39 +244,25 @@ typedef struct crypto_ex_data_func_st
#ifdef CRYPTO_MDEBUG
#define MemCheck_start() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON)
#define MemCheck_stop() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF)
#else
#define MemCheck_start()
#define MemCheck_stop()
#endif
#define MemCheck_on() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE)
#define MemCheck_off() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE)
#define Malloc(num) CRYPTO_dbg_malloc((int)num,__FILE__,__LINE__)
#define is_MemCheck_on() CRYPTO_mem_check_on()
#define Malloc(num) CRYPTO_malloc((int)num,__FILE__,__LINE__)
#define Realloc(addr,num) \
CRYPTO_dbg_realloc((char *)addr,(int)num,__FILE__,__LINE__)
CRYPTO_realloc((char *)addr,(int)num,__FILE__,__LINE__)
#define Remalloc(addr,num) \
CRYPTO_dbg_remalloc((char **)addr,(int)num,__FILE__,__LINE__)
#define FreeFunc CRYPTO_dbg_free
#define Free(addr) CRYPTO_dbg_free(addr)
#define Malloc_locked(num) CRYPTO_malloc_locked((int)num)
#define Free_locked(addr) CRYPTO_free_locked(addr)
#else
#define MemCheck_start()
#define MemCheck_stop()
#define MemCheck_on()
#define MemCheck_off()
#define Remalloc CRYPTO_remalloc
#if defined(WIN32) || defined(MFUNC)
#define Malloc CRYPTO_malloc
#define Realloc(a,n) CRYPTO_realloc(a,(n))
CRYPTO_remalloc((char **)addr,(int)num,__FILE__,__LINE__)
#define FreeFunc CRYPTO_free
#define Free(addr) CRYPTO_free(addr)
#define Malloc_locked CRYPTO_malloc_locked
#define Malloc_locked(num) CRYPTO_malloc_locked((int)num,__FILE__,__LINE__)
#define Free_locked(addr) CRYPTO_free_locked(addr)
#else
#define Malloc malloc
#define Realloc realloc
#define FreeFunc free
#define Free(addr) free(addr)
#define Malloc_locked malloc
#define Free_locked(addr) free(addr)
#endif /* WIN32 || MFUNC */
#endif /* MDEBUG */
/* Case insensiteve linking causes problems.... */
#if defined(WIN16) || defined(VMS)
......@@ -272,6 +282,7 @@ void CRYPTO_free_ex_data(STACK *meth,char *obj,CRYPTO_EX_DATA *ad);
void CRYPTO_new_ex_data(STACK *meth, char *obj, CRYPTO_EX_DATA *ad);
int CRYPTO_mem_ctrl(int mode);
int CRYPTO_mem_check_on(void);
int CRYPTO_get_new_lockid(char *name);
int CRYPTO_num_locks(void); /* return CRYPTO_NUM_LOCKS (shared libs!) */
......@@ -291,25 +302,46 @@ const char *CRYPTO_get_lock_name(int type);
int CRYPTO_add_lock(int *pointer,int amount,int type, const char *file,
int line);
void CRYPTO_set_mem_functions(char *(*m)(),char *(*r)(), void (*free_func)());
void CRYPTO_set_mem_functions(char *(*m)(),char *(*r)(), void (*f)());
void CRYPTO_set_mem_debug_functions(void (*m)(),void (*r)(),void (*f)(),void (*so)(),int (*go)());
void CRYPTO_set_mem_debug_options(int bits);
void CRYPTO_get_mem_functions(char *(**m)(),char *(**r)(), void (**f)());
void CRYPTO_get_mem_debug_functions(void (**m)(),void (**r)(),void (**f)(),void (**so)(),int (**go)());
int CRYPTO_get_mem_debug_options();
void CRYPTO_set_locked_mem_functions(char *(*m)(), void (*free_func)());
void CRYPTO_get_locked_mem_functions(char *(**m)(), void (**f)());
void *CRYPTO_malloc_locked(int num);
void *CRYPTO_malloc_locked(int num, char *file, int line);
void CRYPTO_free_locked(void *);
void *CRYPTO_malloc(int num);
void *CRYPTO_malloc(int num, char *file, int line);
void CRYPTO_free(void *);
void *CRYPTO_realloc(void *addr,int num);
void *CRYPTO_remalloc(void *addr,int num);
void *CRYPTO_realloc(void *addr,int num, char *file, int line);
void *CRYPTO_remalloc(void *addr,int num, char *file, int line);
int CRYPTO_add_info(const char *file, int line, const char *info);
int CRYPTO_remove_info();
int CRYPTO_remove_info(void);
int CRYPTO_remove_all_info(void);
/* The last argument has the following significance:
*
* 0: called before the actual memory allocation has taken place
* 1: called after the actual memory allocation has taken place
*/
void CRYPTO_dbg_malloc(void *addr,int num,const char *file,int line,int before_p);
void CRYPTO_dbg_realloc(void *addr1,void *addr2,int num,const char *file,int line,int before_p);
void CRYPTO_dbg_free(void *,int before_p);
/* Tell the debugging code about options. By default, the following values
* apply:
*
* 0: Clear all options.
* 1: Set the "Show Time" option.
* 2: Set the "Show Thread Number" option.
* 3: 1 + 2
*/
void CRYPTO_dbg_set_options(int num);
int CRYPTO_dbg_get_options();
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 *);
void *CRYPTO_dbg_remalloc(void *addr,int num,const char *file,int line);
#ifndef NO_FP_API
void CRYPTO_mem_leaks_fp(FILE *);
#endif
......
......@@ -59,271 +59,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <openssl/crypto.h>
#ifdef CRYPTO_MDEBUG_TIME
# include <time.h>
#endif
#include <openssl/buffer.h>
#include <openssl/bio.h>
#include <openssl/lhash.h>
#include "cryptlib.h"
/* #ifdef CRYPTO_MDEBUG */
/* static int mh_mode=CRYPTO_MEM_CHECK_ON; */
/* #else */
static int mh_mode=CRYPTO_MEM_CHECK_OFF;
static unsigned long disabling_thread = 0;
/* #endif */
/* State CRYPTO_MEM_CHECK_ON exists only temporarily when the library
* thinks that certain allocations should not be checked (e.g. the data
* structures used for memory checking). It is not suitable as an initial
* state: the library will unexpectedly enable memory checking when it
* executes one of those sections that want to disable checking
* temporarily.
*
* State CRYPTO_MEM_CHECK_ENABLE without ..._ON makes no sense whatsoever.
*/
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;
} APP_INFO;
static LHASH *mh=NULL;
typedef struct mem_st
{
char *addr;
int num;
const char *file;
int line;
#ifdef CRYPTO_MDEBUG_THREAD
unsigned long thread;
#endif
unsigned long order;
#ifdef CRYPTO_MDEBUG_TIME
time_t time;
#endif
APP_INFO *app_info;
} MEM;
int CRYPTO_mem_ctrl(int mode)
{
int ret=mh_mode;
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
switch (mode)
{
/* for applications: */
case CRYPTO_MEM_CHECK_ON: /* aka MemCheck_start() */
mh_mode = CRYPTO_MEM_CHECK_ON|CRYPTO_MEM_CHECK_ENABLE;
disabling_thread = 0;
break;
case CRYPTO_MEM_CHECK_OFF: /* aka MemCheck_stop() */
mh_mode = 0;
disabling_thread = 0;
break;
/* switch off temporarily (for library-internal use): */
case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */
if (mh_mode & CRYPTO_MEM_CHECK_ON)
{
mh_mode&= ~CRYPTO_MEM_CHECK_ENABLE;
if (disabling_thread != CRYPTO_thread_id()) /* otherwise we already have the MALLOC2 lock */
{
/* Long-time lock CRYPTO_LOCK_MALLOC2 must not be claimed while
* we're holding CRYPTO_LOCK_MALLOC, or we'll deadlock if
* somebody else holds CRYPTO_LOCK_MALLOC2 (and cannot release it
* because we block entry to this function).
* Give them a chance, first, and then claim the locks in
* appropriate order (long-time lock first).
*/
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
/* Note that after we have waited for CRYPTO_LOCK_MALLOC2
* and CRYPTO_LOCK_MALLOC, we'll still be in the right
* "case" and "if" branch because MemCheck_start and
* MemCheck_stop may never be used while there are multiple
* OpenSSL threads. */
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
disabling_thread=CRYPTO_thread_id();
}
}
break;
case CRYPTO_MEM_CHECK_ENABLE: /* aka MemCheck_on() */
if (mh_mode & CRYPTO_MEM_CHECK_ON)
{
mh_mode|=CRYPTO_MEM_CHECK_ENABLE;
if (disabling_thread != 0)
{
disabling_thread=0;
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
}
}
break;
default:
break;
}
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
return(ret);
}
static int is_MemCheck_On()
{
int ret = 0;
if (mh_mode & CRYPTO_MEM_CHECK_ON)
{
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
&& disabling_thread != CRYPTO_thread_id();
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
}
return(ret);
}
static int mem_cmp(MEM *a, MEM *b)
{
return(a->addr - b->addr);
}
static unsigned long mem_hash(MEM *a)
{
unsigned long ret;
ret=(unsigned long)a->addr;
ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
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 *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;
if (next != NULL)
{
next->references++;
lh_insert(amih,(char *)next);
}
#ifdef LEVITTE_DEBUG
if (ret->thread != tmp.thread)
{
fprintf(stderr, "remove_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
ret->thread, tmp.thread);
abort();
}
#endif
if (--(ret->references) <= 0)
{
ret->next = NULL;
if (next != NULL)
next->references--;
Free(ret);
}
}
}
return(ret);
}
int CRYPTO_add_info(const char *file, int line, const char *info)
{
APP_INFO *ami, *amim;
int ret=0;
if (is_MemCheck_On())
{
MemCheck_off();
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=1;
ami->next=NULL;
if ((amim=(APP_INFO *)lh_insert(amih,(char *)ami)) != NULL)
{
#ifdef LEVITTE_DEBUG
if (ami->thread != amim->thread)
{
fprintf(stderr, "CRYPTO_add_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
amim->thread, ami->thread);
abort();
}
#endif
ami->next=amim;
}
err:
MemCheck_on();
}
return(ret);
}
int CRYPTO_remove_info()
{
int ret=0;
if (is_MemCheck_On())
{
MemCheck_off();
ret=(remove_info() != NULL);
MemCheck_on();
}
return(ret);
}
static char *(*malloc_locked_func)()=(char *(*)())malloc;
static void (*free_locked_func)()=(void (*)())free;
......@@ -331,6 +68,12 @@ static char *(*malloc_func)()= (char *(*)())malloc;
static char *(*realloc_func)()= (char *(*)())realloc;
static void (*free_func)()= (void (*)())free;
static void (*malloc_debug_func)()= (void (*)())CRYPTO_dbg_malloc;
static void (*realloc_debug_func)()= (void (*)())CRYPTO_dbg_realloc;
static void (*free_debug_func)()= (void (*)())CRYPTO_dbg_free;
static void (*set_debug_options_func)()= (void (*)())CRYPTO_dbg_set_options;
static int (*get_debug_options_func)()= (int (*)())CRYPTO_dbg_get_options;
void CRYPTO_set_mem_functions(char *(*m)(), char *(*r)(), void (*f)())
{
if ((m == NULL) || (r == NULL) || (f == NULL)) return;
......@@ -341,6 +84,17 @@ void CRYPTO_set_mem_functions(char *(*m)(), char *(*r)(), void (*f)())
free_locked_func=f;
}
void CRYPTO_set_mem_debug_functions(void (*m)(), void (*r)(), void (*f)(),void (*so)(),int (*go)())
{
if ((m == NULL) || (r == NULL) || (f == NULL) || (so == NULL) || (go == NULL))
return;
malloc_debug_func=m;
realloc_debug_func=r;
free_debug_func=f;
set_debug_options_func=so;
get_debug_options_func=go;
}
void CRYPTO_set_locked_mem_functions(char *(*m)(), void (*f)())
{
if ((m == NULL) || (f == NULL)) return;
......@@ -355,317 +109,97 @@ void CRYPTO_get_mem_functions(char *(**m)(), char *(**r)(), void (**f)())
if (f != NULL) *f=free_func;
}
void CRYPTO_get_locked_mem_functions(char *(**m)(), void (**f)())
void CRYPTO_get_mem_debug_functions(void (**m)(), void (**r)(), void (**f)(),void (**so)(),int (**go)())
{
if (m != NULL) *m=malloc_locked_func;
if (f != NULL) *f=free_locked_func;
if (m != NULL) *m=malloc_debug_func;
if (r != NULL) *r=realloc_debug_func;
if (f != NULL) *f=free_debug_func;
if (so != NULL) *so=set_debug_options_func;
if (go != NULL) *go=get_debug_options_func;
}
void *CRYPTO_malloc_locked(int num)
{
return(malloc_locked_func(num));
}
void CRYPTO_free_locked(void *str)
{
free_locked_func(str);
}
void *CRYPTO_malloc(int num)
{
return(malloc_func(num));
}
void *CRYPTO_realloc(void *str, int num)
{
return(realloc_func(str,num));
}
void CRYPTO_free(void *str)
void CRYPTO_get_locked_mem_functions(char *(**m)(), void (**f)())
{
free_func(str);
if (m != NULL) *m=malloc_locked_func;
if (f != NULL) *f=free_locked_func;
}
static unsigned long break_order_num=0;
void *CRYPTO_dbg_malloc(int num, const char *file, int line)
void *CRYPTO_malloc_locked(int num, char *file, int line)
{
char *ret;
MEM *m,*mm;
APP_INFO tmp,*amim;
if ((ret=malloc_func(num)) == NULL)
return(NULL);
char *ret = NULL;
if (is_MemCheck_On())
{
MemCheck_off();
if ((m=(MEM *)Malloc(sizeof(MEM))) == NULL)
{
Free(ret);
MemCheck_on();
return(NULL);
}
if (mh == NULL)
{
if ((mh=lh_new(mem_hash,mem_cmp)) == NULL)
{
Free(ret);
Free(m);
ret=NULL;
goto err;
}
}
m->addr=ret;
m->file=file;
m->line=line;
m->num=num;
#ifdef CRYPTO_MDEBUG_THREAD
m->thread=CRYPTO_thread_id();
#endif
if (order == break_order_num)
{
/* BREAK HERE */
m->order=order;
}
m->order=order++;
#ifdef CRYPTO_MDEBUG_TIME
m->time=time(NULL);
malloc_debug_func(NULL, num, file, line, 0);
ret = malloc_locked_func(num);
#ifdef LEVITTE_DEBUG
fprintf(stderr, "LEVITTE_DEBUG: > 0x%p (%d)\n", ret, num);
#endif
malloc_debug_func(ret, num, file, line, 1);
tmp.thread=CRYPTO_thread_id();
m->app_info=NULL;
if (amih != NULL
&& (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:
MemCheck_on();
}
return(ret);
return ret;
}
void CRYPTO_dbg_free(void *addr)
void CRYPTO_free_locked(void *str)
{
MEM m,*mp;
if (is_MemCheck_On() && (mh != NULL))
{
MemCheck_off();
m.addr=addr;
mp=(MEM *)lh_delete(mh,(char *)&m);
if (mp != NULL)
{
if (mp->app_info != NULL)
{
mp->app_info->references--;
}
Free(mp);
}
MemCheck_on();
}
free_func(addr);
free_debug_func(str, 0);
#ifdef LEVITTE_DEBUG
fprintf(stderr, "LEVITTE_DEBUG: < 0x%p\n", str);
#endif
free_locked_func(str);
free_debug_func(NULL, 1);
}
void *CRYPTO_dbg_realloc(void *addr, int num, const char *file, int line)
void *CRYPTO_malloc(int num, char *file, int line)
{
char *ret;
MEM m,*mp;
ret=realloc_func(addr,num);
if (ret == addr) return(ret);
if (is_MemCheck_On())
{
if (ret == NULL) return(NULL);
MemCheck_off();
m.addr=addr;
mp=(MEM *)lh_delete(mh,(char *)&m);
if (mp != NULL)
{
mp->addr=ret;
lh_insert(mh,(char *)mp);
}
MemCheck_on();
}
return(ret);
}
char *ret = NULL;
void *CRYPTO_remalloc(void *a, int n)
{
if (a != NULL) Free(a);
a=(char *)Malloc(n);
return(a);
}
malloc_debug_func(NULL, num, file, line, 0);
ret = malloc_func(num);
#ifdef LEVITTE_DEBUG
fprintf(stderr, "LEVITTE_DEBUG: > 0x%p (%d)\n", ret, num);
#endif
malloc_debug_func(ret, num, file, line, 1);
void *CRYPTO_dbg_remalloc(void *a, int n, const char *file, int line)
{
if (a != NULL) CRYPTO_dbg_free(a);
a=(char *)CRYPTO_dbg_malloc(n,file,line);
return(a);
return ret;
}
typedef struct mem_leak_st
void *CRYPTO_realloc(void *str, int num, char *file, int line)
{
BIO *bio;
int chunks;
long bytes;
} MEM_LEAK;
char *ret = NULL;
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
unsigned long ti;
if(m->addr == (char *)l->bio)
return;
#ifdef CRYPTO_MDEBUG_TIME
lcl = localtime(&m->time);
#endif
sprintf(buf,
#ifdef CRYPTO_MDEBUG_TIME
"[%02d:%02d:%02d] "
#endif
"%5lu file=%s, line=%d, "
#ifdef CRYPTO_MDEBUG_THREAD
"thread=%lu, "
#endif
"number=%d, address=%08lX\n",
#ifdef CRYPTO_MDEBUG_TIME
lcl->tm_hour,lcl->tm_min,lcl->tm_sec,
#endif
m->order,m->file,m->line,
#ifdef CRYPTO_MDEBUG_THREAD
m->thread,
#endif
m->num,(unsigned long)m->addr);
BIO_puts(l->bio,buf);
l->chunks++;
l->bytes+=m->num;
amip=m->app_info;
ami_cnt=0;
if (amip)
ti=amip->thread;
while(amip && amip->thread == ti)
{
int buf_len;
int info_len;
ami_cnt++;
memset(buf,'>',ami_cnt);
sprintf(buf + ami_cnt,
"thread=%lu, file=%s, line=%d, info=\"",
amip->thread, 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;
}
realloc_debug_func(str, NULL, num, file, line, 0);
ret = realloc_func(str,num);
#ifdef LEVITTE_DEBUG
if (amip)
{
fprintf(stderr, "Thread switch detected i backtrace!!!!\n");
abort();
}
fprintf(stderr, "LEVITTE_DEBUG: | 0x%p -> 0x%p (%d)\n", str, ret, num);
#endif
realloc_debug_func(str, ret, num, file, line, 1);
return ret;
}
void CRYPTO_mem_leaks(BIO *b)
void CRYPTO_free(void *str)
{
MEM_LEAK ml;
char buf[80];
if (mh == NULL) return;
ml.bio=b;
ml.bytes=0;
ml.chunks=0;
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
lh_doall_arg(mh,(void (*)())print_leak,(char *)&ml);
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
if (ml.chunks != 0)
{
sprintf(buf,"%ld bytes leaked in %d chunks\n",
ml.bytes,ml.chunks);
BIO_puts(b,buf);
}
#if 0
lh_stats_bio(mh,b);
lh_node_stats_bio(mh,b);
lh_node_usage_stats_bio(mh,b);
free_debug_func(str, 0);
#ifdef LEVITTE_DEBUG
fprintf(stderr, "LEVITTE_DEBUG: < 0x%p\n", str);
#endif
free_func(str);
free_debug_func(NULL, 1);
}
static void (*mem_cb)()=NULL;
static void cb_leak(MEM *m, char *cb)
void *CRYPTO_remalloc(void *a, int num, char *file, int line)
{
void (*mem_callback)()=(void (*)())cb;
mem_callback(m->order,m->file,m->line,m->num,m->addr);
if (a != NULL) Free(a);
a=(char *)Malloc(num);
return(a);
}
void CRYPTO_mem_leaks_cb(void (*cb)())
void CRYPTO_set_mem_debug_options(int bits)
{
if (mh == NULL) return;
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
mem_cb=cb;
lh_doall_arg(mh,(void (*)())cb_leak,(char *)mem_cb);
mem_cb=NULL;
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
set_debug_options_func(bits);
}
#ifndef NO_FP_API
void CRYPTO_mem_leaks_fp(FILE *fp)
int CRYPTO_get_mem_debug_options()
{
BIO *b;
if (mh == NULL) return;
if ((b=BIO_new(BIO_s_file())) == NULL)
return;
BIO_set_fp(b,fp,BIO_NOCLOSE);
CRYPTO_mem_leaks(b);
BIO_free(b);
return get_debug_options_func();
}
#endif
/* crypto/mem_dbg.c */
/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
* project 1999.
*/
/* ====================================================================
* Copyright (c) 1999 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <openssl/crypto.h>
#include <openssl/buffer.h>
#include <openssl/bio.h>
#include <openssl/lhash.h>
#include "cryptlib.h"
/* State CRYPTO_MEM_CHECK_ON exists only temporarily when the library
* thinks that certain allocations should not be checked (e.g. the data
* structures used for memory checking). It is not suitable as an initial
* state: the library will unexpectedly enable memory checking when it
* executes one of those sections that want to disable checking
* temporarily.
*
* State CRYPTO_MEM_CHECK_ENABLE without ..._ON makes no sense whatsoever.
*/
static int mh_mode=CRYPTO_MEM_CHECK_OFF;
static unsigned long disabling_thread = 0;
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;
} APP_INFO;
static LHASH *mh=NULL;
typedef struct mem_st
{
char *addr;
int num;
const char *file;
int line;
unsigned long thread;
unsigned long order;
time_t time;
APP_INFO *app_info;
} MEM;
static int options = V_CRYPTO_MDEBUG_TIME | V_CRYPTO_MDEBUG_THREAD;
int CRYPTO_mem_ctrl(int mode)
{
int ret=mh_mode;
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
switch (mode)
{
/* for applications: */
case CRYPTO_MEM_CHECK_ON: /* aka MemCheck_start() */
mh_mode = CRYPTO_MEM_CHECK_ON|CRYPTO_MEM_CHECK_ENABLE;
disabling_thread = 0;
break;
case CRYPTO_MEM_CHECK_OFF: /* aka MemCheck_stop() */
mh_mode = 0;
disabling_thread = 0;
break;
/* switch off temporarily (for library-internal use): */
case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */
if (mh_mode & CRYPTO_MEM_CHECK_ON)
{
mh_mode&= ~CRYPTO_MEM_CHECK_ENABLE;
if (disabling_thread != CRYPTO_thread_id()) /* otherwise we already have the MALLOC2 lock */
{
/* Long-time lock CRYPTO_LOCK_MALLOC2 must not be claimed while
* we're holding CRYPTO_LOCK_MALLOC, or we'll deadlock if
* somebody else holds CRYPTO_LOCK_MALLOC2 (and cannot release it
* because we block entry to this function).
* Give them a chance, first, and then claim the locks in
* appropriate order (long-time lock first).
*/
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
/* Note that after we have waited for CRYPTO_LOCK_MALLOC2
* and CRYPTO_LOCK_MALLOC, we'll still be in the right
* "case" and "if" branch because MemCheck_start and
* MemCheck_stop may never be used while there are multiple
* OpenSSL threads. */
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
disabling_thread=CRYPTO_thread_id();
}
}
break;
case CRYPTO_MEM_CHECK_ENABLE: /* aka MemCheck_on() */
if (mh_mode & CRYPTO_MEM_CHECK_ON)
{
mh_mode|=CRYPTO_MEM_CHECK_ENABLE;
if (disabling_thread != 0)
{
disabling_thread=0;
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
}
}
break;
default:
break;
}
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
return(ret);
}
int CRYPTO_mem_check_on(void)
{
int ret = 0;
if (mh_mode & CRYPTO_MEM_CHECK_ON)
{
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
&& disabling_thread != CRYPTO_thread_id();
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
}
return(ret);
}
void CRYPTO_dbg_set_options(int bits)
{
options = bits;
}
int CRYPTO_dbg_get_options()
{
return options;
}
static int mem_cmp(MEM *a, MEM *b)
{
return(a->addr - b->addr);
}
static unsigned long mem_hash(MEM *a)
{
unsigned long ret;
ret=(unsigned long)a->addr;
ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
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 *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;
if (next != NULL)
{
next->references++;
lh_insert(amih,(char *)next);
}
#ifdef LEVITTE_DEBUG
if (ret->thread != tmp.thread)
{
fprintf(stderr, "remove_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
ret->thread, tmp.thread);
abort();
}
#endif
if (--(ret->references) <= 0)
{
ret->next = NULL;
if (next != NULL)
next->references--;
Free(ret);
}
}
}
return(ret);
}
int CRYPTO_add_info(const char *file, int line, const char *info)
{
APP_INFO *ami, *amim;
int ret=0;
if (is_MemCheck_on())
{
MemCheck_off();
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=1;
ami->next=NULL;
if ((amim=(APP_INFO *)lh_insert(amih,(char *)ami)) != NULL)
{
#ifdef LEVITTE_DEBUG
if (ami->thread != amim->thread)
{
fprintf(stderr, "CRYPTO_add_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
amim->thread, ami->thread);
abort();
}
#endif
ami->next=amim;
}
err:
MemCheck_on();
}
return(ret);
}
int CRYPTO_remove_info(void)
{
int ret=0;
if (is_MemCheck_on())
{
MemCheck_off();
ret=(remove_info() != NULL);
MemCheck_on();
}
return(ret);
}
int CRYPTO_remove_all_info(void)
{
int ret=0;
if (is_MemCheck_on())
{
MemCheck_off();
while(remove_info() != NULL)
ret++;
MemCheck_on();
}
return(ret);
}
static unsigned long break_order_num=0;
void CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line,
int before_p)
{
MEM *m,*mm;
APP_INFO tmp,*amim;
switch(before_p & 127)
{
case 0:
break;
case 1:
if (addr == NULL)
break;
if (is_MemCheck_on())
{
MemCheck_off();
if ((m=(MEM *)Malloc(sizeof(MEM))) == NULL)
{
Free(addr);
MemCheck_on();
return;
}
if (mh == NULL)
{
if ((mh=lh_new(mem_hash,mem_cmp)) == NULL)
{
Free(addr);
Free(m);
addr=NULL;
goto err;
}
}
m->addr=addr;
m->file=file;
m->line=line;
m->num=num;
if (options & V_CRYPTO_MDEBUG_THREAD)
m->thread=CRYPTO_thread_id();
else
m->thread=0;
if (order == break_order_num)
{
/* BREAK HERE */
m->order=order;
}
m->order=order++;
#ifdef LEVITTE_DEBUG
fprintf(stderr, "LEVITTE_DEBUG: [%5d] %c 0x%p (%d)\n",
m->order,
(before_p & 128) ? '*' : '+',
m->addr, m->num);
#endif
if (options & V_CRYPTO_MDEBUG_TIME)
m->time=time(NULL);
else
m->time=0;
tmp.thread=CRYPTO_thread_id();
m->app_info=NULL;
if (amih != NULL
&& (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:
MemCheck_on();
}
break;
}
return;
}
void CRYPTO_dbg_free(void *addr, int before_p)
{
MEM m,*mp;
switch(before_p)
{
case 0:
if (addr == NULL)
break;
if (is_MemCheck_on() && (mh != NULL))
{
MemCheck_off();
m.addr=addr;
mp=(MEM *)lh_delete(mh,(char *)&m);
if (mp != NULL)
{
#ifdef LEVITTE_DEBUG
fprintf(stderr, "LEVITTE_DEBUG: [%5d] - 0x%p (%d)\n",
mp->order, mp->addr, mp->num);
#endif
if (mp->app_info != NULL)
{
mp->app_info->references--;
}
Free(mp);
}
MemCheck_on();
}
break;
case 1:
break;
}
}
void CRYPTO_dbg_realloc(void *addr1, void *addr2, int num,
const char *file, int line, int before_p)
{
MEM m,*mp;
#ifdef LEVITTE_DEBUG
fprintf(stderr, "LEVITTE_DEBUG: --> CRYPTO_dbg_malloc(addr1 = %p, addr2 = %p, num = %d, file = \"%s\", line = %d, before_p = %d)\n",
addr1, addr2, num, file, line, before_p);
#endif
switch(before_p)
{
case 0:
break;
case 1:
if (addr2 == NULL)
break;
if (addr1 == NULL)
{
CRYPTO_dbg_malloc(addr2, num, file, line, 128 | before_p);
break;
}
if (is_MemCheck_on())
{
MemCheck_off();
m.addr=addr1;
mp=(MEM *)lh_delete(mh,(char *)&m);
if (mp != NULL)
{
#ifdef LEVITTE_DEBUG
fprintf(stderr, "LEVITTE_DEBUG: [%5d] * 0x%p (%d) -> 0x%p (%d)\n",
mp->order,
mp->addr, mp->num,
addr2, num);
#endif
mp->addr=addr2;
mp->num=num;
lh_insert(mh,(char *)mp);
}
MemCheck_on();
}
break;
}
return;
}
typedef struct mem_leak_st
{
BIO *bio;
int chunks;
long bytes;
} MEM_LEAK;
static void print_leak(MEM *m, MEM_LEAK *l)
{
char buf[1024];
char *bufp = buf;
APP_INFO *amip;
int ami_cnt;
struct tm *lcl = NULL;
unsigned long ti;
if(m->addr == (char *)l->bio)
return;
if (options & V_CRYPTO_MDEBUG_TIME)
{
lcl = localtime(&m->time);
sprintf(bufp, "[%02d:%02d:%02d] ",
lcl->tm_hour,lcl->tm_min,lcl->tm_sec);
bufp += strlen(bufp);
}
sprintf(bufp, "%5lu file=%s, line=%d, ",
m->order,m->file,m->line);
bufp += strlen(bufp);
if (options & V_CRYPTO_MDEBUG_THREAD)
{
sprintf(bufp, "thread=%lu, ", m->thread);
bufp += strlen(bufp);
}
sprintf(bufp, "number=%d, address=%08lX\n",
m->num,(unsigned long)m->addr);
bufp += strlen(bufp);
BIO_puts(l->bio,buf);
l->chunks++;
l->bytes+=m->num;
amip=m->app_info;
ami_cnt=0;
if (amip)
ti=amip->thread;
while(amip && amip->thread == ti)
{
int buf_len;
int info_len;
ami_cnt++;
memset(buf,'>',ami_cnt);
sprintf(buf + ami_cnt,
"thread=%lu, file=%s, line=%d, info=\"",
amip->thread, 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;
}
#ifdef LEVITTE_DEBUG
if (amip)
{
fprintf(stderr, "Thread switch detected i backtrace!!!!\n");
abort();
}
#endif
}
void CRYPTO_mem_leaks(BIO *b)
{
MEM_LEAK ml;
char buf[80];
if (mh == NULL) return;
ml.bio=b;
ml.bytes=0;
ml.chunks=0;
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
lh_doall_arg(mh,(void (*)())print_leak,(char *)&ml);
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
if (ml.chunks != 0)
{
sprintf(buf,"%ld bytes leaked in %d chunks\n",
ml.bytes,ml.chunks);
BIO_puts(b,buf);
}
#if 0
lh_stats_bio(mh,b);
lh_node_stats_bio(mh,b);
lh_node_usage_stats_bio(mh,b);
#endif
}
static void (*mem_cb)()=NULL;
static void cb_leak(MEM *m, char *cb)
{
void (*mem_callback)()=(void (*)())cb;
mem_callback(m->order,m->file,m->line,m->num,m->addr);
}
void CRYPTO_mem_leaks_cb(void (*cb)())
{
if (mh == NULL) return;
CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
mem_cb=cb;
lh_doall_arg(mh,(void (*)())cb_leak,(char *)mem_cb);
mem_cb=NULL;
CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
}
#ifndef NO_FP_API
void CRYPTO_mem_leaks_fp(FILE *fp)
{
BIO *b;
if (mh == NULL) return;
if ((b=BIO_new(BIO_s_file())) == NULL)
return;
BIO_set_fp(b,fp,BIO_NOCLOSE);
CRYPTO_mem_leaks(b);
BIO_free(b);
}
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册