Skip to content

Commit 7de2f22

Browse files
authored
Discard ignored signals on New Technology (#592)
1 parent 4b4ea04 commit 7de2f22

File tree

4 files changed

+57
-1
lines changed

4 files changed

+57
-1
lines changed

libc/calls/sig.internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ bool __sig_handle(bool, int, int, ucontext_t *) hidden;
3131
int __sig_add(int, int) hidden;
3232
int __sig_mask(int, const sigset_t *, sigset_t *) hidden;
3333
int __sig_raise(int, int) hidden;
34+
void __sig_check_ignore(const int, const unsigned) hidden;
3435

3536
COSMOPOLITAN_C_END_
3637
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

libc/calls/sig2.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ textwindows int __sig_add(int sig, int si_code) {
246246
}
247247

248248
/**
249-
* Enqueues generic signal for delivery on New Technology.
249+
* Checks for unblocked signals and delivers them on New Technology.
250250
*
251251
* @param restartable is for functions like read() but not poll()
252252
* @return true if EINTR should be returned by caller
@@ -264,3 +264,38 @@ textwindows bool __sig_check(bool restartable) {
264264
}
265265
return delivered;
266266
}
267+
268+
/**
269+
* Determines if a signal should be ignored and if so discards existing
270+
* instances of said signal on New Technology.
271+
*
272+
* Even blocked signals are discarded.
273+
*
274+
* @param sig the signal number to remove
275+
* @threadsafe
276+
*/
277+
textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
278+
struct Signal *cur, *prev, *next;
279+
if (rva != (unsigned)(intptr_t)SIG_IGN &&
280+
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_isfatal(sig))) {
281+
return;
282+
}
283+
if (__sig.queue) {
284+
__sig_lock();
285+
for (prev = 0, cur = __sig.queue; cur; cur = next) {
286+
next = cur->next;
287+
if (sig == cur->sig) {
288+
if (cur == __sig.queue) {
289+
__sig.queue = cur->next;
290+
} else if (prev) {
291+
prev->next = cur->next;
292+
}
293+
__sig_handle(false, cur->sig, cur->si_code, 0);
294+
__sig_free(cur);
295+
} else {
296+
prev = cur;
297+
}
298+
}
299+
__sig_unlock();
300+
}
301+
}

libc/calls/sigaction.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ static int __sigaction(int sig, const struct sigaction *act,
258258
if (act) {
259259
__sighandrvas[sig] = rva;
260260
__sighandflags[sig] = act->sa_flags;
261+
__sig_check_ignore(sig, rva);
261262
}
262263
}
263264
return rc;

test/libc/calls/sigaction_test.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,22 @@ noubsan void ubsanTrumpsSystemsEngineering(void) {
156156
TEST(sigaction, sigFpe_handlerCanEditProcessStateAndRecoverExecution) {
157157
ubsanTrumpsSystemsEngineering();
158158
}
159+
160+
static unsigned OnSignalCnt = 0;
161+
void OnSignal(int sig, siginfo_t *si, void *ctx) {
162+
OnSignalCnt++;
163+
}
164+
165+
TEST(sigaction, ignoringSignalDiscardsSignal) {
166+
struct sigaction sa = {.sa_sigaction = OnSignal, .sa_flags = SA_SIGINFO};
167+
ASSERT_EQ(0, sigaction(SIGUSR1, &sa, NULL));
168+
sigset_t blocked;
169+
sigemptyset(&blocked);
170+
sigaddset(&blocked, SIGUSR1);
171+
ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &blocked, NULL));
172+
ASSERT_EQ(0, raise(SIGUSR1));
173+
ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_IGN));
174+
ASSERT_EQ(0, sigaction(SIGUSR1, &sa, NULL));
175+
ASSERT_EQ(0, sigprocmask(SIG_UNBLOCK, &blocked, NULL));
176+
EXPECT_EQ(0, OnSignalCnt);
177+
}

0 commit comments

Comments
 (0)