core.async

an exception caught in a finally block swallows the exception of the outer try

Details

  • Type: Defect Defect
  • Status: Open Open
  • Priority: Major Major
  • Resolution: Unresolved
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Patch:
    Code

Description

The inner try exception handling clears the exception status of the outer try, making it return successfully instead of rethrowing.
In the following snippet, prn is executed althought it should be dead code.

(let [chan (a/chan)
      npe! nil]
  (a/go
    (try (npe!)
         (finally
           (try (a/>! chan (npe!))
                (catch NullPointerException _))))
    (prn "this is fine.")))

Activity

Hide
Kevin Downey added a comment -

if you could test this with the patch from ASYNC-198 applied that would be great

Show
Kevin Downey added a comment - if you could test this with the patch from ASYNC-198 applied that would be great
Hide
Léo NOEL added a comment -

This patch doesn't fix the issue.
The problem with current design is that only one exception at a time can be stored (in the CURRENT-EXCEPTION slot) so when you have to deal with more than one the latest overwrite the previous.

Show
Léo NOEL added a comment - This patch doesn't fix the issue. The problem with current design is that only one exception at a time can be stored (in the CURRENT-EXCEPTION slot) so when you have to deal with more than one the latest overwrite the previous.
Hide
Kevin Downey added a comment -

0002-async-220-generate-two-finally-blocks.patch
is based on top of the patch for ASYNC-198

finallys can either be entered in the normal course of execution or
when handling an exception. so a finally X behaves sort of like

(try (let [r (code)] (X) r) (catch Throwable t (X) (throw t)))

previously the :try code was generating a single finally block which
tried to determine if it needed to rethrow an exception or not by
looking at the value of CURRENT-EXCEPTION, but this didn't work
correctly in certained nested try/catches.

so now the :try code generates two finally blocks, one that rethrows
and one that doesn't. the rethrow block goes on the exception frames
stack, and the not rethrowing block is jumped to at the end up the
body and each exception handler.

the patch also gets rid of CURRENT-EXCEPTION entirely, as it was only used by finally to determine if it needed to throw or not

Show
Kevin Downey added a comment - 0002-async-220-generate-two-finally-blocks.patch is based on top of the patch for ASYNC-198 finallys can either be entered in the normal course of execution or when handling an exception. so a finally X behaves sort of like (try (let [r (code)] (X) r) (catch Throwable t (X) (throw t))) previously the :try code was generating a single finally block which tried to determine if it needed to rethrow an exception or not by looking at the value of CURRENT-EXCEPTION, but this didn't work correctly in certained nested try/catches. so now the :try code generates two finally blocks, one that rethrows and one that doesn't. the rethrow block goes on the exception frames stack, and the not rethrowing block is jumped to at the end up the body and each exception handler. the patch also gets rid of CURRENT-EXCEPTION entirely, as it was only used by finally to determine if it needed to throw or not

People

Vote (1)
Watch (0)

Dates

  • Created:
    Updated: