diff options
author | Mike Aizatsky <aizatsky@chromium.org> | 2016-01-26 20:10:01 +0000 |
---|---|---|
committer | Mike Aizatsky <aizatsky@chromium.org> | 2016-01-26 20:10:01 +0000 |
commit | ba3cad62c7bd5e839b8f8df765337e4ec113edd4 (patch) | |
tree | 953cd5d0f865f036a920442828438c7771baef8a /lib/sanitizer_common | |
parent | a4225860cbaea66a30477500507710875fb84516 (diff) |
[sanitizers] extracted process management functions
Differential Revision: http://reviews.llvm.org/D16546
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@258849 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/sanitizer_common')
-rw-r--r-- | lib/sanitizer_common/sanitizer_common.cc | 4 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_common.h | 28 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_internal_defs.h | 1 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_posix.h | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_posix_libcdep.cc | 63 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc | 36 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_win.cc | 14 | ||||
-rw-r--r-- | lib/sanitizer_common/tests/sanitizer_linux_test.cc | 30 |
8 files changed, 148 insertions, 30 deletions
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 3f2a6f4b2..ce91dc460 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/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/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 97f5cada7..c41dc9f09 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -279,6 +279,17 @@ 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 not kInvalidFd their corresponding input/output +// streams will be redirect to the file. The files will always be closed +// in parent process even in case of an error. +// The child process will close all fds after STDERR_FILENO +// before passing control to a program. +pid_t StartSubprocess(const char *filename, const char *const argv[], + fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd, + fd_t stderr_fd = kInvalidFd); +// Checks if specified process is still running +bool IsProcessRunning(pid_t pid); u32 GetUid(); void ReExec(); @@ -748,6 +759,23 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp); void DisableReexec(); void MaybeReexec(); +template <typename Fn> +class RunOnDestruction { + public: + explicit RunOnDestruction(Fn fn) : fn_(fn) {} + ~RunOnDestruction() { fn_(); } + + private: + Fn fn_; +}; + +// A simple scope guard. Usage: +// auto cleanup = at_scope_exit([]{ do_cleanup; }); +template <typename Fn> +RunOnDestruction<Fn> at_scope_exit(Fn fn) { + return RunOnDestruction<Fn>(fn); +} + } // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index c78069b52..94808148f 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -89,6 +89,7 @@ typedef unsigned error_t; typedef int fd_t; typedef int error_t; #endif +typedef int pid_t; // WARNING: OFF_T may be different from OS type off_t, depending on the value of // _FILE_OFFSET_BITS. This definition of OFF_T matches the ABI of system calls diff --git a/lib/sanitizer_common/sanitizer_posix.h b/lib/sanitizer_common/sanitizer_posix.h index 3247b6944..ccd39166b 100644 --- a/lib/sanitizer_common/sanitizer_posix.h +++ b/lib/sanitizer_common/sanitizer_posix.h @@ -81,6 +81,8 @@ int my_pthread_attr_getstack(void *attr, void **addr, uptr *size); int internal_sigaction(int signum, const void *act, void *oldact); void internal_sigfillset(__sanitizer_sigset_t *set); +uptr internal_execve(const char *filename, char *const argv[], + char *const envp[]); } // namespace __sanitizer #endif // SANITIZER_POSIX_H diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index c158eedae..91330b555 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -34,6 +34,7 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> +#include <sys/wait.h> #include <unistd.h> #if SANITIZER_FREEBSD @@ -320,6 +321,68 @@ void AdjustStackSize(void *attr_) { } #endif // !SANITIZER_GO +pid_t StartSubprocess(const char *program, const char *const argv[], + fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { + auto file_closer = at_scope_exit([&] { + if (stdin_fd != kInvalidFd) { + internal_close(stdin_fd); + } + if (stdout_fd != kInvalidFd) { + internal_close(stdout_fd); + } + if (stderr_fd != kInvalidFd) { + internal_close(stderr_fd); + } + }); + + 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 (stdin_fd != kInvalidFd) { + internal_close(STDIN_FILENO); + internal_dup2(stdin_fd, STDIN_FILENO); + internal_close(stdin_fd); + } + if (stdout_fd != kInvalidFd) { + internal_close(STDOUT_FILENO); + internal_dup2(stdout_fd, STDOUT_FILENO); + internal_close(stdout_fd); + } + if (stderr_fd != kInvalidFd) { + internal_close(STDERR_FILENO); + internal_dup2(stderr_fd, STDERR_FILENO); + internal_close(stderr_fd); + } + + for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd); + + internal_execve(program, const_cast<char **>(&argv[0]), nullptr); + internal__exit(1); + } + + return pid; +} + +bool IsProcessRunning(pid_t 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; +} + } // namespace __sanitizer #endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index fc8a7d91a..e84fef09f 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/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_, argv, /* stdin */ outfd[0], + /* stdout */ infd[1]); + 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/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 0c1ee81ac..46bdca6e4 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -775,6 +775,20 @@ char **GetArgv() { return 0; } +pid_t StartSubprocess(const char *program, const char *const argv[], + fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { + // FIXME: implement on this platform + // Should be implemented based on + // SymbolizerProcess::StarAtSymbolizerSubprocess + // from lib/sanitizer_common/sanitizer_symbolizer_win.cc. + return -1; +} + +bool IsProcessRunning(pid_t pid) { + // FIXME: implement on this platform. + return false; +} + } // namespace __sanitizer #endif // _WIN32 diff --git a/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/lib/sanitizer_common/tests/sanitizer_linux_test.cc index eef71010a..92d495e10 100644 --- a/lib/sanitizer_common/tests/sanitizer_linux_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_linux_test.cc @@ -263,6 +263,36 @@ 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)) { + if (!bytes_read) { + break; + } + ptr += bytes_read; + } + ASSERT_EQ(5, ptr - buffer); + *ptr = 0; + } + ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer; + internal_close(pipe_fds[0]); +} + } // namespace __sanitizer #endif // SANITIZER_LINUX |