summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Tim Murray <timmurray@google.com> 2022-02-17 10:01:19 -0800
committer Tim Murray <timmurray@google.com> 2022-02-17 11:08:08 -0800
commit00ff352c34cb46d96156cdef69a6acf0bdfa5356 (patch)
tree64fa0c8acb626c89d921440ed7431c84ad4cbf6f
parenta4419eb57ab7f69b8c1d3ce125e2207b66a05393 (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.cpp17
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);