Opened 15 months ago
Last modified 15 months ago
#18549 new bug
abort() calls debugger when no signal handler for SIGABRT is set, inviting the user to kill the app with SIGKILLTHR rather than terminate 'normally' with SIGABRT
Reported by: | nielx | Owned by: | nobody |
---|---|---|---|
Priority: | low | Milestone: | Unscheduled |
Component: | System/libroot.so | Version: | R1/beta4 |
Keywords: | debugger, posix | Cc: | |
Blocked By: | Blocking: | ||
Platform: | All |
Description (last modified by )
Background
While testing binutils, one of the tests (test-pexecute
) fails because it cannot seem to capture the signal that terminated a spawned child process. The child process was killed by calling abort()
, which causes the SIGABRT
signal. The child process did not capture that signal. Instead the Debugger window popped up, and when the process was terminated there, the SIGKILLTHR
was returned instead.
Reproduction Steps
The attached demonstration utility (test-signal.cpp
) demonstrates the problem.
It does the following:
- When running without arguments, its sets up a new process using
posix_spawn()
. - The main process will wait for the completion of the child process using
waitpid()
, which captures (amongst other things) the signal that terminates the child. - The child process uses
abort()
to terminate, which should send theSIGABRT
signal. - The
debug_server
captures the crashing process and brings up the dialog giving the user the options what to do. Select 'Kill' to terminate the process. - The main process evaluates the reason why the child was terminated, and by which signal.
Expected Outcome
The main process can determine that the child process was terminated by SIGABRT
.
Actual Outcome
The child process is marked as terminated by SIGKILLTHR
Note
Based on comments by waddlesplash and PulkoMandy below, the our abort()
call in libroot calls the debugger()
when the SIGABRT is not handled by the team. This then brings up the debug_server
popup window that asks a user to decide what to do next (kill, debugger, core dump). A user can decide to open the Debugger and choose to continue execution. In that case, the application works as expected.
Attachments (1)
Change History (5)
by , 15 months ago
Attachment: | test-signal.cpp added |
---|
follow-up: 2 comment:1 by , 15 months ago
comment:2 by , 15 months ago
Replying to waddlesplash:
I think the alternative here would be to add special handling in the kernel for SIGABRT to invoke Debugger automatically, like SIGSEGV do (when there's no handler, anyway), instead of invoking debugger().
Sounds good idea.
comment:3 by , 15 months ago
It looks like when the user terminates the process through the debug_server, the original unhandled signal is overwritten.
To confirm this, you can attach debugger to the process, then quit debugger and select to resume the debugged process. It should finish exiting cleanly.
I guess debug_server could offer an option to do that directly? "Attempt to continue" or something?
I think the alternative here would be to add special handling in the kernel for SIGABRT to invoke Debugger automatically, like SIGSEGV do (when there's no handler, anyway), instead of invoking debugger().
It should invoke the debug_server prompt, not Debugger directly.
I'm not sure it would change much to the core of the problem, however: we are stretching a bit the meaning of "abnormal program termination", and some programs seem to expect abort() to behave somewhat similarly to exit(EXIT_FAILURE), which, in our case, it doesn't.
@nielx, I am interested in your progress on running the binutils test suite, I tried it (for another binutils port) recently and ran into problems with expect: https://github.com/haikuports/haikuports/issues/8910
comment:4 by , 15 months ago
Component: | System/POSIX → System/libroot.so |
---|---|
Description: | modified (diff) |
Priority: | normal → low |
Summary: | waitpid() does not capture signal of a terminated child process other than SIGKILLTHR → abort() calls debugger when no signal handler for SIGABRT is set, inviting the user to kill the app with SIGKILLTHR rather than terminate 'normally' with SIGABRT |
Thanks PulkoMandy. You were correct in that one could resume the process and get the correct outcome. I guess it was a case of user error (the user is me!). After reviewing the code (thanks waddlesplash), it is clear that the debugger() call only pauses the execution, not terminates it.
Arguably it is more of a UI problem than a bug in our POSIX implementation. Moving priority to low and even contemplating whether or not to change this into an enhancement.
No, this is actually a different issue: abort() doesn't raise the signal but calls debugger() if no signal handler is installed: https://github.com/haiku/haiku/blob/b761f9250ab357afa892fc1e1a9f39ca55317b16/src/system/libroot/posix/stdlib/exit.cpp#L286
Otherwise the application would just exit silently, which is not what we want.
I suppose, reading the specification, that we are indeed noncompliant here: https://pubs.opengroup.org/onlinepubs/9699919799/functions/abort.html
Further there are notes about "override blocking of the SIGABRT" signal, which I don't think we do.
The code to invoke debugger was added by me some years ago, I believe. I think the alternative here would be to add special handling in the kernel for SIGABRT to invoke Debugger automatically, like SIGSEGV do (when there's no handler, anyway), instead of invoking debugger(). Then we would get a crash dialog, and calling processes would see the correct signal.