Bug 1403366 - Stop requiring argv[0] for XRE_GetBinaryPath and the underlying BinaryPath::Get. r=froydnj
☠☠ backed out by 938a07d707e7 ☠ ☠
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 28 Sep 2017 10:37:27 +0900
changeset 383767 3eb67e350f3891717ac5fb7f6ac62f0accc08849
parent 383766 13c57542ba14f008d5f8240ba5ae2055fb7ae586
child 383768 7e08706f9f34d987ee2f03b1c2f30cde9e60cd18
push id95640
push userkwierso@gmail.com
push dateFri, 29 Sep 2017 21:48:43 +0000
treeherdermozilla-inbound@f1251736514d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1403366
milestone58.0a1
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
Bug 1403366 - Stop requiring argv[0] for XRE_GetBinaryPath and the underlying BinaryPath::Get. r=froydnj
browser/app/nsBrowserApp.cpp
ipc/glue/ScopedXREEmbed.cpp
js/xpconnect/src/XPCShellImpl.cpp
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsUpdateDriver.cpp
toolkit/xre/nsXREDirProvider.cpp
xpcom/build/BinaryPath.h
xpcom/build/nsXULAppAPI.h
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -227,19 +227,19 @@ static int do_main(int argc, char* argv[
   if (getenv("LIBFUZZER"))
     gBootstrap->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver);
 #endif
 
   return gBootstrap->XRE_main(argc, argv, config);
 }
 
 static nsresult
-InitXPCOMGlue(const char *argv0)
+InitXPCOMGlue()
 {
-  UniqueFreePtr<char> exePath = BinaryPath::Get(argv0);
+  UniqueFreePtr<char> exePath = BinaryPath::Get();
   if (!exePath) {
     Output("Couldn't find the application directory.\n");
     return NS_ERROR_FAILURE;
   }
 
   gBootstrap = mozilla::GetBootstrap(exePath.get());
   if (!gBootstrap) {
     Output("Couldn't load XPCOM.\n");
@@ -267,17 +267,17 @@ int main(int argc, char* argv[], char* e
     // We need to initialize the sandbox TargetServices before InitXPCOMGlue
     // because we might need the sandbox broker to give access to some files.
     if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) {
       Output("Failed to initialize the sandbox target services.");
       return 255;
     }
 #endif
 
-    nsresult rv = InitXPCOMGlue(argv[0]);
+    nsresult rv = InitXPCOMGlue();
     if (NS_FAILED(rv)) {
       return 255;
     }
 
     int result = content_process_main(gBootstrap.get(), argc, argv);
 
     // InitXPCOMGlue calls NS_LogInit, so we need to balance it here.
     gBootstrap->NS_LogTerm();
@@ -285,17 +285,17 @@ int main(int argc, char* argv[], char* e
     return result;
   }
 #endif
 
 #ifdef HAS_DLL_BLOCKLIST
   DllBlocklist_Initialize();
 #endif
 
-  nsresult rv = InitXPCOMGlue(argv[0]);
+  nsresult rv = InitXPCOMGlue();
   if (NS_FAILED(rv)) {
     return 255;
   }
 
   gBootstrap->XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
 
 #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
   gBootstrap->XRE_EnableSameExecutableForContentProc();
--- a/ipc/glue/ScopedXREEmbed.cpp
+++ b/ipc/glue/ScopedXREEmbed.cpp
@@ -41,27 +41,18 @@ ScopedXREEmbed::SetAppDir(const nsACStri
     NS_WARNING("Invalid application directory passed to content process.");
     mAppDir = nullptr;
   }
 }
 
 void
 ScopedXREEmbed::Start()
 {
-  std::string path;
-#if defined(OS_WIN)
-  path = WideToUTF8(CommandLine::ForCurrentProcess()->program());
-#elif defined(OS_POSIX)
-  path = CommandLine::ForCurrentProcess()->argv()[0];
-#else
-#  error Sorry
-#endif
-
   nsCOMPtr<nsIFile> localFile;
-  nsresult rv = XRE_GetBinaryPath(path.c_str(), getter_AddRefs(localFile));
+  nsresult rv = XRE_GetBinaryPath(getter_AddRefs(localFile));
   if (NS_FAILED(rv))
     return;
 
   nsCOMPtr<nsIFile> parent;
   rv = localFile->GetParent(getter_AddRefs(parent));
   if (NS_FAILED(rv))
     return;
 
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -1110,17 +1110,17 @@ XRE_XPCShellMain(int argc, char** argv, 
         printf_stderr("*** You are running in chaos test mode. See ChaosMode.h. ***\n");
     }
 
     // The provider needs to outlive the call to shutting down XPCOM.
     XPCShellDirProvider dirprovider;
 
     { // Start scoping nsCOMPtrs
         nsCOMPtr<nsIFile> appFile;
-        rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(appFile));
+        rv = XRE_GetBinaryPath(getter_AddRefs(appFile));
         if (NS_FAILED(rv)) {
             printf("Couldn't find application file.\n");
             return 1;
         }
         nsCOMPtr<nsIFile> appDir;
         rv = appFile->GetParent(getter_AddRefs(appDir));
         if (NS_FAILED(rv)) {
             printf("Couldn't get application directory.\n");
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1870,19 +1870,19 @@ StartRemoteClient(const char* aDesktopSt
 
 void
 XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni)
 {
   mozilla::Omnijar::Init(greOmni, appOmni);
 }
 
 nsresult
-XRE_GetBinaryPath(const char* argv0, nsIFile* *aResult)
+XRE_GetBinaryPath(nsIFile* *aResult)
 {
-  return mozilla::BinaryPath::GetFile(argv0, aResult);
+  return mozilla::BinaryPath::GetFile(aResult);
 }
 
 #ifdef XP_WIN
 #include "nsWindowsRestart.cpp"
 #include <shellapi.h>
 
 typedef BOOL (WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
 #endif
@@ -1911,17 +1911,17 @@ static nsresult LaunchChild(nsINativeApp
   SaveToEnv("MOZ_LAUNCHED_CHILD=1");
 
 #if !defined(MOZ_WIDGET_ANDROID) // Android has separate restart code.
 #if defined(XP_MACOSX)
   CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
   LaunchChildMac(gRestartArgc, gRestartArgv);
 #else
   nsCOMPtr<nsIFile> lf;
-  nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
+  nsresult rv = XRE_GetBinaryPath(getter_AddRefs(lf));
   if (NS_FAILED(rv))
     return rv;
 
 #if defined(XP_WIN)
   nsAutoString exePath;
   rv = lf->GetPath(exePath);
   if (NS_FAILED(rv))
     return rv;
@@ -4780,25 +4780,25 @@ XREMain::XRE_main(int argc, char* argv[]
 
   if (!mAppData->remotingName) {
     mAppData->remotingName = mAppData->name;
   }
   // used throughout this file
   gAppData = mAppData.get();
 
   nsCOMPtr<nsIFile> binFile;
-  rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(binFile));
+  rv = XRE_GetBinaryPath(getter_AddRefs(binFile));
   NS_ENSURE_SUCCESS(rv, 1);
 
   rv = binFile->GetPath(gAbsoluteArgv0Path);
   NS_ENSURE_SUCCESS(rv, 1);
 
   if (!mAppData->xreDirectory) {
     nsCOMPtr<nsIFile> lf;
-    rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
+    rv = XRE_GetBinaryPath(getter_AddRefs(lf));
     if (NS_FAILED(rv))
       return 2;
 
     nsCOMPtr<nsIFile> greDir;
     rv = lf->GetParent(getter_AddRefs(greDir));
     if (NS_FAILED(rv))
       return 2;
 
@@ -4971,17 +4971,17 @@ XRE_InitCommandLine(int aArgc, char* aAr
   CommandLine::Init(aArgc, aArgv);
 #else
 
   // these leak on error, but that's OK: we'll just exit()
   char** canonArgs = new char*[aArgc];
 
   // get the canonical version of the binary's path
   nsCOMPtr<nsIFile> binFile;
-  rv = XRE_GetBinaryPath(aArgv[0], getter_AddRefs(binFile));
+  rv = XRE_GetBinaryPath(getter_AddRefs(binFile));
   if (NS_FAILED(rv))
     return NS_ERROR_FAILURE;
 
   nsAutoCString canonBinPath;
   rv = binFile->GetNativePath(canonBinPath);
   if (NS_FAILED(rv))
     return NS_ERROR_FAILURE;
 
--- a/toolkit/xre/nsUpdateDriver.cpp
+++ b/toolkit/xre/nsUpdateDriver.cpp
@@ -503,17 +503,17 @@ ApplyUpdate(nsIFile *greDir, nsIFile *up
     rv = GetCurrentWorkingDir(workingDirPath, sizeof(workingDirPath));
     if (NS_FAILED(rv)) {
       return;
     }
 
     // Get the application file path used by the updater to restart the
     // application after the update has finished.
     nsCOMPtr<nsIFile> appFile;
-    XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile));
+    XRE_GetBinaryPath(getter_AddRefs(appFile));
     if (!appFile) {
       return;
     }
 
 #if defined(XP_WIN)
     nsAutoString appFilePathW;
     rv = appFile->GetPath(appFilePathW);
     if (NS_FAILED(rv)) {
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -421,19 +421,19 @@ nsXREDirProvider::GetFile(const char* aP
       rv = file->AppendNative(NS_LITERAL_CSTRING(APP_REGISTRY_NAME));
   }
   else if (!strcmp(aProperty, NS_APP_USER_PROFILES_ROOT_DIR)) {
     rv = GetUserProfilesRootDir(getter_AddRefs(file), nullptr, nullptr, nullptr);
   }
   else if (!strcmp(aProperty, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR)) {
     rv = GetUserProfilesLocalDir(getter_AddRefs(file), nullptr, nullptr, nullptr);
   }
-  else if (!strcmp(aProperty, XRE_EXECUTABLE_FILE) && gArgv[0]) {
+  else if (!strcmp(aProperty, XRE_EXECUTABLE_FILE)) {
     nsCOMPtr<nsIFile> lf;
-    rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
+    rv = XRE_GetBinaryPath(getter_AddRefs(lf));
     if (NS_SUCCEEDED(rv))
       file = lf;
   }
 
   else if (!strcmp(aProperty, NS_APP_PROFILE_DIR_STARTUP) && mProfileDir) {
     return mProfileDir->Clone(aFile);
   }
   else if (!strcmp(aProperty, NS_APP_PROFILE_LOCAL_DIR_STARTUP)) {
@@ -923,17 +923,17 @@ nsXREDirProvider::GetFilesInternal(const
 
     rv = NS_NewArrayEnumerator(aResult, directories);
   }
   else if (!strcmp(aProperty, NS_APP_PLUGINS_DIR_LIST)) {
     nsCOMArray<nsIFile> directories;
 
     if (mozilla::Preferences::GetBool("plugins.load_appdir_plugins", false)) {
       nsCOMPtr<nsIFile> appdir;
-      rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(appdir));
+      rv = XRE_GetBinaryPath(getter_AddRefs(appdir));
       if (NS_SUCCEEDED(rv)) {
         appdir->SetNativeLeafName(NS_LITERAL_CSTRING("plugins"));
         directories.AppendObject(appdir);
       }
     }
 
     static const char *const kAppendPlugins[] = { "plugins", nullptr };
 
--- a/xpcom/build/BinaryPath.h
+++ b/xpcom/build/BinaryPath.h
@@ -8,53 +8,62 @@
 #define mozilla_BinaryPath_h
 
 #include "nsXPCOMPrivate.h" // for MAXPATHLEN
 #ifdef XP_WIN
 #include <windows.h>
 #elif defined(XP_MACOSX)
 #include <CoreFoundation/CoreFoundation.h>
 #elif defined(XP_UNIX)
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+#if defined(__FreeBSD__) || defined(__DragonFly__) || \
+    defined(__FreeBSD_kernel__) || defined(__NetBSD__) || \
+    defined(__OpenBSD__)
+#include <sys/sysctl.h>
+#endif
+#if defined(__OpenBSD__)
 #include <sys/stat.h>
-#include <string.h>
 #endif
 #include "mozilla/UniquePtr.h"
 #include "mozilla/UniquePtrExtensions.h"
 
 #ifdef MOZILLA_INTERNAL_API
 #include "nsCOMPtr.h"
 #include "nsIFile.h"
 #include "nsString.h"
 #endif
 
 namespace mozilla {
 
 class BinaryPath
 {
 public:
 #ifdef XP_WIN
-  static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
+  static nsresult Get(char aResult[MAXPATHLEN])
   {
     wchar_t wide_path[MAXPATHLEN];
-    nsresult rv = GetW(argv0, wide_path);
+    nsresult rv = GetW(wide_path);
     if (NS_FAILED(rv)) {
       return rv;
     }
     WideCharToMultiByte(CP_UTF8, 0, wide_path, -1,
                         aResult, MAXPATHLEN, nullptr, nullptr);
     return NS_OK;
   }
 
   static nsresult GetLong(wchar_t aResult[MAXPATHLEN])
   {
     static bool cached = false;
     static wchar_t exeLongPath[MAXPATHLEN] = L"";
 
     if (!cached) {
-      nsresult rv = GetW(nullptr, exeLongPath);
+      nsresult rv = GetW(exeLongPath);
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
       if (!::GetLongPathNameW(exeLongPath, exeLongPath, MAXPATHLEN)) {
         return NS_ERROR_FAILURE;
       }
@@ -65,17 +74,17 @@ public:
     if (wcscpy_s(aResult, MAXPATHLEN, exeLongPath)) {
       return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
   }
 
 private:
-  static nsresult GetW(const char* argv0, wchar_t aResult[MAXPATHLEN])
+  static nsresult GetW(wchar_t aResult[MAXPATHLEN])
   {
     static bool cached = false;
     static wchar_t moduleFileName[MAXPATHLEN] = L"";
 
     if (!cached) {
       if (!::GetModuleFileNameW(0, moduleFileName, MAXPATHLEN)) {
         return NS_ERROR_FAILURE;
       }
@@ -86,17 +95,17 @@ private:
     if (wcscpy_s(aResult, MAXPATHLEN, moduleFileName)) {
       return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
   }
 
 #elif defined(XP_MACOSX)
-  static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
+  static nsresult Get(char aResult[MAXPATHLEN])
   {
     // Works even if we're not bundled.
     CFBundleRef appBundle = CFBundleGetMainBundle();
     if (!appBundle) {
       return NS_ERROR_FAILURE;
     }
 
     CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
@@ -126,38 +135,96 @@ private:
       rv = NS_ERROR_FAILURE;
     }
 
     CFRelease(executableURL);
     return rv;
   }
 
 #elif defined(ANDROID)
-  static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
+  static nsresult Get(char aResult[MAXPATHLEN])
   {
     // On Android, we use the GRE_HOME variable that is set by the Java
     // bootstrap code.
     const char* greHome = getenv("GRE_HOME");
     if (!greHome) {
       return NS_ERROR_FAILURE;
     }
 
     snprintf(aResult, MAXPATHLEN, "%s/%s", greHome, "dummy");
     aResult[MAXPATHLEN - 1] = '\0';
     return NS_OK;
   }
 
-#elif defined(XP_UNIX)
-  static nsresult Get(const char* aArgv0, char aResult[MAXPATHLEN])
+#elif defined(XP_LINUX) || defined(XP_SOLARIS)
+  static nsresult Get(char aResult[MAXPATHLEN])
+  {
+#  if defined(XP_SOLARIS)
+    const char path[] = "/proc/self/path/a.out";
+#  else
+    const char path[] = "/proc/self/exe";
+#  endif
+
+    ssize_t len = readlink(path, aResult, MAXPATHLEN - 1);
+    if (len < 0) {
+      return NS_ERROR_FAILURE;
+    }
+    aResult[len] = '\0';
+    return NS_OK;
+  }
+
+#elif defined(__FreeBSD__) || defined(__DragonFly__) || \
+      defined(__FreeBSD_kernel__) || defined(__NetBSD__)
+  static nsresult Get(char aResult[MAXPATHLEN])
+  {
+    int mib[4];
+    mib[0] = CTL_KERN;
+#ifdef __NetBSD__
+    mib[1] = KERN_PROC_ARGS;
+    mib[2] = -1;
+    mib[3] = KERN_PROC_PATHNAME;
+#else
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_PATHNAME;
+    mib[3] = -1;
+#endif
+
+    size_t len = MAXPATHLEN;
+    if (sysctl(mib, 4, aResult, &len, nullptr, 0) < 0) {
+      return NS_ERROR_FAILURE;
+    }
+
+    return NS_OK;
+  }
+
+#elif defined(__OpenBSD__)
+  static nsresult Get(char aResult[MAXPATHLEN])
+  {
+    int mib[4];
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC_ARGS;
+    mib[2] = getpid();
+    mib[3] = KERN_PROC_ARGV;
+
+    size_t len = 0;
+    if (sysctl(mib, 4, nullptr, &len, nullptr, 0) < 0) {
+      return NS_ERROR_FAILURE;
+    }
+
+    auto argv = MakeUnique<const char*[]>(len / sizeof(const char*));
+    if (sysctl(mib, 4, argv.get(), &len, nullptr, 0) < 0) {
+      return NS_ERROR_FAILURE;
+    }
+
+    return GetFromArgv0(argv[0], aResult);
+  }
+
+  static nsresult GetFromArgv0(const char* aArgv0, char aResult[MAXPATHLEN])
   {
     struct stat fileStat;
-    // on unix, there is no official way to get the path of the current binary.
-    // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to
-    // multiple applications, we will try a series of techniques:
-    //
     // 1) use realpath() on argv[0], which works unless we're loaded from the
     //    PATH. Only do so if argv[0] looks like a path (contains a /).
     // 2) manually walk through the PATH and look for ourself
     // 3) give up
     if (strchr(aArgv0, '/') && realpath(aArgv0, aResult) &&
         stat(aResult, &fileStat) == 0) {
       return NS_OK;
     }
@@ -190,37 +257,37 @@ private:
     return NS_ERROR_FAILURE;
   }
 
 #else
 #error Oops, you need platform-specific code here
 #endif
 
 public:
-  static UniqueFreePtr<char> Get(const char *aArgv0)
+  static UniqueFreePtr<char> Get()
   {
     char path[MAXPATHLEN];
-    if (NS_FAILED(Get(aArgv0, path))) {
+    if (NS_FAILED(Get(path))) {
       return nullptr;
     }
     UniqueFreePtr<char> result;
     result.reset(strdup(path));
     return result;
   }
 
 #ifdef MOZILLA_INTERNAL_API
-  static nsresult GetFile(const char* aArgv0, nsIFile** aResult)
+  static nsresult GetFile(nsIFile** aResult)
   {
     nsCOMPtr<nsIFile> lf;
 #ifdef XP_WIN
     wchar_t exePath[MAXPATHLEN];
-    nsresult rv = GetW(aArgv0, exePath);
+    nsresult rv = GetW(exePath);
 #else
     char exePath[MAXPATHLEN];
-    nsresult rv = Get(aArgv0, exePath);
+    nsresult rv = Get(exePath);
 #endif
     if (NS_FAILED(rv)) {
       return rv;
     }
 #ifdef XP_WIN
     rv = NS_NewLocalFile(nsDependentString(exePath), true,
                          getter_AddRefs(lf));
 #else
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -200,22 +200,19 @@ XRE_API(int,
  *
  * @note Pass UTF8 strings on Windows... native charset on other platforms.
  */
 XRE_API(nsresult,
         XRE_GetFileFromPath, (const char* aPath, nsIFile** aResult))
 
 /**
  * Get the path of the running application binary and store it in aResult.
- * @param aArgv0  The value passed as argv[0] of main(). This value is only
- *                used on *nix, and only when other methods of determining
- *                the binary path have failed.
  */
 XRE_API(nsresult,
-        XRE_GetBinaryPath, (const char* aArgv0, nsIFile** aResult))
+        XRE_GetBinaryPath, (nsIFile** aResult))
 
 /**
  * Get the static module built in to libxul.
  */
 XRE_API(const mozilla::Module*,
         XRE_GetStaticModule, ())
 
 /**