From: Bodo Möller Date: Sat, 29 Apr 2000 23:58:05 +0000 (+0000) Subject: Avoid leaking memory in thread_hash (and enable memory leak detection X-Git-Tag: OpenSSL_0_9_5~46 X-Git-Url: https://git.openssl.org/?p=openssl.git;a=commitdiff_plain;h=dcba2534fa9fb9e9a36be554ece9cb58ffc76f41 Avoid leaking memory in thread_hash (and enable memory leak detection for it). --- diff --git a/CHANGES b/CHANGES index 0e8a4c6669..cc07f745e8 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,12 @@ Changes between 0.9.5a and 0.9.6 [xx XXX 2000] + *) Avoid 'thread_hash' memory leak in crypto/err/err.c by freeing + it in ERR_remove_state if appropriate, and change ERR_get_state + accordingly to avoid race conditions (this is necessary because + thread_hash is no longer constant once set). + [Bodo Moeller] + *) Bugfix for linux-elf makefile.one. [Ulf Möller] diff --git a/crypto/err/err.c b/crypto/err/err.c index a0135579f0..c8dba5284b 100644 --- a/crypto/err/err.c +++ b/crypto/err/err.c @@ -116,9 +116,8 @@ #include #include "cryptlib.h" #include -#include -#include #include +#include static LHASH *error_hash=NULL; @@ -545,6 +544,7 @@ LHASH *ERR_get_string_table(void) return(error_hash); } +/* not thread-safe */ LHASH *ERR_get_err_state_table(void) { return(thread_hash); @@ -652,6 +652,12 @@ void ERR_remove_state(unsigned long pid) tmp.pid=pid; CRYPTO_w_lock(CRYPTO_LOCK_ERR); p=(ERR_STATE *)lh_delete(thread_hash,&tmp); + if (lh_num_items(thread_hash) == 0) + { + /* make sure we don't leak memory */ + lh_free(thread_hash); + thread_hash = NULL; + } CRYPTO_w_unlock(CRYPTO_LOCK_ERR); if (p != NULL) ERR_STATE_free(p); @@ -661,33 +667,19 @@ ERR_STATE *ERR_get_state(void) { static ERR_STATE fallback; ERR_STATE *ret=NULL,tmp,*tmpp; + int thread_state_exists; int i; unsigned long pid; pid=(unsigned long)CRYPTO_thread_id(); CRYPTO_r_lock(CRYPTO_LOCK_ERR); - if (thread_hash == NULL) - { - CRYPTO_r_unlock(CRYPTO_LOCK_ERR); - CRYPTO_w_lock(CRYPTO_LOCK_ERR); - if (thread_hash == NULL) - { - MemCheck_off(); - thread_hash=lh_new(pid_hash,pid_cmp); - MemCheck_on(); - CRYPTO_w_unlock(CRYPTO_LOCK_ERR); - if (thread_hash == NULL) return(&fallback); - } - else - CRYPTO_w_unlock(CRYPTO_LOCK_ERR); - } - else + if (thread_hash != NULL) { tmp.pid=pid; ret=(ERR_STATE *)lh_retrieve(thread_hash,&tmp); - CRYPTO_r_unlock(CRYPTO_LOCK_ERR); } + CRYPTO_r_unlock(CRYPTO_LOCK_ERR); /* ret == the error state, if NULL, make a new one */ if (ret == NULL) @@ -702,9 +694,29 @@ ERR_STATE *ERR_get_state(void) ret->err_data[i]=NULL; ret->err_data_flags[i]=0; } + CRYPTO_w_lock(CRYPTO_LOCK_ERR); - tmpp=(ERR_STATE *)lh_insert(thread_hash,ret); + + /* no entry yet in thread_hash for current thread - + * thus, it may have changed since we last looked at it */ + if (thread_hash == NULL) + thread_hash = lh_new(pid_hash, pid_cmp); + if (thread_hash == NULL) + thread_state_exists = 0; /* allocation error */ + else + { + tmpp=(ERR_STATE *)lh_insert(thread_hash,ret); + thread_state_exists = 1; + } + CRYPTO_w_unlock(CRYPTO_LOCK_ERR); + + if (!thread_state_exists) + { + ERR_STATE_free(ret); /* could not insert it */ + return(&fallback); + } + if (tmpp != NULL) /* old entry - should not happen */ { ERR_STATE_free(tmpp); diff --git a/crypto/err/err.h b/crypto/err/err.h index e3984bb7a4..eb62af2af8 100644 --- a/crypto/err/err.h +++ b/crypto/err/err.h @@ -253,14 +253,12 @@ void ERR_remove_state(unsigned long pid); /* if zero we look it up */ ERR_STATE *ERR_get_state(void); #ifdef HEADER_LHASH_H -LHASH *ERR_get_string_table(void ); -LHASH *ERR_get_err_state_table(void ); -#else -char *ERR_get_string_table(void ); -char *ERR_get_err_state_table(void ); +LHASH *ERR_get_string_table(void); +LHASH *ERR_get_err_state_table(void); /* even less thread-safe than + * ERR_get_string_table :-) */ #endif -int ERR_get_next_error_library(void ); +int ERR_get_next_error_library(void); #ifdef __cplusplus }