From: Dan Weinreb
Subject: Unhandled conditions signaled in cleanup handlers
Date: 
Message-ID: <00de7656-8ba9-4559-a6fe-8bc6e38684f7@r40g2000yqj.googlegroups.com>
By "cleanup handler" I mean the rest of the subforms of unwind-protect
after the first one.

The following is mistaken:

    I quoted again the undefined-behavior example from the description
of THROW:

     (catch 'a
	(catch 'b
	     (unwind-protect (throw 'a 1)
		    (throw 'b 2))))

    The THROW of B has the inner catch as destination, but that exit
point is not
    available because it was torn down during step 1 of the processing
of the THROW
    of A (it is an intervening exit point in the pat of that
transfer).

(throw 'a 1) enters the Lisp runtime's stack unwinding code.  Before
it reaches the catch of 'a, it sees the presence of the
unwind-protect.  So it executes the cleanup handler, namely (throw 'b
2).  The catch for 'b then returns.  Although 'a was thrown, it is
never caught.

Regarding this comment:

    [1] Java discards its exception if a `finally' block `ends
abruptly' --
	e.g., returns, or throws an exception.  This really will lose
	exceptions.  Sorry: Java blows goats.

Java and Common Lisp behave the same way.  If a condition is signaled
with "error" inside the dynamic extent of the cleanup handler, and is
not handled within that dynamic scope, then control will be thrown
through the unwind-protect and the form of the unwind-protect never
returns.

Is this a good thing or a bad thing?  Well, it's not easy to say.
Suppose a Lisp function F really does contain an unwind-protect
handler that could, under some circumstance, signal a condition.
Every function should have a well-defined "contract" saying what it
promises to do, including under what conditions it will signal
conditions (and say what class and anything specific about the
condition instance).  In functions like F, you have to be very careful
to get this right.

At ITA, I introduced a macro called safe-unwind-protect, which makes
sure that the above never happens, by wrapping a handler-case for t
(everything) around the cleanup handler.  We use it more often
than plain unwind-protect.

By the way, Guy Steele absolutely understood what he was doing.  This
whole issue was confusing back in the early Lisp machine days, and I'm
pretty sure that any attempt for a cleanup handler to throw went into
the debugger, and you had to try manually to figure out what to do.
It was, as you'd expect, confusing.
From: Mark Wooding
Subject: Re: Unhandled conditions signaled in cleanup handlers
Date: 
Message-ID: <87ljt6n7gm.fsf.mdw@metalzone.distorted.org.uk>
Dan Weinreb <ยทยทยท@alum.mit.edu> writes:

> Regarding this comment:
>
>     [1] Java discards its exception if a `finally' block `ends
> abruptly' --
> 	e.g., returns, or throws an exception.  This really will lose
> 	exceptions.  Sorry: Java blows goats.
>
> Java and Common Lisp behave the same way.

Not quite.  It's true that Java discards the pending abrupt exit if a
`finally' clause exits abruptly, and this is similar to the way that an
UNWIND-PROTECT cleanup-form can hijack the nonlocal control flow; but
what's different, and the reason I made the above comment, is that, if a
`finally' clause is invoked because an exception has been thrown, and
the `finally' clause exits abruptly, then the exception is discarded.
Lisp doesn't discard conditions in this way because it's already handled
them before nonlocal control flow is initiated, and therefore before
UNWIND-PROTECT enters the picture.

-- [mdw]