This repository was archived by the owner on Oct 18, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
This repository was archived by the owner on Oct 18, 2021. It is now read-only.
Fix for TCPConnection/TCPStream Relationship ARC Crash #18
Copy link
Copy link
Open
Description
I spent some time tracking this down (since I wasn't happy with the solution other contributors had suggested (see #9 ), and I believe I understand the issue and implications.
Specifically:
TCPConnectionadds newly open connections to an internal static arraysAllConnectionswhich is the only thing preventing ARC from deallocating the instances.TCPConnectionmaintains astrong_readerand_writer(bothTCPStreamobjects) which in turn also havestrongreference to the connection.- When a
TCPStreamobject receives an EOF it callsTCPConnection -_streamGotEOF:withselfto inform its connection to disconnect. This ultimately causes the connection to calldisconnecton both its_readerand_writerstreams via_streamCanClose:. TCPStream -disconnectcallsTCPConnection -_streamDisconnected:withselfto let its connection know it is closed.- Once both of the
TCPConnectionstreams are closed, the connection calls_closedwhich removes itself from the static arraysAllConnections, causing it to be deallocated. - At this point any subsequent calls to the
TCPConnectioninstance are to a deallocated instance and a crash occurs.
This all manifests itself in the TCPConnection.m _streamGotEOF: method.
My fix is to strongly reference self so self is available in the current scope. This is similar to what MYDeferDealloc does in a non-ARC setting.
Proposed fix:
TCPConnection.m
- (void) _streamGotEOF: (TCPStream*)stream
{
LogTo(TCP,@"%@ got EOF on %@",self,stream);
[stream disconnect];
if( _status == kTCP_Closing ) {
// Strongly reference `self` in this scope, so when `_closed` (ultimately called by `_streamCanClose:`) removes `self` from `sAllConnections` we are not immediately deallocated (and subsequently crash when attempting to call `[self _checkIfClosed]`)
__strong typeof(self) sSelf = self;
[sSelf _streamCanClose: stream];
[sSelf _checkIfClosed];
} else {
[self _stream: stream
gotError: [NSError errorWithDomain: NSPOSIXErrorDomain code: ECONNRESET userInfo: nil]];
}
}
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels