Fix for the NSS_Shutdown crash
authorSergio Villar Senín <svillar@igalia.com>
Tue, 28 Apr 2009 16:29:02 +0000 (18:29 +0200)
committerSergio Villar Senín <svillar@igalia.com>
Thu, 7 May 2009 10:32:45 +0000 (12:32 +0200)
camel/ChangeLog
camel/camel.c

index 3535bfa..fcc2e5c 100644 (file)
@@ -1,3 +1,12 @@
+2009-05-07  Sergio Villar Senin  <svillar@igalia.com>
+
+       ** Fix for bug #580620
+
+       * camel.c (camel_init, camel_shutdown): protect calls to NSS_Init
+       and NSS_Shutdown to avoid simultaneous calls from multiple
+       threads. Do not unconditionally cleanup NSS if it was externally
+       initialized.
+
 2009-05-06  Jeff Cai <jeff.cai@sun.com>
 
        ** Fix for bug #581420
index d19ffcc..be1855b 100644 (file)
 #include "camel-provider.h"
 #include "camel-private.h"
 
+#ifdef HAVE_NSS
+/* To protect NSS initialization and shutdown. This prevents
+   concurrent calls to shutdown() and init() by different threads */
+PRLock *nss_initlock = NULL;
+
+/* Whether or not Camel has initialized the NSS library. We cannot
+   unconditionally call NSS_Shutdown() if NSS was initialized by other
+   library before. This boolean ensures that we only perform a cleanup
+   if and only if Camel is the one that previously initialized NSS */
+volatile gboolean nss_initialized = FALSE;
+#endif
+
 static int initialised = FALSE;
 
 int camel_application_is_exiting = FALSE;
@@ -70,7 +82,11 @@ camel_init (const char *configdir, gboolean nss_init)
                char *nss_configdir;
                PRUint16 indx;
 
-               PR_Init (PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 10);
+               if (nss_initlock == NULL) {
+                       PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 10);
+                       nss_initlock = PR_NewLock();
+               }
+               PR_Lock (nss_initlock);
                
 #ifndef G_OS_WIN32
                nss_configdir = g_strdup (configdir);
@@ -78,16 +94,25 @@ camel_init (const char *configdir, gboolean nss_init)
                nss_configdir = g_win32_locale_filename_from_utf8 (configdir);
 #endif
 
-               if (NSS_InitReadWrite (nss_configdir) == SECFailure) {
-                       /* fall back on using volatile dbs? */
-                       if (NSS_NoDB_Init (nss_configdir) == SECFailure) {
-                               g_free (nss_configdir);
-                               g_warning ("Failed to initialize NSS");
-                               return -1;
+               if (!NSS_IsInitialized()) {
+                       nss_initialized = 1;
+
+                       if (NSS_InitReadWrite (nss_configdir) == SECFailure) {
+                               /* fall back on using volatile dbs? */
+                               if (NSS_NoDB_Init (nss_configdir) == SECFailure) {
+                                       g_free (nss_configdir);
+                                       g_warning ("Failed to initialize NSS");
+                                       nss_initialized = 0;
+                                       PR_Unlock(nss_initlock);
+                                       return -1;
+                               }
                        }
                }
 
                NSS_SetDomesticPolicy ();
+
+               PR_Unlock(nss_initlock);
+
                /* we must enable all ciphersuites */
                for (indx = 0; indx < SSL_NumImplementedCiphers; indx++) {
                        if (!SSL_IS_SSL2_CIPHER(SSL_ImplementedCiphers[indx]))
@@ -138,7 +163,10 @@ camel_shutdown (void)
        /* These next calls must come last. */
 
 #if defined (HAVE_NSS)
-       NSS_Shutdown ();
+       PR_Lock(nss_initlock);
+       if (nss_initialized)
+               NSS_Shutdown ();
+       PR_Unlock(nss_initlock);
 #endif /* HAVE_NSS */
 
        initialised = FALSE;