diff --git a/glib/gmain.c b/glib/gmain.c index ded5dccbf..329e6d399 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -5670,6 +5670,9 @@ ref_unix_signal_handler_unlocked (int signum) action.sa_flags = SA_RESTART | SA_NOCLDSTOP; #else action.sa_flags = SA_NOCLDSTOP; +#endif +#ifdef SA_ONSTACK + action.sa_flags |= SA_ONSTACK; #endif sigaction (signum, &action, NULL); } diff --git a/glib/tests/unix.c b/glib/tests/unix.c index 1defb3de0..08c36c929 100644 --- a/glib/tests/unix.c +++ b/glib/tests/unix.c @@ -30,6 +30,7 @@ #include "glib-unix.h" #include "gstdio.h" +#include #include #include #include @@ -507,6 +508,7 @@ on_sig_received_2 (gpointer data) static void test_signal (int signum) { + struct sigaction action; GMainLoop *mainloop; int id; @@ -515,6 +517,17 @@ test_signal (int signum) sig_received = FALSE; sig_counter = 0; g_unix_signal_add (signum, on_sig_received, mainloop); + + g_assert_no_errno (sigaction (signum, NULL, &action)); + + g_assert_true (action.sa_flags & SA_NOCLDSTOP); +#ifdef SA_RESTART + g_assert_true (action.sa_flags & SA_RESTART); +#endif +#ifdef SA_ONSTACK + g_assert_true (action.sa_flags & SA_ONSTACK); +#endif + kill (getpid (), signum); g_assert (!sig_received); id = g_timeout_add (5000, on_sig_timeout, mainloop); @@ -554,6 +567,46 @@ test_sigterm (void) test_signal (SIGTERM); } +static void +test_signal_alternate_stack (int signal) +{ +#ifndef SA_ONSTACK + g_test_skip ("alternate stack is not supported"); +#else + guint8 stack_memory[MINSIGSTKSZ]; + guint8 zero_mem[MINSIGSTKSZ]; + stack_t stack = { .ss_sp = stack_memory, .ss_size = MINSIGSTKSZ }; + stack_t old_stack = { 0 }; + + memset (stack_memory, 0, MINSIGSTKSZ); + memset (zero_mem, 0, MINSIGSTKSZ); + g_assert_cmpmem (stack_memory, MINSIGSTKSZ, zero_mem, MINSIGSTKSZ); + + g_assert_no_errno (sigaltstack (&stack, &old_stack)); + + test_signal (signal); + + /* Very stupid check to ensure that the alternate stack is used instead of + * the default one. This test would fail if SA_ONSTACK wouldn't be set. + */ + g_assert_cmpint (memcmp (stack_memory, zero_mem, MINSIGSTKSZ), !=, 0); + + g_assert_no_errno (sigaltstack (&old_stack, NULL)); +#endif +} + +static void +test_sighup_alternate_stack (void) +{ + test_signal_alternate_stack (SIGHUP); +} + +static void +test_sigterm_alternate_stack (void) +{ + test_signal_alternate_stack (SIGTERM); +} + static void test_sighup_add_remove (void) { @@ -807,6 +860,9 @@ main (int argc, g_test_add_func ("/glib-unix/sighup", test_sighup); g_test_add_func ("/glib-unix/sigterm", test_sigterm); g_test_add_func ("/glib-unix/sighup_again", test_sighup); + g_test_add_func ("/glib-unix/sighup/alternate-stack", test_sighup_alternate_stack); + g_test_add_func ("/glib-unix/sigterm/alternate-stack", test_sigterm_alternate_stack); + g_test_add_func ("/glib-unix/sighup_again/alternate-stack", test_sighup_alternate_stack); g_test_add_func ("/glib-unix/sighup_add_remove", test_sighup_add_remove); g_test_add_func ("/glib-unix/sighup_nested", test_sighup_nested); g_test_add_func ("/glib-unix/callback_after_signal", test_callback_after_signal);