scc-make: Avoid signal race conditions - scc - simple c99 compiler
 (HTM) git clone git://git.simple-cc.org/scc
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 93e07bb34a825734d760971f811ac43868fd8c48
 (DIR) parent e19109cd35b8d64480c74389b8faaedf5af9b0ed
 (HTM) Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
       Date:   Tue, 28 Oct 2025 21:10:31 +0100
       
       scc-make: Avoid signal race conditions
       
       Expecting ait to be interrupted by a signal is too risky
       and it is very easy to be caught by race conditions. The
       best option is to kill in the snal handler and lock signals
       until we are ready to deal with them.
       
       Diffstat:
         M src/cmd/scc-make/main.c             |       1 +
         M src/cmd/scc-make/make.h             |       1 +
         M src/cmd/scc-make/posix.c            |      35 +++++++++++++++++++++++++------
       
       3 files changed, 31 insertions(+), 6 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/scc-make/main.c b/src/cmd/scc-make/main.c
       @@ -90,6 +90,7 @@ estrdup(char *s)
        void
        sighandler(int signo)
        {
       +        killchild();
                stop = signo;
        }
        
 (DIR) diff --git a/src/cmd/scc-make/make.h b/src/cmd/scc-make/make.h
       @@ -67,6 +67,7 @@ extern char *getmacro(char *);
        extern void setmacro(char *, char *, int, int);
        
        /* system depdendant */
       +extern void killchild(void);
        extern time_t stamp(char *);
        extern int launch(char *, int);
        extern int putenv(char *);
 (DIR) diff --git a/src/cmd/scc-make/posix.c b/src/cmd/scc-make/posix.c
       @@ -12,6 +12,17 @@
        
        #include "make.h"
        
       +
       +static volatile pid_t pid;
       +
       +void
       +killchild(void)
       +{
       +        if (pid != 0)
       +                kill(pid, SIGTERM);
       +        pid = 0;
       +}
       +
        int
        is_dir(char *fname)
        {
       @@ -49,14 +60,13 @@ int
        launch(char *cmd, int ignore)
        {
                int st;
       -        pid_t pid;
       +        sigset_t new, old;
                char *name, *shell;
                char *args[] = {NULL, "-ec" , cmd, NULL};
                static int initsignals;
                extern char **environ;
                extern void sighandler(int);
        
       -
                if (!initsignals) {
                        struct sigaction act = {
                                .sa_handler = sighandler
       @@ -70,10 +80,25 @@ launch(char *cmd, int ignore)
                        initsignals = 1;
                }
        
       +        sigfillset(&new);
       +        sigprocmask(SIG_BLOCK, &new, &old);
       +        if (stop)
       +                goto unblock;
       +
                switch (pid = fork()) {
                case -1:
       +                perror("make");
       +        unblock:
       +                sigprocmask(SIG_SETMASK, &old, NULL);
                        return -1;
                case 0:
       +                signal(SIGINT, SIG_DFL);
       +                signal(SIGHUP, SIG_DFL);
       +                signal(SIGTERM, SIG_DFL);
       +                signal(SIGQUIT, SIG_DFL);
       +
       +                sigprocmask(SIG_SETMASK, &old, NULL);
       +
                        shell = getmacro("SHELL");
        
                        if (ignore)
       @@ -86,10 +111,8 @@ launch(char *cmd, int ignore)
                        execve(shell, args, environ);
                        _exit(127);
                default:
       -                if (wait(&st) < 0) {
       -                        kill(pid, SIGTERM);
       -                        wait(&st);
       -                }
       +                sigprocmask(SIG_SETMASK, &old, NULL);
       +                wait(&st);
        
                        return st;
                }