Skip to content

ISO-TP: Dispose() throws and skips its cleanup when an injected actor was already disposed #205

Description

@dborgards

Severity

Low. It is reachable only through the internal actor-injecting ctor, i.e. from tests today.

Location

  • src/CanKit.Pro.IsoTp/IsoTpChannel.cs:495-503: unguarded _actor.Post(...) in Dispose().
  • IsoTpChannel.cs:148, 155: internal ctor, _ownsActor = actor is null.
  • src/CanKit.Pro.Actor/ProtocolActor.cs:332-339, 746-749: PostInternal throws ObjectDisposedException on a disposed actor.
  • Precedent: src/CanKit.Pro.J1939Tp/J1939TpChannel.cs:338-347 ("An injected actor its owner already disposed took its sessions with it … (Bugbot on test(uds): drive functional response windows from an injected clock #183)") and src/CanKit.Pro.J1939/J1939NodeImpl.cs:1639-1664 both catch ODE at the same call.

Problem

If the channel was built with an injected actor (ownsActor: false) and the caller disposed that actor first, Dispose() throws ObjectDisposedException. That breaks the .NET convention that Dispose is safe to call.

It is worse than just throwing. _disposed is set to 1 first (:478), so everything after the Post is skipped for good: the reader wait (:505), _subscription.Dispose() (:507), the handler unsubscribe (:513), and disposal of _readerCts/_sendGate and the owned _service (:526-527). A second Dispose() returns early.

J1939Tp and J1939Node already guard this exact call; ISO-TP is the odd one out.

Proposed fix

Wrap the Post in catch (ObjectDisposedException), mirroring J1939TpChannel. When the actor is gone, fail _tx and release _busTxIdleWaiter inline, since no loop is left to race with. Add a test that disposes the injected actor, then the channel, and asserts that no exception is thrown and the subscription is released.

Review

From the CanKit.Pro deep review of main @ 2e7beb6 (2026-09-28), finding 6. Re-verified against main @ ff0cbe7. The review suggested checking J1939Tp/J1939Node for the same pattern; both are already guarded.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: isotpCanKit.Pro.IsoTp — ISO 15765-2 codec and channelseverity/lowLow-severity finding from reviewtype: bugSomething behaves differently than documented

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions