Skip to content

reactor: Teardown never disposes live or pooled TcpConnections, so every Stop() leaks their native write slabs #223

Description

@MDA2AV

Summary

Reactor.Teardown frees the ring, the provided-buffer slabs, the UDP blocks and the timespecs, and CloseAcceptedTcpSockets closes the accepted descriptors - but neither _pool nor the TcpConnection objects still in _connections are disposed. Each one owns a NativeMemory.AlignedAlloc'd write slab (WriteSlabSize, 16 KiB by default; more when grown, plus the iovec/msghdr in Segmented mode and the per-connection buffer ring in incremental mode), and TcpConnection has no finalizer, so that memory is unreachable after Stop().

Up to PoolMax x WriteSlabSize per reactor per stop - 16 MiB at the defaults. It matters for hosts that start and stop many servers in one process, which is exactly what the test suites do.

Where

  • src/ioxide/Reactor/Reactor.Runner.cs Teardown()
  • src/ioxide/Reactor/Transport/Tcp/Reactor.Tcp.cs CloseAcceptedTcpSockets() - closes the fd, drops the object
  • src/ioxide/Connection/Tcp/TcpConnection.cs Dispose() - only reached from Recycle when the pool is already full

Fix

In Teardown, after the ring fd is closed (so no SEND can still reference a slab): Dispose() every non-null _connections[fd] and drain _pool through Dispose(). DisposeIncremental goes with them.

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

    bugSomething isn't workingseverity:lowPolish / minor win

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions