Index: lib/sanitizer_common/sanitizer_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -279,6 +279,15 @@ 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,18 @@ void DisableReexec(); void MaybeReexec(); +template +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 +AutoRunner at_scope_exit(Fn fn) { return AutoRunner(fn); } + } // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, Index: lib/sanitizer_common/sanitizer_common.cc =================================================================== --- lib/sanitizer_common/sanitizer_common.cc +++ lib/sanitizer_common/sanitizer_common.cc @@ -423,6 +423,10 @@ 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; Index: lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux.cc +++ lib/sanitizer_common/sanitizer_linux.cc @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -1233,6 +1234,74 @@ // No need to re-exec on Linux. } +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; +} + } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX Index: lib/sanitizer_common/sanitizer_mac.cc =================================================================== --- lib/sanitizer_common/sanitizer_mac.cc +++ lib/sanitizer_common/sanitizer_mac.cc @@ -670,6 +670,18 @@ 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 Index: lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -137,47 +137,23 @@ 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(&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(&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; Index: lib/sanitizer_common/sanitizer_win.cc =================================================================== --- lib/sanitizer_common/sanitizer_win.cc +++ lib/sanitizer_common/sanitizer_win.cc @@ -775,6 +775,18 @@ 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