Add a `Symbolizer::GetEnvP()` method that allows symbolizer implementations to customise the environment of the symbolizer binary.

Summary:
This change introduces the `Symbolizer::GetEnvP()` method that returns a
pointer to environment array used for spawning the symbolizer process.
The motivation is to allow implementations to customise the environment
if required.  The default implementation just returns
`__sanitizer::GetEnviron()` which (provided it's implemented) should
preserve the existing behaviours of the various implementations.

This change has been plumbed through the `internal_spawn(...)` and
`StartSubprocess(...)` process spawning implementations.

For the `StartSubprocess()` implementation we need to call `execve()`
rather than `execv()` to pass the environment. However, it appears that
`internal_execve(...)` exists in sanitizer_common so this patch use that
which seems like a nice clean up.

Support in the Windows implementation of
`SymbolizerProcess:StartSymbolizerSubprocess()` has not been added
because the Windows sanitizer runtime doesn't implement `GetEnviron()`.

rdar://problem/58789439

Reviewers: kubamracek, yln, dvyukov, vitalybuka, eugenis, phosek, aizatsky, rnk

Subscribers: #sanitizers, llvm-commits

Tags: #sanitizers

Differential Revision: https://reviews.llvm.org/D76666
This commit is contained in:
Dan Liew 2020-03-23 19:57:33 -07:00
parent ec184dd548
commit b684c1a50f
8 changed files with 20 additions and 14 deletions

View File

@ -87,8 +87,8 @@ bool IsAbsolutePath(const char *path);
// The child process will close all fds after STDERR_FILENO // The child process will close all fds after STDERR_FILENO
// before passing control to a program. // before passing control to a program.
pid_t StartSubprocess(const char *filename, const char *const argv[], pid_t StartSubprocess(const char *filename, const char *const argv[],
fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd, const char *const envp[], fd_t stdin_fd = kInvalidFd,
fd_t stderr_fd = kInvalidFd); fd_t stdout_fd = kInvalidFd, fd_t stderr_fd = kInvalidFd);
// Checks if specified process is still running // Checks if specified process is still running
bool IsProcessRunning(pid_t pid); bool IsProcessRunning(pid_t pid);
// Waits for the process to finish and returns its exit code. // Waits for the process to finish and returns its exit code.

View File

@ -246,7 +246,8 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
(size_t)newlen); (size_t)newlen);
} }
static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { static fd_t internal_spawn_impl(const char *argv[], const char *envp[],
pid_t *pid) {
fd_t master_fd = kInvalidFd; fd_t master_fd = kInvalidFd;
fd_t slave_fd = kInvalidFd; fd_t slave_fd = kInvalidFd;
@ -302,8 +303,8 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) {
// posix_spawn // posix_spawn
char **argv_casted = const_cast<char **>(argv); char **argv_casted = const_cast<char **>(argv);
char **env = GetEnviron(); char **envp_casted = const_cast<char **>(envp);
res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, env); res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted);
if (res != 0) return kInvalidFd; if (res != 0) return kInvalidFd;
// Disable echo in the new terminal, disable CR. // Disable echo in the new terminal, disable CR.
@ -320,7 +321,7 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) {
return fd; return fd;
} }
fd_t internal_spawn(const char *argv[], pid_t *pid) { fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) {
// The client program may close its stdin and/or stdout and/or stderr thus // The client program may close its stdin and/or stdout and/or stderr thus
// allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this
// case the communication is broken if either the parent or the child tries to // case the communication is broken if either the parent or the child tries to
@ -335,7 +336,7 @@ fd_t internal_spawn(const char *argv[], pid_t *pid) {
break; break;
} }
fd_t fd = internal_spawn_impl(argv, pid); fd_t fd = internal_spawn_impl(argv, envp, pid);
for (; count > 0; count--) { for (; count > 0; count--) {
internal_close(low_fds[count]); internal_close(low_fds[count]);

View File

@ -63,7 +63,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data);
uptr internal_waitpid(int pid, int *status, int options); uptr internal_waitpid(int pid, int *status, int options);
int internal_fork(); int internal_fork();
fd_t internal_spawn(const char *argv[], pid_t *pid); fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid);
int internal_sysctl(const int *name, unsigned int namelen, void *oldp, int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
uptr *oldlenp, const void *newp, uptr newlen); uptr *oldlenp, const void *newp, uptr newlen);

View File

@ -426,7 +426,8 @@ void AdjustStackSize(void *attr_) {
#endif // !SANITIZER_GO #endif // !SANITIZER_GO
pid_t StartSubprocess(const char *program, const char *const argv[], pid_t StartSubprocess(const char *program, const char *const argv[],
fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { const char *const envp[], fd_t stdin_fd, fd_t stdout_fd,
fd_t stderr_fd) {
auto file_closer = at_scope_exit([&] { auto file_closer = at_scope_exit([&] {
if (stdin_fd != kInvalidFd) { if (stdin_fd != kInvalidFd) {
internal_close(stdin_fd); internal_close(stdin_fd);
@ -469,7 +470,8 @@ pid_t StartSubprocess(const char *program, const char *const argv[],
for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd); for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd);
execv(program, const_cast<char **>(&argv[0])); internal_execve(program, const_cast<char **>(&argv[0]),
const_cast<char *const *>(envp));
internal__exit(1); internal__exit(1);
} }

View File

@ -86,6 +86,8 @@ class SymbolizerProcess {
// Customizable by subclasses. // Customizable by subclasses.
virtual bool StartSymbolizerSubprocess(); virtual bool StartSymbolizerSubprocess();
virtual bool ReadFromSymbolizer(char *buffer, uptr max_length); virtual bool ReadFromSymbolizer(char *buffer, uptr max_length);
// Return the environment to run the symbolizer in.
virtual char **GetEnvP() { return GetEnviron(); }
private: private:
virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const {

View File

@ -153,7 +153,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
if (use_posix_spawn_) { if (use_posix_spawn_) {
#if SANITIZER_MAC #if SANITIZER_MAC
fd_t fd = internal_spawn(argv, &pid); fd_t fd = internal_spawn(argv, const_cast<const char **>(GetEnvP()), &pid);
if (fd == kInvalidFd) { if (fd == kInvalidFd) {
Report("WARNING: failed to spawn external symbolizer (errno: %d)\n", Report("WARNING: failed to spawn external symbolizer (errno: %d)\n",
errno); errno);
@ -173,7 +173,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
return false; return false;
} }
pid = StartSubprocess(path_, argv, /* stdin */ outfd[0], pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0],
/* stdout */ infd[1]); /* stdout */ infd[1]);
if (pid < 0) { if (pid < 0) {
internal_close(infd[0]); internal_close(infd[0]);

View File

@ -1064,7 +1064,8 @@ char **GetEnviron() {
} }
pid_t StartSubprocess(const char *program, const char *const argv[], pid_t StartSubprocess(const char *program, const char *const argv[],
fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { const char *const envp[], fd_t stdin_fd, fd_t stdout_fd,
fd_t stderr_fd) {
// FIXME: implement on this platform // FIXME: implement on this platform
// Should be implemented based on // Should be implemented based on
// SymbolizerProcess::StarAtSymbolizerSubprocess // SymbolizerProcess::StarAtSymbolizerSubprocess

View File

@ -264,7 +264,7 @@ TEST(SanitizerCommon, StartSubprocessTest) {
const char *shell = "/bin/sh"; const char *shell = "/bin/sh";
#endif #endif
const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL}; const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL};
int pid = StartSubprocess(shell, argv, int pid = StartSubprocess(shell, argv, GetEnviron(),
/* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]); /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]);
ASSERT_GT(pid, 0); ASSERT_GT(pid, 0);