From: Geoff Thorpe Date: Wed, 6 Aug 2008 15:54:15 +0000 (+0000) Subject: Remove the dual-callback scheme for numeric and pointer thread IDs, X-Git-Tag: OpenSSL_0_9_8k^2~281 X-Git-Url: https://git.openssl.org/?p=openssl.git;a=commitdiff_plain;h=4c3296960de32e5abfbb8f4703a2ce624d82669f Remove the dual-callback scheme for numeric and pointer thread IDs, deprecate the original (numeric-only) scheme, and replace with the CRYPTO_THREADID object. This hides the platform-specifics and should reduce the possibility for programming errors (where failing to explicitly check both thread ID forms could create subtle, platform-specific bugs). Thanks to Bodo, for invaluable review and feedback. --- diff --git a/CHANGES b/CHANGES index 35bd37f9d5..9b524ddcfe 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,30 @@ Changes between 0.9.8i and 0.9.9 [xx XXX xxxx] + *) To cater for systems that provide a pointer-based thread ID rather + than numeric, deprecate the current numeric thread ID mechanism and + replace it with a structure and associated callback type. This + mechanism allows a numeric "hash" to be extracted from a thread ID in + either case, and on platforms where pointers are larger than 'long', + mixing is done to help ensure the numeric 'hash' is usable even if it + can't be guaranteed unique. The default mechanism is to use "&errno" + as a pointer-based thread ID to distinguish between threads. + + Applications that want to provide their own thread IDs should now use + CRYPTO_THREADID_set_callback() to register a callback that will call + either CRYPTO_THREADID_set_numeric() or CRYPTO_THREADID_set_pointer(). + + (This new approach replaces the functions CRYPTO_set_idptr_callback(), + CRYPTO_get_idptr_callback(), and CRYPTO_thread_idptr() that existed in + OpenSSL 0.9.9-dev between June 2006 and August 2008. Also, if an + application was previously providing a numeric thread callback that + was inappropriate for distinguishing threads, then uniqueness might + have been obtained with &errno that happened immediately in the + intermediate development versions of OpenSSL; this is no longer the + case, the numeric thread callback will now override the automatic use + of &errno.) + [Geoff Thorpe, with help from Bodo Moeller] + *) Initial support for different CRL issuing certificates. This covers a simple case where the self issued certificates in the chain exist and the real CRL issuer is higher in the existing chain. @@ -307,30 +331,6 @@ list-message-digest-algorithms and list-cipher-algorithms. [Steve Henson] - *) In addition to the numerical (unsigned long) thread ID, provide - for a pointer (void *) thread ID. This helps accomodate systems - that do not provide an unsigned long thread ID. OpenSSL assumes - it is in the same thread iff both the numerical and the pointer - thread ID agree; so applications are just required to define one - of them appropriately (e.g., by using a pointer to a per-thread - memory object malloc()ed by the application for the pointer-type - thread ID). Exactly analoguous to the existing functions - - void CRYPTO_set_id_callback(unsigned long (*func)(void)); - unsigned long (*CRYPTO_get_id_callback(void))(void); - unsigned long CRYPTO_thread_id(void); - - we now have additional functions - - void CRYPTO_set_idptr_callback(void *(*func)(void)); - void *(*CRYPTO_get_idptr_callback(void))(void); - void *CRYPTO_thread_idptr(void); - - also in . The default value for - CRYPTO_thread_idptr() if the application has not provided its own - callback is &errno. - [Bodo Moeller] - *) Change the array representation of binary polynomials: the list of degrees of non-zero coefficients is now terminated with -1. Previously it was terminated with 0, which was also part of the diff --git a/FAQ b/FAQ index 60a527faea..fb997b6fbe 100644 --- a/FAQ +++ b/FAQ @@ -717,9 +717,7 @@ file. Multi-threaded applications must provide two callback functions to OpenSSL by calling CRYPTO_set_locking_callback() and -CRYPTO_set_id_callback(). (For OpenSSL 0.9.9 or later, the new -function CRYPTO_set_idptr_callback() may be used in place of -CRYPTO_set_id_callback().) This is described in the threads(3) +CRYPTO_set_id_callback(). This is described in the threads(3) manpage. * I've compiled a program under Windows and it crashes: why? diff --git a/apps/apps.h b/apps/apps.h index 93d874976b..bcf597f3ef 100644 --- a/apps/apps.h +++ b/apps/apps.h @@ -181,7 +181,7 @@ extern BIO *bio_err; # define apps_shutdown() \ do { CONF_modules_unload(1); destroy_ui_method(); \ OBJ_cleanup(); EVP_cleanup(); ENGINE_cleanup(); \ - CRYPTO_cleanup_all_ex_data(); ERR_remove_state(0); \ + CRYPTO_cleanup_all_ex_data(); ERR_remove_thread_state(NULL); \ ERR_free_strings(); COMP_zlib_cleanup();} while(0) # else # define apps_startup() \ @@ -191,7 +191,7 @@ extern BIO *bio_err; # define apps_shutdown() \ do { CONF_modules_unload(1); destroy_ui_method(); \ OBJ_cleanup(); EVP_cleanup(); \ - CRYPTO_cleanup_all_ex_data(); ERR_remove_state(0); \ + CRYPTO_cleanup_all_ex_data(); ERR_remove_thread_state(NULL); \ ERR_free_strings(); } while(0) # endif #endif diff --git a/crypto/bn/bn.h b/crypto/bn/bn.h index de2cfcf93c..4749c52341 100644 --- a/crypto/bn/bn.h +++ b/crypto/bn/bn.h @@ -130,6 +130,7 @@ #include /* FILE */ #endif #include +#include #ifdef __cplusplus extern "C" { @@ -564,10 +565,11 @@ int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx); int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx); int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *); int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *); +#ifndef OPENSSL_NO_DEPRECATED unsigned long BN_BLINDING_get_thread_id(const BN_BLINDING *); void BN_BLINDING_set_thread_id(BN_BLINDING *, unsigned long); -void *BN_BLINDING_get_thread_idptr(const BN_BLINDING *); -void BN_BLINDING_set_thread_idptr(BN_BLINDING *, void *); +#endif +CRYPTO_THREADID *BN_BLINDING_thread_id(BN_BLINDING *); unsigned long BN_BLINDING_get_flags(const BN_BLINDING *); void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long); BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b, diff --git a/crypto/bn/bn_blind.c b/crypto/bn/bn_blind.c index e9b6173e24..e060592fdc 100644 --- a/crypto/bn/bn_blind.c +++ b/crypto/bn/bn_blind.c @@ -121,10 +121,11 @@ struct bn_blinding_st BIGNUM *Ai; BIGNUM *e; BIGNUM *mod; /* just a reference */ +#ifndef OPENSSL_NO_DEPRECATED unsigned long thread_id; /* added in OpenSSL 0.9.6j and 0.9.7b; * used only by crypto/rsa/rsa_eay.c, rsa_lib.c */ - void *thread_idptr; /* added in OpenSSL 0.9.9; - * used only by crypto/rsa/rsa_eay.c, rsa_lib.c */ +#endif + CRYPTO_THREADID tid; unsigned int counter; unsigned long flags; BN_MONT_CTX *m_ctx; @@ -160,6 +161,7 @@ BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod) BN_set_flags(ret->mod, BN_FLG_CONSTTIME); ret->counter = BN_BLINDING_COUNTER; + CRYPTO_THREADID_current(&ret->tid); return(ret); err: if (ret != NULL) BN_BLINDING_free(ret); @@ -265,6 +267,7 @@ int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *ct return(ret); } +#ifndef OPENSSL_NO_DEPRECATED unsigned long BN_BLINDING_get_thread_id(const BN_BLINDING *b) { return b->thread_id; @@ -274,15 +277,11 @@ void BN_BLINDING_set_thread_id(BN_BLINDING *b, unsigned long n) { b->thread_id = n; } +#endif -void *BN_BLINDING_get_thread_idptr(const BN_BLINDING *b) +CRYPTO_THREADID *BN_BLINDING_thread_id(BN_BLINDING *b) { - return b->thread_idptr; - } - -void BN_BLINDING_set_thread_idptr(BN_BLINDING *b, void *p) - { - b->thread_idptr = p; + return &b->tid; } unsigned long BN_BLINDING_get_flags(const BN_BLINDING *b) diff --git a/crypto/bn/exptest.c b/crypto/bn/exptest.c index 89ebcc8711..074a8e882a 100644 --- a/crypto/bn/exptest.c +++ b/crypto/bn/exptest.c @@ -187,7 +187,7 @@ int main(int argc, char *argv[]) BN_free(b); BN_free(m); BN_CTX_free(ctx); - ERR_remove_state(0); + ERR_remove_thread_state(NULL); CRYPTO_mem_leaks(out); BIO_free(out); printf(" done\n"); diff --git a/crypto/cryptlib.c b/crypto/cryptlib.c index b89bd7a6fa..fe5d3066d7 100644 --- a/crypto/cryptlib.c +++ b/crypto/cryptlib.c @@ -184,8 +184,10 @@ static void (MS_FAR *locking_callback)(int mode,int type, const char *file,int line)=0; static int (MS_FAR *add_lock_callback)(int *pointer,int amount, int type,const char *file,int line)=0; +#ifndef OPENSSL_NO_DEPRECATED static unsigned long (MS_FAR *id_callback)(void)=0; -static void *(MS_FAR *idptr_callback)(void)=0; +#endif +static void (MS_FAR *threadid_callback)(CRYPTO_THREADID *)=0; static struct CRYPTO_dynlock_value *(MS_FAR *dynlock_create_callback) (const char *file,int line)=0; static void (MS_FAR *dynlock_lock_callback)(int mode, @@ -414,6 +416,108 @@ void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type, add_lock_callback=func; } +/* the memset() here and in set_pointer() seem overkill, but for the sake of + * CRYPTO_THREADID_cmp() this avoids any platform silliness that might cause two + * "equal" THREADID structs to not be memcmp()-identical. */ +void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val) + { + memset(id, 0, sizeof(*id)); + id->val = val; + } + +static const unsigned char hash_coeffs[] = { 3, 5, 7, 11, 13, 17, 19, 23 }; +void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr) + { + unsigned char *dest = (void *)&id->val; + unsigned int accum = 0; + unsigned char dnum = sizeof(id->val); + + memset(id, 0, sizeof(*id)); + id->ptr = ptr; + if (sizeof(id->val) >= sizeof(id->ptr)) + { + /* 'ptr' can be embedded in 'val' without loss of uniqueness */ + id->val = (unsigned long)id->ptr; + return; + } + /* hash ptr ==> val. Each byte of 'val' gets the mod-256 total of a + * linear function over the bytes in 'ptr', the co-efficients of which + * are a sequence of low-primes (hash_coeffs is an 8-element cycle) - + * the starting prime for the sequence varies for each byte of 'val' + * (unique polynomials unless pointers are >64-bit). For added spice, + * the totals accumulate rather than restarting from zero, and the index + * of the 'val' byte is added each time (position dependence). If I was + * a black-belt, I'd scan big-endian pointers in reverse to give + * low-order bits more play, but this isn't crypto and I'd prefer nobody + * mistake it as such. Plus I'm lazy. */ + while (dnum--) + { + const unsigned char *src = (void *)&id->ptr; + unsigned char snum = sizeof(id->ptr); + while (snum--) + accum += *(src++) * hash_coeffs[(snum + dnum) & 7]; + accum += dnum; + *(dest++) = accum & 255; + } + } + +int CRYPTO_THREADID_set_callback(void (*func)(CRYPTO_THREADID *)) + { + if (threadid_callback) + return 0; + threadid_callback = func; + return 1; + } + +void (*CRYPTO_THREADID_get_callback(void))(CRYPTO_THREADID *) + { + return threadid_callback; + } + +void CRYPTO_THREADID_current(CRYPTO_THREADID *id) + { + if (threadid_callback) + { + threadid_callback(id); + return; + } +#ifndef OPENSSL_NO_DEPRECATED + /* If the deprecated callback was set, fall back to that */ + if (id_callback) + { + CRYPTO_THREADID_set_numeric(id, id_callback()); + return; + } +#endif + /* Else pick a backup */ +#ifdef OPENSSL_SYS_WIN16 + CRYPTO_THREADID_set_numeric(id, (unsigned long)GetCurrentTask()); +#elif defined(OPENSSL_SYS_WIN32) + CRYPTO_THREADID_set_numeric(id, (unsigned long)GetCurrentThreadId()); +#elif defined(OPENSSL_SYS_BEOS) + CRYPTO_THREADID_set_numeric(id, (unsigned long)find_thread(NULL)); +#else + /* For everything else, default to using the address of 'errno' */ + CRYPTO_THREADID_set_pointer(id, &errno); +#endif + } + +int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *a, const CRYPTO_THREADID *b) + { + return memcmp(a, b, sizeof(*a)); + } + +void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dest, const CRYPTO_THREADID *src) + { + memcpy(dest, src, sizeof(*src)); + } + +unsigned long CRYPTO_THREADID_hash(const CRYPTO_THREADID *id) + { + return id->val; + } + +#ifndef OPENSSL_NO_DEPRECATED unsigned long (*CRYPTO_get_id_callback(void))(void) { return(id_callback); @@ -446,33 +550,13 @@ unsigned long CRYPTO_thread_id(void) ret=id_callback(); return(ret); } - -void *(*CRYPTO_get_idptr_callback(void))(void) - { - return(idptr_callback); - } - -void CRYPTO_set_idptr_callback(void *(*func)(void)) - { - idptr_callback=func; - } - -void *CRYPTO_thread_idptr(void) - { - void *ret=NULL; - - if (idptr_callback == NULL) - ret = &errno; - else - ret = idptr_callback(); - - return ret; - } +#endif void CRYPTO_lock(int mode, int type, const char *file, int line) { #ifdef LOCK_DEBUG { + CRYPTO_THREADID id; char *rw_text,*operation_text; if (mode & CRYPTO_LOCK) @@ -489,8 +573,9 @@ void CRYPTO_lock(int mode, int type, const char *file, int line) else rw_text="ERROR"; - fprintf(stderr,"lock:%08lx/%08p:(%s)%s %-18s %s:%d\n", - CRYPTO_thread_id(), CRYPTO_thread_idptr(), rw_text, operation_text, + CRYPTO_THREADID_current(&id); + fprintf(stderr,"lock:%08lx:(%s)%s %-18s %s:%d\n", + CRYPTO_THREADID_hash(&id), rw_text, operation_text, CRYPTO_get_lock_name(type), file, line); } #endif @@ -526,11 +611,14 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file, ret=add_lock_callback(pointer,amount,type,file,line); #ifdef LOCK_DEBUG - fprintf(stderr,"ladd:%08lx/%0xp:%2d+%2d->%2d %-18s %s:%d\n", - CRYPTO_thread_id(), CRYPTO_thread_idptr(), - before,amount,ret, + { + CRYPTO_THREADID id; + CRYPTO_THREADID_current(&id); + fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n", + CRYPTO_THREADID_hash(&id), before,amount,ret, CRYPTO_get_lock_name(type), file,line); + } #endif } else @@ -539,11 +627,15 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file, ret= *pointer+amount; #ifdef LOCK_DEBUG - fprintf(stderr,"ladd:%08lx/%0xp:%2d+%2d->%2d %-18s %s:%d\n", - CRYPTO_thread_id(), CRYPTO_thread_idptr(), + { + CRYPTO_THREADID id; + CRYPTO_THREADID_current(&id); + fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n", + CRYPTO_THREADID_hash(&id), *pointer,amount,ret, CRYPTO_get_lock_name(type), file,line); + } #endif *pointer=ret; CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,file,line); diff --git a/crypto/crypto.h b/crypto/crypto.h index 8bc927b429..bcc8ca4ad3 100644 --- a/crypto/crypto.h +++ b/crypto/crypto.h @@ -421,12 +421,27 @@ void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type, const char *file, int line)); int (*CRYPTO_get_add_lock_callback(void))(int *num,int mount,int type, const char *file,int line); + +/* Don't use this structure directly. */ +typedef struct crypto_threadid_st + { + void *ptr; + unsigned long val; + } CRYPTO_THREADID; +/* Only use CRYPTO_THREADID_set_[numeric|pointer]() within callbacks */ +void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val); +void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr); +int CRYPTO_THREADID_set_callback(void (*threadid_func)(CRYPTO_THREADID *)); +void (*CRYPTO_THREADID_get_callback(void))(CRYPTO_THREADID *); +void CRYPTO_THREADID_current(CRYPTO_THREADID *id); +int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *a, const CRYPTO_THREADID *b); +void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dest, const CRYPTO_THREADID *src); +unsigned long CRYPTO_THREADID_hash(const CRYPTO_THREADID *id); +#ifndef OPENSSL_NO_DEPRECATED void CRYPTO_set_id_callback(unsigned long (*func)(void)); unsigned long (*CRYPTO_get_id_callback(void))(void); unsigned long CRYPTO_thread_id(void); -void CRYPTO_set_idptr_callback(void *(*func)(void)); -void *(*CRYPTO_get_idptr_callback(void))(void); -void *CRYPTO_thread_idptr(void); +#endif const char *CRYPTO_get_lock_name(int type); int CRYPTO_add_lock(int *pointer,int amount,int type, const char *file, diff --git a/crypto/dsa/dsatest.c b/crypto/dsa/dsatest.c index 5a699ca5d3..edffd24e6b 100644 --- a/crypto/dsa/dsatest.c +++ b/crypto/dsa/dsatest.c @@ -222,7 +222,7 @@ end: ERR_print_errors(bio_err); if (dsa != NULL) DSA_free(dsa); CRYPTO_cleanup_all_ex_data(); - ERR_remove_state(0); + ERR_remove_thread_state(NULL); ERR_free_strings(); CRYPTO_mem_leaks(bio_err); if (bio_err != NULL) diff --git a/crypto/ec/ectest.c b/crypto/ec/ectest.c index b74d6435be..7509cb9c7c 100644 --- a/crypto/ec/ectest.c +++ b/crypto/ec/ectest.c @@ -1326,7 +1326,7 @@ int main(int argc, char *argv[]) #endif CRYPTO_cleanup_all_ex_data(); ERR_free_strings(); - ERR_remove_state(0); + ERR_remove_thread_state(NULL); CRYPTO_mem_leaks_fp(stderr); return 0; diff --git a/crypto/ecdh/ecdhtest.c b/crypto/ecdh/ecdhtest.c index 1575006b51..212a87efa4 100644 --- a/crypto/ecdh/ecdhtest.c +++ b/crypto/ecdh/ecdhtest.c @@ -343,7 +343,7 @@ err: if (ctx) BN_CTX_free(ctx); BIO_free(out); CRYPTO_cleanup_all_ex_data(); - ERR_remove_state(0); + ERR_remove_thread_state(NULL); CRYPTO_mem_leaks_fp(stderr); EXIT(ret); return(ret); diff --git a/crypto/ecdsa/ecdsatest.c b/crypto/ecdsa/ecdsatest.c index b07e31252b..aa4e1481a8 100644 --- a/crypto/ecdsa/ecdsatest.c +++ b/crypto/ecdsa/ecdsatest.c @@ -490,7 +490,7 @@ err: if (ret) ERR_print_errors(out); CRYPTO_cleanup_all_ex_data(); - ERR_remove_state(0); + ERR_remove_thread_state(NULL); ERR_free_strings(); CRYPTO_mem_leaks(out); if (out != NULL) diff --git a/crypto/engine/enginetest.c b/crypto/engine/enginetest.c index cf82f490db..3c1d2b4fbe 100644 --- a/crypto/engine/enginetest.c +++ b/crypto/engine/enginetest.c @@ -276,7 +276,7 @@ end: ENGINE_cleanup(); CRYPTO_cleanup_all_ex_data(); ERR_free_strings(); - ERR_remove_state(0); + ERR_remove_thread_state(NULL); CRYPTO_mem_leaks_fp(stderr); return to_return; } diff --git a/crypto/err/err.c b/crypto/err/err.c index f615cb4766..69713a6e2f 100644 --- a/crypto/err/err.c +++ b/crypto/err/err.c @@ -429,13 +429,13 @@ static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *d) static unsigned long err_state_hash(const ERR_STATE *a) { - return (a->pid + (unsigned long)a->pidptr) * 13; + return CRYPTO_THREADID_hash(&a->tid) * 13; } static IMPLEMENT_LHASH_HASH_FN(err_state, ERR_STATE) static int err_state_cmp(const ERR_STATE *a, const ERR_STATE *b) { - return (a->pid != b->pid) || (a->pidptr != b->pidptr); + return CRYPTO_THREADID_cmp(&a->tid, &b->tid); } static IMPLEMENT_LHASH_COMP_FN(err_state, ERR_STATE) @@ -980,40 +980,37 @@ const char *ERR_reason_error_string(unsigned long e) return((p == NULL)?NULL:p->string); } -void ERR_remove_state(unsigned long pid) +void ERR_remove_thread_state(const CRYPTO_THREADID *id) { ERR_STATE tmp; - void *pidptr; - err_fns_check(); - if (pid != 0) - pidptr = &errno; + if (id) + CRYPTO_THREADID_cpy(&tmp.tid, id); else - { - pid = CRYPTO_thread_id(); - pidptr = CRYPTO_thread_idptr(); - } - - tmp.pid=pid; - tmp.pidptr=pidptr; + CRYPTO_THREADID_current(&tmp.tid); + err_fns_check(); /* thread_del_item automatically destroys the LHASH if the number of * items reaches zero. */ ERRFN(thread_del_item)(&tmp); } +#ifndef OPENSSL_NO_DEPRECATED +void ERR_remove_state(unsigned long pid) + { + ERR_remove_thread_state(NULL); + } +#endif + ERR_STATE *ERR_get_state(void) { static ERR_STATE fallback; ERR_STATE *ret,tmp,*tmpp=NULL; int i; - unsigned long pid; - void *pidptr; + CRYPTO_THREADID tid; err_fns_check(); - pid = CRYPTO_thread_id(); - pidptr = CRYPTO_thread_idptr(); - tmp.pid = pid; - tmp.pidptr = pidptr; + CRYPTO_THREADID_current(&tid); + CRYPTO_THREADID_cpy(&tmp.tid, &tid); ret=ERRFN(thread_get_item)(&tmp); /* ret == the error state, if NULL, make a new one */ @@ -1021,8 +1018,7 @@ ERR_STATE *ERR_get_state(void) { ret=(ERR_STATE *)OPENSSL_malloc(sizeof(ERR_STATE)); if (ret == NULL) return(&fallback); - ret->pid=pid; - ret->pidptr=pidptr; + CRYPTO_THREADID_cpy(&ret->tid, &tid); ret->top=0; ret->bottom=0; for (i=0; i 0 * mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE) */ -/* The following two variables, disabling_thread_id and disabling_thread_idptr, - * are valid iff num_disable > 0. CRYPTO_LOCK_MALLOC2 is locked exactly in - * this case (by the thread named in disabling_thread_id / disabling_thread_idptr). +/* Valid iff num_disable > 0. CRYPTO_LOCK_MALLOC2 is locked exactly in this + * case (by the thread named in disabling_thread). */ -static unsigned long disabling_thread_id = 0; -static void *disabling_thread_idptr = NULL; +static CRYPTO_THREADID disabling_threadid; static void app_info_free(APP_INFO *inf) { @@ -240,9 +236,9 @@ int CRYPTO_mem_ctrl(int mode) case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */ if (mh_mode & CRYPTO_MEM_CHECK_ON) { - if (!num_disable - || (disabling_thread_id != CRYPTO_thread_id()) - || (disabling_thread_idptr != CRYPTO_thread_idptr())) /* otherwise we already have the MALLOC2 lock */ + CRYPTO_THREADID cur; + CRYPTO_THREADID_current(&cur); + if (!num_disable || CRYPTO_THREADID_cmp(&disabling_threadid, &cur)) /* 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 @@ -260,8 +256,7 @@ int CRYPTO_mem_ctrl(int mode) CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2); CRYPTO_w_lock(CRYPTO_LOCK_MALLOC); mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE; - disabling_thread_id=CRYPTO_thread_id(); - disabling_thread_idptr=CRYPTO_thread_idptr(); + CRYPTO_THREADID_cpy(&disabling_threadid, &cur); } num_disable++; } @@ -294,11 +289,12 @@ int CRYPTO_is_mem_check_on(void) if (mh_mode & CRYPTO_MEM_CHECK_ON) { + CRYPTO_THREADID cur; + CRYPTO_THREADID_current(&cur); CRYPTO_r_lock(CRYPTO_LOCK_MALLOC); ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE) - || (disabling_thread_id != CRYPTO_thread_id()) - || (disabling_thread_idptr != CRYPTO_thread_idptr()); + || CRYPTO_THREADID_cmp(&disabling_threadid, &cur); CRYPTO_r_unlock(CRYPTO_LOCK_MALLOC); } @@ -344,20 +340,17 @@ static IMPLEMENT_LHASH_HASH_FN(mem, MEM) /* static int app_info_cmp(APP_INFO *a, APP_INFO *b) */ static int app_info_cmp(const void *a_void, const void *b_void) { - return (((const APP_INFO *)a_void)->thread_id != ((const APP_INFO *)b_void)->thread_id) - || (((const APP_INFO *)a_void)->thread_idptr != ((const APP_INFO *)b_void)->thread_idptr); + return CRYPTO_THREADID_cmp(&((const APP_INFO *)a_void)->threadid, + &((const APP_INFO *)b_void)->threadid); } static IMPLEMENT_LHASH_COMP_FN(app_info, APP_INFO) static unsigned long app_info_hash(const APP_INFO *a) { - unsigned long id1, id2; unsigned long ret; - id1=(unsigned long)a->thread_id; - id2=(unsigned long)a->thread_idptr; - ret = id1 + id2; - + ret = CRYPTO_THREADID_hash(&a->threadid); + /* This is left in as a "who am I to question legacy?" measure */ ret=ret*17851+(ret>>14)*7+(ret>>4)*251; return(ret); } @@ -370,8 +363,7 @@ static APP_INFO *pop_info(void) if (amih != NULL) { - tmp.thread_id=CRYPTO_thread_id(); - tmp.thread_idptr=CRYPTO_thread_idptr(); + CRYPTO_THREADID_current(&tmp.threadid); if ((ret=lh_APP_INFO_delete(amih,&tmp)) != NULL) { APP_INFO *next=ret->next; @@ -382,10 +374,11 @@ static APP_INFO *pop_info(void) (void)lh_APP_INFO_insert(amih,next); } #ifdef LEVITTE_DEBUG_MEM - if (ret->thread_id != tmp.thread_id || ret->thread_idptr != tmp.thread_idptr) + if (CRYPTO_THREADID_cmp(&ret->threadid, &tmp.threadid)) { - fprintf(stderr, "pop_info(): deleted info has other thread ID (%lu/%p) than the current thread (%lu/%p)!!!!\n", - ret->thread_id, ret->thread_idptr, tmp.thread_id, tmp.thread_idptr); + fprintf(stderr, "pop_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n", + CRYPTO_THREADID_hash(&ret->threadid), + CRYPTO_THREADID_hash(&tmp.threadid)); abort(); } #endif @@ -425,8 +418,7 @@ int CRYPTO_push_info_(const char *info, const char *file, int line) } } - ami->thread_id=CRYPTO_thread_id(); - ami->thread_idptr=CRYPTO_thread_idptr(); + CRYPTO_THREADID_current(&ami->threadid); ami->file=file; ami->line=line; ami->info=info; @@ -436,10 +428,11 @@ int CRYPTO_push_info_(const char *info, const char *file, int line) if ((amim=lh_APP_INFO_insert(amih,ami)) != NULL) { #ifdef LEVITTE_DEBUG_MEM - if (ami->thread_id != amim->thread_id || ami->thread_idptr != amim->thread_idptr) + if (CRYPTO_THREADID_cmp(&ami->threadid, &amim->threadid)) { - fprintf(stderr, "CRYPTO_push_info(): previous info has other thread ID (%lu/%p) than the current thread (%lu/%p)!!!!\n", - amim->thread_id, amim->thread_idptr, ami->thread_id, ami->thread_idptr); + fprintf(stderr, "CRYPTO_push_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n", + CRYPTO_THREADID_hash(&amim->threadid), + CRYPTO_THREADID_hash(&ami->threadid)); abort(); } #endif @@ -525,15 +518,9 @@ void CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line, m->line=line; m->num=num; if (options & V_CRYPTO_MDEBUG_THREAD) - { - m->thread_id=CRYPTO_thread_id(); - m->thread_idptr=CRYPTO_thread_idptr(); - } + CRYPTO_THREADID_current(&m->threadid); else - { - m->thread_id=0; - m->thread_idptr=NULL; - } + memset(&m->threadid, 0, sizeof(m->threadid)); if (order == break_order_num) { @@ -552,8 +539,7 @@ void CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line, else m->time=0; - tmp.thread_id=CRYPTO_thread_id(); - tmp.thread_idptr=CRYPTO_thread_idptr(); + CRYPTO_THREADID_current(&tmp.threadid); m->app_info=NULL; if (amih != NULL && (amim=lh_APP_INFO_retrieve(amih,&tmp)) != NULL) @@ -682,8 +668,7 @@ static void print_leak_doall_arg(const MEM *m, MEM_LEAK *l) APP_INFO *amip; int ami_cnt; struct tm *lcl = NULL; - unsigned long ti; - void *tip; + CRYPTO_THREADID ti; #define BUF_REMAIN (sizeof buf - (size_t)(bufp - buf)) @@ -705,7 +690,8 @@ static void print_leak_doall_arg(const MEM *m, MEM_LEAK *l) if (options & V_CRYPTO_MDEBUG_THREAD) { - BIO_snprintf(bufp, BUF_REMAIN, "thread=%lu/%p, ", m->thread_id, m->thread_idptr); + BIO_snprintf(bufp, BUF_REMAIN, "thread=%lu, ", + CRYPTO_THREADID_hash(&m->threadid)); bufp += strlen(bufp); } @@ -722,9 +708,8 @@ static void print_leak_doall_arg(const MEM *m, MEM_LEAK *l) ami_cnt=0; if (!amip) return; - ti=amip->thread_id; - tip=amip->thread_idptr; - + CRYPTO_THREADID_cpy(&ti, &amip->threadid); + do { int buf_len; @@ -733,8 +718,9 @@ static void print_leak_doall_arg(const MEM *m, MEM_LEAK *l) ami_cnt++; memset(buf,'>',ami_cnt); BIO_snprintf(buf + ami_cnt, sizeof buf - ami_cnt, - " thread=%lu/%p, file=%s, line=%d, info=\"", - amip->thread_id, amip->thread_idptr, amip->file, amip->line); + " thread=%lu, file=%s, line=%d, info=\"", + CRYPTO_THREADID_hash(&amip->threadid), amip->file, + amip->line); buf_len=strlen(buf); info_len=strlen(amip->info); if (128 - buf_len - 3 < info_len) @@ -754,7 +740,7 @@ static void print_leak_doall_arg(const MEM *m, MEM_LEAK *l) amip = amip->next; } - while(amip && amip->thread_id == ti && amip->thread_idptr == tip); + while(amip && !CRYPTO_THREADID_cmp(&amip->threadid, &ti)); #ifdef LEVITTE_DEBUG_MEM if (amip) diff --git a/crypto/rand/md_rand.c b/crypto/rand/md_rand.c index cfc78774f7..810b4c2d4a 100644 --- a/crypto/rand/md_rand.c +++ b/crypto/rand/md_rand.c @@ -145,8 +145,7 @@ static unsigned int crypto_lock_rand = 0; /* may be set only when a thread * holds CRYPTO_LOCK_RAND * (to prevent double locking) */ /* access to lockin_thread is synchronized by CRYPTO_LOCK_RAND2 */ -static unsigned long locking_thread_id = 0; /* valid iff crypto_lock_rand is set */ -static void *locking_thread_idptr = NULL; /* valid iff crypto_lock_rand is set */ +static CRYPTO_THREADID locking_threadid; /* valid iff crypto_lock_rand is set */ #ifdef PREDICT @@ -214,8 +213,10 @@ static void ssleay_rand_add(const void *buf, int num, double add) /* check if we already have the lock */ if (crypto_lock_rand) { + CRYPTO_THREADID cur; + CRYPTO_THREADID_current(&cur); CRYPTO_r_lock(CRYPTO_LOCK_RAND2); - do_not_lock = (locking_thread_id == CRYPTO_thread_id()) && (locking_thread_idptr == CRYPTO_thread_idptr()); + do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur); CRYPTO_r_unlock(CRYPTO_LOCK_RAND2); } else @@ -373,8 +374,7 @@ static int ssleay_rand_bytes(unsigned char *buf, int num) /* prevent ssleay_rand_bytes() from trying to obtain the lock again */ CRYPTO_w_lock(CRYPTO_LOCK_RAND2); - locking_thread_id = CRYPTO_thread_id(); - locking_thread_idptr = CRYPTO_thread_idptr(); + CRYPTO_THREADID_current(&locking_threadid); CRYPTO_w_unlock(CRYPTO_LOCK_RAND2); crypto_lock_rand = 1; @@ -529,15 +529,17 @@ static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num) static int ssleay_rand_status(void) { + CRYPTO_THREADID cur; int ret; int do_not_lock; + CRYPTO_THREADID_current(&cur); /* check if we already have the lock * (could happen if a RAND_poll() implementation calls RAND_status()) */ if (crypto_lock_rand) { CRYPTO_r_lock(CRYPTO_LOCK_RAND2); - do_not_lock = (locking_thread_id == CRYPTO_thread_id()) && (locking_thread_idptr == CRYPTO_thread_idptr()); + do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur); CRYPTO_r_unlock(CRYPTO_LOCK_RAND2); } else @@ -549,8 +551,7 @@ static int ssleay_rand_status(void) /* prevent ssleay_rand_bytes() from trying to obtain the lock again */ CRYPTO_w_lock(CRYPTO_LOCK_RAND2); - locking_thread_id = CRYPTO_thread_id(); - locking_thread_idptr = CRYPTO_thread_idptr(); + CRYPTO_THREADID_cpy(&locking_threadid, &cur); CRYPTO_w_unlock(CRYPTO_LOCK_RAND2); crypto_lock_rand = 1; } diff --git a/crypto/rsa/rsa_eay.c b/crypto/rsa/rsa_eay.c index a1ecd6d478..7321349237 100644 --- a/crypto/rsa/rsa_eay.c +++ b/crypto/rsa/rsa_eay.c @@ -264,6 +264,7 @@ static BN_BLINDING *rsa_get_blinding(RSA *rsa, int *local, BN_CTX *ctx) { BN_BLINDING *ret; int got_write_lock = 0; + CRYPTO_THREADID cur; CRYPTO_r_lock(CRYPTO_LOCK_RSA); @@ -281,7 +282,8 @@ static BN_BLINDING *rsa_get_blinding(RSA *rsa, int *local, BN_CTX *ctx) if (ret == NULL) goto err; - if ((BN_BLINDING_get_thread_id(ret) == CRYPTO_thread_id()) && (BN_BLINDING_get_thread_idptr(ret) == CRYPTO_thread_idptr())) + CRYPTO_THREADID_current(&cur); + if (!CRYPTO_THREADID_cmp(&cur, BN_BLINDING_thread_id(ret))) { /* rsa->blinding is ours! */ diff --git a/crypto/rsa/rsa_lib.c b/crypto/rsa/rsa_lib.c index dd09609743..6b1b029d7e 100644 --- a/crypto/rsa/rsa_lib.c +++ b/crypto/rsa/rsa_lib.c @@ -417,8 +417,7 @@ BN_BLINDING *RSA_setup_blinding(RSA *rsa, BN_CTX *in_ctx) RSAerr(RSA_F_RSA_SETUP_BLINDING, ERR_R_BN_LIB); goto err; } - BN_BLINDING_set_thread_id(ret, CRYPTO_thread_id()); - BN_BLINDING_set_thread_idptr(ret, CRYPTO_thread_idptr()); + CRYPTO_THREADID_current(BN_BLINDING_thread_id(ret)); err: BN_CTX_end(ctx); if (in_ctx == NULL) diff --git a/crypto/rsa/rsa_test.c b/crypto/rsa/rsa_test.c index 4080de8bcf..c8705a0f6e 100644 --- a/crypto/rsa/rsa_test.c +++ b/crypto/rsa/rsa_test.c @@ -328,7 +328,7 @@ int main(int argc, char *argv[]) } CRYPTO_cleanup_all_ex_data(); - ERR_remove_state(0); + ERR_remove_thread_state(NULL); CRYPTO_mem_leaks_fp(stderr); diff --git a/doc/crypto/BN_BLINDING_new.pod b/doc/crypto/BN_BLINDING_new.pod index 7b087f7288..5e3fe1d66c 100644 --- a/doc/crypto/BN_BLINDING_new.pod +++ b/doc/crypto/BN_BLINDING_new.pod @@ -22,8 +22,11 @@ functions. BN_CTX *ctx); int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *ctx); + #ifndef OPENSSL_NO_DEPRECATED unsigned long BN_BLINDING_get_thread_id(const BN_BLINDING *); void BN_BLINDING_set_thread_id(BN_BLINDING *, unsigned long); + #endif + CRYPTO_THREADID *BN_BLINDING_thread_id(BN_BLINDING *); unsigned long BN_BLINDING_get_flags(const BN_BLINDING *); void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long); BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b, @@ -54,11 +57,11 @@ BN_BLINDING_convert() and BN_BLINDING_invert() are wrapper functions for BN_BLINDING_convert_ex() and BN_BLINDING_invert_ex() with B set to NULL. -BN_BLINDING_set_thread_id() and BN_BLINDING_get_thread_id() -set and get the "thread id" value of the B structure, -a field provided to users of B structure to help them -provide proper locking if needed for multi-threaded use. The -"thread id" of a newly allocated B structure is zero. +BN_BLINDING_thread_id() provides access to the B +object within the B structure. This is to help users +provide proper locking if needed for multi-threaded use. The "thread +id" object of a newly allocated B structure is +initialised to the thread id in which BN_BLINDING_new() was called. BN_BLINDING_get_flags() returns the BN_BLINDING flags. Currently there are two supported flags: B and @@ -83,8 +86,8 @@ BN_BLINDING_update(), BN_BLINDING_convert(), BN_BLINDING_invert(), BN_BLINDING_convert_ex() and BN_BLINDING_invert_ex() return 1 on success and 0 if an error occured. -BN_BLINDING_get_thread_id() returns the thread id (a B -value) or 0 if not set. +BN_BLINDING_thread_id() returns a pointer to the thread id object +within a B object. BN_BLINDING_get_flags() returns the currently set B flags (a B value). @@ -98,6 +101,9 @@ L =head1 HISTORY +BN_BLINDING_thread_id was first introduced in OpenSSL 0.9.9, and it +deprecates BN_BLINDING_set_thread_id and BN_BLINDING_get_thread_id. + BN_BLINDING_convert_ex, BN_BLINDIND_invert_ex, BN_BLINDING_get_thread_id, BN_BLINDING_set_thread_id, BN_BLINDING_set_flags, BN_BLINDING_get_flags and BN_BLINDING_create_param were first introduced in OpenSSL 0.9.8 diff --git a/doc/crypto/threads.pod b/doc/crypto/threads.pod index 230cbe890b..e6266a1ec6 100644 --- a/doc/crypto/threads.pod +++ b/doc/crypto/threads.pod @@ -2,8 +2,9 @@ =head1 NAME -CRYPTO_set_locking_callback, CRYPTO_set_id_callback, -CRYPTO_set_idptr_callback, CRYPTO_num_locks, +CRYPTO_THREADID_set_callback, CRYPTO_THREADID_get_callback, +CRYPTO_THREADID_current, CRYPTO_THREADID_cmp, CRYPTO_THREADID_cpy, +CRYPTO_THREADID_hash, CRYPTO_set_locking_callback, CRYPTO_num_locks, CRYPTO_set_dynlock_create_callback, CRYPTO_set_dynlock_lock_callback, CRYPTO_set_dynlock_destroy_callback, CRYPTO_get_new_dynlockid, CRYPTO_destroy_dynlockid, CRYPTO_lock - OpenSSL thread support @@ -12,16 +13,26 @@ CRYPTO_destroy_dynlockid, CRYPTO_lock - OpenSSL thread support #include - void CRYPTO_set_locking_callback(void (*locking_function)(int mode, - int n, const char *file, int line)); - - void CRYPTO_set_id_callback(unsigned long (*id_function)(void)); - - void CRYPTO_set_idptr_callback(void *(*idptr_function)(void)); + /* Don't use this structure directly. */ + typedef struct crypto_threadid_st + { + void *ptr; + unsigned long val; + } CRYPTO_THREADID; + /* Only use CRYPTO_THREADID_set_[numeric|pointer]() within callbacks */ + void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val); + void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr); + int CRYPTO_THREADID_set_callback(void (*threadid_func)(CRYPTO_THREADID *)); + void (*CRYPTO_THREADID_get_callback(void))(CRYPTO_THREADID *); + void CRYPTO_THREADID_current(CRYPTO_THREADID *id); + int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *a, + const CRYPTO_THREADID *b); + void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dest, + const CRYPTO_THREADID *src); + unsigned long CRYPTO_THREADID_hash(const CRYPTO_THREADID *id); int CRYPTO_num_locks(void); - /* struct CRYPTO_dynlock_value needs to be defined by the user */ struct CRYPTO_dynlock_value; @@ -53,7 +64,8 @@ CRYPTO_destroy_dynlockid, CRYPTO_lock - OpenSSL thread support =head1 DESCRIPTION OpenSSL can safely be used in multi-threaded applications provided -that at least two callback functions are set. +that at least two callback functions are set, locking_function and +threadid_func. locking_function(int mode, int n, const char *file, int line) is needed to perform locking on shared data structures. @@ -68,17 +80,42 @@ B, and releases it otherwise. B and B are the file number of the function setting the lock. They can be useful for debugging. -id_function(void) is a function that returns a numerical thread ID, -for example pthread_self() if it returns an integer (see NOTES below). -By OpenSSL's defaults, this is not needed on Windows nor on platforms -where getpid() returns a different ID for each thread (see NOTES -below). +threadid_func(CRYPTO_THREADID *id) is needed to record the currently-executing +thread's identifier into B. The implementation of this callback should not +fill in B directly, but should use CRYPTO_THREADID_set_numeric() if thread +IDs are numeric, or CRYPTO_THREADID_set_pointer() if they are pointer-based. +If the application does not register such a callback using +CRYPTO_THREADID_set_callback(), then a default implementation is used - on +Windows and BeOS this uses the system's default thread identifying APIs, and on +all other platforms it uses the address of B. The latter is satisfactory +for thread-safety if and only if the platform has a thread-local error number +facility. -idptr_function(void) is a function that similarly returns a thread ID, -but of type void *. This is not needed on platforms where &errno is -different for each thread. OpenSSL assumes that it is in the same -thread iff both the numerical and the pointer thread ID agree, so it -suffices to define one of these two callback functions appropriately. +Once threadid_func() is registered, or if the built-in default implementation is +to be used; + +=over 4 + +=item * +CRYPTO_THREADID_current() records the currently-executing thread ID into the +given B object. + +=item * +CRYPTO_THREADID_cmp() compares two thread IDs (returning zero for equality, ie. +the same semantics as memcmp()). + +=item * +CRYPTO_THREADID_cpy() duplicates a thread ID value, + +=item * +CRYPTO_THREADID_hash() returns a numeric value usable as a hash-table key. This +is usually the exact numeric or pointer-based thread ID used internally, however +this also handles the unusual case where pointers are larger than 'long' +variables and the platform's thread IDs are pointer-based - in this case, mixing +is done to attempt to produce a unique numeric value even though it is not as +wide as the platform's true thread IDs. + +=back Additionally, OpenSSL supports dynamic locks, and sometimes, some parts of OpenSSL need it for better performance. To enable this, the following @@ -150,24 +187,6 @@ You can find out if OpenSSL was configured with thread support: Also, dynamic locks are currently not used internally by OpenSSL, but may do so in the future. -Defining id_function(void) has it's own issues. Generally speaking, -pthread_self() should be used, even on platforms where getpid() gives -different answers in each thread, since that may depend on the machine -the program is run on, not the machine where the program is being -compiled. For instance, Red Hat 8 Linux and earlier used -LinuxThreads, whose getpid() returns a different value for each -thread. Red Hat 9 Linux and later use NPTL, which is -Posix-conformant, and has a getpid() that returns the same value for -all threads in a process. A program compiled on Red Hat 8 and run on -Red Hat 9 will therefore see getpid() returning the same value for -all threads. - -There is still the issue of platforms where pthread_self() returns -something other than an integer. It is for cases like this that -CRYPTO_set_idptr_callback() comes in handy. (E.g., call malloc(1) -once in each thread, and have idptr_function() return a pointer to -this object.) - =head1 EXAMPLES B shows examples of the callback functions on @@ -179,8 +198,10 @@ CRYPTO_set_locking_callback() and CRYPTO_set_id_callback() are available in all versions of SSLeay and OpenSSL. CRYPTO_num_locks() was added in OpenSSL 0.9.4. All functions dealing with dynamic locks were added in OpenSSL 0.9.5b-dev. - -CRYPTO_set_idptr_callback() was added in OpenSSL 0.9.9. +B and associated functions were introduced in OpenSSL 0.9.9 +to replace (actually, deprecate) the previous CRYPTO_set_id_callback(), +CRYPTO_get_id_callback(), and CRYPTO_thread_id() functions which assumed +thread IDs to always be represented by 'unsigned long'. =head1 SEE ALSO diff --git a/ssl/ssltest.c b/ssl/ssltest.c index 83a571d69b..b20ab0fb05 100644 --- a/ssl/ssltest.c +++ b/ssl/ssltest.c @@ -1014,7 +1014,7 @@ end: #endif CRYPTO_cleanup_all_ex_data(); ERR_free_strings(); - ERR_remove_state(0); + ERR_remove_thread_state(NULL); EVP_cleanup(); CRYPTO_mem_leaks(bio_err); if (bio_err != NULL) BIO_free(bio_err);