ssluse.c: fix calling of OpenSSL's ERR_remove_state(0)
authorYang Tse <yangsita@gmail.com>
Fri, 4 Nov 2011 12:08:37 +0000 (13:08 +0100)
committerYang Tse <yangsita@gmail.com>
Fri, 4 Nov 2011 12:08:37 +0000 (13:08 +0100)
Move calling of ERR_remove_state(0) a.k.a ERR_remove_thread_state(NULL)
from Curl_ossl_close_all() to Curl_ossl_cleanup().

In this way ERR_remove_state(0) is now only called in libcurl by
curl_global_cleanup(). Previously it would get called by functions
curl_easy_cleanup(), curl_multi_cleanup and potentially each time a
connection was removed from a connection cache leading to premature
destruction of OpenSSL's thread local state hash.

Multi-threaded apps using OpenSSL enabled libcurl should still call
function ERR_remove_state(0) or ERR_remove_thread_state(NULL) at the
very end end of threads that do not call curl_global_cleanup().

lib/ssluse.c

index d65fd98..af70fe0 100644 (file)
 #define X509_STORE_set_flags(x,y) Curl_nop_stmt
 #endif
 
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+#define HAVE_ERR_REMOVE_THREAD_STATE 1
+#endif
+
 /*
  * Number of bytes to read from the random number seed file. This must be
  * a finite value (because some entropy "files" like /dev/urandom have
@@ -697,21 +701,28 @@ int Curl_ossl_init(void)
 /* Global cleanup */
 void Curl_ossl_cleanup(void)
 {
-  /* Free the SSL error strings */
-  ERR_free_strings();
-
-  /* EVP_cleanup() removes all ciphers and digests from the table. */
+  /* Free ciphers and digests lists */
   EVP_cleanup();
 
 #ifdef HAVE_ENGINE_CLEANUP
+  /* Free engine list */
   ENGINE_cleanup();
 #endif
 
 #ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
-  /* this function was not present in 0.9.6b, but was added sometimes
-     later */
+  /* Free OpenSSL ex_data table */
   CRYPTO_cleanup_all_ex_data();
 #endif
+
+  /* Free OpenSSL error strings */
+  ERR_free_strings();
+
+  /* Free thread local error state, destroying hash upon zero refcount */
+#ifdef HAVE_ERR_REMOVE_THREAD_STATE
+  ERR_remove_thread_state(NULL);
+#else
+  ERR_remove_state(0);
+#endif
 }
 
 /*
@@ -960,17 +971,6 @@ void Curl_ossl_session_free(void *ptr)
  */
 int Curl_ossl_close_all(struct SessionHandle *data)
 {
-  /*
-    ERR_remove_state() frees the error queue associated with
-    thread pid.  If pid == 0, the current thread will have its
-    error queue removed.
-
-    Since error queue data structures are allocated
-    automatically for new threads, they must be freed when
-    threads are terminated in oder to avoid memory leaks.
-  */
-  ERR_remove_state(0);
-
 #ifdef HAVE_OPENSSL_ENGINE_H
   if(data->state.engine) {
     ENGINE_finish(data->state.engine);