Fix use-after-free in RTMP test sender lifetime management - #3543
chenBright wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Pull request overview
Fixes an ASan-reported heap-use-after-free in the RTMP playback test by ensuring the PlayingDummyStream stays alive for the duration of its sender bthread, even when send failure synchronously triggers OnStop().
Changes:
- Manually increments the stream refcount before starting the sender bthread and releases it on startup failure.
- Transfers that reference to the sender bthread via an adopting
intrusive_ptr. - Avoids joining the sender bthread from within itself during
OnStop().
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
de8d3ed to
73024b9
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved sender-loop and regression-test coverage issues remain.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (3)
test/brpc_rtmp_unittest.cpp:366
- This regression test never runs
PlayingDummyStream::OnStop()orRunSendData; it invokesSelfStopStream::OnStop()directly, and that sender exits unconditionally after one call. It would pass even if the production self-bthread guard were removed, or ifPlayingDummyStream::SendData()continued forever, so it does not cover the changed behavior. Exercise the production sender/stop path (or factor the stop/lifetime logic into the tested helper) and assert that the sender exits.
// Regression test for a use-after-free where a send failure synchronously ran
// OnStop() on the sender bthread and dropped the framework's reference while
// SendData() was still using the stream. This reproduces the ordering
// deterministically without a socket: the sender bthread runs OnStop() itself,
// which releases the framework's reference, and then keeps touching the stream.
test/brpc_rtmp_unittest.cpp:436
- The outer
streamintrusive pointer remains held while the sender is joined, so it supplies a reference that can mask a missing sender-owned reference. Removing the sender handoff would still leave the object alive and satisfyalive_after_stop; release the outer pointer immediately afterStart()and assert destruction after the join instead.
butil::intrusive_ptr<SelfStopStream> stream(
new SelfStopStream(&destroyed, &alive_after_stop, &stop_on_sender));
sender = stream->Start();
ASSERT_EQ(0, bthread_join(sender, nullptr));
test/brpc_rtmp_unittest.cpp:436
- This regression test never runs
PlayingDummyStream::OnPlay()/SendData()and keeps the outerstreamreference alive acrossbthread_join(). Therefore it would still pass if the sender-owned reference were removed: the test's own reference prevents destruction beforealive_after_stopis checked. Exercise the production send-failure path or release the test owner before joining so the assertion proves the sender reference is required.
butil::intrusive_ptr<SelfStopStream> stream(
new SelfStopStream(&destroyed, &alive_after_stop, &stop_on_sender));
sender = stream->Start();
ASSERT_EQ(0, bthread_join(sender, nullptr));
- Files reviewed: 1/1 changed files
- Comments generated: 1
- Review effort level: Lite
What problem does this PR solve?
Issue Number: resolve
Problem Summary:
A heap-use-after-free reported by ASan ci in the RTMP playback test.
A send failure can synchronously invoke the stop callback on the sender
bthread. Joining the current bthread fails, allowing the framework to release
the stream while the sender continues accessing it.
What is changed and the side effects?
Changed:
it if startup fails.
until sending finishes.
Side effects:
Performance effects:
Breaking backward compatibility:
Check List: