Bug 775588 - Expose path to tmpdir, profiledir in OS.Constants and make sure that weird loaders that violate loading order do not segfault. r=khuey
authorDavid Rajchenbach-Teller <dteller@mozilla.com>
Wed, 22 Aug 2012 16:58:08 -0400
changeset 105104 1a822acf8faa09193f5544d74f9feb4a0ddde483
parent 105103 a5b7988bdde72799211c36c683e9b48b6d890e49
child 105105 a9fefd087abca7b6685beb8796e13f1935708f07
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewerskhuey
bugs775588
milestone17.0a1
Bug 775588 - Expose path to tmpdir, profiledir in OS.Constants and make sure that weird loaders that violate loading order do not segfault. r=khuey
dom/system/OSFileConstants.cpp
--- a/dom/system/OSFileConstants.cpp
+++ b/dom/system/OSFileConstants.cpp
@@ -28,16 +28,19 @@
 // Used to provide information on the OS
 
 #include "nsThreadUtils.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsIXULRuntime.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
+#include "nsAutoPtr.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsAppDirectoryServiceDefs.h"
 
 #include "OSFileConstants.h"
 #include "nsIOSFileConstantsService.h"
 
 /**
  * This module defines the basic libc constants (error numbers, open modes,
  * etc.) used by OS.File and possibly other OS-bound JavaScript libraries.
  */
@@ -48,61 +51,105 @@ namespace mozilla {
 // Use an anonymous namespace to hide the symbols and avoid any collision
 // with, for instance, |extern bool gInitialized;|
 namespace {
 /**
  * |true| if this module has been initialized, |false| otherwise
  */
 bool gInitialized = false;
 
+typedef struct {
+  /**
+   * The name of the directory holding all the libraries (libxpcom, libnss, etc.)
+   */
+  nsString libDir;
+  nsString tmpDir;
+  nsString profileDir;
+} Paths;
+
 /**
- * The name of the directory holding all the libraries (libxpcom, libnss, etc.)
+ * System directories.
+ */
+Paths* gPaths = NULL;
+
+}
+
+/**
+ * Return the path to one of the special directories.
  */
-nsString* gLibDirectory;
+nsresult GetPathToSpecialDir(const char *aKey, nsString& aOutPath)
+{
+  nsCOMPtr<nsIFile> file;
+  nsresult rv = NS_GetSpecialDirectory(aKey, getter_AddRefs(file));
+  if (NS_FAILED(rv) || !file) {
+    return rv;
+  }
+
+  return file->GetPath(aOutPath);
 }
 
 /**
  * Perform the part of initialization that can only be
  * executed on the main thread.
  */
 nsresult InitOSFileConstants()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (gInitialized) {
     return NS_OK;
   }
 
   gInitialized = true;
 
-  // Initialize gLibDirectory
-  nsCOMPtr<nsIFile> xpcomLib;
-  nsresult rv = NS_GetSpecialDirectory("XpcomLib", getter_AddRefs(xpcomLib));
-  if (NS_FAILED(rv) || !xpcomLib) {
+  nsAutoPtr<Paths> paths(new Paths);
+
+  // Initialize paths->libDir
+  nsCOMPtr<nsIFile> file;
+  nsresult rv = NS_GetSpecialDirectory("XpcomLib", getter_AddRefs(file));
+  if (NS_FAILED(rv)) {
     return rv;
   }
 
   nsCOMPtr<nsIFile> libDir;
-  rv = xpcomLib->GetParent(getter_AddRefs(libDir));
+  rv = file->GetParent(getter_AddRefs(libDir));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  rv = libDir->GetPath(paths->libDir);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  gLibDirectory = new nsString();
-  return libDir->GetPath(*gLibDirectory);
+  rv = GetPathToSpecialDir(NS_OS_TEMP_DIR, paths->tmpDir);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_50_DIR, paths->profileDir);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  gPaths = paths.forget();
+  return NS_OK;
 }
 
+/**
+ * Perform the cleaning up that can only be executed on the main thread.
+ */
 void CleanupOSFileConstants()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!gInitialized) {
     return;
   }
 
   gInitialized = false;
-  delete gLibDirectory;
+  delete gPaths;
 }
 
 
 /**
  * Define a simple read-only property holding an integer.
  *
  * @param name The name of the constant. Used both as the JS name for the
  * constant and to access its value. Must be defined.
@@ -474,25 +521,46 @@ JSObject *GetOrCreateObjectProperty(JSCo
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
       JSMSG_UNEXPECTED_TYPE, aProperty, "not an object");
     return NULL;
   }
   return JS_DefineObject(cx, aObject, aProperty, NULL, NULL, JSPROP_ENUMERATE);
 }
 
 /**
+ * Set a property of an object from a nsString.
+ */
+bool SetStringProperty(JSContext *cx, JSObject *aObject, const char *aProperty,
+                       const nsString aValue)
+{
+  JSString* strValue = JS_NewUCStringCopyZ(cx, aValue.get());
+  jsval valValue = STRING_TO_JSVAL(strValue);
+  return JS_SetProperty(cx, aObject, aProperty, &valValue);
+}
+
+/**
  * Define OS-specific constants.
  *
  * This function creates or uses JS object |OS.Constants| to store
  * all its constants.
  */
 bool DefineOSFileConstants(JSContext *cx, JSObject *global)
 {
   MOZ_ASSERT(gInitialized);
 
+  if (gPaths == NULL) {
+    // If an initialization error was ignored, we may end up with
+    // |gInitialized == true| but |gPaths == NULL|. We cannot
+    // |MOZ_ASSERT| this, as this would kill precompile_cache.js,
+    // so we simply return an error.
+    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+      JSMSG_CANT_OPEN, "OSFileConstants", "initialization has failed");
+    return false;
+  }
+
   JSObject *objOS;
   if (!(objOS = GetOrCreateObjectProperty(cx, global, "OS"))) {
     return false;
   }
   JSObject *objConstants;
   if (!(objConstants = GetOrCreateObjectProperty(cx, objOS, "Constants"))) {
     return false;
   }
@@ -545,41 +613,50 @@ bool DefineOSFileConstants(JSContext *cx
 
   // Build OS.Constants.Path
 
   JSObject *objPath;
   if (!(objPath = GetOrCreateObjectProperty(cx, objConstants, "Path"))) {
     return false;
   }
 
-
   // Locate libxul
   {
-    nsAutoString xulPath(*gLibDirectory);
+    nsAutoString xulPath(gPaths->libDir);
 
     xulPath.Append(PR_GetDirectorySeparator());
 
 #if defined(XP_MACOSX)
     // Under MacOS X, for some reason, libxul is called simply "XUL"
     xulPath.Append(NS_LITERAL_STRING("XUL"));
 #else
     // On other platforms, libxul is a library "xul" with regular
     // library prefix/suffix
     xulPath.Append(NS_LITERAL_STRING(DLL_PREFIX));
     xulPath.Append(NS_LITERAL_STRING("xul"));
     xulPath.Append(NS_LITERAL_STRING(DLL_SUFFIX));
 #endif // defined(XP_MACOSX)
 
-    JSString* strPathToLibXUL = JS_NewUCStringCopyZ(cx, xulPath.get());
-    jsval valXul = STRING_TO_JSVAL(strPathToLibXUL);
-    if (!JS_SetProperty(cx, objPath, "libxul", &valXul)) {
+    if (!SetStringProperty(cx, objPath, "libxul", xulPath)) {
       return false;
     }
   }
 
+  if (!SetStringProperty(cx, objPath, "libDir", gPaths->libDir)) {
+    return false;
+  }
+
+  if (!SetStringProperty(cx, objPath, "tmpDir", gPaths->tmpDir)) {
+    return false;
+  }
+
+  if (!SetStringProperty(cx, objPath, "profileDir", gPaths->profileDir)) {
+    return false;
+  }
+
   return true;
 }
 
 NS_IMPL_ISUPPORTS1(OSFileConstantsService, nsIOSFileConstantsService)
 
 OSFileConstantsService::OSFileConstantsService()
 {
   MOZ_ASSERT(NS_IsMainThread());