Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions libc/signal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,15 @@ int kill(pid_t pid, int sig)
}
unsigned sigidx = sig - 1;
if (is_sig_dfl(signal_actions[sigidx])) {
// Per POSIX, the default disposition of SIGCHLD, SIGURG and SIGWINCH is
// to IGNORE (not to terminate the process). OSv treats an unhandled
// SIG_DFL signal as fatal and powers the VM off, which is wrong for
// these three: e.g. delivering SIGCHLD to a process with no handler
// installed must be silently ignored, not fatal. Honor the ignore
// default for them instead of powering off.
if (sig == SIGCHLD || sig == SIGURG || sig == SIGWINCH) {
return 0;
}
// Our default is to power off.
debugf("Uncaught signal %d (\"%s\"). Powering off.\n",
sig, strsignal(sig));
Expand Down
1 change: 1 addition & 0 deletions modules/tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ tests := tst-pthread.so misc-ramdisk.so tst-vblk.so tst-mq-smoke.so tst-bsd-evh.
tst-queue-mpsc.so tst-af-local.so tst-pipe.so tst-yield.so \
misc-ctxsw.so tst-read.so tst-symlink.so tst-openat.so \
tst-eventfd.so tst-remove.so misc-wake.so tst-epoll.so misc-lfring.so \
tst-sig-dfl-ignore.so \
misc-fsx.so tst-sleep.so tst-resolve.so tst-except.so \
misc-tcp-sendonly.so tst-tcp-nbwrite.so misc-tcp-hash-srv.so \
misc-loadbalance.so misc-scheduler.so tst-console.so tst-app.so \
Expand Down
43 changes: 43 additions & 0 deletions tests/tst-sig-dfl-ignore.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2026 Greg Burd
*
* This work is open source software, licensed under the terms of the
* BSD license as described in the LICENSE file in the top-level directory.
*
* SIGCHLD, SIGURG and SIGWINCH have a POSIX default disposition of "ignore".
* Delivering one of them to a process that has installed no handler must be a
* no-op, NOT fatal. Before the fix, OSv's kill() treated any SIG_DFL signal as
* uncaught-and-fatal and powered the VM off, so raising SIGCHLD with no handler
* would kill the guest. This test raises each of the three with the default
* disposition and asserts the process simply survives.
*/

#include <signal.h>
#include <unistd.h>
#include <cstdio>
#include <cassert>
#include <initializer_list>

int main()
{
printf("=== tst-sig-dfl-ignore ===\n");

// No handlers installed => default disposition. Per POSIX these three
// default to ignore, so raise() must return 0 and we must keep running.
for (int sig : {SIGCHLD, SIGURG, SIGWINCH}) {
int r = raise(sig);
printf("raise(%d) -> %d\n", sig, r);
assert(r == 0);
}

// kill(getpid(), ...) of the same signals must also be a no-op survivor.
for (int sig : {SIGCHLD, SIGURG, SIGWINCH}) {
int r = kill(getpid(), sig);
printf("kill(self, %d) -> %d\n", sig, r);
assert(r == 0);
}

// If we reached here, the process was not terminated by any of them.
printf("=== tst-sig-dfl-ignore: PASS (survived SIGCHLD/SIGURG/SIGWINCH) ===\n");
return 0;
}