[clang] Use platform specific calls to get the executable absolute path (PR #68091)

Liviu Ionescu via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 3 04:22:11 PDT 2023


https://github.com/ilg-ul created https://github.com/llvm/llvm-project/pull/68091

This patch fixes #66704.

>From f3812174546270051c4a2903b9a99408bf5b7ba0 Mon Sep 17 00:00:00 2001
From: Liviu Ionescu <ilg at livius.net>
Date: Tue, 3 Oct 2023 14:07:48 +0300
Subject: [PATCH 1/2] [clang][driver] Use platform specific calls to get the
 executable absolute path (#66704)

In clang/tools/driver/driver.cpp, the function SetInstallDir() tries to determine the
location where the toolchain is installed, basically by taking the parent folder of
the executable absolute path. This is not correct when the compiler is invoked
via a link, since it returns the parent of the link.

This leads to subtle errors, for example on macOS it silently picks the wrong
system headers.
---
 clang/tools/driver/driver.cpp | 61 +++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 531b5b4a61c1804..c8ad167cba0a423 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -57,6 +57,15 @@ using namespace clang;
 using namespace clang::driver;
 using namespace llvm::opt;
 
+#if defined(__linux__)
+#include <unistd.h>
+#elif defined(__APPLE__)
+#include <libproc.h>
+#include <unistd.h>
+#elif defined(__MINGW32__)
+#include <windows.h>
+#endif
+
 std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
   if (!CanonicalPrefixes) {
     SmallString<128> ExecutablePath(Argv0);
@@ -331,6 +340,56 @@ static void SetInstallDir(SmallVectorImpl<const char *> &argv,
   // path being a symlink.
   SmallString<128> InstalledPath(argv[0]);
 
+#if defined(__linux__)
+
+  char ProcessAbsolutePath[PATH_MAX];
+
+  int len = readlink("/proc/self/exe", ProcessAbsolutePath,
+                     sizeof(ProcessAbsolutePath) - 1);
+  if ( len <= 0 ) {
+    llvm::errs() << "Internal error: readlink(\"/proc/self/exe\") failed with "
+                 << strerror(errno) << "\n";
+    exit(1);
+  }
+
+  ProcessAbsolutePath[len] = 0;
+  InstalledPath = ProcessAbsolutePath;
+
+#elif defined(__APPLE__)
+
+  // The size must be higher than PROC_PIDPATHINFO_SIZE, otherwise the call
+  // fails with ENOMEM (12) - Cannot allocate memory.
+  // https://opensource.apple.com/source/Libc/Libc-498/darwin/libproc.c
+  char ProcessAbsolutePath[PROC_PIDPATHINFO_SIZE+1];
+
+  int len = proc_pidpath(getpid(), ProcessAbsolutePath,
+                         sizeof(ProcessAbsolutePath) - 1);
+  if ( len <= 0 ) {
+    llvm::errs() << "Internal error: proc_pidpath() failed with "
+                 << strerror(errno) << "\n";
+    exit(1);
+  }
+
+  ProcessAbsolutePath[len] = 0;
+  InstalledPath = ProcessAbsolutePath;
+
+#elif defined(__MINGW32__)
+
+  char ProcessAbsolutePath[PATH_MAX];
+
+  len = GetModuleFileName(NULL, ProcessAbsolutePath,
+                          sizeof(ProcessAbsolutePath) - 1);
+  if ( len <= 0 ) {
+    llvm::errs() << "Internal error: GetModuleFileName() failed with "
+                 << strerror(errno) << "\n";
+    exit(1);
+  }
+
+  ProcessAbsolutePath[len] = 0;
+  InstalledPath = ProcessAbsolutePath;
+
+#else
+
   // Do a PATH lookup, if there are no directory components.
   if (llvm::sys::path::filename(InstalledPath) == InstalledPath)
     if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName(
@@ -341,6 +400,8 @@ static void SetInstallDir(SmallVectorImpl<const char *> &argv,
   if (CanonicalPrefixes)
     llvm::sys::fs::make_absolute(InstalledPath);
 
+#endif
+
   StringRef InstalledPathParent(llvm::sys::path::parent_path(InstalledPath));
   if (llvm::sys::fs::exists(InstalledPathParent))
     TheDriver.setInstalledDir(InstalledPathParent);

>From eb7b122d5e6ce160d3f0880aac44a2df720d182f Mon Sep 17 00:00:00 2001
From: Liviu Ionescu <ilg at livius.net>
Date: Tue, 3 Oct 2023 14:16:30 +0300
Subject: [PATCH 2/2] clang-format driver.cpp patch

---
 clang/tools/driver/driver.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index c8ad167cba0a423..45e1469aafca95e 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -346,7 +346,7 @@ static void SetInstallDir(SmallVectorImpl<const char *> &argv,
 
   int len = readlink("/proc/self/exe", ProcessAbsolutePath,
                      sizeof(ProcessAbsolutePath) - 1);
-  if ( len <= 0 ) {
+  if (len <= 0) {
     llvm::errs() << "Internal error: readlink(\"/proc/self/exe\") failed with "
                  << strerror(errno) << "\n";
     exit(1);
@@ -360,11 +360,11 @@ static void SetInstallDir(SmallVectorImpl<const char *> &argv,
   // The size must be higher than PROC_PIDPATHINFO_SIZE, otherwise the call
   // fails with ENOMEM (12) - Cannot allocate memory.
   // https://opensource.apple.com/source/Libc/Libc-498/darwin/libproc.c
-  char ProcessAbsolutePath[PROC_PIDPATHINFO_SIZE+1];
+  char ProcessAbsolutePath[PROC_PIDPATHINFO_SIZE + 1];
 
   int len = proc_pidpath(getpid(), ProcessAbsolutePath,
                          sizeof(ProcessAbsolutePath) - 1);
-  if ( len <= 0 ) {
+  if (len <= 0) {
     llvm::errs() << "Internal error: proc_pidpath() failed with "
                  << strerror(errno) << "\n";
     exit(1);
@@ -379,7 +379,7 @@ static void SetInstallDir(SmallVectorImpl<const char *> &argv,
 
   len = GetModuleFileName(NULL, ProcessAbsolutePath,
                           sizeof(ProcessAbsolutePath) - 1);
-  if ( len <= 0 ) {
+  if (len <= 0) {
     llvm::errs() << "Internal error: GetModuleFileName() failed with "
                  << strerror(errno) << "\n";
     exit(1);



More information about the cfe-commits mailing list