diff options
author | Lukas Larsson <[email protected]> | 2016-08-31 11:11:27 +0200 |
---|---|---|
committer | Lukas Larsson <[email protected]> | 2016-09-02 09:51:55 +0200 |
commit | 7c5f497ab6f4b145554ee884e9fa0ec86246e9ee (patch) | |
tree | 70ed27668b160a44ff81cf7c6dca96ecedd58373 /erts/emulator/sys | |
parent | bba0f5924fa9478d41903331a3285f117c112731 (diff) | |
download | otp-7c5f497ab6f4b145554ee884e9fa0ec86246e9ee.tar.gz otp-7c5f497ab6f4b145554ee884e9fa0ec86246e9ee.tar.bz2 otp-7c5f497ab6f4b145554ee884e9fa0ec86246e9ee.zip |
erts: Fix child setup signal hander bug
When running the signal handler, the errno has to be restored
to its original value, otherwise code running in the same thread
may misbehave.
Diffstat (limited to 'erts/emulator/sys')
-rw-r--r-- | erts/emulator/sys/unix/erl_child_setup.c | 14 | ||||
-rw-r--r-- | erts/emulator/sys/unix/sys.c | 12 |
2 files changed, 19 insertions, 7 deletions
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c index 6b9ddd8da4..69fc6c2879 100644 --- a/erts/emulator/sys/unix/erl_child_setup.c +++ b/erts/emulator/sys/unix/erl_child_setup.c @@ -348,7 +348,7 @@ child_error: * for posterity. */ static void handle_sigchld(int sig) { - int buff[2], res; + int buff[2], res, __preverrno = errno; sys_sigblock(SIGCHLD); @@ -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__) @@ -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); } diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index 6fb86f6dda..089efec3e8 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -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 */ |