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

Re: Exception handling and "trap" vs. TRAPNAL()

On Oct 1, 10:28pm, DervishD wrote:
} I am still not sure whether this is a bug or a feature:
}     trap 'false' DEBUG
}     true
}     [[ $? -eq 1 ]] && print "What?"
}     This snippet doesn't print anything, and won't do even if using
} TRAPDEBUG and "return 1" instead of "false".

Guess what.

The bit of documentation that PWS quoted earlier is significantly at
odds with the actual implementation.

Here's that paragraph again:

  The return status from the function is handled specially.  If it is
  zero, the signal is assumed to have been handled, and execution
  continues normally.

So far we're right on the mark.

  Otherwise, the normal effect of the signal is produced;

This is clearly inaccurate.  If it were accurate, a non-zero return
from TRAPHUP, TRAPABRT, or TRAPALRM (among others) ought to cause the
shell to exit.  This demonstrably does not happen.  What *does* happen
is that all levels of nested loop are broken (as if by the "break N"
command with a sufficiently large N) and the shell is forced to behave
as if a shell-level error occurred.

(I'll note in passing that it actually has to be a GREATER THAN zero
return value, not just non-zero; "return -1" doesn't cause any of the
effects discussed here.  But this bit of doc is already so far wrong
that signedness makes little difference.)

However, this effect is only achieved in two cases: (1) An explicit
"return" command is used; it's a side-effect of the "return" builtin
that the value of $? is recorded as the return value of the trap.
(2) The TRAPNAL function itself exits with a shell-level error, such
as a syntax error or an assignment to a read-only variable.  Merely
falling off the end of the function with $? > 0 is not sufficient.

It's my contention that case (2) above is an oddball.  It ought to
behave the same way for "TRAPNAL() { ... }" and "trap ... NAL".  That
it does not is because the same local variable is overloaded to mean
both "$? > 0 was true" and "error condition was true", not because of
some strange special-case.

  if this causes execution to terminate, the status returned to the
  shell is the status returned from the function.

This is also demonstrably wrong.  Both cases above cause the return
status to be set via the "behave as if a shell-level error occurred"
reaction, so usually $? == 1.  The side-effect of "return" on $? lasts
only long enough to set up the forced error, then is erased as part
of unwinding the trap context.

In fact, ONLY in the case of "trap 'return X' NAL" is $? = X caused
to happen, and that's because the trap executes in the context of the
caller and forces the caller itself to return.  This behavior of the
return builtin in an "inline trap" is not documented anywhere as far
as I can tell, but you can watch it in action (and badly cripple
your shell) by writing --

    trap return DEBUG

-- and then attempting to execute any function that has more than one
command in the body.

A much more accurate description of the behavior of TRAPNAL can be
found under the "return" command entry:

  If return was executed from a trap in a TRAPNAL function, the
  effect is different for zero and non-zero return status.  With zero
  status (or after an implicit return at the end of the trap), the
  shell will return to whatever it was previously processing; with a
  non-zero status, the shell will behave as interrupted except that
  the return status of the trap is retained.

Aha!  "Behave as if interrupted" NOT "the normal effect of the signal."
The doc under "TRAPNAL" needs to be repaired.  (Here's another case of
zsh code overloading a variable; "interrupt" and "shell-level error"
are indistinguishable after a certain point.)

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