Thanks everyone for the workarounds. With some guidance from Todd
Miller, I ended up gaining more confidence that it indeed was a bug, and
creating a patch to fix it (attached).

Patch description:
  When ERREXIT (set -e) is in effect, don't disable it after a
  short-circuited `&&` or `||` chain in later iterations of `for` loops.
  It should be disabled after a short-circuited `&&` or `||` chain only
  in the *final* iteration of loops (as well as in conditionals, which
  was already working).

  The crucial fix involves the new save_xerrok variable. In addition,
  this patch does five things:

  a) Fixes descriptions for three tests (seterror tests 1, 2 and 4)
  which seemed out of sync.

  b) Improves test coverage with three more basic tests (seterror tests
  8-10, which were already working).

  c) Adds a test for the bug (seterror-11) as well as analogous tests
  for `while` and `until` loops (tests 12 and 13). Somehow only `for`
  loops seem to suffer from this bug, but I don't understand why the
  other loops work. Perhaps I've just failed to recreate the right test.
  There may also be more bugs lurking in deeper nests of conditionals
  and loops, or more perverse combinations of loops with `&&` or `||`
  chains.

  d) Cleans up the implementation of execute() to consistently make use
  of the fact that xerrok can never be NULL past the first few lines.

  e) Fixes indentation in 4 lines.

Comments and suggestions appreciated, particularly regarding new test
cases to try. Let me know if I should split it up into multiple patches.

This whole implementation of ERREXIT is getting increasingly hairy with
a global variable disabling ERREXIT (Flags&XERROK), an output parameter
(xerrok) to disable ERREXIT on the way out while unwinding recursive
calls for conditionals and loops, and now a new save_xerrok local
variable to suppress xerrok in loops. And after all that I'm still not
confident that we've killed all the bugs. Perhaps there's a cleaner way
to make these tests pass in execute().

Previous changes to this flow (because #$%# CVS makes it hard to
cross-correlate changes across files):
Jared Yanovich, Jan 2009: https://marc.info/?l=openbsd-cvs&m=123327168125592
Todd Miller, Jun 2010: https://marc.info/?l=openbsd-cvs&m=137089861723907

Attachment: set-e.patch
Description: Binary data

Reply via email to