Conversation
|
@claude is attempting to deploy a commit to the Vercel Labs Team on Vercel. A member of the Team first needs to authorize it. |
🤖 auto-maintain reviewAutomated, advisory triage for
Review panel: 🟡 medium highest severity just-bash maintainer code review: 🟡 medium
General code review: 🟡 medium
Adversarial security: 🟢 low
Adversarial security (second opinion): 🟢 low
Standard Bash and host portability: 🟡 medium
Posted by auto-maintain. This automated code review is advisory; a human maintainer makes the call. |
629f044 to
3cc9008
Compare
|
Thanks — the
The reason it slipped through: the test I wrote for exactly this read Fix: a new On scope: only Worth noting Coverage is now 28 cases (up from 23), adding
Both commits are now GPG-signed and verified — the earlier |
`break` and `continue` are builtins that return 0, and they are the last
command a loop body runs. All four loop forms kept `exitCode` at the
status of whatever ran before them, so the loop reported that instead:
while :; do false; break; done; echo $? # was 1, bash says 0
`handleLoopError` now reports the builtin's own status alongside the
break/continue action, and each loop adopts it. The hand-rolled
break/continue path in a `while` condition resets the status too.
`continue` sets the status without pinning it - a later iteration still
overwrites it - and a loop that ends normally is unchanged.
Reported downstream as ai-ecoverse/slicc#2978.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Lars Trieloff <lars@trieloff.net>
The previous commit corrected the value a loop returns, but `$?` still
read the command before the `continue`. A `for` loop runs nothing between
the builtin and the next iteration's first command, so the failure stayed
visible there:
for i in 1 2; do echo "$i:$?"; false; continue; done
# was 1:0 2:1, bash says 1:0 2:0
New `adoptLoopStatus` sets the loop's exit code and `ctx.state.lastExitCode`
together, and every site that consumes a break/continue goes through it -
the four loop bodies, the while-condition path, and the multi-level
`continue n` that unwinds into an enclosing loop.
`while`/`until` masked the bug because their condition runs between
iterations and resets `$?`; they are covered now too.
The test asserting this previously read `$?` after a `[` command, so it
only ever saw that command's status. It now reads `$?` as the body's first
command, which is the only position that can observe a stale value.
Reported downstream as ai-ecoverse/slicc#2978.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Lars Trieloff <lars@trieloff.net>
48e7a1c to
726ebb2
Compare
$?afterbreakis the failed command, notbreakbreakandcontinueare builtins that return 0, and they are the last command a loop body runs — so in bash a loop left through them reports 0. just-bash reported the status of whatever ran before thebreak. Noset -eneeded to see it:All four loop forms were affected —
for, C-stylefor,while,until— plus abreak/continuein awhilecondition, and a multi-levelbreak 2unwinding through an enclosing loop.Why it surfaced as a
set -ebugThe stale status is invisible until something reads
$?. Underset -ethe phantom failing loop ends the script with no output and no diagnostic:Inserting any successful command between the failed
&&list and thebreakhides it, which is what made this look like an errexit or&&-exemption problem downstream. It is neither — the&&exemption works fine; the loop's status is simply wrong. Same shape as #400 (bare assignment leaking the previous$?).The fix
Each loop body kept
exitCode = stmtResult.exitCodeand never reset it whenhandleLoopErrorturned aBreakError/ContinueErrorinto abreak/continueaction.handleLoopErrornow reports the builtin's own status (0) alongside the action, and each of the four loops adopts it — one line per site rather than four divergent copies. The hand-rolled break/continue path in awhilecondition resets the status too.continuesets the status at the point it runs but does not pin it — a later iteration still overwrites it, sofor i in 1 2; do if [ $i = 1 ]; then true; continue; fi; false; doneremains 1. A loop that ends normally is unchanged, andreturnfrom a function still reports the last command rather than 0.Tests
src/comparison-tests/loop-break-status.comparison.test.ts— 23 cases recorded against real bash: bare$?afterbreak/continuein all four loop forms;breaknested inif/case;break 2,break 3,break 5past the nesting depth,continue 2;breakandcontinuein awhilecondition;$?observed from the next iteration after acontinue; theset -erepro above; and negative controls (a normally-ending loop,return).13 of the 23 fail on
mainand all 23 pass here. A separate 35-case matrix diffed against/bin/bashalso matches on every case.pnpm typecheck,pnpm lint,pnpm knipclean.pnpm test:runis green except 6 pre-existing Python/WASM sandbox failures that reproduce identically on a cleanmaincheckout in this environment.Reported downstream as ai-ecoverse/slicc#2978 (diagnosed there as an errexit/
&&issue — the root cause is the loop status).🤖 Generated with Claude Code