From 6a933f695b41914b5242ceea8998eeeb7e3fe1c8 Mon Sep 17 00:00:00 2001 From: Jakub Majocha <1760221+majocha@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:10:03 +0100 Subject: [PATCH] Fix Post on disposed mailbox (#17849) (#17922) * nullify disposed waithandle * add test * rns --------- Co-authored-by: Tomas Grosup --- docs/release-notes/.FSharp.Core/9.0.200.md | 9 +++++ src/FSharp.Core/mailbox.fs | 7 ++-- .../MailboxProcessorType.fs | 39 +++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 docs/release-notes/.FSharp.Core/9.0.200.md diff --git a/docs/release-notes/.FSharp.Core/9.0.200.md b/docs/release-notes/.FSharp.Core/9.0.200.md new file mode 100644 index 00000000000..075290e821a --- /dev/null +++ b/docs/release-notes/.FSharp.Core/9.0.200.md @@ -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 \ No newline at end of file diff --git a/src/FSharp.Core/mailbox.fs b/src/FSharp.Core/mailbox.fs index a938263a05b..a6fdd418e26 100644 --- a/src/FSharp.Core/mailbox.fs +++ b/src/FSharp.Core/mailbox.fs @@ -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 diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/MailboxProcessorType.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/MailboxProcessorType.fs index f3964aaa78c..1e2fcd58545 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/MailboxProcessorType.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/MailboxProcessorType.fs @@ -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 + [] + 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() + }