Add missing calls to PR_UnloadLibrary (excluding XPCOM component loader and nsPluginsDir*). b=374332 r=bsmedberg
authordbaron@dbaron.org
Sun, 15 Apr 2007 15:22:58 -0700
changeset 544 6e869e9d711ca29905ad64fa17ffd5fd8c24b496
parent 543 21e3ecb149698b2bcaeb892a0e76c757f0e61d4c
child 545 209502e208d000be1448d6822e9497ae1a774ebd
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs374332
milestone1.9a4pre
Add missing calls to PR_UnloadLibrary (excluding XPCOM component loader and nsPluginsDir*). b=374332 r=bsmedberg
accessible/src/atk/nsAppRootAccessible.cpp
extensions/auth/nsAuthFactory.cpp
extensions/auth/nsAuthGSSAPI.cpp
extensions/auth/nsAuthGSSAPI.h
extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp
gfx/src/thebes/nsSystemFontsGTK2.cpp
gfx/src/thebes/nsSystemFontsGTK2.h
gfx/thebes/public/gfxPangoFonts.h
gfx/thebes/src/gfxBeOSPlatform.cpp
gfx/thebes/src/gfxPangoFonts.cpp
gfx/thebes/src/gfxPlatformGtk.cpp
uriloader/exthandler/unix/nsGNOMERegistry.cpp
widget/src/gtk/nsSound.cpp
widget/src/gtk/nsSound.h
widget/src/gtk2/nsIdleServiceGTK.cpp
widget/src/gtk2/nsSound.cpp
widget/src/gtk2/nsSound.h
widget/src/gtk2/nsWidgetFactory.cpp
widget/src/gtk2/nsWindow.cpp
xpcom/io/nsILocalFile.idl
--- a/accessible/src/atk/nsAppRootAccessible.cpp
+++ b/accessible/src/atk/nsAppRootAccessible.cpp
@@ -46,16 +46,17 @@
 #include "nsIServiceManager.h"
 
 #include <gtk/gtk.h>
 #include <atk/atk.h>
 
 typedef GType (* AtkGetTypeType) (void);
 GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
 static PRBool sATKChecked = PR_FALSE;
+static PRLibrary *sATKLib = nsnull;
 static PRBool sInitialized = PR_FALSE;
 static const char sATKLibName[] = "libatk-1.0.so.0";
 static const char sATKHyperlinkImplGetTypeSymbol[] = "atk_hyperlink_impl_get_type";
 
 /* app root accessible */
 static nsAppRootAccessible *sAppRoot = nsnull;
 
 /* gail function pointer */
@@ -562,30 +563,36 @@ NS_IMETHODIMP nsAppRootAccessible::Init(
 {
     sInitialized = PR_FALSE;
     NS_IF_RELEASE(sAppRoot);
     if (sAtkBridge.lib) {
         // Do not shutdown/unload atk-bridge,
         // an exit function registered will take care of it
         // if (sAtkBridge.shutdown)
         //     (*sAtkBridge.shutdown)();
+        PR_UnloadLibrary(sAtkBridge.lib);
         sAtkBridge.lib = NULL;
         sAtkBridge.init = NULL;
         sAtkBridge.shutdown = NULL;
     }
     if (sGail.lib) {
         // Do not shutdown gail because
         // 1) Maybe it's not init-ed by us. e.g. GtkEmbed
         // 2) We need it to avoid assert in spi_atk_tidy_windows
         // if (sGail.shutdown)
         //   (*sGail.shutdown)();
+        PR_UnloadLibrary(sGail.lib);
         sGail.lib = NULL;
         sGail.init = NULL;
         sGail.shutdown = NULL;
     }
+    if (sATKLib) {
+        PR_UnloadLibrary(sATKLib);
+        sATKLib = nsnull;
+    }
 }
 
 NS_IMETHODIMP nsAppRootAccessible::GetName(nsAString& _retval)
 {
     nsCOMPtr<nsIStringBundleService> bundleService = 
       do_GetService(NS_STRINGBUNDLE_CONTRACTID);
 
     NS_ASSERTION(bundleService, "String bundle service must be present!");
@@ -815,19 +822,19 @@ nsAppRootAccessible::RemoveRootAccessibl
     InvalidateChildren();
     return rv;
 }
 
 nsAppRootAccessible *
 nsAppRootAccessible::Create()
 {
     if (!sATKChecked) {
-        PRLibrary *atkLib = PR_LoadLibrary(sATKLibName);
-        if (atkLib) {
-            AtkGetTypeType pfn_atk_hyperlink_impl_get_type = (AtkGetTypeType) PR_FindFunctionSymbol(atkLib, sATKHyperlinkImplGetTypeSymbol);
+        sATKLib = PR_LoadLibrary(sATKLibName);
+        if (sATKLib) {
+            AtkGetTypeType pfn_atk_hyperlink_impl_get_type = (AtkGetTypeType) PR_FindFunctionSymbol(sATKLib, sATKHyperlinkImplGetTypeSymbol);
             if (pfn_atk_hyperlink_impl_get_type) {
                 g_atk_hyperlink_impl_type = pfn_atk_hyperlink_impl_get_type();
             }
         }
         sATKChecked = PR_TRUE;
     }
     if (!sAppRoot && sInitialized) {
         sAppRoot = new nsAppRootAccessible();
--- a/extensions/auth/nsAuthFactory.cpp
+++ b/extensions/auth/nsAuthFactory.cpp
@@ -265,9 +265,16 @@ InitNegotiateAuth(nsIModule *self)
 {
   gNegotiateLog = PR_NewLogModule("negotiateauth");
   return NS_OK;
 }
 #else
 #define InitNegotiateAuth nsnull
 #endif
 
-NS_IMPL_NSGETMODULE_WITH_CTOR(nsAuthModule, components, InitNegotiateAuth)
+PR_STATIC_CALLBACK(void)
+DestroyNegotiateAuth(nsIModule *self)
+{
+  nsAuthGSSAPI::Shutdown();
+}
+
+NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(nsAuthModule, components,
+                                   InitNegotiateAuth, DestroyNegotiateAuth)
--- a/extensions/auth/nsAuthGSSAPI.cpp
+++ b/extensions/auth/nsAuthGSSAPI.cpp
@@ -98,17 +98,17 @@ static const char *gssFuncStr[] = {
     "gss_wrap",
     "gss_unwrap"
 };
 
 #define gssFuncItems NS_ARRAY_LENGTH(gssFuncStr)
 
 static PRFuncPtr gssFunPtr[gssFuncItems]; 
 static PRBool    gssNativeImp = PR_TRUE;
-static PRBool    gssFunInit = PR_FALSE;
+static PRLibrary* gssLibrary = nsnull;
 
 #define gss_display_status_ptr      ((gss_display_status_type)*gssFunPtr[0])
 #define gss_init_sec_context_ptr    ((gss_init_sec_context_type)*gssFunPtr[1])
 #define gss_indicate_mechs_ptr      ((gss_indicate_mechs_type)*gssFunPtr[2])
 #define gss_release_oid_set_ptr     ((gss_release_oid_set_type)*gssFunPtr[3])
 #define gss_delete_sec_context_ptr  ((gss_delete_sec_context_type)*gssFunPtr[4])
 #define gss_import_name_ptr         ((gss_import_name_type)*gssFunPtr[5])
 #define gss_release_buffer_ptr      ((gss_release_buffer_type)*gssFunPtr[6])
@@ -218,17 +218,17 @@ gssInit()
             !(KLCacheHasValidTicketsPtr =
                PR_FindFunctionSymbol(lib, "KLCacheHasValidTickets"))) {
         LOG(("Fail to load KLCacheHasValidTickets function from gssapi library\n"));
         PR_UnloadLibrary(lib);
         return NS_ERROR_FAILURE;
     }
 #endif
 
-    gssFunInit = PR_TRUE;
+    gssLibrary = lib;
     return NS_OK;
 }
 
 #if defined( PR_LOGGING )
 
 // Generate proper GSSAPI error messages from the major and
 // minor status codes.
 void
@@ -237,17 +237,17 @@ LogGssError(OM_uint32 maj_stat, OM_uint3
     OM_uint32 new_stat;
     OM_uint32 msg_ctx = 0;
     gss_buffer_desc status1_string;
     gss_buffer_desc status2_string;
     OM_uint32 ret;
     nsCAutoString errorStr;
     errorStr.Assign(prefix);
 
-    if (!gssFunInit)
+    if (!gssLibrary)
         return;
 
     errorStr += ": ";
     do {
         ret = gss_display_status_ptr(&new_stat,
                                      maj_stat,
                                      GSS_C_GSS_CODE,
                                      GSS_C_NULL_OID,
@@ -291,17 +291,17 @@ nsAuthGSSAPI::nsAuthGSSAPI(pType package
         { 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
     static gss_OID_desc gss_spnego_mech_oid_desc =
         { 6, (void *) "\x2b\x06\x01\x05\x05\x02" };
 
     LOG(("entering nsAuthGSSAPI::nsAuthGSSAPI()\n"));
 
     mComplete = PR_FALSE;
 
-    if (!gssFunInit && NS_FAILED(gssInit()))
+    if (!gssLibrary && NS_FAILED(gssInit()))
         return;
 
     mCtx = GSS_C_NO_CONTEXT;
     mMechOID = &gss_krb5_mech_oid_desc;
 
     // if the type is kerberos we accept it as default
     // and exit 
 
@@ -335,24 +335,33 @@ nsAuthGSSAPI::nsAuthGSSAPI(pType package
         }
         gss_release_oid_set_ptr(&minstat, &mech_set);
     }
 }
 
 void
 nsAuthGSSAPI::Reset()
 {
-    if (gssFunInit && mCtx != GSS_C_NO_CONTEXT) {
+    if (gssLibrary && mCtx != GSS_C_NO_CONTEXT) {
         OM_uint32 minor_status;
         gss_delete_sec_context_ptr(&minor_status, &mCtx, GSS_C_NO_BUFFER);
     }
     mCtx = GSS_C_NO_CONTEXT;
     mComplete = PR_FALSE;
 }
 
+/* static */ void
+nsAuthGSSAPI::Shutdown()
+{
+    if (gssLibrary) {
+        PR_UnloadLibrary(gssLibrary);
+        gssLibrary = nsnull;
+    }
+}
+
 NS_IMPL_ISUPPORTS1(nsAuthGSSAPI, nsIAuthModule)
 
 NS_IMETHODIMP
 nsAuthGSSAPI::Init(const char *serviceName,
                    PRUint32    serviceFlags,
                    const PRUnichar *domain,
                    const PRUnichar *username,
                    const PRUnichar *password)
@@ -360,17 +369,17 @@ nsAuthGSSAPI::Init(const char *serviceNa
     // we don't expect to be passed any user credentials
     NS_ASSERTION(!domain && !username && !password, "unexpected credentials");
 
     // it's critial that the caller supply a service name to be used
     NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG);
 
     LOG(("entering nsAuthGSSAPI::Init()\n"));
 
-    if (!gssFunInit)
+    if (!gssLibrary)
        return NS_ERROR_NOT_INITIALIZED;
 
     mServiceName = serviceName;
     mServiceFlags = serviceFlags;
     return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -385,17 +394,17 @@ nsAuthGSSAPI::GetNextToken(const void *i
     gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
     gss_buffer_t  in_token_ptr = GSS_C_NO_BUFFER;
     gss_name_t server;
     nsCAutoString userbuf;
     nsresult rv;
 
     LOG(("entering nsAuthGSSAPI::GetNextToken()\n"));
 
-    if (!gssFunInit)
+    if (!gssLibrary)
        return NS_ERROR_NOT_INITIALIZED;
 
     // If they've called us again after we're complete, reset to start afresh.
     if (mComplete)
         Reset();
     
     if (mServiceFlags & REQ_DELEGATE)
         req_flags |= GSS_C_DELEG_FLAG;
--- a/extensions/auth/nsAuthGSSAPI.h
+++ b/extensions/auth/nsAuthGSSAPI.h
@@ -55,16 +55,18 @@
 class nsAuthGSSAPI : public nsIAuthModule
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIAUTHMODULE
 
     nsAuthGSSAPI(pType package);
 
+    static void Shutdown();
+
 private:
     ~nsAuthGSSAPI() { Reset(); }
 
     void    Reset();
     gss_OID GetOID() { return mMechOID; }
 
 private:
     gss_ctx_id_t mCtx;
--- a/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp
+++ b/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp
@@ -605,16 +605,18 @@ GConfProxy::~GConfProxy()
 {
     if (mGConfClient)
         g_object_unref(G_OBJECT(mGConfClient));
 
     if (mObservers) {
         (void)mObservers->EnumerateForwards(gconfDeleteObserver, nsnull);
         delete mObservers;
     }
+
+    PR_UnloadLibrary(mGConfLib);
 }
 
 PRBool
 GConfProxy::Init()
 {
     SYSPREF_LOG(("GConfProxy:: Init GConfProxy\n"));
     if (!mSysPrefService)
         return PR_FALSE;
--- a/gfx/src/thebes/nsSystemFontsGTK2.cpp
+++ b/gfx/src/thebes/nsSystemFontsGTK2.cpp
@@ -51,49 +51,73 @@
 #include <pango/pangox.h>
 #include <pango/pango-fontmap.h>
 
 #include <fontconfig/fontconfig.h>
 #include "nsSystemFontsGTK2.h"
 #include "gfxPlatformGtk.h"
 
 // Glue to avoid build/runtime dependencies on Pango > 1.6
-
+#ifndef THEBES_USE_PANGO_CAIRO
 static gboolean
 (* PTR_pango_font_description_get_size_is_absolute)(PangoFontDescription*)
     = nsnull;
+static PRLibrary *gPangoLib = nsnull;
 
 static void InitPangoLib()
 {
     static PRBool initialized = PR_FALSE;
     if (initialized)
         return;
     initialized = PR_TRUE;
 
-    PRLibrary* lib = PR_LoadLibrary("libpango-1.0.so");
-    if (!lib)
+    gPangoLib = PR_LoadLibrary("libpango-1.0.so");
+    if (!gPangoLib)
         return;
 
     PTR_pango_font_description_get_size_is_absolute =
         (gboolean (*)(PangoFontDescription*))
-        PR_FindFunctionSymbol(lib, "pango_font_description_get_size_is_absolute");
+        PR_FindFunctionSymbol(gPangoLib,
+                              "pango_font_description_get_size_is_absolute");
+}
 
-    // leak lib deliberately
+static void
+ShutdownPangoLib()
+{
+    if (gPangoLib) {
+        PR_UnloadLibrary(gPangoLib);
+        gPangoLib = nsnull;
+    }
 }
 
 static gboolean
 MOZ_pango_font_description_get_size_is_absolute(PangoFontDescription *desc)
 {
     if (PTR_pango_font_description_get_size_is_absolute) {
         return PTR_pango_font_description_get_size_is_absolute(desc);
     }
 
     // In old versions of pango, this was always false.
     return PR_FALSE;
 }
+#else
+static inline void InitPangoLib()
+{
+}
+
+static inline void ShutdownPangoLib()
+{
+}
+
+static inline gboolean
+MOZ_pango_font_description_get_size_is_absolute(PangoFontDescription *desc)
+{
+    pango_font_description_get_size_is_absolute(desc);
+}
+#endif
 
 #define DEFAULT_PIXEL_FONT_SIZE 16.0f
 
 nsSystemFontsGTK2::nsSystemFontsGTK2()
   : mDefaultFontName(NS_LITERAL_STRING("sans-serif"))
   , mButtonFontName(NS_LITERAL_STRING("sans-serif"))
   , mFieldFontName(NS_LITERAL_STRING("sans-serif"))
   , mMenuFontName(NS_LITERAL_STRING("sans-serif"))
@@ -176,16 +200,21 @@ nsSystemFontsGTK2::nsSystemFontsGTK2()
 
     gtk_widget_ensure_style(label);
 
     GetSystemFontInfo(label, &mButtonFontName, &mButtonFontStyle);
 
     gtk_widget_destroy(window);  // no unref, windows are different
 }
 
+nsSystemFontsGTK2::~nsSystemFontsGTK2()
+{
+    ShutdownPangoLib();
+}
+
 nsresult
 nsSystemFontsGTK2::GetSystemFontInfo(GtkWidget *aWidget, nsString *aFontName,
                                      gfxFontStyle *aFontStyle) const
 {
     GtkSettings *settings = gtk_widget_get_settings(aWidget);
 
     aFontStyle->style       = FONT_STYLE_NORMAL;
     aFontStyle->decorations = FONT_DECORATION_NONE;
--- a/gfx/src/thebes/nsSystemFontsGTK2.h
+++ b/gfx/src/thebes/nsSystemFontsGTK2.h
@@ -40,16 +40,17 @@
 #define _NS_SYSTEMFONTSGTK2_H_
 
 #include <gfxFont.h>
 
 class nsSystemFontsGTK2
 {
 public:
     nsSystemFontsGTK2();
+    ~nsSystemFontsGTK2();
 
     nsresult GetSystemFont(nsSystemFontID anID, nsString *aFontName,
                            gfxFontStyle *aFontStyle) const;
 
 private:
 
     nsresult GetSystemFontInfo(GtkWidget *aWidget, nsString *aFontName,
                                gfxFontStyle *aFontStyle) const;
--- a/gfx/thebes/public/gfxPangoFonts.h
+++ b/gfx/thebes/public/gfxPangoFonts.h
@@ -60,16 +60,18 @@ class FontSelector;
 class gfxPangoTextRun;
 
 class gfxPangoFont : public gfxFont {
 public:
     gfxPangoFont (const nsAString& aName,
                   const gfxFontStyle *aFontStyle);
     virtual ~gfxPangoFont ();
 
+    static void Shutdown();
+
     virtual const gfxFont::Metrics& GetMetrics();
 
     PangoFontDescription *GetPangoFontDescription() { RealizeFont(); return mPangoFontDesc; }
     PangoContext *GetPangoContext() { RealizeFont(); return mPangoCtx; }
 
     void GetMozLang(nsACString &aMozLang);
     void GetActualFontFamily(nsACString &aFamily);
     PangoFont *GetPangoFont();
--- a/gfx/thebes/src/gfxBeOSPlatform.cpp
+++ b/gfx/thebes/src/gfxBeOSPlatform.cpp
@@ -32,16 +32,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxBeOSPlatform.h"
 #include "gfxFontconfigUtils.h"
+#include "gfxPangoFonts.h"
 
 #include "gfxImageSurface.h"
 #include "gfxBeOSSurface.h"
 
 gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nsnull;
 
 gfxBeOSPlatform::gfxBeOSPlatform()
 {
@@ -49,16 +50,18 @@ gfxBeOSPlatform::gfxBeOSPlatform()
         sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
 }
 
 gfxBeOSPlatform::~gfxBeOSPlatform()
 {
     gfxFontconfigUtils::Shutdown();
     sFontconfigUtils = nsnull;
 
+    gfxPangoFont::Shutdown();
+
 #if 0
     // It would be nice to do this (although it might need to be after
     // the cairo shutdown that happens in ~gfxPlatform).  It even looks
     // idempotent.  But it has fatal assertions that fire if stuff is
     // leaked, and we hit them.
     FcFini();
 #endif
 }
--- a/gfx/thebes/src/gfxPangoFonts.cpp
+++ b/gfx/thebes/src/gfxPangoFonts.cpp
@@ -191,63 +191,76 @@ gfxPangoFontGroup::Copy(const gfxFontSty
 
 // Glue to avoid build/runtime dependencies on Pango > 1.6,
 // because we like living in 1999
 
 #ifndef THEBES_USE_PANGO_CAIRO
 static void
 (* PTR_pango_font_description_set_absolute_size)(PangoFontDescription*, double)
     = nsnull;
+static PRLibrary *gPangoLib = nsnull;
 
 static void InitPangoLib()
 {
     static PRBool initialized = PR_FALSE;
     if (initialized)
         return;
     initialized = PR_TRUE;
 
     g_type_init();
 
-    PRLibrary *lib = PR_LoadLibrary("libpango-1.0.so");
-    if (!lib)
+    gPangoLib = PR_LoadLibrary("libpango-1.0.so");
+    if (!gPangoLib)
         return;
 
     PTR_pango_font_description_set_absolute_size =
         (void (*)(PangoFontDescription*, double))
-        PR_FindFunctionSymbol(lib, "pango_font_description_set_absolute_size");
+        PR_FindFunctionSymbol(gPangoLib,
+                              "pango_font_description_set_absolute_size");
 
-    // leak lib deliberately
-
-    lib = nsnull;
+    PRLibrary *lib = nsnull;
     int *xft_max_freetype_files_ptr = nsnull;
     xft_max_freetype_files_ptr = (int*) PR_FindSymbolAndLibrary("XftMaxFreeTypeFiles", &lib);
     if (xft_max_freetype_files_ptr && *xft_max_freetype_files_ptr < 50)
         *xft_max_freetype_files_ptr = 50;
     if (lib)
         PR_UnloadLibrary(lib);
 }
 
 static void
+ShutdownPangoLib()
+{
+    if (gPangoLib) {
+        PR_UnloadLibrary(gPangoLib);
+        gPangoLib = nsnull;
+    }
+}
+
+static void
 MOZ_pango_font_description_set_absolute_size(PangoFontDescription *desc,
                                              double size)
 {
     if (PTR_pango_font_description_set_absolute_size) {
         PTR_pango_font_description_set_absolute_size(desc, size);
     } else {
         pango_font_description_set_size(desc,
                                         (gint)(size * 72.0 /
                                                gfxPlatformGtk::DPI()));
     }
 }
 #else
-static void InitPangoLib()
+static inline void InitPangoLib()
 {
 }
 
-static void
+static inline void ShutdownPangoLib()
+{
+}
+
+static inline void
 MOZ_pango_font_description_set_absolute_size(PangoFontDescription *desc, double size)
 {
     pango_font_description_set_absolute_size(desc, size);
 }
 #endif
 
 gfxPangoFont::gfxPangoFont(const nsAString &aName,
                            const gfxFontStyle *aFontStyle)
@@ -266,16 +279,22 @@ gfxPangoFont::~gfxPangoFont()
 
     if (mPangoFontDesc)
         pango_font_description_free(mPangoFontDesc);
 
     if (mCairoFont)
         cairo_scaled_font_destroy(mCairoFont);
 }
 
+/* static */ void
+gfxPangoFont::Shutdown()
+{
+    ShutdownPangoLib();
+}
+
 static PangoStyle
 ThebesStyleToPangoStyle (const gfxFontStyle *fs)
 {
     if (fs->style == FONT_STYLE_ITALIC)
         return PANGO_STYLE_ITALIC;
     if (fs->style == FONT_STYLE_OBLIQUE)
         return PANGO_STYLE_OBLIQUE;
 
--- a/gfx/thebes/src/gfxPlatformGtk.cpp
+++ b/gfx/thebes/src/gfxPlatformGtk.cpp
@@ -37,16 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #define PANGO_ENABLE_BACKEND
 #define PANGO_ENABLE_ENGINE
 
 #include "gfxPlatformGtk.h"
 
 #include "gfxFontconfigUtils.h"
+#include "gfxPangoFonts.h"
 
 #include "cairo.h"
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
 
 #include "gfxImageSurface.h"
 #include "gfxXlibSurface.h"
 
@@ -87,16 +88,19 @@ gfxPlatformGtk::gfxPlatformGtk()
     if (!sFontconfigUtils)
         sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
 }
 
 gfxPlatformGtk::~gfxPlatformGtk()
 {
     gfxFontconfigUtils::Shutdown();
     sFontconfigUtils = nsnull;
+
+    gfxPangoFont::Shutdown();
+
 #ifndef THEBES_USE_PANGO_CAIRO
     pango_xft_shutdown_display(GDK_DISPLAY(), 0);
 #endif
 
 #if 0
     // It would be nice to do this (although it might need to be after
     // the cairo shutdown that happens in ~gfxPlatform).  It even looks
     // idempotent.  But it has fatal assertions that fire if stuff is
--- a/uriloader/exthandler/unix/nsGNOMERegistry.cpp
+++ b/uriloader/exthandler/unix/nsGNOMERegistry.cpp
@@ -97,24 +97,28 @@ DECL_FUNC_PTR(gnome_vfs_mime_application
 DECL_FUNC_PTR(gnome_program_init);
 DECL_FUNC_PTR(libgnome_module_info_get);
 DECL_FUNC_PTR(gnome_program_get);
 
 static void
 CleanUp()
 {
   // Unload all libraries
-  if (gnomeLib)
+  if (gnomeLib) {
     PR_UnloadLibrary(gnomeLib);
-  if (gconfLib)
+    gnomeLib = nsnull;
+  }
+  if (gconfLib) {
     PR_UnloadLibrary(gconfLib);
-  if (vfsLib)
+    gconfLib = nsnull;
+  }
+  if (vfsLib) {
     PR_UnloadLibrary(vfsLib);
-
-  gnomeLib = gconfLib = vfsLib = nsnull;
+    vfsLib = nsnull;
+  }
 }
 
 static PRLibrary *
 LoadVersionedLibrary(const char* libName, const char* libVersion)
 {
   char *platformLibName = PR_GetLibraryName(nsnull, libName);
   nsCAutoString versionLibName(platformLibName);
   versionLibName.Append(libVersion);
--- a/widget/src/gtk/nsSound.cpp
+++ b/widget/src/gtk/nsSound.cpp
@@ -119,16 +119,25 @@ nsSound::Init()
   if (!esdref)
     return NS_ERROR_FAILURE;
 
   mInited = PR_TRUE;
 
   return NS_OK;
 }
 
+/* static */ void
+nsSound::Shutdown()
+{
+  if (elib) {
+    PR_UnloadLibrary(elib)
+    elib = nsnull;
+  }
+}
+
 #define GET_WORD(s, i) (s[i+1] << 8) | s[i]
 #define GET_DWORD(s, i) (s[i+3] << 24) | (s[i+2] << 16) | (s[i+1] << 8) | s[i]
 
 NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
                                         nsISupports *context,
                                         nsresult aStatus,
                                         PRUint32 dataLen,
                                         const PRUint8 *data)
--- a/widget/src/gtk/nsSound.h
+++ b/widget/src/gtk/nsSound.h
@@ -48,16 +48,18 @@
 class nsSound : public nsISound, 
                 public nsIStreamLoaderObserver
 {
  public: 
 
   nsSound();
   virtual ~nsSound();
 
+  static void Shutdown();
+
   NS_DECL_ISUPPORTS
   NS_DECL_NSISOUND
   NS_DECL_NSISTREAMLOADEROBSERVER
 
 private:
   PRBool mInited;
 
 };
--- a/widget/src/gtk2/nsIdleServiceGTK.cpp
+++ b/widget/src/gtk2/nsIdleServiceGTK.cpp
@@ -63,16 +63,17 @@ static _XScreenSaverAllocInfo_fn _XSSAll
 static _XScreenSaverQueryInfo_fn _XSSQueryInfo = nsnull;
 
 
 NS_IMPL_ISUPPORTS1(nsIdleServiceGTK, nsIIdleService)
 
 nsIdleServiceGTK::nsIdleServiceGTK()
     : mXssInfo(nsnull)
 {
+    NS_ASSERTION(!xsslib, "created two instances of the idle service");
 #ifdef PR_LOGGING
     if (!sIdleLog)
         sIdleLog = PR_NewLogModule("nsIIdleService");
 #endif
 
     xsslib = PR_LoadLibrary("libXss.so.1");
     if (!xsslib) // ouch.
     {
@@ -98,18 +99,20 @@ nsIdleServiceGTK::nsIdleServiceGTK()
 #endif
  
 }
 
 nsIdleServiceGTK::~nsIdleServiceGTK()
 {
     if (mXssInfo)
         XFree(mXssInfo);
-    if (xsslib)
+    if (xsslib) {
         PR_UnloadLibrary(xsslib);
+        xsslib = nsnull;
+    }
 }
 
 NS_IMETHODIMP
 nsIdleServiceGTK::GetIdleTime(PRUint32 *aTimeDiff)
 {
     // Ask xscreensaver about idle time:
     int event_base, error_base;
     *aTimeDiff = 0;
--- a/widget/src/gtk2/nsSound.cpp
+++ b/widget/src/gtk2/nsSound.cpp
@@ -90,17 +90,17 @@ nsSound::nsSound()
 {
     mInited = PR_FALSE;
 }
 
 nsSound::~nsSound()
 {
     /* see above comment */
     if (esdref != -1) {
-        EsdCloseType EsdClose = (EsdCloseType) PR_FindSymbol(elib, "esd_close");
+        EsdCloseType EsdClose = (EsdCloseType) PR_FindFunctionSymbol(elib, "esd_close");
         (*EsdClose)(esdref);
         esdref = -1;
     }
 }
 
 NS_IMETHODIMP
 nsSound::Init()
 {
@@ -112,31 +112,40 @@ nsSound::Init()
     if (elib) 
         return NS_OK;
 
     EsdOpenSoundType EsdOpenSound;
 
     elib = PR_LoadLibrary("libesd.so.0");
     if (!elib) return NS_ERROR_FAILURE;
 
-    EsdOpenSound = (EsdOpenSoundType) PR_FindSymbol(elib, "esd_open_sound");
+    EsdOpenSound = (EsdOpenSoundType) PR_FindFunctionSymbol(elib, "esd_open_sound");
 
     if (!EsdOpenSound)
         return NS_ERROR_FAILURE;
 
     esdref = (*EsdOpenSound)("localhost");
 
     if (!esdref)
         return NS_ERROR_FAILURE;
 
     mInited = PR_TRUE;
 
     return NS_OK;
 }
 
+/* static */ void
+nsSound::Shutdown()
+{
+    if (elib) {
+        PR_UnloadLibrary(elib);
+        elib = nsnull;
+    }
+}
+
 #define GET_WORD(s, i) (s[i+1] << 8) | s[i]
 #define GET_DWORD(s, i) (s[i+3] << 24) | (s[i+2] << 16) | (s[i+1] << 8) | s[i]
 
 NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
                                         nsISupports *context,
                                         nsresult aStatus,
                                         PRUint32 dataLen,
                                         const PRUint8 *data)
@@ -254,18 +263,18 @@ NS_IMETHODIMP nsSound::OnStreamComplete(
 
 #if 0
     printf("f: %d | c: %d | sps: %li | abps: %li | ba: %d | bps: %d | rate: %li\n",
          format, channels, samples_per_sec, avg_bytes_per_sec, block_align, bits_per_sample, rate);
 #endif
 
     /* open up connection to esd */  
     EsdPlayStreamType EsdPlayStream = 
-        (EsdPlayStreamType) PR_FindSymbol(elib, 
-                                          "esd_play_stream");
+        (EsdPlayStreamType) PR_FindFunctionSymbol(elib, 
+                                                  "esd_play_stream");
     // XXX what if that fails? (Bug 241738)
 
     mask = ESD_PLAY | ESD_STREAM;
 
     if (bits_per_sample == 8)
         mask |= ESD_BITS8;
     else 
         mask |= ESD_BITS16;
@@ -293,19 +302,19 @@ NS_IMETHODIMP nsSound::OnStreamComplete(
     }
 #endif
 
     fd = (*EsdPlayStream)(mask, samples_per_sec, NULL, "mozillaSound"); 
   
     if (fd < 0) {
       int *esd_audio_format = (int *) PR_FindSymbol(elib, "esd_audio_format");
       int *esd_audio_rate = (int *) PR_FindSymbol(elib, "esd_audio_rate");
-      EsdAudioOpenType EsdAudioOpen = (EsdAudioOpenType) PR_FindSymbol(elib, "esd_audio_open");
-      EsdAudioWriteType EsdAudioWrite = (EsdAudioWriteType) PR_FindSymbol(elib, "esd_audio_write");
-      EsdAudioCloseType EsdAudioClose = (EsdAudioCloseType) PR_FindSymbol(elib, "esd_audio_close");
+      EsdAudioOpenType EsdAudioOpen = (EsdAudioOpenType) PR_FindFunctionSymbol(elib, "esd_audio_open");
+      EsdAudioWriteType EsdAudioWrite = (EsdAudioWriteType) PR_FindFunctionSymbol(elib, "esd_audio_write");
+      EsdAudioCloseType EsdAudioClose = (EsdAudioCloseType) PR_FindFunctionSymbol(elib, "esd_audio_close");
 
       *esd_audio_format = mask;
       *esd_audio_rate = samples_per_sec;
       fd = (*EsdAudioOpen)();
 
       if (fd < 0)
         return NS_ERROR_FAILURE;
 
--- a/widget/src/gtk2/nsSound.h
+++ b/widget/src/gtk2/nsSound.h
@@ -48,16 +48,18 @@
 
 class nsSound : public nsISound, 
                 public nsIStreamLoaderObserver
 { 
 public: 
     nsSound(); 
     virtual ~nsSound();
 
+    static void Shutdown();
+
     NS_DECL_ISUPPORTS
     NS_DECL_NSISOUND
     NS_DECL_NSISTREAMLOADEROBSERVER
 
 private:
     PRBool mInited;
 
 };
--- a/widget/src/gtk2/nsWidgetFactory.cpp
+++ b/widget/src/gtk2/nsWidgetFactory.cpp
@@ -275,16 +275,17 @@ static const nsModuleComponentInfo compo
     "@mozilla.org/widget/idleservice;1",
     nsIdleServiceGTKConstructor },
 };
 
 PR_STATIC_CALLBACK(void)
 nsWidgetGtk2ModuleDtor(nsIModule *aSelf)
 {
   nsFilePicker::Shutdown();
+  nsSound::Shutdown();
   nsWindow::ReleaseGlobals();
   nsAppShellShutdown(aSelf);
 }
 
 NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(nsWidgetGtk2Module,
                                    components,
                                    nsAppShellInit,
                                    nsWidgetGtk2ModuleDtor)
--- a/widget/src/gtk2/nsWindow.cpp
+++ b/widget/src/gtk2/nsWindow.cpp
@@ -1007,18 +1007,28 @@ nsWindow::SetCursor(imgIContainer* aCurs
         nsWindow *window = get_window_for_gtk_widget(widget);
         return window->SetCursor(aCursor, aHotspotX, aHotspotY);
     }
 
     if (!sPixbufCursorChecked) {
         PRLibrary* lib;
         _gdk_cursor_new_from_pixbuf = (_gdk_cursor_new_from_pixbuf_fn)
             PR_FindFunctionSymbolAndLibrary("gdk_cursor_new_from_pixbuf", &lib);
+        if (lib) {
+            // We already link against GDK, so we can unload it.
+            PR_UnloadLibrary(lib);
+            lib = nsnull;
+        }
         _gdk_display_get_default = (_gdk_display_get_default_fn)
             PR_FindFunctionSymbolAndLibrary("gdk_display_get_default", &lib);
+        if (lib) {
+            // We already link against GDK, so we can unload it.
+            PR_UnloadLibrary(lib);
+            lib = nsnull;
+        }
         sPixbufCursorChecked = PR_TRUE;
     }
     mCursor = nsCursor(-1);
 
     // Get first image frame
     nsCOMPtr<gfxIImageFrame> frame;
     aCursor->GetFrameAt(0, getter_AddRefs(frame));
     if (!frame)
--- a/xpcom/io/nsILocalFile.idl
+++ b/xpcom/io/nsILocalFile.idl
@@ -96,19 +96,32 @@ interface nsILocalFile : nsIFile
      *
      *  This attribute will determine if the nsLocalFile will auto
      *  resolve symbolic links.  By default, this value will be false
      *  on all non unix systems.  On unix, this attribute is effectively
      *  a noop.  
      */
     attribute PRBool followLinks;  
 
+    /**
+     * Return the result of PR_Open on the file.  The caller is
+     * responsible for calling PR_Close on the result.
+     */
     [noscript] PRFileDescStar openNSPRFileDesc(in long flags, in long mode);
+
+    /**
+     * Return the result of fopen on the file.  The caller is
+     * responsible for calling fclose on the result.
+     */
     [noscript] FILE           openANSIFileDesc(in string mode);
 
+    /**
+     * Return the result of PR_LoadLibrary on the file.  The caller is
+     * responsible for calling PR_UnloadLibrary on the result.
+     */
     [noscript] PRLibraryStar  load();
     
     readonly attribute PRInt64 diskSpaceAvailable;
 
     /**
      *  appendRelative[Native]Path
      *
      *  Append a relative path to the current path of the nsILocalFile object.