forked from OSchip/llvm-project
[sanitizers] extracted process management functions
Differential Revision: http://reviews.llvm.org/D16542 llvm-svn: 258710
This commit is contained in:
parent
d3d51061fb
commit
53849fee26
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue