gmain: Use alternate signal stack if the application provides one

Some applications, toolkits or languages may define an alternative stack
to use for traces. This is for example the case of go.

So, in case an application defines an alternate signal stack, GLib should
use that instead of the default one to receive signals otherwise it may
break the application expectations and write where it's not allowed to.
This commit is contained in:
Marco Trevisan (Treviño) 2024-03-25 20:28:21 +01:00
parent 4607dd77a1
commit 137db219a7
2 changed files with 59 additions and 0 deletions

View File

@ -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);
}

View File

@ -30,6 +30,7 @@
#include "glib-unix.h"
#include "gstdio.h"
#include <signal.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>
@ -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);