unix: fix SIGCHLD race in process.c

Start the SIGCHLD signal watcher before calling fork(). There was a very subtle
race where a child process could quit (and generate a SIGCHILD) before the
signal handler was installed.

To reproduce, call uv_spawn() repeatedly with the below x86_64 program:

    // compile with `gcc -O2 -nostdlib`
    void _start(void)
    {
      // syscall(SYS_exit, 0)
      __asm__ __volatile__ (
        "xorq %rdi, %rdi;"
        "xorq %rax, %rax;"
        "mov $0x3c, %al;"
        "syscall;"
      );
      for (;;);
    }
This commit is contained in:
Ben Noordhuis 2012-08-13 16:36:29 +02:00
parent 9d7e300364
commit 758a76922b

View File

@ -400,6 +400,8 @@ int uv_spawn(uv_loop_t* loop,
if (uv__make_pipe(signal_pipe, 0))
goto error;
uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
pid = fork();
if (pid == -1) {
@ -440,7 +442,6 @@ int uv_spawn(uv_loop_t* loop,
q = uv__process_queue(loop, pid);
ngx_queue_insert_tail(q, &process->queue);
uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
process->pid = pid;
process->exit_cb = options.exit_cb;