Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Possible bug: Zsh function does not terminate when ${name:?word} fails



On Wed, 14 Sep 2016 10:00:44 +0200
Ronald Fischer <ynnor@xxxxx> wrote:
> I have in my .zshrc the following function definition (simplified
> example):
> 
> function foo {
>   local p=${1:?parameter missing}
>   echo continue ....
> }
> 
> Running the function by just typing foo produces, as expected, the
> message parameter missing, but it also outputs continue. I had expected
> that the function terminates when the :? check fails, but it continues
> to run.

Yes, that's a bug.  As documented it should return to the top-level
prompt when interactive --- that means it will abort not just the
function but any surrounding code.  If that's not what you want you
might want to look at the ERR_RETURN option as an alternative.

I have to admit the resetting of error flags in zsh is something I've
never got properly to grips with, but now we have individual bits in the
errflag status variable this is straightforward to fix; most of the
logic we need is already there.  The lack of that until a couple of
years ago may be why this has been the way it has for so long.

pws

diff --git a/Src/subst.c b/Src/subst.c
index 1c2027f..92fde45 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -2922,6 +2922,13 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
                 if (isset(EXECOPT)) {
                     *idend = '\0';
                     zerr("%s: %s", idbeg, *s ? s : "parameter not set");
+                    /*
+                     * In interactive shell we need to return to
+                     * top-level prompt --- don't clear this error
+                     * after handling a command as we do with
+                     * most errors.
+                     */
+                    errflag |= ERRFLAG_HARD;
                     if (!interact) {
                         if (mypid == getpid()) {
                             /*
diff --git a/Src/zsh.h b/Src/zsh.h
index 996bc33..2dc5e7e 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2807,7 +2807,14 @@ enum errflag_bits {
     /*
      * User interrupt.
      */
-    ERRFLAG_INT = 2
+    ERRFLAG_INT = 2,
+    /*
+     * Hard error --- return to top-level prompt in interactive
+     * shell.  In non-interactive shell we'll typically already
+     * have exited.  This is reset by "errflag = 0" in
+     * loop(toplevel = 1, ...).
+     */
+    ERRFLAG_HARD = 4
 };
 
 /***********/
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index be6e104..7623051 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -95,6 +95,20 @@
 ?(eval):1: unset1: exiting1
 ?(eval):2: null1: exiting2
 
+  PROMPT="" $ZTST_testdir/../Src/zsh -fis <<<'
+  unsetopt PROMPT_SP
+  PS2="" PS3="" PS4="" RPS1="" RPS2=""
+  foo() {
+      print ${1:?no arguments given}
+      print not reached
+  }
+  foo
+  print reached
+  '
+0:interactive shell returns to top level on ${...?...} error
+?foo:1: 1: no arguments given
+>reached
+
   print ${set1:+word1} ${set1+word2} ${null1:+word3} ${null1+word4}
   print ${unset1:+word5} ${unset1+word6}
 0:${...:+...}, ${...+...}



Messages sorted by: Reverse Date, Date, Thread, Author