OpenSSL 内存管理分析笔记
面向开发者使用的最外层接口:
OPENSSL_malloc(num)
<===> CRYPTO_malloc((int)num,__FILE__,__LINE__)
OPENSSL_realloc(addr,num)
<===> CRYPTO_realloc((char *)addr, (int)num, __FILE__, __LINE__)
OPENSSL_realloc_clean(addr,old_num,num)
<===> CRYPTO_realloc_clean(addr,old_num,num,__FILE__,__LINE__)
OPENSSL_remalloc(addr,num)
<===> CRYPTO_remalloc((char **)addr,(int)num,__FILE__,__LINE__)
OPENSSL_free(addr)
<===> CRYPTO_free(addr)
OPENSSL_malloc_locked(num)
<===> CRYPTO_malloc_locked((int)num,__FILE__,__LINE__)
OPENSSL_free_locked(addr)
<===> CRYPTO_free_locked(addr)
CRYPTO_XXXX 在Crypto.h中声明, 在Mem.c来实现。Mem.c中,使用了两类内存申请函数,
一类为直接调用malloc(default_XXXXX), 一类为调用Mem_dbg.c中的dbg版本的函数(CRYPTO_dbg_XXXX)。
================================================================================
malloc_func, malloc_ex_func, realloc_func, realloc_ex_func, free_func
malloc_locked_func, malloc_locked_ex_func,malloc_debug_func,realloc_debug_func,
free_debug_func,set_debug_options_func,get_debug_options_func
这些函数由,CRYPTO_XXXX 来调用(其内部首先判断Debug版本的是否为NULL,如果不为NULL,
则调用Debug版本的,否则调用非Debug版本的。Debug版本的调用比较特殊,会调用两次。
0: called before the actual memory allocation has taken place
1: called after the actual memory allocation has taken place
================================================================================
static void *(*malloc_func)(size_t) = malloc;
static void *default_malloc_ex(size_t num, const char *file, int line)
{ return malloc_func(num); }
static void *(*malloc_ex_func)(size_t, const char *file, int line)
= default_malloc_ex;
static void *(*realloc_func)(void *, size_t)= realloc;
static void *default_realloc_ex(void *str, size_t num,
const char *file, int line)
{ return realloc_func(str,num); }
static void *(*realloc_ex_func)(void *, size_t, const char *file, int line)
= default_realloc_ex;
static void (*free_func)(void *) = free;
static void *(*malloc_locked_func)(size_t) = malloc;
static void *default_malloc_locked_ex(size_t num, const char *file, int line)
{ return malloc_locked_func(num); }
static void *(*malloc_locked_ex_func)(size_t, const char *file, int line)
= default_malloc_locked_ex;
static void (*free_locked_func)(void *) = free;
================================================================================
#ifdef CRYPTO_MDEBUG
/* use default functions from mem_dbg.c */
static void (*malloc_debug_func)(void *,int,const char *,int,int)
= CRYPTO_dbg_malloc;
static void (*realloc_debug_func)(void *,void *,int,const char *,int,int)
= CRYPTO_dbg_realloc;
static void (*free_debug_func)(void *,int) = CRYPTO_dbg_free;
static void (*set_debug_options_func)(long) = CRYPTO_dbg_set_options;
static long (*get_debug_options_func)(void) = CRYPTO_dbg_get_options;
#else
/* applications can use CRYPTO_malloc_debug_init() to select above case
* at run-time */
static void (*malloc_debug_func)(void *,int,const char *,int,int) = NULL;
static void (*realloc_debug_func)(void *,void *,int,const char *,int,int)
= NULL;
static void (*free_debug_func)(void *,int) = NULL;
static void (*set_debug_options_func)(long) = NULL;
static long (*get_debug_options_func)(void) = NULL;
#endif
================================================================================
如何使用(使用最外层函数,也就俗称的接口,这里成为Openssl API):
1. 初始化
#define CRYPTO_malloc_init() CRYPTO_set_mem_functions(malloc, realloc, free)
如果编译Openssl的时候定义了CRYPTO_MDEBUG 或 CRYPTO_MDEBUG_ALL
或 CRYPTO_MDEBUG_TIME 或 CRYPTO_MDEBUG_THREAD,则此函数无需调用,默认是被设置好的。详情见Mem.c。
#define CRYPTO_malloc_debug_init() do {\
CRYPTO_set_mem_debug_functions(\
CRYPTO_dbg_malloc,\
CRYPTO_dbg_realloc,\
CRYPTO_dbg_free,\
CRYPTO_dbg_set_options,\
CRYPTO_dbg_get_options);\
} while(0)
2. 配置选项
/* Adds time to the memory checking information */
#define V_CRYPTO_MDEBUG_TIME 0x1
/* Adds thread number to the memory checking information */
#define V_CRYPTO_MDEBUG_THREAD 0x2
#define V_CRYPTO_MDEBUG_ALL (V_CRYPTO_MDEBUG_TIME | V_CRYPTO_MDEBUG_THREAD)
// 设置显示信息,显示时间和Thread ID。
CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
/* for applications */
#define CRYPTO_MEM_CHECK_OFF 0x0
#define CRYPTO_MEM_CHECK_ON 0x1
/* for libs*/
#define CRYPTO_MEM_CHECK_ENABLE 0x2
#define CRYPTO_MEM_CHECK_DISABLE 0x3
// 可以直接调用这个,也可以调用底下的接口函数
int CRYPTO_mem_ctrl(int mode);
int CRYPTO_is_mem_check_on(void);
/* for applications */
#define MemCheck_start() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON)
#define MemCheck_stop() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF)
/* for library-internal use */
#define MemCheck_on() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE)
#define MemCheck_off() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE)
#define is_MemCheck_on() CRYPTO_is_mem_check_on()
3. 使用最外层接口
OPENSSL_malloc(num)
OPENSSL_realloc(addr,num)
OPENSSL_realloc_clean(addr,old_num,num)
OPENSSL_remalloc(addr,num)
OPENSSL_free(addr)
OPENSSL_malloc_locked(num)
OPENSSL_free_locked(addr)
示例:
int main()
{
char *p = NULL;
BIO *b = NULL;
CRYPTO_malloc_debug_init();
CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
p = (char*)OPENSSL_malloc(4);
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);
b = BIO_new_file("leak.log","w");
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
CRYPTO_mem_leaks(b);
OPENSSL_free(p);
BIO_free(b);
return 0;
}
所以,提取OpenSSL中部分代码,只需要重新定义OPENSSL_XXXX这几个宏即可。