fdm: always check for signals after epoll_pwait(), not only on EINTR #535

Manually merged
dnkl merged 1 commits from fdm-always-check-for-signals into master 8 months ago
  1. 3
      CHANGELOG.md
  2. 32
      fdm.c

3
CHANGELOG.md

@ -110,6 +110,9 @@
scaling factor > 1 (https://codeberg.org/dnkl/foot/issues/509).
* Crash caused by certain CSI sequences with very large parameter
values (https://codeberg.org/dnkl/foot/issues/522).
* Rare occurrences where the window did not close when the shell
exited. Only seen on FreeBSD
(https://codeberg.org/dnkl/foot/issues/534)
### Security

32
fdm.c

@ -52,6 +52,7 @@ struct fdm {
hooks_t hooks_high;
};
static volatile sig_atomic_t got_signal = false;
static volatile sig_atomic_t *received_signals = NULL;
struct fdm *
@ -71,6 +72,7 @@ fdm_init(void)
xassert(received_signals == NULL); /* Only one FDM instance supported */
received_signals = xcalloc(SIGRTMAX, sizeof(received_signals[0]));
got_signal = false;
struct fdm *fdm = malloc(sizeof(*fdm));
if (unlikely(fdm == NULL)) {
@ -328,6 +330,7 @@ fdm_hook_del(struct fdm *fdm, fdm_hook_t hook, enum fdm_hook_priority priority)
static void
signal_handler(int signo)
{
got_signal = true;
received_signals[signo] = true;
}
@ -424,27 +427,28 @@ fdm_poll(struct fdm *fdm)
int r = epoll_pwait(
fdm->epoll_fd, events, tll_length(fdm->fds), -1, &fdm->sigmask);
if (unlikely(r < 0)) {
if (errno == EINTR) {
/* TODO: is it possible to receive a signal without
* getting EINTR here? */
int errno_copy = errno;
for (int i = 0; i < SIGRTMAX; i++) {
if (received_signals[i]) {
if (unlikely(got_signal)) {
got_signal = false;
received_signals[i] = false;
struct sig_handler *handler = &fdm->signal_handlers[i];
for (int i = 0; i < SIGRTMAX; i++) {
if (received_signals[i]) {
received_signals[i] = false;
struct sig_handler *handler = &fdm->signal_handlers[i];
xassert(handler->callback != NULL);
if (!handler->callback(fdm, i, handler->callback_data))
return false;
}
xassert(handler->callback != NULL);
if (!handler->callback(fdm, i, handler->callback_data))
return false;
}
}
}
if (unlikely(r < 0)) {
if (errno_copy == EINTR)
return true;
}
LOG_ERRNO("failed to epoll");
LOG_ERRNO_P(errno_copy, "failed to epoll");
return false;
}

Loading…
Cancel
Save