The signal handler in libc_r (thread_sig_handler) requires alternative stack frame because thread_sigframe_add() changes the original stack. If signal stack is disabled and thread_sig_handler() is called with the original stack, thread_sigframe_add() destroys his own stack. Thread_init() calls sigaltstack() and sets the alternative signal stack. But alternative stack is disabled by the process forking. Then the signal handler fails and the process only receives SIGKILL and SIGSTOP signals. Fix: After forking, define the alternative stack manually and the problem solves. If the invalidation of the signal stack at forking is correct, sigaltstack() must be called somewhere in lib/libc_r/uthread/uthread_fork.c. If the signal stack should be copied to the new process, P_ALTSTACK flag in the process's p_flag must be copied somewhere in sys/kern/kern_fork.c. How-To-Repeat: Running this program. The parent process stops at waitpid() call. The child process can only be stopped by 'kill -KILL pid' command. (It must be compiled with pthread. For example, cc -pthread sample.c) #include <sys/types.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> static void handler(int signo) { fprintf(stderr,"handler called!\n"); _exit(0); } int main(void) { int i; pid_t pid, pid2; int status; pid = fork(); if (pid == -1) return 0; if (pid == 0) { /* child process */ signal(SIGTERM,handler); while(1) ; _exit(0); } /* parent process */ sleep(1); kill(pid, SIGTERM); fprintf(stderr, "waitpid start\n"); waitpid(pid, &status, 0); fprintf(stderr, "waitpid end\n"); return 0; }
Responsible Changed From-To: freebsd-bugs->deischen He maintains libc_r and has a fix.
State Changed From-To: open->closed Fix applied to -current. Will apply to -stable in a few days or when the code freeze is over (whichever comes last).