diff options
author | 2022-02-17 10:01:19 -0800 | |
---|---|---|
committer | 2022-02-17 11:08:08 -0800 | |
commit | 00ff352c34cb46d96156cdef69a6acf0bdfa5356 (patch) | |
tree | 64fa0c8acb626c89d921440ed7431c84ad4cbf6f | |
parent | a4419eb57ab7f69b8c1d3ce125e2207b66a05393 (diff) |
dumpstate: fix race in waitpid_with_timeout()
If the child process exits fast enough, then sigtimedwait will never
get a signal and never actually call waitpid. Check to see if the
child process has already died before calling sigtimedwait.
Test: dumpstate_test
Bug: 215574756
Change-Id: I5d0fa5d537e502b2a8254f8d6ba218f3f7161229
-rw-r--r-- | cmds/dumpstate/DumpstateUtil.cpp | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp index c833d0e6bd..81baf855f0 100644 --- a/cmds/dumpstate/DumpstateUtil.cpp +++ b/cmds/dumpstate/DumpstateUtil.cpp @@ -48,11 +48,26 @@ static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) { sigemptyset(&child_mask); sigaddset(&child_mask, SIGCHLD); + // block SIGCHLD before we check if a process has exited if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) { printf("*** sigprocmask failed: %s\n", strerror(errno)); return false; } + // if the child has exited already, handle and reset signals before leaving + pid_t child_pid = waitpid(pid, status, WNOHANG); + if (child_pid != pid) { + if (child_pid > 0) { + printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid); + sigprocmask(SIG_SETMASK, &old_mask, nullptr); + return false; + } + } else { + sigprocmask(SIG_SETMASK, &old_mask, nullptr); + return true; + } + + // wait for a SIGCHLD timespec ts; ts.tv_sec = MSEC_TO_SEC(timeout_ms); ts.tv_nsec = (timeout_ms % 1000) * 1000000; @@ -76,7 +91,7 @@ static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) { return false; } - pid_t child_pid = waitpid(pid, status, WNOHANG); + child_pid = waitpid(pid, status, WNOHANG); if (child_pid != pid) { if (child_pid != -1) { printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid); |