diff --git a/bin/sh/error.c b/bin/sh/error.c index 0c981a3eff92..72061b8a1bef 100644 --- a/bin/sh/error.c +++ b/bin/sh/error.c @@ -73,11 +73,15 @@ static void exverror(int, const char *, va_list) __printf0like(2, 0); * Called to raise an exception. Since C doesn't include exceptions, we * just do a longjmp to the exception handler. The type of exception is * stored in the global variable "exception". + * + * Interrupts are disabled; they should be reenabled when the exception is + * caught. */ void exraise(int e) { + INTOFF; if (handler == NULL) abort(); exception = e; @@ -138,8 +142,15 @@ onint(void) static void exverror(int cond, const char *msg, va_list ap) { - CLEAR_PENDING_INT; - INTOFF; + /* + * An interrupt trumps an error. Certain places catch error + * exceptions or transform them to a plain nonzero exit code + * in child processes, and if an error exception can be handled, + * an interrupt can be handled as well. + * + * exraise() will disable interrupts for the exception handler. + */ + FORCEINTON; #ifdef DEBUG if (msg) diff --git a/bin/sh/error.h b/bin/sh/error.h index 4611821644dd..38488c261e62 100644 --- a/bin/sh/error.h +++ b/bin/sh/error.h @@ -72,6 +72,8 @@ extern volatile sig_atomic_t intpending; #define INTOFF suppressint++ #define INTON { if (--suppressint == 0 && intpending) onint(); } +#define is_int_on() suppressint +#define SETINTON(s) suppressint = (s) #define FORCEINTON {suppressint = 0; if (intpending) onint();} #define CLEAR_PENDING_INT intpending = 0 #define int_pending() intpending diff --git a/bin/sh/eval.c b/bin/sh/eval.c index 81de2d79e0f5..2bad1384950c 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -782,7 +782,6 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd) savelocalvars = localvars; localvars = NULL; reffunc(cmdentry.u.func); - INTON; savehandler = handler; if (setjmp(jmploc.loc)) { if (exception == EXSHELLPROC) @@ -798,6 +797,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd) longjmp(handler->loc, 1); } handler = &jmploc; + INTON; for (sp = varlist.list ; sp ; sp = sp->next) mklocal(sp->text); funcnest++; diff --git a/bin/sh/parser.c b/bin/sh/parser.c index 5218dc0f2922..855becc0f7bb 100644 --- a/bin/sh/parser.c +++ b/bin/sh/parser.c @@ -1312,6 +1312,7 @@ parsebackq: { int saveprompt; const int bq_startlinno = plinno; + str = NULL; if (setjmp(jmploc.loc)) { if (str) ckfree(str); @@ -1323,7 +1324,6 @@ parsebackq: { longjmp(handler->loc, 1); } INTOFF; - str = NULL; savelen = out - stackblock(); if (savelen > 0) { str = ckmalloc(savelen); diff --git a/bin/sh/redir.c b/bin/sh/redir.c index 695e1507255c..08878f6beac3 100644 --- a/bin/sh/redir.c +++ b/bin/sh/redir.c @@ -166,8 +166,11 @@ openredirect(union node *redir, char memory[10]) /* * We suppress interrupts so that we won't leave open file - * descriptors around. This may not be such a good idea because - * an open of a device or a fifo can block indefinitely. + * descriptors around. Because the signal handler remains + * installed and we do not use system call restart, interrupts + * will still abort blocking opens such as fifos (they will fail + * with EINTR). There is, however, a race condition if an interrupt + * arrives after INTOFF and before open blocks. */ INTOFF; memory[fd] = 0; diff --git a/bin/sh/var.c b/bin/sh/var.c index 2c1caf148000..6caf9564f8e8 100644 --- a/bin/sh/var.c +++ b/bin/sh/var.c @@ -195,7 +195,9 @@ setvarsafe(char *name, char *val, int flags) struct jmploc jmploc; struct jmploc *const savehandler = handler; int err = 0; + int inton; + inton = is_int_on(); if (setjmp(jmploc.loc)) err = 1; else { @@ -203,6 +205,7 @@ setvarsafe(char *name, char *val, int flags) setvar(name, val, flags); } handler = savehandler; + SETINTON(inton); return err; }