change behaviour of argument-less exit in traps to match SUSv4; Debian #599484 (original patch from Jonathan Nieder, thanks!) in a variant that appears to handle nested traps well

This commit is contained in:
tg 2010-11-01 17:29:05 +00:00
parent e57379aab7
commit 27dce9168a
5 changed files with 59 additions and 23 deletions

14
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.395 2010/10/01 19:04:37 tg Exp $ # $MirOS: src/bin/mksh/check.t,v 1.396 2010/11/01 17:29:00 tg Exp $
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $ # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
@ -25,7 +25,7 @@
# http://www.research.att.com/~gsf/public/ifs.sh # http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout: expected-stdout:
@(#)MIRBSD KSH R39 2010/10/01 @(#)MIRBSD KSH R39 2010/11/01
description: description:
Check version of shell. Check version of shell.
stdin: stdin:
@ -4845,6 +4845,16 @@ expected-stdout:
E 0 E 0
F 0 F 0
--- ---
name: exit-trap-1
description:
Check that "exit" with no arguments behaves SUSv4 conformant.
stdin:
trap 'echo hi; exit' EXIT
exit 9
expected-stdout:
hi
expected-exit: 9
---
name: test-stlt-1 name: test-stlt-1
description: description:
Check that test also can handle string1 < string2 etc. Check that test also can handle string1 < string2 etc.

View File

@ -25,7 +25,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.163 2010/09/15 21:08:18 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.164 2010/11/01 17:29:02 tg Exp $");
#if HAVE_KILLPG #if HAVE_KILLPG
/* /*
@ -2293,7 +2293,8 @@ c_exitreturn(const char **wp)
warningf(true, "%s: %s", arg, "bad number"); warningf(true, "%s: %s", arg, "bad number");
} else } else
exstat = n; exstat = n;
} } else if (trap_exstat != -1)
exstat = trap_exstat;
if (wp[0][0] == 'r') { /* return */ if (wp[0][0] == 'r') { /* return */
struct env *ep; struct env *ep;

View File

@ -26,7 +26,7 @@
#include <sys/file.h> #include <sys/file.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.102 2010/09/14 21:26:13 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.103 2010/11/01 17:29:03 tg Exp $");
/*- /*-
* MirOS: This is the default mapping type, and need not be specified. * MirOS: This is the default mapping type, and need not be specified.
@ -1066,6 +1066,8 @@ inittraps(void)
int i; int i;
const char *cs; const char *cs;
trap_exstat = -1;
/* Populate sigtraps based on sys_signame and sys_siglist. */ /* Populate sigtraps based on sys_signame and sys_siglist. */
for (i = 0; i <= NSIG; i++) { for (i = 0; i <= NSIG; i++) {
sigtraps[i].signal = i; sigtraps[i].signal = i;
@ -1271,22 +1273,29 @@ runtraps(int flag)
intrsig = 0; intrsig = 0;
if (flag & TF_FATAL) if (flag & TF_FATAL)
fatal_trap = 0; fatal_trap = 0;
++trap_nested;
for (p = sigtraps, i = NSIG+1; --i >= 0; p++) for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
if (p->set && (!flag || if (p->set && (!flag ||
((p->flags & flag) && p->trap == NULL))) ((p->flags & flag) && p->trap == NULL)))
runtrap(p); runtrap(p, false);
if (!--trap_nested)
runtrap(NULL, true);
} }
void void
runtrap(Trap *p) runtrap(Trap *p, bool is_last)
{ {
int i = p->signal; int old_changed = 0, i;
char *trapstr = p->trap; char *trapstr;
int oexstat;
int old_changed = 0;
if (p == NULL)
/* just clean up, see runtraps() above */
goto donetrap;
i = p->signal;
trapstr = p->trap;
p->set = 0; p->set = 0;
if (trapstr == NULL) { /* SIG_DFL */ if (trapstr == NULL) {
/* SIG_DFL */
if (p->flags & TF_FATAL) { if (p->flags & TF_FATAL) {
/* eg, SIGHUP */ /* eg, SIGHUP */
exstat = 128 + i; exstat = 128 + i;
@ -1297,22 +1306,23 @@ runtrap(Trap *p)
exstat = 128 + i; exstat = 128 + i;
unwind(LINTR); unwind(LINTR);
} }
return; goto donetrap;
} }
if (trapstr[0] == '\0') /* SIG_IGN */ if (trapstr[0] == '\0')
return; /* SIG_IGN */
goto donetrap;
if (i == SIGEXIT_ || i == SIGERR_) { /* avoid recursion on these */ if (i == SIGEXIT_ || i == SIGERR_) { /* avoid recursion on these */
old_changed = p->flags & TF_CHANGED; old_changed = p->flags & TF_CHANGED;
p->flags &= ~TF_CHANGED; p->flags &= ~TF_CHANGED;
p->trap = NULL; p->trap = NULL;
} }
oexstat = exstat; if (trap_exstat == -1)
trap_exstat = exstat;
/* /*
* Note: trapstr is fully parsed before anything is executed, thus * Note: trapstr is fully parsed before anything is executed, thus
* no problem with afree(p->trap) in settrap() while still in use. * no problem with afree(p->trap) in settrap() while still in use.
*/ */
command(trapstr, current_lineno); command(trapstr, current_lineno);
exstat = oexstat;
if (i == SIGEXIT_ || i == SIGERR_) { if (i == SIGEXIT_ || i == SIGERR_) {
if (p->flags & TF_CHANGED) if (p->flags & TF_CHANGED)
/* don't clear TF_CHANGED */ /* don't clear TF_CHANGED */
@ -1321,6 +1331,13 @@ runtrap(Trap *p)
p->trap = trapstr; p->trap = trapstr;
p->flags |= old_changed; p->flags |= old_changed;
} }
donetrap:
/* we're the last trap of a sequence executed */
if (is_last && trap_exstat != -1) {
exstat = trap_exstat;
trap_exstat = -1;
}
} }
/* clear pending traps and reset user's trap handlers; used after fork(2) */ /* clear pending traps and reset user's trap handlers; used after fork(2) */

10
main.c
View File

@ -33,7 +33,7 @@
#include <locale.h> #include <locale.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.172 2010/09/14 21:26:14 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/main.c,v 1.173 2010/11/01 17:29:04 tg Exp $");
extern char **environ; extern char **environ;
@ -672,10 +672,14 @@ unwind(int i)
/* ordering for EXIT vs ERR is a bit odd (this is what AT&T ksh does) */ /* ordering for EXIT vs ERR is a bit odd (this is what AT&T ksh does) */
if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR) && if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR) &&
sigtraps[SIGEXIT_].trap)) { sigtraps[SIGEXIT_].trap)) {
runtrap(&sigtraps[SIGEXIT_]); ++trap_nested;
runtrap(&sigtraps[SIGEXIT_], trap_nested == 1);
--trap_nested;
i = LLEAVE; i = LLEAVE;
} else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) { } else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) {
runtrap(&sigtraps[SIGERR_]); ++trap_nested;
runtrap(&sigtraps[SIGERR_], trap_nested == 1);
--trap_nested;
i = LLEAVE; i = LLEAVE;
} }
while (1) { while (1) {

10
sh.h
View File

@ -154,9 +154,9 @@
#endif #endif
#ifdef EXTERN #ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.418 2010/10/08 17:56:57 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.419 2010/11/01 17:29:05 tg Exp $");
#endif #endif
#define MKSH_VERSION "R39 2010/10/01" #define MKSH_VERSION "R39 2010/11/01"
#ifndef MKSH_INCLUDES_ONLY #ifndef MKSH_INCLUDES_ONLY
@ -584,6 +584,8 @@ EXTERN struct mksh_kshstate_v {
int exstat_; /* exit status */ int exstat_; /* exit status */
int subst_exstat_; /* exit status of last $(..)/`..` */ int subst_exstat_; /* exit status of last $(..)/`..` */
struct env env_; /* top-level parsing & execution env. */ struct env env_; /* top-level parsing & execution env. */
short trap_exstat_; /* exit status before running a trap */
uint8_t trap_nested_; /* running nested traps */
uint8_t shell_flags_[FNFLAGS]; uint8_t shell_flags_[FNFLAGS];
} kshstate_v; } kshstate_v;
EXTERN struct mksh_kshstate_f { EXTERN struct mksh_kshstate_f {
@ -602,6 +604,8 @@ EXTERN struct mksh_kshstate_f {
#define kshppid kshstate_f.kshppid_ #define kshppid kshstate_f.kshppid_
#define exstat kshstate_v.exstat_ #define exstat kshstate_v.exstat_
#define subst_exstat kshstate_v.subst_exstat_ #define subst_exstat kshstate_v.subst_exstat_
#define trap_exstat kshstate_v.trap_exstat_
#define trap_nested kshstate_v.trap_nested_
/* evil hack: return hash(kshstate_f concat (kshstate_f'.h:=hash(arg))) */ /* evil hack: return hash(kshstate_f concat (kshstate_f'.h:=hash(arg))) */
uint32_t evilhash(const char *); uint32_t evilhash(const char *);
@ -1526,7 +1530,7 @@ void intrcheck(void);
int fatal_trap_check(void); int fatal_trap_check(void);
int trap_pending(void); int trap_pending(void);
void runtraps(int intr); void runtraps(int intr);
void runtrap(Trap *); void runtrap(Trap *, bool);
void cleartraps(void); void cleartraps(void);
void restoresigs(void); void restoresigs(void);
void settrap(Trap *, const char *); void settrap(Trap *, const char *);