Skip to content

Commit

Permalink
erts: Fix child setup signal hander bug
Browse files Browse the repository at this point in the history
When running the signal handler, the errno has to be restored
to its original value, otherwise code running in the same thread
may misbehave.
  • Loading branch information
garazdawi committed Sep 2, 2016
1 parent bba0f59 commit 7c5f497
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 7 deletions.
14 changes: 12 additions & 2 deletions erts/emulator/sys/unix/erl_child_setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ start_new_child(int pipes[])
* for posterity. */

static void handle_sigchld(int sig) {
int buff[2], res;
int buff[2], res, __preverrno = errno;

sys_sigblock(SIGCHLD);

Expand All @@ -362,6 +362,16 @@ static void handle_sigchld(int sig) {
}

sys_sigrelease(SIGCHLD);

/* We save and restore the original errno as otherwise
the thread we are running in may end up with an
unexpected errno. An example of when this happened
was when the select in main had gotten an EINTR but
before the errno was checked the signal handler
was called and set errno to ECHILD from waitpid
which caused erl_child_setup to abort as it does
not expect ECHILD to be set after select */
errno = __preverrno;
}

#if defined(__ANDROID__)
Expand Down Expand Up @@ -423,7 +433,7 @@ main(int argc, char *argv[])
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
if (sigaction(SIGCHLD, &sa, 0) == -1) {
perror(0);
perror(NULL);
exit(1);
}

Expand Down
12 changes: 7 additions & 5 deletions erts/emulator/sys/unix/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -715,11 +715,13 @@ static RETSIGTYPE suspend_signal(void)
static RETSIGTYPE suspend_signal(int signum)
#endif
{
int res;
int buf[1];
do {
res = read(sig_suspend_fds[0], buf, sizeof(int));
} while (res < 0 && errno == EINTR);
int res, buf[1], __errno = errno;
do {
res = read(sig_suspend_fds[0], buf, sizeof(int));
} while (res < 0 && errno == EINTR);

/* restore previous errno in case read changed it */
errno = __errno;
}
#endif /* #ifdef ERTS_SYS_SUSPEND_SIGNAL */

Expand Down

0 comments on commit 7c5f497

Please sign in to comment.