← WebKit — 2026-W37

f90b4eaa220663e3507f7811d041c812ea016dc5  [Cocoa] Hold a strong reference to QueuedVideoOutput in its main run loop callbacks

severity medium class UAF confidence 0.45 signal score 12.52 Source/WebCore/platform
Primitive: WeakPtr parent/this dereferenced across async main-runloop callbacks without holding a strong reference for the call's duration
Triage note: QueuedVideoOutput.mm changes 'if (parent) parent->method()' / 'if (weakThis) weakThis->method()' to 'if (RefPtr protected = weak.get()) protected->method()' in callOnMainRunLoop/ensureOnMainRunLoop blocks (addVideoFrameEntries, purgeVideoFrameEntries, rateChanged, purgeImagesBeforeTime, nextImageTimeReached). This protects against the target being freed during the dispatched call; a genuine lifetime-safety improvement but a protect()-style migration with no explicitly identified crash.
Structural signals: smartptr_member_added (+6.47), uaf_lifetime (+4.75), surgical (+1.3)

Commit message

[Cocoa] Hold a strong reference to QueuedVideoOutput in its main run loop callbacks
<rdar://181438985>

Reviewed by Jonathan Bedard.

The WebQueuedVideoOutputDelegate callbacks and the AVFoundation time
observer blocks hop their work to the main run loop capturing only a
WeakPtr to the QueuedVideoOutput, then dereference it as a raw pointer
after a plain null check.  The null check does not keep the object
alive: addVideoFrameEntries() fires the current-image-changed
observers, which can synchronously tear down the media player and
release the last strong reference to the QueuedVideoOutput while the
callback is still on the stack, so the trailing member access reads
freed memory.

Promote the captured WeakPtr to a RefPtr inside each block before use
so the object is kept alive for the duration of the call.  The sole
strong owner only ever runs on the main thread, so the non-atomic
RefPtr is sufficient and no ThreadSafeRefCounted change is needed.

No new tests since this change is not directly testable.

* Source/WebCore/platform/graphics/avfoundation/objc/QueuedVideoOutput.mm:
(-[WebQueuedVideoOutputDelegate outputMediaDataWillChange:]):
(-[WebQueuedVideoOutputDelegate outputSequenceWasFlushed:]):
(-[WebQueuedVideoOutputDelegate observeValueForKeyPath:ofObject:change:context:]):
(WebCore::QueuedVideoOutput::QueuedVideoOutput):
(WebCore::QueuedVideoOutput::configureNextImageTimeObserver):

Originally-landed-as: [email protected] (f53714d59190). rdar://184745139
Canonical link: https://commits.webkit.org/320818@main

Before / after

Loading diff…