fix(windows): shut down IMFMediaSource deterministically to stop fatal 0xC000070A threadpool crash - #2117
Conversation
…atal 0xC000070A A handle was being closed while an ntdll threadpool wait was still registered on it, killing the process with a non-catchable 0xC000070A. Full-dump analysis (CapSoftware#2115) places the dangling wait in Media Foundation's camera KS layer; nothing in the repo ever called IMFMediaSource::Shutdown(), leaving teardown to COM refcount order, which races the KS proxy's waits. - MediaSourceGuard: Arc-shared RAII owner that calls Shutdown() when the last Device clone drops - CaptureHandle co-owns the guard so an active capture can't have its source shut down underneath it - Drop for DeviceSourcesIterator: release each IMFActivate and CoTaskMemFree the MFEnumDeviceSources array (previously leaked on every enumeration) Fixes the crash in CapSoftware#2115. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Correction to the verification claim in this PR — please weigh it accordingly. I reported multi-hour crash-free sessions on a patched build. On continued use (2026-08-15) the same fatal signature recurred on that build: What the new full dump does show, compared to the dumps in #2115:
So the evidence is consistent with — but does not prove — the MF camera site being fixed and a second site of the same bug class (handle closed with a threadpool wait still registered) remaining elsewhere in the process. I can't currently name the second owner. The change in this PR still stands on its own merits regardless of that: Happy to keep digging on the second site and report back. Apologies for the overstated verification. |
Fixes the Windows crash reported in #2115.
Problem
0xC000070Ais ntdll's fatal threadpool assertion: a HANDLE was closed while athreadpool wait was still registered on it. Full-dump analysis (see #2115) places the
dangling wait in Media Foundation's camera kernel-streaming layer (
mfksproxy.dll,mf.dll/mfplat.dllobjects adjacent to the failedTP_WAIT).Nothing in the repo ever calls
IMFMediaSource::Shutdown(). Teardown is left to COMrefcount release, which runs on whatever thread drops the last reference and races the
KS proxy's registered waits. MF documents Shutdown-before-release as the required
teardown order for media sources.
Because camera enumeration runs continuously (
spawn_devices_snapshot_emitterevery500ms→5s plus the frontend's 5s poll), fresh
IMFMediaSourceobjects are created andrefcount-dropped several times a minute for the app's whole lifetime, so the race
window recurs constantly. On the reporting machine this crashed the app 9 times in
about an hour, including 4 seconds after launch, with no camera selected
(
cameraId: null) — enumeration alone triggers it.Fix (
crates/camera-mediafoundation/src/lib.rs)MediaSourceGuard— RAII owner of theIMFMediaSourcethat callsShutdown()ondrop. Held as
ArcbyDevice(which derivesClone), so shutdown fires exactlyonce, when the last clone drops.
CaptureHandleholds a clone of the guard, so a source cannot be shut down while acapture engine is still using it, even if the originating
Devicedropsmid-capture.
Drop for DeviceSourcesIterator— releases eachIMFActivateand frees theMFEnumDeviceSourcesarray withCoTaskMemFree. Previously the array leaked onevery enumeration (i.e. every few seconds, forever).
media_sourcealso goes frompubfield to private; external access already wentthrough
Deref, so no callers change.Verification
RTX 3070 laptop, one camera in PnP Error state — roster in Windows: fatal 0xC000070A — camera enumeration (MF/mfksproxy) closes a handle with a threadpool wait still registered (0.5.9) #2115).
camera re-enabled deliberately), survived multiple sessions including one ~3-hour
session of active use (record → edit → export → idle) ending in a clean tray quit:
zero unclean shutdowns, zero WER events, zero panics in captured logs. WER
LocalDumps was armed at DumpType=2 the whole time and captured nothing.
(
STATUS_INVALID_HANDLEwhen the slot is empty,STATUS_ACCESS_DENIEDwhen thehandle slot was recycled), consistent with close-while-registered.
Happy to split the iterator leak fix into its own commit if preferred.
🤖 Generated with Claude Code
Greptile Summary
This PR makes Windows Media Foundation camera-source teardown deterministic and fixes enumeration resource leaks.
Confidence Score: 5/5
The PR appears safe to merge with deterministic source shutdown and enumeration cleanup correctly tied to existing ownership lifetimes.
The source remains owned through active capture, Shutdown runs before the guard’s final COM release, and iterator entries are cloned rather than moved so their new centralized cleanup does not double-release them.
Important Files Changed
Reviews (1): Last reviewed commit: "fix(windows): shut down IMFMediaSource d..." | Re-trigger Greptile
Context used: