ash: Return without arguments in a trap should use status outside traps
authorDenys Vlasenko <vda.linux@googlemail.com>
Thu, 20 Feb 2020 15:47:01 +0000 (16:47 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 20 Feb 2020 15:47:01 +0000 (16:47 +0100)
Fixes exitcode_trap4.tests.
Upstream commit:

    Date: Mon, 6 Oct 2014 21:51:26 +0800
    Return without arguments in a trap should use status outside traps

    POSIX now requires that return without arguments in a trap should
    return the last command status prior to executing traps.  This
    patch implements this behaviour.

    Incidentally this also changes the behaviour of return without
    arguments in a loop conditional to use the last exit status in
    the body as opposed to the last command in the conditional when
    there is one.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c

index a6f777800d1d9049b31c2385e09fafb4bbd18b9d..bea24601cbb85e05d37452927114f2aea53e396e 100644 (file)
@@ -9091,6 +9091,7 @@ defun(union node *func)
 #define SKIPBREAK      (1 << 0)
 #define SKIPCONT       (1 << 1)
 #define SKIPFUNC       (1 << 2)
+#define SKIPFUNCDEF    (1 << 3)
 static smallint evalskip;       /* set to SKIPxxx if we are skipping commands */
 static int skipcount;           /* number of levels to skip */
 static int loopnest;            /* current loop nesting level */
@@ -9148,7 +9149,8 @@ dotrap(void)
                if (!p)
                        continue;
                evalstring(p, 0);
-               exitstatus = status;
+               if (evalskip != SKIPFUNC)
+                       exitstatus = status;
        }
 
        savestatus = last_status;
@@ -9783,7 +9785,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
        shellparam = saveparam;
        exception_handler = savehandler;
        INT_ON;
-       evalskip &= ~SKIPFUNC;
+       evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
        return e;
 }
 
@@ -9928,12 +9930,23 @@ execcmd(int argc UNUSED_PARAM, char **argv)
 static int FAST_FUNC
 returncmd(int argc UNUSED_PARAM, char **argv)
 {
+       int skip;
+       int status;
+
        /*
         * If called outside a function, do what ksh does;
         * skip the rest of the file.
         */
-       evalskip = SKIPFUNC;
-       return argv[1] ? number(argv[1]) : exitstatus;
+       if (argv[1]) {
+               skip = SKIPFUNC;
+               status = number(argv[1]);
+       } else {
+               skip = SKIPFUNCDEF;
+               status = exitstatus;
+       }
+       evalskip = skip;
+
+       return status;
 }
 
 /* Forward declarations for builtintab[] */
@@ -13372,7 +13385,7 @@ cmdloop(int top)
                skip = evalskip;
 
                if (skip) {
-                       evalskip &= ~SKIPFUNC;
+                       evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
                        break;
                }
        }