Skip to content

Commit 7ea3c31

Browse files
Isaac Connorclaude
andcommitted
fix: hold shared_ptr to self in RtpConnection trigger lambda
SendRtpPacket queues a lambda onto the RtspConnection's task scheduler ring buffer; the scheduler runs it on the event-loop thread later. The lambda captured raw `this`, so if the RtpConnection was destroyed between enqueue and execution (client disconnect, session teardown, shutdown drain) the deferred callback dereferenced freed memory and crashed deep in the xop send path, with the originating stack pointing at ZoneMinderFifoSource::WriteRun's PushFrame call. Make RtpConnection inherit from std::enable_shared_from_this and have the lambda capture `auto self = shared_from_this()`, so the connection stays alive at least until every queued trigger has fired. All RtpConnections are already owned via shared_ptr (RtspConnection::rtp_conn_, MediaSession::clients_ weak_ptr lifted at the send site), so adopting shared_from_this here is safe. The same shared-ptr-capture pattern is already used in TcpConnection::AddTriggerEvent. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent abdf5ad commit 7ea3c31

2 files changed

Lines changed: 17 additions & 11 deletions

File tree

src/xop/RtpConnection.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -247,19 +247,25 @@ int RtpConnection::SendRtpPacket(MediaChannelId channel_id, RtpPacket pkt)
247247

248248
RtspConnection *rtsp_conn = (RtspConnection *)conn.get();
249249

250-
bool ret = rtsp_conn->task_scheduler_->AddTriggerEvent([this, channel_id, pkt] {
251-
this->SetFrameType(pkt.type);
252-
this->SetRtpHeader(channel_id, pkt);
253-
if((media_channel_info_[channel_id].is_play || media_channel_info_[channel_id].is_record) && has_key_frame_ ) {
254-
if(transport_mode_ == RTP_OVER_TCP) {
255-
SendRtpOverTcp(channel_id, pkt);
250+
// Capture a shared_ptr to self so the trigger lambda cannot UAF if the
251+
// RtpConnection is destroyed between enqueue and the event-loop thread
252+
// invoking it (e.g. client disconnect, session teardown). Previously the
253+
// lambda captured raw `this`, which crashed deep in xop send paths when
254+
// the connection went away before the scheduler drained the queue.
255+
auto self = shared_from_this();
256+
bool ret = rtsp_conn->task_scheduler_->AddTriggerEvent([self, channel_id, pkt] {
257+
self->SetFrameType(pkt.type);
258+
self->SetRtpHeader(channel_id, pkt);
259+
if((self->media_channel_info_[channel_id].is_play || self->media_channel_info_[channel_id].is_record) && self->has_key_frame_ ) {
260+
if(self->transport_mode_ == RTP_OVER_TCP) {
261+
self->SendRtpOverTcp(channel_id, pkt);
256262
}
257263
else {
258-
SendRtpOverUdp(channel_id, pkt);
264+
self->SendRtpOverUdp(channel_id, pkt);
259265
}
260-
261-
//media_channel_info_[channel_id].octetCount += pkt.size;
262-
//media_channel_info_[channel_id].packetCount += 1;
266+
267+
//self->media_channel_info_[channel_id].octetCount += pkt.size;
268+
//self->media_channel_info_[channel_id].packetCount += 1;
263269
}
264270
});
265271

src/xop/RtpConnection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace xop
1919

2020
class RtspConnection;
2121

22-
class RtpConnection
22+
class RtpConnection : public std::enable_shared_from_this<RtpConnection>
2323
{
2424
public:
2525
RtpConnection(std::weak_ptr<TcpConnection> rtsp_connection);

0 commit comments

Comments
 (0)