tint: make FindExecutable look in explicit CWD-prefixed path first

When FindExecutable tests to see if the input executable file exists, it
first checks the input path as-is. If the input path is a relative one,
the existence check will, by definition, look in the cwd implicitly, and
if it exists, returns true, and we return the relative path as-is. This
seems fine, except when the executable is a shared object (.so/.dylib),
where dlopen'ing by relative path may fail if RPATH wasn't set to look
in relative paths. To mitigate this, we explicitly search in an absolute
path made up of the input path prefixed by the CWD. If found, we return
this absolute path, and are able to load the shared object regardless of
RPATH.

Note that I added the same behaviour to command_windows, although it's
not really necessary there, since DLL loading by relative path always
succeeds (there's no RPATH on Windows). However, adding this to Windows
means the path we get back from FindExecutable will be absolute like on
posix, which is better for consistency between the platforms.

Bug: tint:2234
Change-Id: I53d4f9ec79ee593db8ab4e92415321e6d2e8f0ed
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/186563
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/utils/command/command_posix.cc b/src/tint/utils/command/command_posix.cc
index 61bb0b1..f3c30de 100644
--- a/src/tint/utils/command/command_posix.cc
+++ b/src/tint/utils/command/command_posix.cc
@@ -29,6 +29,7 @@
 
 #include "src/tint/utils/command/command.h"
 
+#include <limits.h>
 #include <sys/poll.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
@@ -119,7 +120,19 @@
     return s.st_mode & S_IXUSR;
 }
 
+std::string GetCWD() {
+    char cwd[PATH_MAX] = "";
+    [[maybe_unused]] auto res = getcwd(cwd, sizeof(cwd));
+    return cwd;
+}
+
 std::string FindExecutable(const std::string& name) {
+    if (name.length() >= 1 && name[0] != '/') {
+        auto in_cwd = GetCWD() + "/" + name;
+        if (ExecutableExists(in_cwd)) {
+            return in_cwd;
+        }
+    }
     if (ExecutableExists(name)) {
         return name;
     }
diff --git a/src/tint/utils/command/command_windows.cc b/src/tint/utils/command/command_windows.cc
index 2916d9a..a6a577b 100644
--- a/src/tint/utils/command/command_windows.cc
+++ b/src/tint/utils/command/command_windows.cc
@@ -145,7 +145,20 @@
     return false;
 }
 
+std::string GetCWD() {
+    char cwd[MAX_PATH] = "";
+    GetCurrentDirectoryA(sizeof(cwd), cwd);
+    return cwd;
+}
+
 std::string FindExecutable(const std::string& name) {
+    auto in_cwd = GetCWD() + "/" + name;
+    if (ExecutableExists(in_cwd)) {
+        return in_cwd;
+    }
+    if (ExecutableExists(in_cwd + ".exe")) {
+        return in_cwd + ".exe";
+    }
     if (ExecutableExists(name)) {
         return name;
     }