Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: SegFault in stringsubst
On Apr 18, 10:02am, Bart Schaefer wrote:
}
} * I don't know whether the lastval ternary test is the right thing, or
} if an unconditional return of 1 is appropriate (should lastval be
} checked in the code I already committed?);
I had to come up with a pretty convoluted example to get this to matter.
The most straighforward way to force errflag to be set by substitution
is to use the ${param:?message} syntax:
unset x
X=${x:-$(return 5)} # sets $? to 5
X=${${x:-$(return 5)}:?fail} # sets $? to 1
So I think the right answer is that lastval shouldn't matter here, we
just return 1 for the error.
Curiously, though, *without* Andrew's 32563 patch:
() { : } ${${:-$(return 5)}:?fail} # sets $? to 5
Thus lastval is already being preserved, possibly incorrectly, because
execfuncdef() does not zero lastval before calling execshfunc() where
errflag is eventually tested. This also means that:
() { echo $? } ${:-$(return 5)}
outputs 5, because the status from the argument list is passed in to the
function body. That's consistent with the behavior of non-anonymous
functions (and is consistent with functions in bash, for that matter).
} * if we're testing errflag here, we should also do it when evaluating
} "for" and "select" loops (loop.c), which is pushing a new failure
} mode pretty far afield from the original bug;
In "for"/"select", this failure would be occurring in the list of words
that appears after the "in" token. I stepped through this, and found
that errflag is tested fairly early when the first command in the loop
body begins to execute -- early enough that the loop body becomes a
no-op and we've simply wasted a few cycles pushing/popping the pipeline
state.
Catching the error early therefore amounts to a minor optimization.
However, lastval is zeroed by execfor() before calling execlist(), so
if for some reason we DO want to preserve lastval, that optimization
is necessary.
ASIDE:
unset x
for x in ${x:-$(exit 5)} y; do echo $?; done
outputs 5 in bash and 0 in zsh. This suggests that perhaps execfor()
should NOT be clobbering lastval. (Same for "select".)
} * which means I'd be a lot happier if we were detecting this as a
} syntax error instead of a run-time error, but that may be pretty
} difficult to do.
I've made myself comfortable with having this be a runtime error.
The final question is whether the bytecode program counter should be
updated before returning these error conditions. Looking at execfor()
as the example, I think it should be, which I haven't done in previous
patch.
Therefore, ignoring the aside above for the time being, I suggest:
diff --git a/Src/exec.c b/Src/exec.c
index d821d16..8249def 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -4243,8 +4243,10 @@ execfuncdef(Estate state, UNUSED(int do_exec))
if (htok && names) {
execsubst(names);
- if (errflag)
+ if (errflag) {
+ state->pc = end;
return 1;
+ }
}
while (!names || (s = (char *) ugetnode(names))) {
@@ -4301,8 +4303,13 @@ execfuncdef(Estate state, UNUSED(int do_exec))
end += *state->pc++;
args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok);
- if (htok && args)
+ if (htok && args) {
execsubst(args);
+ if (errflag) {
+ state->pc = end;
+ return 1;
+ }
+ }
if (!args)
args = newlinklist();
diff --git a/Src/loop.c b/Src/loop.c
index 90a0761..dc8f232 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -87,8 +87,13 @@ execfor(Estate state, int do_exec)
state->pc = end;
return 0;
}
- if (htok)
+ if (htok) {
execsubst(args);
+ if (errflag) {
+ state->pc = end;
+ return 1;
+ }
+ }
} else {
char **x;
@@ -223,8 +228,13 @@ execselect(Estate state, UNUSED(int do_exec))
state->pc = end;
return 0;
}
- if (htok)
+ if (htok) {
execsubst(args);
+ if (errflag) {
+ state->pc = end;
+ return 1;
+ }
+ }
}
if (!args || empty(args)) {
state->pc = end;
Messages sorted by:
Reverse Date,
Date,
Thread,
Author