Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] Fix ERR_EXIT behavior in function calls and "always" statements
- X-seq: zsh-workers 50980
- From: Philippe Altherr <philippe.altherr@xxxxxxxxx>
- To: Zsh hackers list <zsh-workers@xxxxxxx>
- Cc: Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx>, Lawrence Velázquez <larryv@xxxxxxx>
- Subject: [PATCH] Fix ERR_EXIT behavior in function calls and "always" statements
- Date: Wed, 16 Nov 2022 15:40:12 +0100
- Archived-at: <https://zsh.org/workers/50980>
- List-id: <zsh-workers.zsh.org>
The attached patch fixes the ERR_EXIT behavior in function calls and "always" statements. The patch does the following:
- Revert the following patches, which are based on an unfortunate misunderstanding of the expected behavior of ERR_EXIT:
- Add saving and restoring of local_noerrexit in doshfunc in exec.c
- This fixes the ERR_EXIT behavior in function calls.
- Add "this_noerrexit = 1;" at the very end of exectry in loop.c
- This makes "always" statements compliant with the exception 3 of the POSIX specification of "set -e".
- Add new tests in C03traps.ztst
Philippe
diff --git a/NEWS b/NEWS
index 9c28169bb..cdafd1ff5 100644
--- a/NEWS
+++ b/NEWS
@@ -4,15 +4,6 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
Note also the list of incompatibilities in the README file.
-Changes since 5.9
------------------
-
-Handling of ERR_EXIT is corrected when the final status of a structured
-command (for, select, while, repeat, if, case, or a list in braces) is
-nonzero. To be compatible with other shells, "zsh -e" now exits in
-those circumstances, whereas previous versions did not. This does not
-affect the handling of nonzero status within conditional statements.
-
Changes since 5.8.1
-------------------
diff --git a/Src/exec.c b/Src/exec.c
index ce0c1f1ad..b9061e3a4 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -49,7 +49,8 @@ struct funcsave {
int zoptind, lastval, optcind, numpipestats;
int *pipestats;
char *scriptname;
- int breaks, contflag, loops, emulation, noerrexit, oflags, restore_sticky;
+ int breaks, contflag, loops, emulation, noerrexit, this_noerrexit, oflags;
+ int restore_sticky;
Emulation_options sticky;
struct funcstack fstack;
};
@@ -451,7 +452,7 @@ execcursh(Estate state, int do_exec)
cmdpop();
state->pc = end;
- this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+ this_noerrexit = 1;
return lastval;
}
@@ -1442,8 +1443,6 @@ execlist(Estate state, int dont_change_job, int exiting)
execsimple(state);
else
execpline(state, code, ltype, (ltype & Z_END) && exiting);
- if (!locallevel || unset(ERRRETURN))
- this_noerrexit = noerrexit;
state->pc = next;
goto sublist_done;
break;
@@ -5763,6 +5762,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
funcsave->pipestats = NULL;
funcsave->numpipestats = numpipestats;
funcsave->noerrexit = noerrexit;
+ funcsave->this_noerrexit = this_noerrexit;
if (trap_state == TRAP_STATE_PRIMED)
trap_return--;
/*
@@ -6009,6 +6009,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
trap_return++;
ret = lastval;
noerrexit = funcsave->noerrexit;
+ this_noerrexit = funcsave->this_noerrexit;
if (noreturnval) {
lastval = funcsave->lastval;
numpipestats = funcsave->numpipestats;
diff --git a/Src/loop.c b/Src/loop.c
index be5261369..7c3e04b8a 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -208,7 +208,7 @@ execfor(Estate state, int do_exec)
loops--;
simple_pline = old_simple_pline;
state->pc = end;
- this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+ this_noerrexit = 1;
return lastval;
}
@@ -336,7 +336,7 @@ execselect(Estate state, UNUSED(int do_exec))
loops--;
simple_pline = old_simple_pline;
state->pc = end;
- this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+ this_noerrexit = 1;
return lastval;
}
@@ -478,7 +478,7 @@ execwhile(Estate state, UNUSED(int do_exec))
popheap();
loops--;
state->pc = end;
- this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+ this_noerrexit = 1;
return lastval;
}
@@ -532,7 +532,7 @@ execrepeat(Estate state, UNUSED(int do_exec))
loops--;
simple_pline = old_simple_pline;
state->pc = end;
- this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+ this_noerrexit = 1;
return lastval;
}
@@ -587,7 +587,7 @@ execif(Estate state, int do_exec)
lastval = 0;
}
state->pc = end;
- this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+ this_noerrexit = 1;
return lastval;
}
@@ -701,7 +701,7 @@ execcase(Estate state, int do_exec)
if (!anypatok)
lastval = 0;
- this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+ this_noerrexit = 1;
return lastval;
}
@@ -793,6 +793,7 @@ exectry(Estate state, int do_exec)
cmdpop();
popheap();
state->pc = end;
+ this_noerrexit = 1;
return endval;
}
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 5cc45e2de..01d8fa25b 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -721,21 +721,40 @@ F:Must be tested with a top-level script rather than source or function
>Good
(setopt err_exit
- for x in y; do
+ false && true
+ print OK
+ )
+0:ERR_EXIT not triggered by "false && true"
+>OK
+
+ (setopt err_exit
+ fn() {
false && true
- done
+ }
+ fn
print OK
)
-1:ERR_EXIT triggered by status 1 at end of for
+1:ERR_EXIT not triggered by "false && true" but by return from fn
(setopt err_exit
- integer x=0
- while (( ! x++ )); do
+ for x in y; do
false && true
done
print OK
)
-1:ERR_EXIT triggered by status 1 at end of while
+0:ERR_EXIT not triggered by status 1 at end of for
+>OK
+
+ (setopt err_exit
+ fn() {
+ for x in y; do
+ false && true
+ done
+ }
+ fn
+ print OK
+ )
+1:ERR_EXIT not triggered by status 1 at end of for but by return from fn
(setopt err_exit
repeat 1; do
@@ -743,7 +762,19 @@ F:Must be tested with a top-level script rather than source or function
done
print OK
)
-1:ERR_EXIT triggered by status 1 at end of repeat
+0:ERR_EXIT not triggered by status 1 at end of repeat
+>OK
+
+ (setopt err_exit
+ fn() {
+ repeat 1; do
+ false && true
+ done
+ }
+ fn
+ print OK
+ )
+1:ERR_EXIT not triggered by status 1 at end of repeat but by return from fn
(setopt err_exit
if true; then
@@ -751,15 +782,93 @@ F:Must be tested with a top-level script rather than source or function
fi
print OK
)
-1:ERR_EXIT triggered by status 1 at end of if
+0:ERR_EXIT not triggered by status 1 at end of if
+>OK
+
+ (setopt err_exit
+ fn() {
+ if true; then
+ false && true
+ fi
+ }
+ fn
+ print OK
+ )
+1:ERR_EXIT not triggered by status 1 at end of if but by return from fn
+
+ (setopt err_exit
+ loop=true
+ while print COND; $loop; do
+ loop=false
+ false && true
+ done
+ print OK
+ )
+0:ERR_EXIT not triggered by status 1 at end of while
+>COND
+>COND
+>OK
+
+ (setopt err_exit
+ fn() {
+ loop=true
+ while print COND; $loop; do
+ loop=false
+ false && true
+ done
+ }
+ fn
+ print OK
+ )
+1:ERR_EXIT not triggered by status 1 at end of while but by return from fn
+>COND
+>COND
(setopt err_exit
{
false && true
+ } always {
+ print ALWAYS
}
print OK
)
-1:ERR_EXIT triggered by status 1 at end of { }
+0:ERR_EXIT not triggered by status 1 at end of always
+>ALWAYS
+>OK
+
+ (setopt err_exit
+ fn() {
+ {
+ false && true
+ } always {
+ print ALWAYS
+ }
+ }
+ fn
+ print OK
+ )
+1:ERR_EXIT not triggered by status 1 at end of always but by return from fn
+>ALWAYS
+
+ (setopt err_exit
+ {
+ false && true
+ }
+ print OK
+ )
+0:ERR_EXIT not triggered by status 1 at end of { }
+>OK
+
+ (setopt err_exit
+ fn() {
+ {
+ false && true
+ }
+ }
+ fn
+ print OK
+ )
+1:ERR_EXIT not triggered by status 1 at end of { } but by return from fn
unsetopt err_exit err_return
(setopt err_exit
Messages sorted by:
Reverse Date,
Date,
Thread,
Author