Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internal exception surfacing when calling Post on disposed MailBoxProcessor #17849

Closed
majocha opened this issue Oct 8, 2024 · 5 comments · Fixed by #17922
Closed

Internal exception surfacing when calling Post on disposed MailBoxProcessor #17849

majocha opened this issue Oct 8, 2024 · 5 comments · Fixed by #17922
Labels
Area-Diagnostics mistakes and possible improvements to diagnostics Bug Impact-Low (Internal MS Team use only) Describes an issue with limited impact on existing code.
Milestone

Comments

@majocha
Copy link
Contributor

majocha commented Oct 8, 2024

Message: 
System.ObjectDisposedException : Cannot access a disposed object.
Object name: 'Microsoft.Win32.SafeHandles.SafeWaitHandle'.

  Stack Trace: 
SafeHandle.DangerousAddRef(Boolean& success)
Kernel32.SetEvent(SafeWaitHandle handle)
EventWaitHandle.Set()
Mailbox`1.Post(TMsg msg) line 193
FSharpMailboxProcessor`1.Post(TMsg message) line 419

I can see the above exception occasionally in this test:

member this.``After dispose is called, mailbox should stop receiving and processing messages``() = task {

I assume the expected behavior here is no exception?

I'll try to come up with consistent minimal repro, but the problem seems to be here:

match pulse with
| null -> () // no one waiting, leaving the message in the queue is sufficient
| ev ->
// someone is waiting on the wait handle
ev.Set() |> ignore

ev is disposed and Set will fail.

The fix seems to be to also assign null to pulse when disposing it here:

interface System.IDisposable with
member _.Dispose() =
lock syncRoot (fun () ->
if isNotNull inboxStore then
inboxStore.Clear()
arrivals.Clear()
isDisposed <- true)
if isNotNull pulse then
(pulse :> IDisposable).Dispose()

@majocha
Copy link
Contributor Author

majocha commented Oct 8, 2024

This happens with timeouts or cancellation enabled, only then a wait handle is used in Mailbox.

@majocha
Copy link
Contributor Author

majocha commented Oct 8, 2024

Minimal repro:

open System.Threading

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

// ensure pulse gets created
Thread.Sleep 100

mb.Post 1
mb.Dispose()
mb.Post 2

@T-Gro
Copy link
Member

T-Gro commented Oct 14, 2024

@T-Gro
Copy link
Member

T-Gro commented Oct 14, 2024

I think getting an ObjectDisposedException is the right scenario if the object was disposed.
But it should be better controlled by Fsharp.Core and not thrown from internal usage.

@abonie abonie added Impact-Low (Internal MS Team use only) Describes an issue with limited impact on existing code. Area-Library Issues for FSharp.Core not covered elsewhere Area-Diagnostics mistakes and possible improvements to diagnostics and removed Needs-Triage Area-Library Issues for FSharp.Core not covered elsewhere labels Oct 21, 2024
@majocha
Copy link
Contributor Author

majocha commented Oct 24, 2024

Related to https://github.com/dotnet/fsharp/pull/13036/files#diff-89da65b208fb5d835cded7993284e2c562b2d6530cc320cc030f5079dfc0372b possibly?

I think the exception happens in a code path that was there before that PR.

I think getting an ObjectDisposedException is the right scenario if the object was disposed. But it should be better controlled by Fsharp.Core and not thrown from internal usage.

This may be a breaking change. It seems the current standard behavior most of the time is waiting indefinitely on a disposed wait handle. Only on rare occasions where the wait handle is disposed while it's not awaited this here bug happens.

psfinaki pushed a commit that referenced this issue Oct 30, 2024
* nullify disposed waithandle

* add test

* rns

---------

Co-authored-by: Tomas Grosup <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Diagnostics mistakes and possible improvements to diagnostics Bug Impact-Low (Internal MS Team use only) Describes an issue with limited impact on existing code.
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

3 participants