Fix use-after-free in TCrossConnectionBase.Close - #197
Merged
winddriver merged 1 commit intoAug 5, 2026
Conversation
TCrossConnectionBase.Close passes Self to FOwner.TriggerDisconnected as an ICrossConnection. The compiler builds a temporary interface reference that is released at the end of that statement, while TriggerDisconnected removes the connection from FConnections and then runs LogicDisconnected -- either of which can drop the last remaining reference. When it does, the object is gone before InternalClose runs and before FSocket is reset, so both touch freed memory. Keep an ICrossConnection reference alive for the whole method. Seen in production as EUseAfterFreeError reached through TIocpCrossSocket.Send -> AConnection.Close on an already dead socket.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Selfis an object reference being passed where anICrossConnectionis expected, so the compiler materialises a temporary interface reference and releases it at the end of that statement. Inside the call,TriggerDisconnecteddoesEither the list removal or the user callback can drop the last remaining reference to the connection. When that happens, the temporary is the only thing keeping the object alive, and it is gone by the time
InternalCloseand theFSocketreset run — both then touch freed memory.Most call sites happen to be safe because they hold their own
LConnection: ICrossConnectionlocal, so this only bites on the paths where the caller's reference has already been dropped.Fix
Hold an
ICrossConnectionfor the whole method. Two lines, no behaviour change on the paths that were already safe.How it showed up
EUseAfterFreeErrorin production (FastMM full-debug), reached throughTIocpCrossSocket.Send->AConnection.Closeon an already-dead socket.Checked
Compiles clean on Win64 (Delphi 37.0) — no new warnings or hints.