### Changes between 3.6 and 4.0 [xx XXX xxxx]
+ * OPENSSL_cleanup() now runs in a global destructor, or not at all by default.
+
+ OpenSSL_cleanup() will no longer by default free global objects when run from
+ an application. Instead it sets a flag for a global destructor to do this after
+ the process exits, and after subordinate libraries using OpenSSL have run their
+ destructors. If destructor support is not available, OpenSSL_cleanup() will do
+ nothing, leaving the global objects to be cleaned up by the Operating System.
+
+ *Bob Beck*
+
* Added CSHAKE as per [SP 800-185]
*Shane Lontis*
OPENSSL_thread_stop();
break;
case DLL_PROCESS_DETACH:
+#if defined(OSSL_DLLMAIN_DESTRUCTOR)
+ ossl_cleanup_destructor();
+#endif /* defined(OSSL_DLLMAIN_DESTRUCTOR) */
break;
}
return TRUE;
static CRYPTO_ONCE base = CRYPTO_ONCE_STATIC_INIT;
static int base_inited = 0;
+static int do_global_cleanup = 0;
DEFINE_RUN_ONCE_STATIC(ossl_init_base)
{
/* no need to init trace */
return 1;
}
-void OPENSSL_cleanup(void)
+/*
+ * Global cleanup function. This is optional, and not strictly
+ * necessary to run. Operating systems have successfully been
+ * recovering memory from exiting tasks since the days when I amused
+ * myself by drawing dinosaurs in crayon on used punch cards.
+ *
+ * If we have destructor support, this function is installed and
+ * always run as a global destructor. It only does anything if
+ * someone has called OPENSSL_cleanup() before it is run.
+ *
+ * This ensures that we do the actual cleanup requested by an
+ * OPENSSL_cleanup() only after subordinate library destructors which
+ * may call into OpenSSL have run.
+ *
+ * If we do not have destructor support, then this function is not
+ * normally run, and OPENSSL_cleanup() will do nothing. If we are
+ * compiled with the compile time define of
+ * DO_NOT_SKIP_OPENSSL_CLEANUP, this function will be called
+ * directly from OPENSSL_cleanup() so that cleanup will happen
+ * when OPENSSL_cleanup() is called.
+ */
+void ossl_cleanup_destructor(void)
{
/*
* At some point we should consider looking at this function with a view to
if (!base_inited)
return;
+ /* If we have not been told to clean up, and we are invoked, return */
+ if (!do_global_cleanup)
+ return;
+
/* Might be explicitly called */
if (stopped)
return;
return 1;
}
+void OPENSSL_cleanup(void)
+{
+ do_global_cleanup = 1;
+#if defined(OSSL_CLEANUP_USING_DESTRUCTOR)
+ return;
+#endif /* defined(OSSL_CLEANUP_USING_DESTRUCTOR) */
+
+#if defined(DO_NOT_SKIP_OPENSSL_CLEANUP)
+ ossl_cleanup_destructor();
+#endif /* defined(DO_NOT_SKIP_OPENSSL_CLEANUP) */
+}
+
int OPENSSL_atexit(void (*handler)(void))
{
#if defined(__TANDEM)
OPENSSL_init_crypto(OPENSSL_INIT_NO_ADD_ALL_CIPHERS
| OPENSSL_INIT_NO_ADD_ALL_DIGESTS, NULL);
-The OPENSSL_cleanup() function deinitialises OpenSSL (both libcrypto
-and libssl). All resources allocated by OpenSSL are freed. An application
-using the OpenSSL library may call this function to free library resources
-prior to application exit. Note that there are some
-use cases in which subordinate libraries may also use OpenSSL and may not
-be finished with their references to it at application exit time (for example,
-if a subordinate library attempts to free an OpenSSL resource from a library
-destructor, calling OPENSSL_cleanup() may result in crashes or other unexpected
-behavior). If this is likely to be a problem then it is recommended that OPENSSL_cleanup()
-not be called, allowing the operating system to reap all library resources on process
-exit.
-
-Note, this may, on some leak detection tools (like valgrind) result in
-reports that indicate reachable memory remains on exit in certain
-configurations. As these are not formally leaks, it is recommended that
-reachable memory reports be suppressed when running such tools.
+The OPENSSL_cleanup() function requests deinitialization of OpenSSL
+(both libcrypto and libssl). OpenSSL installs a global destructor
+function at initialization time if the toolchain supports this. This
+destructor is run after exit and after subordinate library destructors
+have run. By default the destructor does nothing. If deinitialization
+has been requested by a call to OPENSSL_cleanup(), then the destructor
+frees all global resources allocated by OpenSSL.
+
+If the toolchain building OpenSSL does not support a global
+destructor, by default OPENSSL_cleanup will do nothing, as this is the
+safest option, allowing the operating system to then reap all library
+resources on process exit. Note, this may, on some leak detection
+tools (like valgrind) result in reports that indicate reachable memory
+remains on exit in certain configurations. As these are not formally
+leaks, it is recommended that reachable memory reports be suppressed
+when running such tools.
+
+If OpenSSL is compiled with the compile time option of DO_NOT_SKIP_OPENSSL_CLEANUP
+OPENSSL_cleanup() will deinitialize the library immediately when called. This
+is not normally recommended unless you are certain that the global resources
+will not be used by something after the point at which OPENSSL_cleanup() is
+called.
Once OPENSSL_cleanup() has been called the library cannot be reinitialised.
Attempts to call OPENSSL_init_crypto() will fail and an ERR_R_INIT_FAIL error
#endif
#endif
+
+/*
+ * Can we use a global destructor? We can use a global destructor via
+ * __attribute__ on anything like a modern gcc/clang. We can also use
+ * it via dllmain on anything win32/win64.
+ *
+ * Older things may not do this.
+ * The assumption here is then if you don't have destructor support,
+ * it is safe to call OPENSSL_cleanup before an application exits
+ * because no library it is linked with will run code in a destructor
+ * that will call into OpenSSL after exit() happens.
+ *
+ */
+#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN64)
+#define OSSL_CLEANUP_USING_DESTRUCTOR
+#define OSSL_DLLMAIN_DESTRUCTOR
+/*
+ * destructor will be installed in libcrypto's dllmain.c
+ * This means effectively anything not win16 or dos will handle
+ * this.
+ */
+void ossl_cleanup_destructor(void);
+#else
+#if defined(__has_attribute)
+#if __has_attribute(destructor)
+/*
+ * This seems to have been a thing with any gcc or clang since the
+ * early 2000's. So this could pretty much instead be just unconditional
+ * on __GNUC__ or __clang__.
+ */
+#define OSSL_CLEANUP_USING_DESTRUCTOR
+/* destructor is installed by compiler */
+void ossl_cleanup_destructor(void) __attribute__((destructor));
+#else
+/* We are not using a destructor */
+/*
+ * So we are on something that is not close to Windows or being
+ * compiled with a modern GCC/Clang derivative. either way
+ * this probably means something like a toolchain that is
+ * more than 20 years old.
+ */
+void ossl_cleanup_destructor(void);
+#endif /* defined (__has_attribute(destructor) */
+#endif /* defined (__has_attribute) */
+#endif /* defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN64) */