Backed out changeset eae2252a519f (bug 1321593) for leaks, e.g. in clipboard and jetpack tests. r=backout
authorSebastian Hengst <archaeopteryx@coole-files.de>
Mon, 12 Dec 2016 22:10:17 +0100
changeset 325696 34405a5f3ec29f32e2c8a44132552693cbd14118
parent 325695 0ca33efe1b83fbc8968f59c87f7485710d82eb69
child 325697 5a9057b86e7b692f6281fcdfb0c8e5c1363c68ea
push id35031
push usercbook@mozilla.com
push dateTue, 13 Dec 2016 15:54:45 +0000
treeherderautoland@ca1d68c2fb54 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1321593
milestone53.0a1
backs outeae2252a519f3ac5850f5110a6a1be45891ea5e9
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset eae2252a519f (bug 1321593) for leaks, e.g. in clipboard and jetpack tests. r=backout
browser/app/nsBrowserApp.cpp
build/appini_header.py
mozglue/android/APKOpen.cpp
toolkit/xre/CreateAppData.cpp
toolkit/xre/ProfileReset.cpp
toolkit/xre/nsAndroidStartup.cpp
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsAppRunner.h
toolkit/xre/nsNativeAppSupportWin.cpp
xpcom/build/XREAppData.h
xpcom/build/moz.build
xpcom/build/nsXREAppData.h
xpcom/build/nsXULAppAPI.h
xpcom/glue/AppData.cpp
xpcom/glue/AppData.h
xpcom/glue/XREAppData.cpp
xpcom/glue/moz.build
xpcom/glue/objs.mozbuild
xpcom/system/nsIXULAppInfo.idl
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsXULAppAPI.h"
-#include "mozilla/XREAppData.h"
+#include "mozilla/AppData.h"
 #include "application.ini.h"
 #include "nsXPCOMGlue.h"
 #if defined(XP_WIN)
 #include <windows.h>
 #include <stdlib.h>
 #elif defined(XP_UNIX)
 #include <sys/resource.h>
 #include <unistd.h>
@@ -158,34 +158,36 @@ static bool IsArg(const char* arg, const
   if (*arg == '/')
     return !strcasecmp(++arg, s);
 #endif
 
   return false;
 }
 
 XRE_GetFileFromPathType XRE_GetFileFromPath;
-XRE_ParseAppDataType XRE_ParseAppData;
+XRE_CreateAppDataType XRE_CreateAppData;
+XRE_FreeAppDataType XRE_FreeAppData;
 XRE_TelemetryAccumulateType XRE_TelemetryAccumulate;
 XRE_StartupTimelineRecordType XRE_StartupTimelineRecord;
 XRE_mainType XRE_main;
 XRE_StopLateWriteChecksType XRE_StopLateWriteChecks;
 XRE_XPCShellMainType XRE_XPCShellMain;
 XRE_GetProcessTypeType XRE_GetProcessType;
 XRE_SetProcessTypeType XRE_SetProcessType;
 XRE_InitChildProcessType XRE_InitChildProcess;
 XRE_EnableSameExecutableForContentProcType XRE_EnableSameExecutableForContentProc;
 #ifdef LIBFUZZER
 XRE_LibFuzzerSetMainType XRE_LibFuzzerSetMain;
 XRE_LibFuzzerGetFuncsType XRE_LibFuzzerGetFuncs;
 #endif
 
 static const nsDynamicFunctionLoad kXULFuncs[] = {
     { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
-    { "XRE_ParseAppData", (NSFuncPtr*) &XRE_ParseAppData },
+    { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
+    { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
     { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate },
     { "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord },
     { "XRE_main", (NSFuncPtr*) &XRE_main },
     { "XRE_StopLateWriteChecks", (NSFuncPtr*) &XRE_StopLateWriteChecks },
     { "XRE_XPCShellMain", (NSFuncPtr*) &XRE_XPCShellMain },
     { "XRE_GetProcessType", (NSFuncPtr*) &XRE_GetProcessType },
     { "XRE_SetProcessType", (NSFuncPtr*) &XRE_SetProcessType },
     { "XRE_InitChildProcess", (NSFuncPtr*) &XRE_InitChildProcess },
@@ -255,53 +257,55 @@ static int do_main(int argc, char* argv[
     shellData.sandboxBrokerServices =
       sandboxing::GetInitializedBrokerServices();
 #endif
 
     return XRE_XPCShellMain(--argc, argv, envp, &shellData);
   }
 
   if (appini) {
-    XREAppData appData;
-    rv = XRE_ParseAppData(appini, appData);
+    nsXREAppData *appData;
+    rv = XRE_CreateAppData(appini, &appData);
     if (NS_FAILED(rv)) {
       Output("Couldn't read application.ini");
       return 255;
     }
 #if defined(HAS_DLL_BLOCKLIST)
     // The dll blocklist operates in the exe vs. xullib. Pass a flag to
     // xullib so automated tests can check the result once the browser
     // is up and running.
     appData->flags |=
       DllBlocklist_CheckStatus() ? NS_XRE_DLL_BLOCKLIST_ENABLED : 0;
 #endif
-    appData.xreDirectory = xreDirectory;
-    appini->GetParent(getter_AddRefs(appData.directory));
-    return XRE_main(argc, argv, appData, mainFlags);
+    // xreDirectory already has a refcount from NS_NewLocalFile
+    appData->xreDirectory = xreDirectory;
+    int result = XRE_main(argc, argv, appData, mainFlags);
+    XRE_FreeAppData(appData);
+    return result;
   }
 
-  XREAppData appData;
-  appData = sAppData;
+  ScopedAppData appData(&sAppData);
   nsCOMPtr<nsIFile> exeFile;
   rv = mozilla::BinaryPath::GetFile(argv[0], getter_AddRefs(exeFile));
   if (NS_FAILED(rv)) {
     Output("Couldn't find the application directory.\n");
     return 255;
   }
 
   nsCOMPtr<nsIFile> greDir;
   exeFile->GetParent(getter_AddRefs(greDir));
 #ifdef XP_MACOSX
   greDir->SetNativeLeafName(NS_LITERAL_CSTRING(kOSXResourcesFolder));
 #endif
   nsCOMPtr<nsIFile> appSubdir;
   greDir->Clone(getter_AddRefs(appSubdir));
   appSubdir->Append(NS_LITERAL_STRING(kDesktopFolder));
 
-  appData.directory = appSubdir;
+  SetStrongPtr(appData.directory, static_cast<nsIFile*>(appSubdir.get()));
+  // xreDirectory already has a refcount from NS_NewLocalFile
   appData.xreDirectory = xreDirectory;
 
 #if defined(HAS_DLL_BLOCKLIST)
   appData.flags |=
     DllBlocklist_CheckStatus() ? NS_XRE_DLL_BLOCKLIST_ENABLED : 0;
 #endif
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
@@ -316,17 +320,17 @@ static int do_main(int argc, char* argv[
   appData.sandboxBrokerServices = brokerServices;
 #endif
 
 #ifdef LIBFUZZER
   if (getenv("LIBFUZZER"))
     XRE_LibFuzzerSetMain(argc, argv, libfuzzer_main);
 #endif
 
-  return XRE_main(argc, argv, appData, mainFlags);
+  return XRE_main(argc, argv, &appData, mainFlags);
 }
 
 static bool
 FileExists(const char *path)
 {
 #ifdef XP_WIN
   wchar_t wideDir[MAX_PATH];
   MultiByteToWideChar(CP_UTF8, 0, path, -1, wideDir, MAX_PATH);
--- a/build/appini_header.py
+++ b/build/appini_header.py
@@ -1,14 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 '''Parses a given application.ini file and outputs the corresponding
-   StaticXREAppData structure as a C++ header file'''
+   XULAppData structure as a C++ header file'''
 
 import ConfigParser
 import sys
 
 def main(output, file):
     config = ConfigParser.RawConfigParser()
     config.read(file)
     flags = set()
@@ -29,26 +29,29 @@ def main(output, file):
     if missing:
         print >>sys.stderr, \
             "Missing values in %s: %s" % (file, ', '.join(missing))
         sys.exit(1)
 
     if not 'Crash Reporter:serverurl' in appdata:
         appdata['Crash Reporter:serverurl'] = ''
 
-    output.write('''#include "mozilla/XREAppData.h"
-             static const mozilla::StaticXREAppData sAppData = {
+    output.write('''#include "nsXREAppData.h"
+             static const nsXREAppData sAppData = {
+                 sizeof(nsXREAppData),
+                 NULL, // directory
                  "%(App:vendor)s",
                  "%(App:name)s",
                  "%(App:remotingname)s",
                  "%(App:version)s",
                  "%(App:buildid)s",
                  "%(App:id)s",
                  NULL, // copyright
                  %(flags)s,
+                 NULL, // xreDirectory
                  "%(Gecko:minversion)s",
                  "%(Gecko:maxversion)s",
                  "%(Crash Reporter:serverurl)s",
                  %(App:profile)s
              };''' % appdata)
 
 if __name__ == '__main__':
     if len(sys.argv) != 1:
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -439,17 +439,17 @@ FreeArgv(char** argv, int argc)
 {
   for (int ix=0; ix < argc; ix++) {
     // String was allocated with strndup, so need to use free to deallocate.
     free(argv[ix]);
   }
   delete[](argv);
 }
 
-typedef void (*GeckoStart_t)(JNIEnv*, char**, int, const StaticXREAppData&);
+typedef void (*GeckoStart_t)(JNIEnv*, char**, int, const nsXREAppData*);
 typedef int GeckoProcessType;
 
 extern "C" APKOPEN_EXPORT void MOZ_JNICALL
 Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jobjectArray jargs, int crashFd, int ipcFd)
 {
   int argc = 0;
   char** argv = CreateArgvFromObjectArray(jenv, jargs, &argc);
 
@@ -458,17 +458,17 @@ Java_org_mozilla_gecko_mozglue_GeckoLoad
     xul_dlsym("GeckoStart", &GeckoStart);
 
     if (GeckoStart == nullptr) {
       FreeArgv(argv, argc);
       return;
     }
 
     ElfLoader::Singleton.ExpectShutdown(false);
-    GeckoStart(jenv, argv, argc, sAppData);
+    GeckoStart(jenv, argv, argc, &sAppData);
     ElfLoader::Singleton.ExpectShutdown(true);
   } else {
     void (*fXRE_SetAndroidChildFds)(int, int);
     xul_dlsym("XRE_SetAndroidChildFds", &fXRE_SetAndroidChildFds);
 
     void (*fXRE_SetProcessType)(char*);
     xul_dlsym("XRE_SetProcessType", &fXRE_SetProcessType);
 
--- a/toolkit/xre/CreateAppData.cpp
+++ b/toolkit/xre/CreateAppData.cpp
@@ -2,76 +2,164 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsXULAppAPI.h"
 #include "nsINIParser.h"
 #include "nsIFile.h"
 #include "nsAutoPtr.h"
-#include "mozilla/XREAppData.h"
+#include "mozilla/AppData.h"
 
 using namespace mozilla;
 
-static void
-ReadString(nsINIParser &parser, const char* section,
-           const char* key, XREAppData::CharPtr& result)
+nsresult
+XRE_CreateAppData(nsIFile* aINIFile, nsXREAppData **aAppData)
 {
+  NS_ENSURE_ARG(aINIFile && aAppData);
+
+  nsAutoPtr<ScopedAppData> data(new ScopedAppData());
+  if (!data)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  nsresult rv = XRE_ParseAppData(aINIFile, data);
+  if (NS_FAILED(rv))
+    return rv;
+
+  if (!data->directory) {
+    nsCOMPtr<nsIFile> appDir;
+    rv = aINIFile->GetParent(getter_AddRefs(appDir));
+    if (NS_FAILED(rv))
+      return rv;
+
+    appDir.forget(&data->directory);
+  }
+
+  *aAppData = data.forget();
+  return NS_OK;
+}
+
+struct ReadString {
+  const char *section;
+  const char *key;
+  const char **buffer;
+};
+
+static void
+ReadStrings(nsINIParser &parser, const ReadString *reads)
+{
+  nsresult rv;
   nsCString str;
-  nsresult rv = parser.GetString(section, key, str);
-  if (NS_SUCCEEDED(rv)) {
-    result = str.get();
+
+  while (reads->section) {
+    rv = parser.GetString(reads->section, reads->key, str);
+    if (NS_SUCCEEDED(rv)) {
+      SetAllocatedString(*reads->buffer, str);
+    }
+
+    ++reads;
   }
 }
 
 struct ReadFlag {
   const char *section;
   const char *key;
   uint32_t flag;
 };
 
 static void
-ReadFlag(nsINIParser &parser, const char* section,
-         const char* key, uint32_t flag, uint32_t& result)
+ReadFlags(nsINIParser &parser, const ReadFlag *reads, uint32_t *buffer)
 {
+  nsresult rv;
   char buf[6]; // large enough to hold "false"
-  nsresult rv = parser.GetString(section, key, buf, sizeof(buf));
-  if (NS_SUCCEEDED(rv) || rv == NS_ERROR_LOSS_OF_SIGNIFICANT_DATA) {
-    if (buf[0] == '1' || buf[0] == 't' || buf[0] == 'T') {
-      result |= flag;
+
+  while (reads->section) {
+    rv = parser.GetString(reads->section, reads->key, buf, sizeof(buf));
+    if (NS_SUCCEEDED(rv) || rv == NS_ERROR_LOSS_OF_SIGNIFICANT_DATA) {
+      if (buf[0] == '1' || buf[0] == 't' || buf[0] == 'T') {
+        *buffer |= reads->flag;
+      }
+      if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
+        *buffer &= ~reads->flag;
+      }
     }
-    if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
-      result &= ~flag;
-    }
+
+    ++reads;
   }
 }
 
 nsresult
-XRE_ParseAppData(nsIFile* aINIFile, XREAppData& aAppData)
+XRE_ParseAppData(nsIFile* aINIFile, nsXREAppData *aAppData)
 {
-  NS_ENSURE_ARG(aINIFile);
+  NS_ENSURE_ARG(aINIFile && aAppData);
 
   nsresult rv;
 
   nsINIParser parser;
   rv = parser.Init(aINIFile);
   if (NS_FAILED(rv))
     return rv;
 
-  ReadString(parser, "App", "Vendor", aAppData.vendor);
-  ReadString(parser, "App", "Name", aAppData.name),
-  ReadString(parser, "App", "RemotingName", aAppData.remotingName);
-  ReadString(parser, "App", "Version", aAppData.version);
-  ReadString(parser, "App", "BuildID", aAppData.buildID);
-  ReadString(parser, "App", "ID", aAppData.ID);
-  ReadString(parser, "App", "Copyright", aAppData.copyright);
-  ReadString(parser, "App", "Profile", aAppData.profile);
-  ReadString(parser, "Gecko", "MinVersion", aAppData.minVersion);
-  ReadString(parser, "Gecko", "MaxVersion", aAppData.maxVersion);
-  ReadString(parser, "Crash Reporter", "ServerURL", aAppData.crashReporterURL);
-  ReadString(parser, "App", "UAName", aAppData.UAName);
-  ReadFlag(parser, "XRE", "EnableProfileMigrator",
-           NS_XRE_ENABLE_PROFILE_MIGRATOR, aAppData.flags);
-  ReadFlag(parser, "Crash Reporter", "Enabled",
-           NS_XRE_ENABLE_CRASH_REPORTER, aAppData.flags);
+  nsCString str;
+
+  ReadString strings[] = {
+    { "App", "Vendor",        &aAppData->vendor },
+    { "App", "Name",          &aAppData->name },
+    { "App", "RemotingName",  &aAppData->remotingName },
+    { "App", "Version",       &aAppData->version },
+    { "App", "BuildID",       &aAppData->buildID },
+    { "App", "ID",            &aAppData->ID },
+    { "App", "Copyright",     &aAppData->copyright },
+    { "App", "Profile",       &aAppData->profile },
+    { nullptr }
+  };
+  ReadStrings(parser, strings);
+
+  ReadFlag flags[] = {
+    { "XRE", "EnableProfileMigrator", NS_XRE_ENABLE_PROFILE_MIGRATOR },
+    { nullptr }
+  };
+  ReadFlags(parser, flags, &aAppData->flags);
+
+  if (aAppData->size > offsetof(nsXREAppData, xreDirectory)) {
+    ReadString strings2[] = {
+      { "Gecko", "MinVersion", &aAppData->minVersion },
+      { "Gecko", "MaxVersion", &aAppData->maxVersion },
+      { nullptr }
+    };
+    ReadStrings(parser, strings2);
+  }
+
+  if (aAppData->size > offsetof(nsXREAppData, crashReporterURL)) {
+    ReadString strings3[] = {
+      { "Crash Reporter", "ServerURL", &aAppData->crashReporterURL },
+      { nullptr }
+    };
+    ReadStrings(parser, strings3);
+    ReadFlag flags2[] = {
+      { "Crash Reporter", "Enabled", NS_XRE_ENABLE_CRASH_REPORTER },
+      { nullptr }
+    };
+    ReadFlags(parser, flags2, &aAppData->flags);
+  }
+
+  if (aAppData->size > offsetof(nsXREAppData, UAName)) {
+    ReadString strings4[] = {
+      { "App", "UAName",    &aAppData->UAName },
+      { nullptr }
+    };
+    ReadStrings(parser, strings4);
+  }
 
   return NS_OK;
 }
+
+void
+XRE_FreeAppData(nsXREAppData *aAppData)
+{
+  if (!aAppData) {
+    NS_ERROR("Invalid arg");
+    return;
+  }
+
+  ScopedAppData* sad = static_cast<ScopedAppData*>(aAppData);
+  delete sad;
+}
--- a/toolkit/xre/ProfileReset.cpp
+++ b/toolkit/xre/ProfileReset.cpp
@@ -10,27 +10,24 @@
 #include "nsIWindowWatcher.h"
 
 #include "ProfileReset.h"
 
 #include "nsDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
-#include "nsString.h"
 #include "nsToolkitCompsCID.h"
 #include "nsXPCOMCIDInternal.h"
-#include "mozilla/XREAppData.h"
+#include "nsXREAppData.h"
 
 #include "mozilla/Services.h"
 #include "prtime.h"
 
-using namespace mozilla;
-
-extern const XREAppData* gAppData;
+extern const nsXREAppData* gAppData;
 
 static const char kProfileProperties[] =
   "chrome://mozapps/locale/profile/profileSelection.properties";
 
 /**
  * Creates a new profile with a timestamp in the name to use for profile reset.
  */
 nsresult
--- a/toolkit/xre/nsAndroidStartup.cpp
+++ b/toolkit/xre/nsAndroidStartup.cpp
@@ -16,20 +16,18 @@
 #include "nsString.h"
 #include "nsIFile.h"
 #include "nsAppRunner.h"
 #include "APKOpen.h"
 #include "nsExceptionHandler.h"
 
 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, MOZ_APP_NAME, args)
 
-using namespace mozilla;
-
 extern "C" NS_EXPORT void
-GeckoStart(JNIEnv* env, char** argv, int argc, const StaticXREAppData& aAppData)
+GeckoStart(JNIEnv* env, char** argv, int argc, const nsXREAppData* appData)
 {
     mozilla::jni::SetGeckoThreadEnv(env);
 
 #ifdef MOZ_CRASHREPORTER
     const struct mapping_info *info = getLibraryMapping();
     while (info->name) {
       CrashReporter::AddLibraryMapping(info->name, info->base,
                                        info->len, info->offset);
@@ -37,16 +35,13 @@ GeckoStart(JNIEnv* env, char** argv, int
     }
 #endif
 
     if (!argv) {
         LOG("Failed to get arguments for GeckoStart\n");
         return;
     }
 
-    XREAppData appData;
-    appData = aAppData;
-
     int result = XRE_main(argc, argv, appData, 0);
 
     if (result)
         LOG("XRE_main returned %d", result);
 }
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -16,17 +16,17 @@
 #include "mozilla/Poison.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Services.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsAppRunner.h"
-#include "mozilla/XREAppData.h"
+#include "mozilla/AppData.h"
 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
 #include "nsUpdateDriver.h"
 #endif
 #include "ProfileReset.h"
 
 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
 #include "EventTracer.h"
 #endif
@@ -1603,33 +1603,33 @@ DumpHelp()
 
 #ifdef MOZ_X11
   printf("X11 options\n"
          "  --display=DISPLAY  X display to use\n"
          "  --sync             Make X calls synchronous\n");
 #endif
 #ifdef XP_UNIX
   printf("  --g-fatal-warnings Make all warnings fatal\n"
-         "\n%s options\n", (const char*) gAppData->name);
+         "\n%s options\n", gAppData->name);
 #endif
 
   printf("  -h or --help       Print this message.\n"
          "  -v or --version    Print %s version.\n"
          "  -P <profile>       Start with <profile>.\n"
          "  --profile <path>   Start with profile at <path>.\n"
          "  --migration        Start with migration wizard.\n"
          "  --ProfileManager   Start with ProfileManager.\n"
          "  --no-remote        Do not accept or send remote commands; implies\n"
          "                     --new-instance.\n"
          "  --new-instance     Open new instance, not a new window in running instance.\n"
          "  --UILocale <locale> Start with <locale> resources as UI Locale.\n"
-         "  --safe-mode        Disables extensions and themes for this session.\n", (const char*) gAppData->name);
+         "  --safe-mode        Disables extensions and themes for this session.\n", gAppData->name);
 
 #if defined(XP_WIN)
-  printf("  --console          Start %s with a debugging console.\n", (const char*) gAppData->name);
+  printf("  --console          Start %s with a debugging console.\n", gAppData->name);
 #endif
 
   // this works, but only after the components have registered.  so if you drop in a new command line handler, --help
   // won't not until the second run.
   // out of the bug, because we ship a component.reg file, it works correctly.
   DumpArbitraryHelp();
 }
 
@@ -1674,20 +1674,20 @@ static int MSCRTReportHook( int aReportT
 }
 
 #endif
 
 static inline void
 DumpVersion()
 {
   if (gAppData->vendor)
-    printf("%s ", (const char*) gAppData->vendor);
-  printf("%s %s", (const char*) gAppData->name, (const char*) gAppData->version);
+    printf("%s ", gAppData->vendor);
+  printf("%s %s", gAppData->name, gAppData->version);
   if (gAppData->copyright)
-      printf(", %s", (const char*) gAppData->copyright);
+      printf(", %s", gAppData->copyright);
   printf("\n");
 }
 
 #ifdef MOZ_ENABLE_XREMOTE
 static RemoteResult
 ParseRemoteCommandLine(nsCString& program,
                        const char** profile,
                        const char** username)
@@ -2798,17 +2798,17 @@ static void MakeOrSetMinidumpPath(nsIFil
 
     nsAutoString pathStr;
     if (NS_SUCCEEDED(dumpD->GetPath(pathStr)))
       CrashReporter::SetMinidumpPath(pathStr);
   }
 }
 #endif
 
-const XREAppData* gAppData = nullptr;
+const nsXREAppData* gAppData = nullptr;
 
 #ifdef MOZ_WIDGET_GTK
 static void MOZ_gdk_display_close(GdkDisplay *display)
 {
 #if CLEANUP_MEMORY
   // XXX wallpaper for bug 417163: don't close the Display if we're using the
   // Qt theme because we crash (in Qt code) when using jemalloc.
   bool skip_display_close = false;
@@ -3015,34 +3015,34 @@ public:
 #endif
   {};
 
   ~XREMain() {
     mScopedXPCOM = nullptr;
     mAppData = nullptr;
   }
 
-  int XRE_main(int argc, char* argv[], const XREAppData& aAppData);
+  int XRE_main(int argc, char* argv[], const nsXREAppData* aAppData);
   int XRE_mainInit(bool* aExitFlag);
   int XRE_mainStartup(bool* aExitFlag);
   nsresult XRE_mainRun();
 
   nsCOMPtr<nsINativeAppSupport> mNativeApp;
   nsCOMPtr<nsIToolkitProfileService> mProfileSvc;
   nsCOMPtr<nsIFile> mProfD;
   nsCOMPtr<nsIFile> mProfLD;
   nsCOMPtr<nsIProfileLock> mProfileLock;
 #ifdef MOZ_ENABLE_XREMOTE
   nsCOMPtr<nsIRemoteService> mRemoteService;
   nsProfileLock mRemoteLock;
   nsCOMPtr<nsIFile> mRemoteLockDir;
 #endif
 
   UniquePtr<ScopedXPCOMStartup> mScopedXPCOM;
-  UniquePtr<XREAppData> mAppData;
+  nsAutoPtr<mozilla::ScopedAppData> mAppData;
 
   nsXREDirProvider mDirProvider;
   nsAutoCString mProfileName;
   nsAutoCString mDesktopStartupID;
 
   bool mStartOffline;
   bool mShuttingDown;
 #ifdef MOZ_ENABLE_XREMOTE
@@ -3154,17 +3154,17 @@ XREMain::XRE_mainInit(bool* aExitFlag)
   else if (ar == ARG_FOUND) {
     nsCOMPtr<nsIFile> overrideLF;
     rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF));
     if (NS_FAILED(rv)) {
       Output(true, "Error: unrecognized override.ini path.\n");
       return 1;
     }
 
-    rv = XRE_ParseAppData(overrideLF, *mAppData);
+    rv = XRE_ParseAppData(overrideLF, mAppData.get());
     if (NS_FAILED(rv)) {
       Output(true, "Couldn't read override.ini");
       return 1;
     }
   }
 
   // Check sanity and correctness of app data.
 
@@ -3193,41 +3193,43 @@ XREMain::XRE_mainInit(bool* aExitFlag)
 
 #ifdef XP_MACOSX
     nsCOMPtr<nsIFile> parent;
     greDir->GetParent(getter_AddRefs(parent));
     greDir = parent.forget();
     greDir->AppendNative(NS_LITERAL_CSTRING("Resources"));
 #endif
 
-    mAppData->xreDirectory = greDir;
+    greDir.forget(&mAppData->xreDirectory);
   }
 
   if (!mAppData->directory) {
-    mAppData->directory = mAppData->xreDirectory;
-  }
-
-  if (!mAppData->minVersion) {
-    Output(true, "Error: Gecko:MinVersion not specified in application.ini\n");
-    return 1;
+    NS_IF_ADDREF(mAppData->directory = mAppData->xreDirectory);
   }
 
-  if (!mAppData->maxVersion) {
-    // If no maxVersion is specified, we assume the app is only compatible
-    // with the initial preview release. Do not increment this number ever!
-    mAppData->maxVersion = "1.*";
-  }
-
-  if (mozilla::Version(mAppData->minVersion) > gToolkitVersion ||
-      mozilla::Version(mAppData->maxVersion) < gToolkitVersion) {
-    Output(true, "Error: Platform version '%s' is not compatible with\n"
-           "minVersion >= %s\nmaxVersion <= %s\n",
-           (const char*) gToolkitVersion, (const char*) mAppData->minVersion,
-           (const char*) mAppData->maxVersion);
-    return 1;
+  if (mAppData->size > offsetof(nsXREAppData, minVersion)) {
+    if (!mAppData->minVersion) {
+      Output(true, "Error: Gecko:MinVersion not specified in application.ini\n");
+      return 1;
+    }
+
+    if (!mAppData->maxVersion) {
+      // If no maxVersion is specified, we assume the app is only compatible
+      // with the initial preview release. Do not increment this number ever!
+      SetAllocatedString(mAppData->maxVersion, "1.*");
+    }
+
+    if (mozilla::Version(mAppData->minVersion) > gToolkitVersion ||
+        mozilla::Version(mAppData->maxVersion) < gToolkitVersion) {
+      Output(true, "Error: Platform version '%s' is not compatible with\n"
+             "minVersion >= %s\nmaxVersion <= %s\n",
+             gToolkitVersion,
+             mAppData->minVersion, mAppData->maxVersion);
+      return 1;
+    }
   }
 
   rv = mDirProvider.Initialize(mAppData->directory, mAppData->xreDirectory);
   if (NS_FAILED(rv))
     return 1;
 
 #ifdef MOZ_CRASHREPORTER
   if (EnvHasValue("MOZ_CRASHREPORTER")) {
@@ -4525,17 +4527,17 @@ XRE_CreateStatsObject()
 }
 
 /*
  * XRE_main - A class based main entry point used by most platforms.
  *            Note that on OSX, aAppData->xreDirectory will point to
  *            .app/Contents/Resources.
  */
 int
-XREMain::XRE_main(int argc, char* argv[], const XREAppData& aAppData)
+XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
 {
   ScopedLogging log;
 
   // NB: this must happen after the creation of |ScopedLogging log| since
   // ScopedLogging::ScopedLogging calls NS_LogInit, and
   // XRE_CreateStatsObject calls Telemetry::CreateStatisticsRecorder,
   // and NS_LogInit must be called before Telemetry::CreateStatisticsRecorder.
   // NS_LogInit must be called before Telemetry::CreateStatisticsRecorder
@@ -4554,22 +4556,26 @@ XREMain::XRE_main(int argc, char* argv[]
   PROFILER_LABEL("Startup", "XRE_Main",
     js::ProfileEntry::Category::OTHER);
 
   nsresult rv = NS_OK;
 
   gArgc = argc;
   gArgv = argv;
 
-  mAppData = MakeUnique<XREAppData>(aAppData);
+  NS_ENSURE_TRUE(aAppData, 2);
+
+  mAppData = new ScopedAppData(aAppData);
+  if (!mAppData)
+    return 1;
   if (!mAppData->remotingName) {
-    mAppData->remotingName = mAppData->name;
+    SetAllocatedString(mAppData->remotingName, mAppData->name);
   }
   // used throughout this file
-  gAppData = mAppData.get();
+  gAppData = mAppData;
 
   nsCOMPtr<nsIFile> binFile;
   rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(binFile));
   NS_ENSURE_SUCCESS(rv, 1);
 
   rv = binFile->GetPath(gAbsoluteArgv0Path);
   NS_ENSURE_SUCCESS(rv, 1);
 
@@ -4691,17 +4697,17 @@ XREMain::XRE_main(int argc, char* argv[]
 }
 
 void
 XRE_StopLateWriteChecks(void) {
   mozilla::StopLateWriteChecks();
 }
 
 int
-XRE_main(int argc, char* argv[], const XREAppData& aAppData, uint32_t aFlags)
+XRE_main(int argc, char* argv[], const nsXREAppData* aAppData, uint32_t aFlags)
 {
   XREMain main;
 
   int result = main.XRE_main(argc, argv, aAppData);
   mozilla::RecordShutdownEndTimeStamp();
   return result;
 }
 
--- a/toolkit/xre/nsAppRunner.h
+++ b/toolkit/xre/nsAppRunner.h
@@ -37,18 +37,20 @@ class nsIToolkitProfileService;
 class nsIFile;
 class nsIProfileLock;
 class nsIProfileUnlocker;
 class nsIFactory;
 class nsString;
 
 extern nsXREDirProvider* gDirServiceProvider;
 
-// NOTE: gAppData will be null in embedded contexts.
-extern const mozilla::XREAppData* gAppData;
+// NOTE: gAppData will be null in embedded contexts. The "size" parameter
+// will be the size of the original structure passed to XRE_main, but the
+// structure will have all of the members available.
+extern const nsXREAppData* gAppData;
 extern bool gSafeMode;
 
 extern int    gArgc;
 extern char **gArgv;
 extern int    gRestartArgc;
 extern char **gRestartArgv;
 extern bool gLogConsoleErrors;
 extern nsString gAbsoluteArgv0Path;
--- a/toolkit/xre/nsNativeAppSupportWin.cpp
+++ b/toolkit/xre/nsNativeAppSupportWin.cpp
@@ -680,17 +680,17 @@ nsNativeAppSupportWin::StartDDE() {
     // Initialize DDE.
     NS_ENSURE_TRUE( DMLERR_NO_ERROR == DdeInitialize( &mInstance,
                                                       nsNativeAppSupportWin::HandleDDENotification,
                                                       APPCLASS_STANDARD,
                                                       0 ),
                     NS_ERROR_FAILURE );
 
     // Allocate DDE strings.
-    NS_ENSURE_TRUE( ( mApplication = DdeCreateStringHandleA( mInstance, (char*)(const char*) gAppData->name, CP_WINANSI ) ) && InitTopicStrings(),
+    NS_ENSURE_TRUE( ( mApplication = DdeCreateStringHandleA( mInstance, (char*) gAppData->name, CP_WINANSI ) ) && InitTopicStrings(),
                     NS_ERROR_FAILURE );
 
     // Next step is to register a DDE service.
     NS_ENSURE_TRUE( DdeNameService( mInstance, mApplication, 0, DNS_REGISTER ), NS_ERROR_FAILURE );
 
 #if MOZ_DEBUG_DDE
     printf( "DDE server started\n" );
 #endif
--- a/xpcom/build/moz.build
+++ b/xpcom/build/moz.build
@@ -3,32 +3,32 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 EXPORTS += [
     'nsXPCOM.h',
     'nsXPCOMCID.h',
     'nsXPCOMCIDInternal.h',
+    'nsXREAppData.h',
     'nsXULAppAPI.h',
     'XREChildData.h',
     'xrecore.h',
     'XREShellData.h',
 ]
 
 EXPORTS.mozilla += [
     'FileLocation.h',
     'IOInterposer.h',
     'LateWriteChecks.h',
     'Omnijar.h',
     'PoisonIOInterposer.h',
     'ServiceList.h',
     'Services.h',
     'XPCOM.h',
-    'XREAppData.h',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     EXPORTS += ['nsWindowsDllInterceptor.h']
     EXPORTS.mozilla += ['perfprobe.h']
     SOURCES += [
         'perfprobe.cpp',
         'PoisonIOInterposerBase.cpp',
rename from xpcom/build/XREAppData.h
rename to xpcom/build/nsXREAppData.h
--- a/xpcom/build/XREAppData.h
+++ b/xpcom/build/nsXREAppData.h
@@ -4,196 +4,147 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsXREAppData_h
 #define nsXREAppData_h
 
 #include <stdint.h>
 #include "mozilla/Attributes.h"
-#include "nsCOMPtr.h"
-#include "nsCRTGlue.h"
-#include "nsIFile.h"
+
+class nsIFile;
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 namespace sandbox {
 class BrokerServices;
 }
 #endif
 
-namespace mozilla {
-
-struct StaticXREAppData;
-
 /**
  * Application-specific data needed to start the apprunner.
+ *
+ * @note When this structure is allocated and manipulated by XRE_CreateAppData,
+ *       string fields will be allocated with moz_xmalloc, and interface pointers
+ *       are strong references.
  */
-class XREAppData
+struct nsXREAppData
 {
-public:
-  XREAppData() { }
-  ~XREAppData() { }
-  XREAppData(const XREAppData& aOther)
-  {
-    *this = aOther;
-  }
-
-  XREAppData& operator=(const StaticXREAppData& aOther);
-  XREAppData& operator=(const XREAppData& aOther);
-  XREAppData& operator=(XREAppData&& aOther) = default;
-
-  struct NSFreePolicy
-  {
-    void operator()(const void* ptr) {
-      NS_Free(const_cast<void*>(ptr));
-    }
-  };
-
-  // Lots of code reads these fields directly like a struct, so rather
-  // than using UniquePtr directly, use an auto-converting wrapper.
-  class CharPtr
-  {
-  public:
-    explicit CharPtr() = default;
-    explicit CharPtr(const char* v)
-    {
-      *this = v;
-    }
-    CharPtr(CharPtr&&) = default;
-    ~CharPtr() = default;
-
-    CharPtr& operator=(const char* v)
-    {
-      if (v) {
-        mValue.reset(NS_strdup(v));
-      } else {
-        mValue = nullptr;
-      }
-      return *this;
-    }
-    CharPtr& operator=(const CharPtr& v)
-    {
-      *this = (const char*) v;
-      return *this;
-    }
-
-    operator const char*() const {
-      return mValue.get();
-    }
-
-  private:
-    UniquePtr<const char, NSFreePolicy> mValue;
-  };
+  /**
+   * This should be set to sizeof(nsXREAppData). This structure may be
+   * extended in future releases, and this ensures that binary compatibility
+   * is maintained.
+   */
+  uint32_t size;
 
   /**
    * The directory of the application to be run. May be null if the
    * xulrunner and the app are installed into the same directory.
    */
-  nsCOMPtr<nsIFile> directory;
+  nsIFile* MOZ_NON_OWNING_REF directory;
 
   /**
    * The name of the application vendor. This must be ASCII, and is normally
    * mixed-case, e.g. "Mozilla". Optional (may be null), but highly
    * recommended. Must not be the empty string.
    */
-  CharPtr vendor;
+  const char* vendor;
 
   /**
    * The name of the application. This must be ASCII, and is normally
    * mixed-case, e.g. "Firefox". Required (must not be null or an empty
    * string).
    */
-  CharPtr name;
+  const char* name;
 
   /**
    * The internal name of the application for remoting purposes. When left
    * unspecified, "name" is used instead. This must be ASCII, and is normally
    * lowercase, e.g. "firefox". Optional (may be null but not an empty string).
    */
-  CharPtr remotingName;
+  const char* remotingName;
 
   /**
    * The major version, e.g. "0.8.0+". Optional (may be null), but
    * required for advanced application features such as the extension
    * manager and update service. Must not be the empty string.
    */
-  CharPtr version;
+  const char* version;
 
   /**
    * The application's build identifier, e.g. "2004051604"
    */
-  CharPtr buildID;
+  const char* buildID;
 
   /**
    * The application's UUID. Used by the extension manager to determine
    * compatible extensions. Optional, but required for advanced application
    * features such as the extension manager and update service.
    *
    * This has traditionally been in the form
    * "{AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE}" but for new applications
    * a more readable form is encouraged: "appname@vendor.tld". Only
    * the following characters are allowed: a-z A-Z 0-9 - . @ _ { } *
    */
-  CharPtr ID;
+  const char* ID;
 
   /**
    * The copyright information to print for the -h commandline flag,
    * e.g. "Copyright (c) 2003 mozilla.org".
    */
-  CharPtr copyright;
+  const char* copyright;
 
   /**
    * Combination of NS_XRE_ prefixed flags (defined below).
    */
-  uint32_t flags = 0;
+  uint32_t flags;
 
   /**
    * The location of the XRE. XRE_main may not be able to figure this out
    * programatically.
    */
-  nsCOMPtr<nsIFile> xreDirectory;
+  nsIFile* MOZ_NON_OWNING_REF xreDirectory;
 
   /**
    * The minimum/maximum compatible XRE version.
    */
-  CharPtr minVersion;
-  CharPtr maxVersion;
+  const char* minVersion;
+  const char* maxVersion;
 
   /**
    * The server URL to send crash reports to.
    */
-  CharPtr crashReporterURL;
+  const char* crashReporterURL;
 
   /**
    * The profile directory that will be used. Optional (may be null). Must not
    * be the empty string, must be ASCII. The path is split into components
    * along the path separator characters '/' and '\'.
    *
    * The application data directory ("UAppData", see below) is normally
    * composed as follows, where $HOME is platform-specific:
    *
    *   UAppData = $HOME[/$vendor]/$name
    *
    * If present, the 'profile' string will be used instead of the combination of
    * vendor and name as follows:
    *
    *   UAppData = $HOME/$profile
    */
-  CharPtr profile;
+  const char* profile;
 
   /**
    * The application name to use in the User Agent string.
    */
-  CharPtr UAName;
+  const char* UAName;
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
   /**
    * Chromium sandbox BrokerServices.
    */
-  sandbox::BrokerServices* sandboxBrokerServices = nullptr;
+  sandbox::BrokerServices* sandboxBrokerServices;
 #endif
 };
 
 /**
  * Indicates whether or not the profile migrator service may be
  * invoked at startup when creating a profile.
  */
 #define NS_XRE_ENABLE_PROFILE_MIGRATOR (1 << 1)
@@ -205,34 +156,9 @@ public:
  */
 #define NS_XRE_DLL_BLOCKLIST_ENABLED (1 << 2)
 
 /**
  * Indicates whether or not to use Breakpad crash reporting.
  */
 #define NS_XRE_ENABLE_CRASH_REPORTER (1 << 3)
 
-/**
- * A static version of the XRE app data is compiled into the application
- * so that it is not necessary to read application.ini at startup.
- *
- * This structure is initialized into and matches nsXREAppData
- */
-struct StaticXREAppData
-{
-  const char* vendor;
-  const char* name;
-  const char* remotingName;
-  const char* version;
-  const char* buildID;
-  const char* ID;
-  const char* copyright;
-  uint32_t flags;
-  const char* minVersion;
-  const char* maxVersion;
-  const char* crashReporterURL;
-  const char* profile;
-  const char* UAName;
-};
-
-} // namespace mozilla
-
-#endif // XREAppData_h
+#endif // nsXREAppData_h
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -7,17 +7,17 @@
 #ifndef _nsXULAppAPI_h__
 #define _nsXULAppAPI_h__
 
 #include "nsID.h"
 #include "xrecore.h"
 #include "nsXPCOM.h"
 #include "nsISupports.h"
 #include "mozilla/Logging.h"
-#include "mozilla/XREAppData.h"
+#include "nsXREAppData.h"
 #include "js/TypeDecls.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Vector.h"
 #include "mozilla/TimeStamp.h"
 #include "XREChildData.h"
 #include "XREShellData.h"
@@ -199,17 +199,17 @@
  * @param aFlags    Platform specific flags.
  *
  * @return         A native result code suitable for returning from main().
  *
  * @note           If the binary is linked against the standalone XPCOM glue,
  *                 XPCOMGlueStartup() should be called before this method.
  */
 XRE_API(int,
-        XRE_main, (int argc, char* argv[], const mozilla::XREAppData& aAppData,
+        XRE_main, (int argc, char* argv[], const nsXREAppData* aAppData,
                    uint32_t aFlags))
 
 /**
  * Given a path relative to the current working directory (or an absolute
  * path), return an appropriate nsIFile object.
  *
  * @note Pass UTF8 strings on Windows... native charset on other platforms.
  */
@@ -357,25 +357,43 @@ XRE_API(void,
 
 /**
  * Terminate embedding started with XRE_InitEmbedding or XRE_InitEmbedding2
  */
 XRE_API(void,
         XRE_TermEmbedding, ())
 
 /**
+ * Create a new nsXREAppData structure from an application.ini file.
+ *
+ * @param aINIFile The application.ini file to parse.
+ * @param aAppData A newly-allocated nsXREAppData structure. The caller is
+ *                 responsible for freeing this structure using
+ *                 XRE_FreeAppData.
+ */
+XRE_API(nsresult,
+        XRE_CreateAppData, (nsIFile* aINIFile,
+                            nsXREAppData** aAppData))
+
+/**
  * Parse an INI file (application.ini or override.ini) into an existing
  * nsXREAppData structure.
  *
  * @param aINIFile The INI file to parse
  * @param aAppData The nsXREAppData structure to fill.
  */
 XRE_API(nsresult,
         XRE_ParseAppData, (nsIFile* aINIFile,
-                           mozilla::XREAppData& aAppData))
+                           nsXREAppData* aAppData))
+
+/**
+ * Free a nsXREAppData structure that was allocated with XRE_CreateAppData.
+ */
+XRE_API(void,
+        XRE_FreeAppData, (nsXREAppData* aAppData))
 
 enum GeckoProcessType
 {
   GeckoProcessType_Default = 0,
 
   GeckoProcessType_Plugin,
   GeckoProcessType_Content,
 
rename from xpcom/glue/XREAppData.cpp
rename to xpcom/glue/AppData.cpp
--- a/xpcom/glue/XREAppData.cpp
+++ b/xpcom/glue/AppData.cpp
@@ -1,56 +1,95 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/XREAppData.h"
+#include "mozilla/AppData.h"
+#include "nsXULAppAPI.h"
+#include "nsINIParser.h"
+#include "nsIFile.h"
 #include "nsCRTGlue.h"
+#include "nsAutoPtr.h"
 
 namespace mozilla {
 
-XREAppData&
-XREAppData::operator=(const StaticXREAppData& aOther)
+void
+SetAllocatedString(const char*& aStr, const char* aNewValue)
 {
-  vendor = aOther.vendor;
-  name = aOther.name;
-  remotingName = aOther.remotingName;
-  version = aOther.version;
-  buildID = aOther.buildID;
-  ID = aOther.ID;
-  copyright = aOther.copyright;
-  flags = aOther.flags;
-  minVersion = aOther.minVersion;
-  maxVersion = aOther.maxVersion;
-  crashReporterURL = aOther.crashReporterURL;
-  profile = aOther.profile;
-  UAName = aOther.UAName;
+  NS_Free(const_cast<char*>(aStr));
+  if (aNewValue) {
+    aStr = NS_strdup(aNewValue);
+  } else {
+    aStr = nullptr;
+  }
+}
 
-  return *this;
+void
+SetAllocatedString(const char*& aStr, const nsACString& aNewValue)
+{
+  NS_Free(const_cast<char*>(aStr));
+  if (aNewValue.IsEmpty()) {
+    aStr = nullptr;
+  } else {
+    aStr = ToNewCString(aNewValue);
+  }
 }
 
-XREAppData&
-XREAppData::operator=(const XREAppData& aOther)
+ScopedAppData::ScopedAppData(const nsXREAppData* aAppData)
 {
-  directory = aOther.directory;
-  vendor = aOther.vendor;
-  name = aOther.name;
-  remotingName = aOther.remotingName;
-  version = aOther.version;
-  buildID = aOther.buildID;
-  ID = aOther.ID;
-  copyright = aOther.copyright;
-  flags = aOther.flags;
-  xreDirectory = aOther.xreDirectory;
-  minVersion = aOther.minVersion;
-  maxVersion = aOther.maxVersion;
-  crashReporterURL = aOther.crashReporterURL;
-  profile = aOther.profile;
-  UAName = aOther.UAName;
+  Zero();
+
+  this->size = aAppData->size;
+
+  SetAllocatedString(this->vendor, aAppData->vendor);
+  SetAllocatedString(this->name, aAppData->name);
+  SetAllocatedString(this->remotingName, aAppData->remotingName);
+  SetAllocatedString(this->version, aAppData->version);
+  SetAllocatedString(this->buildID, aAppData->buildID);
+  SetAllocatedString(this->ID, aAppData->ID);
+  SetAllocatedString(this->copyright, aAppData->copyright);
+  SetAllocatedString(this->profile, aAppData->profile);
+  SetStrongPtr(this->directory, aAppData->directory);
+  this->flags = aAppData->flags;
+
+  if (aAppData->size > offsetof(nsXREAppData, xreDirectory)) {
+    SetStrongPtr(this->xreDirectory, aAppData->xreDirectory);
+    SetAllocatedString(this->minVersion, aAppData->minVersion);
+    SetAllocatedString(this->maxVersion, aAppData->maxVersion);
+  }
+
+  if (aAppData->size > offsetof(nsXREAppData, crashReporterURL)) {
+    SetAllocatedString(this->crashReporterURL, aAppData->crashReporterURL);
+  }
+
+  if (aAppData->size > offsetof(nsXREAppData, UAName)) {
+    SetAllocatedString(this->UAName, aAppData->UAName);
+  }
+
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
-  sandboxBrokerServices = aOther.sandboxBrokerServices;
+  sandboxBrokerServices = aAppData->sandboxBrokerServices;
 #endif
-  return *this;
+}
+
+ScopedAppData::~ScopedAppData()
+{
+  SetAllocatedString(this->vendor, nullptr);
+  SetAllocatedString(this->name, nullptr);
+  SetAllocatedString(this->remotingName, nullptr);
+  SetAllocatedString(this->version, nullptr);
+  SetAllocatedString(this->buildID, nullptr);
+  SetAllocatedString(this->ID, nullptr);
+  SetAllocatedString(this->copyright, nullptr);
+  SetAllocatedString(this->profile, nullptr);
+
+  NS_IF_RELEASE(this->directory);
+
+  SetStrongPtr(this->xreDirectory, (nsIFile*)nullptr);
+  SetAllocatedString(this->minVersion, nullptr);
+  SetAllocatedString(this->maxVersion, nullptr);
+
+  SetAllocatedString(this->crashReporterURL, nullptr);
+  SetAllocatedString(this->UAName, nullptr);
 }
 
 } // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/xpcom/glue/AppData.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_AppData_h
+#define mozilla_AppData_h
+
+#include "nsXREAppData.h"
+#include "nscore.h"
+#include "nsStringGlue.h"
+#include "nsISupportsUtils.h"
+
+namespace mozilla {
+
+// Like nsXREAppData, but releases all strong refs/allocated memory
+// in the destructor.
+class ScopedAppData : public nsXREAppData
+{
+public:
+  ScopedAppData()
+  {
+    Zero();
+    this->size = sizeof(*this);
+  }
+
+  explicit ScopedAppData(const nsXREAppData* aAppData);
+
+  void Zero() { memset(this, 0, sizeof(*this)); }
+
+  ~ScopedAppData();
+};
+
+/**
+ * Given |aStr| is holding a string allocated with NS_Alloc, or null:
+ * replace the value in |aStr| with a new value.
+ *
+ * @param aNewValue Null is permitted. The string is cloned with NS_strdup.
+ */
+void SetAllocatedString(const char*& aStr, const char* aNewValue);
+
+/**
+ * Given "str" is holding a string allocated with NS_Alloc, or null:
+ * replace the value in "str" with a new value.
+ *
+ * @param aNewValue If |aNewValue| is the empty string, |aStr| will be set
+ *                  to null.
+ */
+void SetAllocatedString(const char*& aStr, const nsACString& aNewValue);
+
+template<class T>
+void
+SetStrongPtr(T*& aPtr, T* aNewValue)
+{
+  NS_IF_RELEASE(aPtr);
+  aPtr = aNewValue;
+  NS_IF_ADDREF(aPtr);
+}
+
+} // namespace mozilla
+
+#endif
--- a/xpcom/glue/moz.build
+++ b/xpcom/glue/moz.build
@@ -62,16 +62,17 @@ EXPORTS += [
     'nsTWeakRef.h',
     'nsVersionComparator.h',
     'nsWeakReference.h',
     'nsXPTCUtils.h',
     'PLDHashTable.h',
 ]
 
 EXPORTS.mozilla += [
+    'AppData.h',
     'AutoRestore.h',
     'BlockingResourceBase.h',
     'CondVar.h',
     'DeadlockDetector.h',
     'EnumeratedArrayCycleCollection.h',
     'FileUtils.h',
     'GenericFactory.h',
     'IntentionalCrash.h',
--- a/xpcom/glue/objs.mozbuild
+++ b/xpcom/glue/objs.mozbuild
@@ -1,15 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 xpcom_glue_src_lcppsrcs = [
+    'AppData.cpp',
     'FileUtils.cpp',
     'nsArrayEnumerator.cpp',
     'nsArrayUtils.cpp',
     'nsCategoryCache.cpp',
     'nsClassInfoImpl.cpp',
     'nsCOMArray.cpp',
     'nsComponentManagerUtils.cpp',
     'nsCOMPtr.cpp',
@@ -24,17 +25,16 @@ xpcom_glue_src_lcppsrcs = [
     'nsMemory.cpp',
     'nsQuickSort.cpp',
     'nsTArray.cpp',
     'nsThreadUtils.cpp',
     'nsTObserverArray.cpp',
     'nsVersionComparator.cpp',
     'nsWeakReference.cpp',
     'PLDHashTable.cpp',
-    'XREAppData.cpp',
 ]
 
 xpcom_glue_src_cppsrcs = [
     '/xpcom/glue/%s' % s for s in xpcom_glue_src_lcppsrcs
 ]
 
 xpcom_gluens_src_lcppsrcs = [
     'BlockingResourceBase.cpp',
--- a/xpcom/system/nsIXULAppInfo.idl
+++ b/xpcom/system/nsIXULAppInfo.idl
@@ -8,46 +8,46 @@
  * A scriptable interface to the nsXULAppAPI structure. See nsXULAppAPI.h for
  * a detailed description of each attribute.
  */
 
 [scriptable, uuid(ddea4f31-3c5e-4769-ac68-21ab4b3d7845)]
 interface nsIXULAppInfo : nsIPlatformInfo
 {
   /**
-   * @see XREAppData.vendor
-   * @returns an empty string if XREAppData.vendor is not set.
+   * @see nsXREAppData.vendor
+   * @returns an empty string if nsXREAppData.vendor is not set.
    */
   readonly attribute ACString vendor;
 
   /**
-   * @see XREAppData.name
+   * @see nsXREAppData.name
    */
   readonly attribute ACString name;
 
   /**
-   * @see XREAppData.ID
-   * @returns an empty string if XREAppData.ID is not set.
+   * @see nsXREAppData.ID
+   * @returns an empty string if nsXREAppData.ID is not set.
    */
   readonly attribute ACString ID;
 
   /**
    * The version of the XUL application. It is different than the
    * version of the XULRunner platform. Be careful about which one you want.
    *
-   * @see XREAppData.version
-   * @returns an empty string if XREAppData.version is not set.
+   * @see nsXREAppData.version
+   * @returns an empty string if nsXREAppData.version is not set.
    */
   readonly attribute ACString version;
 
   /**
    * The build ID/date of the application. For xulrunner applications,
    * this will be different than the build ID of the platform. Be careful
    * about which one you want.
    */
   readonly attribute ACString appBuildID;
 
   /**
-   * @see XREAppData.UAName
-   * @returns an empty string if XREAppData.UAName is not set.
+   * @see nsXREAppData.UAName
+   * @returns an empty string if nsXREAppData.UAName is not set.
    */
   readonly attribute ACString UAName;
 };