waitpid WNOHANG on debugged-process returns -ECHILD
Originator: | rsesek | ||
Number: | rdar://47533738 | Date Originated: | 2019-01-24 |
Status: | Open | Resolved: | |
Product: | macOS + SDK | Product Version: | 10.14.3 18D42 |
Classification: | Bug | Reproducible: | Always |
Area: Something not on this list Summary: In order to implement a "waitpid with timeout" function, we have a function that calls waitpid(pid, &stat, WNOHANG) in a loop, with nanosleep() calls up to a certain timeout. We've found that if a debugger is attached to the child being waited on, waitpid() returns -1 with errno set to ECHILD. Before the debugger is attached, and after it is again detached, waitpid() returns 0. It is in the debugger-attached state that waitpid() returns unexpected results. Steps to Reproduce: 1. Download waitpid-debugger.c and compile it 2. Run the program, output like this will be observed: PARENT: created child 43439 PARENT: starting waitpid PARENT: waitpid() returned 0, stat=0, errno=0 (Undefined error: 0) CHILD: now running, pid=43439 CHILD: busy loop PARENT: waitpid() returned 0, stat=0, errno=0 (Undefined error: 0) PARENT: waitpid() returned 0, stat=0, errno=0 (Undefined error: 0) CHILD: busy loop 3. In a new shell, do `lldb -p <pid-of-child>` 4. Observe the output change to: PARENT: waitpid() returned -1, stat=0, errno=10 (No child processes) 5. In lldb, detach from the process 6. Observe the output return to: PARENT: waitpid() returned 0, stat=0, errno=0 (Undefined error: 0) Expected Results: waitpid() should continue to return 0 when a debugger is attached to the process. Actual Results: waitpid() returns -1 with ECHILD errno. Note that continuing in lldb to move the process out of the STOPPED state does not affect the results, nor does passing WUNTRACED in the options to waitpid(). Version/Build: 10.14.3 18D42 10.10.5 14F1713 =================================== % cat /Volumes/Build/tests/waitpid-debugger.c // clang -o waitpid-debugger waitpid-debugger.c #include <stdio.h> #include <string.h> #include <sys/errno.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> void do_parent(pid_t child_pid) { printf("PARENT: created child %d\n", child_pid); printf("PARENT: starting waitpid\n"); for (;;) { errno = 0; int statloc = 0; int rv = waitpid(child_pid, &statloc, WNOHANG|WUNTRACED); printf("PARENT: waitpid() returned %d, stat=%d, errno=%d (%s)\n", rv, statloc, errno, strerror(errno)); #if 0 if (rv != 0) break; #endif sleep(2); } printf("PARENT: exiting\n"); } void do_child() { printf("CHILD: now running, pid=%d\n", getpid()); for (;;) { printf("CHILD: busy loop\n"); sleep(5); } } int main() { pid_t pid = fork(); if (pid == -1) { perror("fork()"); return 1; } else if (pid == 0) { do_child(); } else { do_parent(pid); } return 0; }
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!