Skip to content

Fix use-after-free from SampleBuffer self-deletion in its own FdWatch callback - #818

Open
MarkRose wants to merge 1 commit into
sm0svx:masterfrom
MarkRose:fix-rtlusb-samplebuffer-self-delete
Open

Fix use-after-free from SampleBuffer self-deletion in its own FdWatch callback#818
MarkRose wants to merge 1 commit into
sm0svx:masterfrom
MarkRose:fix-rtlusb-samplebuffer-self-delete

Conversation

@MarkRose

Copy link
Copy Markdown
Contributor

RtlUsb::SampleBuffer::removeSamples() is invoked as the activity callback
of the FdWatch that monitors the read end of its internal signal pipe.
When the RTL reader thread exits and closes the write end of that pipe,
read() returns 0 (EOF) and removeSamples() responded by synchronously
calling closeReadPipe() (which deletes the FdWatch currently dispatching
this very callback) and then emitting writePipeClosed(), which is
connected to RtlUsb::verboseClose() and ends up deleting the SampleBuffer
object itself — all while still executing a member function on that
same object's call stack. This is a self-delete-during-callback bug that
can lead to use-after-free.

  • Add SampleBuffer::handleWritePipeClosed(), a small helper that performs
    the closeReadPipe()/writePipeClosed() cleanup, and defer its invocation
    via Async::Application::runTask() from removeSamples() instead of
    calling it inline. This ensures the FdWatch and the owning SampleBuffer
    are only destroyed after control has returned to the top-level event
    loop, not from within the FdWatch's own activity dispatch.

Co-Authored-By: Claude Opus 4.8 [email protected]

… callback

RtlUsb::SampleBuffer::removeSamples() is invoked as the activity callback
of the FdWatch that monitors the read end of its internal signal pipe.
When the RTL reader thread exits and closes the write end of that pipe,
read() returns 0 (EOF) and removeSamples() responded by synchronously
calling closeReadPipe() (which deletes the FdWatch currently dispatching
this very callback) and then emitting writePipeClosed(), which is
connected to RtlUsb::verboseClose() and ends up deleting the SampleBuffer
object itself — all while still executing a member function on that
same object's call stack. This is a self-delete-during-callback bug that
can lead to use-after-free.

- Add SampleBuffer::handleWritePipeClosed(), a small helper that performs
  the closeReadPipe()/writePipeClosed() cleanup, and defer its invocation
  via Async::Application::runTask() from removeSamples() instead of
  calling it inline. This ensures the FdWatch and the owning SampleBuffer
  are only destroyed after control has returned to the top-level event
  loop, not from within the FdWatch's own activity dispatch.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@MarkRose MarkRose closed this Jul 12, 2026
@MarkRose MarkRose reopened this Jul 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant