You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix lost asynchronous exception in asyncFetchPackages (fixeshaskell#6322)
The concrete bug is that `try` catches asynchronous exceptions,
preventing `withAsync` from interrupting it when its `body`
action finishes prematurely.
This manifests during `cabal build` when hitting Ctrl-C during
download, e.g.:
1. Ctrl-C interrupts a curl process
2. This interrupt is converted into a UserInterrupt exception
via the process package's delegate_ctlc functionality.
3. UserInterrupt bubbles up through `fetchPackage`, is caught by
the `try` (fine) and writen to the result mvar.
Meanwhile, `fetchPackage` continues its loop, starting to
fetch the next package.
4. Some `rebuildTarget` is waiting for the interrupted download;
`waitAsyncFetchPackage` rethrows UserInterrupt in that thread.
5. UserInterrupt bubbles up through `collectJob`, `execute`, the
`body` action.
6. `withAsync`'s finalizer cancels the `fetchPackages` async.
7. The `fetchPackages` async receives the AsyncCancelled exception
while fetching the next package (see 3. above). This interrupts
the download action (it shouldn't matter whether we happen to
be running curl again or not), and AsyncCancelled bubbles up
through `fetchPackage`, is caught by the `try` (not fine!) and
written to the mvar. But no-one is reading that mvar anymore
because the build job already aborted (step 5), and that
AsyncCancelled exception is lost.
8. `fetchPackages` keeps doing its thing, exiting eventually.
Note that this change affects both instances of `try` in this story:
`UserInterrupt` is also an asynchronous exception, so after the
change the `UserInterrupt` takes a different path from step 3. That
appears to be fine, though.
0 commit comments