Skip to content

Commit

Permalink
Fix Post on disposed mailbox (#17849) (#17922)
Browse files Browse the repository at this point in the history
* nullify disposed waithandle

* add test

* rns

---------

Co-authored-by: Tomas Grosup <tomasgrosup@microsoft.com>
  • Loading branch information
majocha and T-Gro authored Oct 30, 2024
1 parent d566f53 commit 6a933f6
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 3 deletions.
9 changes: 9 additions & 0 deletions docs/release-notes/.FSharp.Core/9.0.200.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
### Fixed

* Fix exception on Post after MailboxProcessor was disposed ([Issue #17849](https://github.com/dotnet/fsharp/issues/17849), [PR #17922](https://github.com/dotnet/fsharp/pull/17922))

### Added

### Changed

### Breaking Changes
7 changes: 4 additions & 3 deletions src/FSharp.Core/mailbox.fs
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,11 @@ type Mailbox<'Msg>(cancellationSupported: bool, isThrowExceptionAfterDisposed: b
inboxStore.Clear()

arrivals.Clear()
isDisposed <- true)
isDisposed <- true

if isNotNull pulse then
(pulse :> IDisposable).Dispose()
if isNotNull pulse then
(pulse :> IDisposable).Dispose()
pulse <- null)

#if DEBUG
member x.UnsafeContents = (x.inbox, arrivals, pulse, savedCont) |> box
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -557,3 +557,42 @@ module MailboxProcessorType =
}

Assert.True(iteration.Result > 1, "TryScan did not timeout")

let ordered() =
let mutable current = 1
fun n ->
if n < current then failwith $"step {n} already happened"
SpinWait.SpinUntil(fun () -> n = current)
current <- n + 1

// See https://github.com/dotnet/fsharp/issues/17849
[<Fact>]
let ``Disposed MailboxProcessor does not throw on Post`` () =
task {
let step = ordered()

let cts = new CancellationTokenSource()
let mb =
MailboxProcessor.Start( (fun inbox ->
async {
step 1
do! inbox.Receive()
do! inbox.Receive()
return ()
}),
cancellationToken = cts.Token
)

step 2
// ensure pulse gets created
do! Task.Delay 100
mb.Post()

mb.Dispose()

do! Task.Delay 100

mb.Post()

cts.Cancel()
}

0 comments on commit 6a933f6

Please sign in to comment.