Skip to content

Commit 985af57

Browse files
i#7748: Fix signal stack overflow during thread synch (#7749)
I have noticed an intermittent failure of ap.detach_state which appears to be caused by signal stack overflow while the two threads in the test are synching. The intended order of events goes something like this: - Thread 1 is trying to synch with thread 2 and sends it a suspend signal. - Thread 2 handles the suspend and waits to be woken up. - Thread 1 finds that thread 2 was not suspended at a safe spot, wakes up thread 2 and waits to be notified that thread 2 has resumed. - Thread 2 wakes up, notifies 1 that it has resumed and returns from the signal handler. - Thread 1 goes back around the synch loop and sends another suspend signal. The process loops until thread 2 is suspended in a good state. The problem comes if thread 2 is interrupted during step 4 after it has notified thread 1 but before the signal handler returns. In that case thread 1 can send another suspend signal before the first signal handler call exits. SIGILL (the suspend signal) is unblocked during the signal handler (see i#184) so on a busy system these signals stack up until we run out of signal stack and crash. The solution I have found is for thread 2 to block the suspend signal before notifying thread 1 to make sure it cannot be interrupted with a second suspend signal. Fixes #7748
1 parent 92be9e4 commit 985af57

File tree

1 file changed

+10
-0
lines changed

1 file changed

+10
-0
lines changed

core/unix/signal.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8837,7 +8837,17 @@ handle_suspend_signal(dcontext_t *dcontext, kernel_siginfo_t *siginfo,
88378837

88388838
if (unblocked_sigs) {
88398839
/* re-block so our exit from main_signal_handler is not interrupted */
8840+
kernel_sigaddset(&prevmask, SUSPEND_SIGNAL);
88408841
sigprocmask_syscall(SIG_SETMASK, &prevmask, NULL, sizeof(prevmask));
8842+
} else {
8843+
/* Prevent another SUSPEND_SIGNAL interrupting main_signal_handler before we
8844+
* exit.
8845+
*/
8846+
kernel_sigset_t mask;
8847+
kernel_sigemptyset(&mask);
8848+
kernel_sigaddset(&mask, SUSPEND_SIGNAL);
8849+
8850+
sigprocmask_syscall(SIG_BLOCK, &mask, NULL, sizeof(mask));
88418851
}
88428852
ostd->suspended_sigcxt = NULL;
88438853

0 commit comments

Comments
 (0)