<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://bugs.webkit.org/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4.1"
          urlbase="https://bugs.webkit.org/"
          
          maintainer="admin@webkit.org"
>

    <bug>
          <bug_id>313426</bug_id>
          
          <creation_ts>2026-04-27 07:01:25 -0700</creation_ts>
          <short_desc>Leak due to retain cycle between LibWebRTCRtp{Sender,Receiver}TransformBackend and libwebrtc sender/receiver after RTCPeerConnection closes</short_desc>
          <delta_ts>2026-04-27 22:42:22 -0700</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>WebKit</product>
          <component>WebRTC</component>
          <version>WebKit Nightly Build</version>
          <rep_platform>Unspecified</rep_platform>
          <op_sys>Unspecified</op_sys>
          <bug_status>RESOLVED</bug_status>
          <resolution>FIXED</resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords>InRadar</keywords>
          <priority>P2</priority>
          <bug_severity>Normal</bug_severity>
          <target_milestone>---</target_milestone>
          <dependson>218750</dependson>
          
          <everconfirmed>1</everconfirmed>
          <reporter name="David Kilzer (:ddkilzer)">ddkilzer</reporter>
          <assigned_to name="David Kilzer (:ddkilzer)">ddkilzer</assigned_to>
          <cc>webkit-bug-importer</cc>
    
    <cc>youennf</cc>
          

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>2204907</commentid>
    <comment_count>0</comment_count>
    <who name="David Kilzer (:ddkilzer)">ddkilzer</who>
    <bug_when>2026-04-27 07:01:25 -0700</bug_when>
    <thetext>`WebCore::LibWebRTCRtpSenderTransformBackend` and `WebCore::LibWebRTCRtpReceiverTransformBackend` leak due to retain cycles whenever a page uses an `RTCRtpScriptTransform` or `RTCRtpSFrameTransform` on an `RTCRtpSender` or `RTCRtpReceiver`. The cycle persists after `RTCPeerConnection.close()` and after JavaScript has dropped all references to the sender/receiver, so the leak is permanent for the remaining lifetime of the WebContent process.

Each cycle has this structure (shown by `leaks --groupByType` on a memgraph captured from a WebContent process that ran `LayoutTests/http/wpt/webrtc/` tests):

```
541 (5.61M) ROOT CYCLE: webrtc::RefCountedObject&lt;webrtc::RtpSenderProxyWithInternal&lt;webrtc::RtpSenderInternal&gt;&gt;
  528 (5.61M) ROOT CYCLE: webrtc::RefCountedObject&lt;webrtc::AudioRtpSender&gt;
    26 (1.83K) ROOT CYCLE: WebCore::LibWebRTCRtpSenderTransformBackend
      CYCLE BACK TO webrtc::RefCountedObject&lt;webrtc::RtpSenderProxyWithInternal&lt;webrtc::RtpSenderInternal&gt;&gt;
    13 (1.22K) ROOT CYCLE: webrtc::RefCountedObject&lt;webrtc::DtmfSender&gt;
    13 (624 bytes) ROOT CYCLE: webrtc::RefCountedObject&lt;webrtc::DtmfSenderProxyWithInternal&lt;webrtc::DtmfSenderInterface&gt;&gt;
```

The receiver side has an analogous cycle involving `LibWebRTCRtpReceiverTransformBackend`, `webrtc::AudioRtpReceiver`/`webrtc::VideoRtpReceiver`, and `webrtc::RtpReceiverProxyWithInternal`.

Root cause:

1. `LibWebRTCRtpSenderTransformBackend` stores the libwebrtc sender as `const Ref&lt;webrtc::RtpSenderInterface&gt; m_rtcSender;` (strong ref, from backend -&gt; sender).

2. On the first call to `LibWebRTCRtpSenderTransformBackend::setTransformableFrameCallback()`, the backend registers itself with the sender via `m_rtcSender-&gt;SetFrameTransformer(scoped_refptr&lt;FrameTransformerInterface&gt;(this))`. libwebrtc stores this in `RtpSenderBase::frame_transformer_`, a `scoped_refptr&lt;FrameTransformerInterface&gt;` (strong ref, from sender -&gt; backend).

3. Both sides hold strong refs, so neither drops first. The cycle keeps both objects alive indefinitely.

`LibWebRTCRtpReceiverTransformBackend` has the same two-way relationship with its `webrtc::RtpReceiverInterface` via `SetFrameTransformer()` in `setTransformableFrameCallback()`.

Reproduction:

Run any WebRTC layout test that attaches a transform to a sender or receiver (for example `http/wpt/webrtc/unset-transform.html`, `http/wpt/webrtc/audiovideo-script-transform.html`, `webrtc/sframe-keys.html`, or `webrtc/video-sframe.html`) with `run-webkit-tests --debug --leaks`. `leaks --groupByType` on the resulting WebContent memgraph reports multiple `ROOT CYCLE` entries naming `WebCore::LibWebRTCRtpSenderTransformBackend` or `WebCore::LibWebRTCRtpReceiverTransformBackend`.

The cycle has existed since WebRTC transform infrastructure was introduced in Bug 218750, 231538@main (2020-11-13).</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2204908</commentid>
    <comment_count>1</comment_count>
    <who name="Radar WebKit Bug Importer">webkit-bug-importer</who>
    <bug_when>2026-04-27 07:01:35 -0700</bug_when>
    <thetext>&lt;rdar://problem/175674797&gt;</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2204920</commentid>
    <comment_count>2</comment_count>
    <who name="David Kilzer (:ddkilzer)">ddkilzer</who>
    <bug_when>2026-04-27 07:46:22 -0700</bug_when>
    <thetext>Pull request: https://github.com/WebKit/WebKit/pull/63695</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2205247</commentid>
    <comment_count>3</comment_count>
    <who name="EWS">ews-feeder</who>
    <bug_when>2026-04-27 22:42:20 -0700</bug_when>
    <thetext>Committed 312177@main (0f476dfaa434): &lt;https://commits.webkit.org/312177@main&gt;

Reviewed commits have been landed. Closing PR #63695 and removing active labels.</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>