summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_common.cc4
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_common.h23
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_linux.h2
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc68
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_mac.cc12
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc36
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_win.cc12
-rw-r--r--compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc23
8 files changed, 150 insertions, 30 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.cc b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
index 3f2a6f4b2c7..ce91dc460bd 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
@@ -423,6 +423,10 @@ bool TemplateMatch(const char *templ, const char *str) {
static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':';
char *FindPathToBinary(const char *name) {
+ if (FileExists(name)) {
+ return internal_strdup(name);
+ }
+
const char *path = GetEnv("PATH");
if (!path)
return nullptr;
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
index 97f5cada7de..7721b47b44a 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
@@ -279,6 +279,15 @@ const char *GetPwd();
char *FindPathToBinary(const char *name);
bool IsPathSeparator(const char c);
bool IsAbsolutePath(const char *path);
+// Starts a subprocess and returs its pid.
+// If *_fd parameters are >=0 their corresponding input/output
+// streams would be redirect to the file. The files would always be closed
+// in parent process even in case of an error.
+int StartSubprocess(const char *program, char *const argv[],
+ fd_t std_in_fd = kInvalidFd, fd_t std_out_fd = kInvalidFd,
+ fd_t std_err_fd = kInvalidFd);
+// Checks if specified process is still running
+bool IsProcessRunning(int pid);
u32 GetUid();
void ReExec();
@@ -748,6 +757,20 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
void DisableReexec();
void MaybeReexec();
+template <typename Fn>
+struct AutoRunner {
+ explicit AutoRunner(Fn fn) : fn_(fn) {}
+ ~AutoRunner() { fn_(); }
+ Fn fn_;
+};
+
+// A simple scope guard. Usage:
+// auto cleanup = at_scope_exit([]{ do_cleanup; });
+template <typename Fn>
+AutoRunner<Fn> at_scope_exit(Fn fn) {
+ return AutoRunner<Fn>(fn);
+}
+
} // namespace __sanitizer
inline void *operator new(__sanitizer::operator_new_size_type size,
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
index a61198ff47a..c247b36c1ee 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
@@ -43,6 +43,8 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
// internal_sigaction instead.
int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
+uptr internal_execve(const char *filename, char *const argv[],
+ char *const envp[]);
#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \
|| defined(__powerpc64__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc
index 8cf2c73b1d5..7a4592e6bd3 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -34,6 +34,7 @@
#include <pthread.h>
#include <signal.h>
#include <sys/resource.h>
+#include <sys/wait.h>
#if SANITIZER_FREEBSD
#include <pthread_np.h>
@@ -546,6 +547,73 @@ void LogMessageOnPrintf(const char *str) {
WriteToSyslog(str);
}
+int StartSubprocess(const char *program, char *const argv[], fd_t std_in_fd,
+ fd_t std_out_fd, fd_t std_err_fd) {
+ auto file_closer = at_scope_exit([&] {
+ if (std_in_fd >= 0) {
+ internal_close(std_in_fd);
+ }
+ if (std_out_fd >= 0) {
+ internal_close(std_out_fd);
+ }
+ if (std_err_fd >= 0) {
+ internal_close(std_err_fd);
+ }
+ });
+
+ if (!FileExists(program)) {
+ Report("WARNING: Program %s not found!\n", program);
+ return -1;
+ }
+
+ int pid = internal_fork();
+
+ if (pid < 0) {
+ int rverrno;
+ if (internal_iserror(pid, &rverrno)) {
+ Report("WARNING: failed to fork (errno %d)\n", rverrno);
+ }
+ return pid;
+ }
+
+ if (pid == 0) {
+ // Child subprocess
+ if (std_in_fd >= 0) {
+ internal_close(STDIN_FILENO);
+ internal_dup2(std_in_fd, STDIN_FILENO);
+ internal_close(std_in_fd);
+ }
+ if (std_out_fd >= 0) {
+ internal_close(STDOUT_FILENO);
+ internal_dup2(std_out_fd, STDOUT_FILENO);
+ internal_close(std_out_fd);
+ }
+ if (std_err_fd >= 0) {
+ internal_close(STDERR_FILENO);
+ internal_dup2(std_err_fd, STDERR_FILENO);
+ internal_close(std_err_fd);
+ }
+
+ for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd);
+
+ internal_execve(program, argv, nullptr);
+ internal__exit(1);
+ }
+
+ return pid;
+}
+
+bool IsProcessRunning(int pid) {
+ int process_status;
+ uptr waitpid_status = internal_waitpid(pid, &process_status, WNOHANG);
+ int local_errno;
+ if (internal_iserror(waitpid_status, &local_errno)) {
+ VReport(1, "Waiting on the process failed (errno %d).\n", local_errno);
+ return false;
+ }
+ return waitpid_status == 0;
+}
+
#endif // SANITIZER_LINUX
} // namespace __sanitizer
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc
index 5d81eaeb10f..4501725fe33 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc
@@ -670,6 +670,18 @@ char **GetArgv() {
return *_NSGetArgv();
}
+int StartSubprocess(const char *program, char *const argv[],
+ fd_t std_in_fd = kInvalidFd, fd_t std_out_fd = kInvalidFd,
+ fd_t std_err_fd = kInvalidFd) {
+ // FIXME: implement on this platform.
+ return -1;
+}
+
+bool IsProcessRunning(int pid) {
+ // FIXME: implement on this platform.
+ return false;
+}
+
} // namespace __sanitizer
#endif // SANITIZER_MAC
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index fc8a7d91ac7..903169f39d6 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -137,47 +137,23 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
CHECK(infd);
CHECK(outfd);
- // Real fork() may call user callbacks registered with pthread_atfork().
- pid = internal_fork();
- if (pid == -1) {
- // Fork() failed.
+ const char *argv[kArgVMax];
+ GetArgV(path_, argv);
+ pid = StartSubprocess(path_, const_cast<char **>(&argv[0]),
+ outfd[0] /* stdin */, infd[1] /* stdout */);
+ if (pid < 0) {
internal_close(infd[0]);
- internal_close(infd[1]);
internal_close(outfd[0]);
- internal_close(outfd[1]);
- Report("WARNING: failed to fork external symbolizer "
- " (errno: %d)\n", errno);
return false;
- } else if (pid == 0) {
- // Child subprocess.
- internal_close(STDOUT_FILENO);
- internal_close(STDIN_FILENO);
- internal_dup2(outfd[0], STDIN_FILENO);
- internal_dup2(infd[1], STDOUT_FILENO);
- internal_close(outfd[0]);
- internal_close(outfd[1]);
- internal_close(infd[0]);
- internal_close(infd[1]);
- for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--)
- internal_close(fd);
- const char *argv[kArgVMax];
- GetArgV(path_, argv);
- execv(path_, const_cast<char **>(&argv[0]));
- internal__exit(1);
}
- // Continue execution in parent process.
- internal_close(outfd[0]);
- internal_close(infd[1]);
input_fd_ = infd[0];
output_fd_ = outfd[1];
}
// Check that symbolizer subprocess started successfully.
- int pid_status;
SleepForMillis(kSymbolizerStartupTimeMillis);
- int exited_pid = waitpid(pid, &pid_status, WNOHANG);
- if (exited_pid != 0) {
+ if (!IsProcessRunning(pid)) {
// Either waitpid failed, or child has already exited.
Report("WARNING: external symbolizer didn't start up correctly!\n");
return false;
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc
index 0c1ee81ac70..5915a01d59b 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc
@@ -775,6 +775,18 @@ char **GetArgv() {
return 0;
}
+int StartSubprocess(const char *program, char *const argv[],
+ fd_t std_in_fd = kInvalidFd, fd_t std_out_fd = kInvalidFd,
+ fd_t std_err_fd = kInvalidFd) {
+ // FIXME: implement on this platform.
+ return -1;
+}
+
+bool IsProcessRunning(int pid) {
+ // FIXME: implement on this platform.
+ return false;
+}
+
} // namespace __sanitizer
#endif // _WIN32
diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc
index eef71010afe..773d77739eb 100644
--- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc
+++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc
@@ -263,6 +263,29 @@ TEST(SanitizerLinux, ThreadSelfTest) {
}
#endif
+TEST(SanitizerCommon, StartSubprocessTest) {
+ int pipe_fds[2];
+ ASSERT_EQ(0, pipe(pipe_fds));
+ const char *argv[] = {"/bin/sh", "-c", "echo -n 'hello'"};
+ int pid = StartSubprocess("/bin/sh", const_cast<char **>(&argv[0]),
+ kInvalidFd /* stdin */, pipe_fds[1] /* stdout */);
+ ASSERT_GT(pid, 0);
+
+ // wait for process to finish.
+ while (IsProcessRunning(pid)) {
+ }
+ ASSERT_FALSE(IsProcessRunning(pid));
+
+ char buffer[256];
+ char *ptr = buffer;
+ uptr bytes_read;
+ while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) {
+ ptr += bytes_read;
+ }
+ ASSERT_EQ(0, memcmp(buffer, "hello", 5)) << "Buffer: " << buffer;
+ internal_close(pipe_fds[0]);
+}
+
} // namespace __sanitizer
#endif // SANITIZER_LINUX
OpenPOWER on IntegriCloud