Skip to content

Instantly share code, notes, and snippets.

@fredemmott
Created May 13, 2020 23:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fredemmott/984c00d869740b5de00294b80b7e0a89 to your computer and use it in GitHub Desktop.
Save fredemmott/984c00d869740b5de00294b80b7e0a89 to your computer and use it in GitHub Desktop.
diff --git a/hphp/hack/hhi/hsl/ext_hsl_os_subprocesses.hhi b/hphp/hack/hhi/hsl/ext_hsl_os_subprocesses.hhi
index 59f4eb477b..9a0d09b546 100644
--- a/hphp/hack/hhi/hsl/ext_hsl_os_subprocesses.hhi
+++ b/hphp/hack/hhi/hsl/ext_hsl_os_subprocesses.hhi
@@ -15,6 +15,7 @@ use type HH\Lib\OS\FileDescriptor;
type ForkAndExecveOptions = shape(
?'cwd' => string,
?'setsid' => bool,
+ ?'execvpe' => bool,
?'setpgid' => int,
);
diff --git a/hphp/runtime/ext/hsl/ext_hsl_os.cpp b/hphp/runtime/ext/hsl/ext_hsl_os.cpp
index 4de7bb8245..0b255004d8 100644
--- a/hphp/runtime/ext/hsl/ext_hsl_os.cpp
+++ b/hphp/runtime/ext/hsl/ext_hsl_os.cpp
@@ -910,7 +910,8 @@ Object HHVM_FUNCTION(HSL_os_poll_async,
const StaticString
s_cwd("cwd"),
s_setsid("setsid"),
- s_setpgid("setpgid");
+ s_setpgid("setpgid"),
+ s_execvpe("execvpe");
int64_t HHVM_FUNCTION(HSL_os_fork_and_execve,
const String& path,
@@ -955,6 +956,16 @@ int64_t HHVM_FUNCTION(HSL_os_fork_and_execve,
flags |= Process::FORK_AND_EXECVE_FLAG_SETPGID;
}
+ if (options.exists(s_execvpe)) {
+ const auto& val = options[s_execvpe];
+ if (!val.isBoolean()) {
+ throw_errno_exception(EINVAL, "'execvpe' option must be a bool");
+ }
+ if (val.asBooleanVal()) {
+ flags |= Process::FORK_AND_EXECVE_FLAG_EXECVPE;
+ }
+ }
+
auto vec_str_to_cpp_arr = ([] (const Array& vec) {
std::vector<std::string> arr;
for (ArrayIter iter(vec); iter; ++iter) {
diff --git a/hphp/util/process.cpp b/hphp/util/process.cpp
index 5300b3e519..22d98dbee5 100644
--- a/hphp/util/process.cpp
+++ b/hphp/util/process.cpp
@@ -32,6 +32,10 @@
#include <folly/portability/Unistd.h>
#endif
+#ifdef __APPLE__
+#include <crt_externs.h>
+#endif
+
#include <folly/Conv.h>
#include <folly/Format.h>
#include <folly/ScopeGuard.h>
@@ -571,10 +575,43 @@ pid_t Process::ForkAndExecve(
}
char** argv_arr = build_cstrarr(argv);
- char** envp_arr = build_cstrarr(envp);
+ char** envp_arr = nullptr;
SCOPE_EXIT { free(argv_arr); free(envp_arr); };
- execve(path.c_str(), argv_arr, envp_arr);
+ if (flags & Process::FORK_AND_EXECVE_FLAG_EXECVPE) {
+ // we could use real `execvpe` on linux, but let's just use the emulation
+ // everywhere so we have reliable cross-platform behavior and testability
+
+ // We could either:
+ // - use `execve()` and implement our own $PATH behavior
+ // - use `execvp()` and implement our own envp behavior
+ // The latter seems less likely to lead to accidental problems, so let's
+ // do that.
+
+#if defined(__linux__)
+ clearenv();
+#elif defined(__APPLE__)
+ // `environ` in MacOS-speak
+ *(_NSGetEnviron()) = nullptr;
+#else
+ static_assert(false, "Unsupported platform");
+#endif
+ for (const auto& var : envp) {
+ // Need a null-terminated, mutable char*
+ char* buf = (char*) malloc(var.length() + 1);
+ buf[var.length()] = 0;
+ memcpy(buf, var.c_str(), var.length());
+
+ if (putenv(buf) != 0) {
+ dprintf(fork_w, "%s %d", "putenv", errno);
+ _Exit(1);
+ }
+ }
+ execvp(path.c_str(), argv_arr);
+ } else {
+ envp_arr = build_cstrarr(envp);
+ execve(path.c_str(), argv_arr, envp_arr);
+ }
dprintf(fork_w, "%s %d", "execve", errno);
_Exit(1);
}
@@ -621,6 +658,9 @@ pid_t Process::ForkAndExecve(
if (failed_call == "execve") {
return -5;
}
+ if (failed_call == "putenv") {
+ return -6;
+ }
return -9999;
}
diff --git a/hphp/util/process.h b/hphp/util/process.h
index 9fd067d6d3..55c1ac0bc4 100644
--- a/hphp/util/process.h
+++ b/hphp/util/process.h
@@ -258,6 +258,7 @@ struct Process {
static const int FORK_AND_EXECVE_FLAG_NONE = 0;
static const int FORK_AND_EXECVE_FLAG_SETPGID = 1 << 0;
static const int FORK_AND_EXECVE_FLAG_SETSID = 1 << 1;
+ static const int FORK_AND_EXECVE_FLAG_EXECVPE = 1 << 2;
/** Opens a process with the given arguments, environment, working directory,
* and file descriptors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment