Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Windows: fatal 0xC000070A — camera enumeration (MF/mfksproxy) closes a handle with a threadpool wait still registered (0.5.9)

オープン
#2,115 コメント 3 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
35/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
静か
技術スタック
rust, tauri

調査の方向性

crates/camera-mediafoundation/src/lib.rs の cap_camera_windows::get_devices() と CameraInfo::formats_impl() から開始し、Media Foundation source-reader の teardown を追跡して、cameraId を null に設定した状態で Windows のクラッシュを再現します。提供されたダンプとログを使用して、カメラ列挙パスが wait の登録中にハンドルを閉じなくなったことを確認します。apps/desktop/src-tauri/src/export.rs のエクスポートダイアログの問題は別スコープであり、この修正と混在させないでください。

索引モデルが issue の本文から書いたものです。

説明

Summary

Cap 0.5.9 on Windows 11 dies repeatedly with a non-catchable fatal exception raised by
ntdll's threadpool waiter thread. I decoded two crash dumps (one triage, one full-memory) — a
HANDLE is closed while a threadpool wait is still registered on it, and the full dump
places the wait in Media Foundation's camera kernel-streaming layer (mfksproxy.dll,
mf.dll/mfplat.dll). It reproduces with no camera selected (cameraId: null) — device
enumeration alone triggers it.

9 crashes across ~1 hour of normal use, including one 4 seconds after launch.

I could not identify which component owns the handle (see What I could not determine), but the
failure mode itself is unambiguous.

I searched open and closed issues for 0xc000070a, INVALID_HANDLE, and threadpool and found
no match. The nearest existing report is #1954 (Windows crash on AMD 780M iGPU) — different
module, different exception code (0xC0000005 in atio6axx.dll), so I don't believe this is a
duplicate. Close it as one if you disagree.

Environment
Cap 0.5.9 (installed build, not self-compiled)
OS Windows 11 Home, build 10.0.26200
ntdll 10.0.26100.8972
GPU NVIDIA GeForce RTX 3070 Laptop (driver 32.0.15.8129) + AMD Radeon iGPU
WebView2 151.0.4129.78
The crash

Windows Error Reporting:

Faulting application name: Cap.exe, version: 0.5.9.0
Faulting module name:      ntdll.dll, version: 10.0.26100.8972
Exception code:            0xC000070A
Fault offset:              0x0000000000087154

0xC000070A is ntdll's fatal threadpool assertion, raised from the waiter thread. Its message
form is "Status 0x%x was returned, waiting on handle 0x%x for wait 0x%p, in waiter 0x%p" — and
the four values are carried in the exception record. From the minidump:

Exception parameter Value Meaning
0 0xC0000008 STATUS_INVALID_HANDLE
1 0x28 the handle being waited on
2 0x00000207_40931cf0 the TP_WAIT object
4 ntdll+0x4c6f0 the waiter

Interpretation: something registered a threadpool wait (SetThreadpoolWait /
RegisterWaitForSingleObject) on handle 0x28, then closed that handle without first
unregistering the wait. NtWaitForSingleObject on the waiter thread returned
STATUS_INVALID_HANDLE, and ntdll responded by raising a fatal exception. This kills the process
outright — it cannot be caught or recovered from.

The crashing thread is unnamed and its stack is entirely ntdll/KERNELBASE, consistent with a
threadpool waiter rather than application code. The 31 named threads at crash time (main,
15× tokio-runtime-worker, D3D Background Thread 0-3, EBWorkerThread, MojoThread,
sentry-transport) show the app was otherwise idle in the editor.

Frequency and crash sites

7 crashes in ~30 minutes. From cap-desktop.log, the last thing each session logged before dying:

# Last logged activity before death Time alive
1 editor open, captions loaded — then 20 s idle ~1 m 49 s
2 idle in editor ~10 m
3 mid editor-open — YUV pipelines created 5 s earlier ~1 m 18 s
4 idle in editor ~6 m
5 startup only — no window shown yet 15 s
6 5 failed save dialogs in 12 s (see below) ~10 m
7 mid list_windows_with_thumbnails 7 s

Sessions 5 and 7 died seconds after launch with no user interaction, so these are not user quits.

Only crash #1 produced a Windows Application Error event. I suspect WER bucket throttling
(identical signature repeating within minutes), but I have not confirmed that.

Possibly related: list_windows_with_thumbnails

Offered as an observation, not a diagnosis. In my logs this runs very frequently — dozens of
calls per minute, each re-selecting a DXGI adapter:

INFO list_windows_with_thumbnails: cap_d3d_adapter: Selected DXGI adapter by VRAM
     adapter=NVIDIA GeForce RTX 3070 Laptop GPU vendor_id="0x10DE" vram_mb=8020

GraphicsCapture.dll is loaded in the dump, and Windows.Graphics.Capture registers threadpool
waits on frame-arrival events. Rapid create/destroy of capture sessions is a plausible place for
a close-before-unregister race. Crash #7 occurred inside this call. That is circumstantial.

Second bug: export save dialog silently no-ops

Separate from the crash, and reproducible:

13:24:45.663  INFO cap_desktop_lib::export: Showing save file dialog file_name="....mp4"
13:24:45.664  INFO cap_desktop_lib::export: Save file dialog completed path=None

0.8 ms between "showing" and "completed". The native dialog never opened. This repeated 5
times in 12 seconds as I retried, then the process died.

Two distinct problems:

  1. The dialog fails to open. Root cause unknown — needs investigation on the Windows side.
  2. The failure is indistinguishable from a user cancel. In
    apps/desktop/src-tauri/src/export.rs (~line 1289), tauri-plugin-dialog's save_file()
    callback yields Option<PathBuf>, and both "user cancelled" and "dialog failed to open" arrive
    as None. Cap logs path=None and silently does nothing.

From a user's perspective: you click Export, nothing happens, no error appears, so you click
again. Surfacing the underlying error instead of swallowing it would be a small, self-contained
improvement — and would have made this far easier to report.

Minor: crash telemetry under-reports

crash_sentinel::mark_clean_exit() appears to have a single call site in
apps/desktop/src-tauri/src/lib.rs. Exits through any other path leave session-active.json
behind and get reported as unclean on next launch. This cuts both ways — it adds noise to real
crash data. Low priority, mentioned only because it made the logs harder to interpret.

UPDATE: full dump captured — the wait belongs to Media Foundation's camera layer

After enabling LocalDumps with DumpType=2 I caught the crash again (9th occurrence) and got a
full-memory dump. Same signature, one variation:

Exception parameter First dump Full dump
0 (wait status) 0xC0000008 STATUS_INVALID_HANDLE 0xC0000022 STATUS_ACCESS_DENIED
1 (handle) 0x28 0x30

Both statuses from the same wait = classic close-while-registered: INVALID_HANDLE when the slot
is empty, ACCESS_DENIED when the slot has been recycled by a new object without SYNCHRONIZE
rights.

This time the TP_WAIT object was in the captured memory:

  • The two heap objects adjacent to the TP_WAIT carry vtables in mf.dll and
    mfplat.dll.
  • The crashing waiter thread's stack contains repeated frames in mfksproxy.dll — the Media
    Foundation kernel-streaming (camera) proxy — i.e. this waiter had been servicing camera KS
    event waits.

So: a camera-device event handle was closed while its MF work-queue wait was still registered.

Two more data points that narrow it further:

  • The crash reproduced with every camera deselected — my store has "cameraId": null
    and also after I disabled the broken Camo device. Camera enumeration alone is sufficient.
  • Reading the source: cap_camera_windows::get_devices() runs on every camera listing, and
    CameraInfo::formats_impl() activates each device's media source and builds a source reader
    just to read formats. crates/camera-mediafoundation/src/lib.rs sets
    MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN (the comment says "Media source shuts
    down on drop if this isn't specified") — which means the media source outlives the reader
    and is never explicitly Shutdown()
    . Teardown then happens by COM refcount on whatever
    thread releases last, racing the KS event waits the frame server still has registered.
    I believe that is the bug, or very close to it.

Suggested direction (happy to be corrected by someone who knows this code):

  • call IMFMediaSource::Shutdown() deterministically before the last release in the
    enumeration/formats path, or
  • don't activate media sources at all during enumeration (MFEnumDeviceSources attributes +
    IMFActivate metadata are enough to list devices; formats could be read lazily), and
  • rate-limit get_devices() — it currently runs per listing call.
What I could not determine
  • Which exact release site closes the handle. Naming that needs symbols/AppVerifier; the
    module attribution above is from the dump's memory, which is solid, but the code path is
    inferred from reading the crates.
  • Whether the failed export dialogs caused crash #6 or merely preceded it.
  • My machine's device roster (a Camo virtual camera that was stuck in an Error PnP state, a
    phantom Yealink conference camera, two virtual display adapters) may make the race easier to
    hit — but the crash occurred with Camo disabled, so it is not required.
Also seen (probably unrelated, flagging in case it isn't)

Every hardware H.264 encoder fails pre-flight on this machine, so recording falls back to CPU:

WARN h264_nvenc failed pre-flight: ffmpeg::Error(1: Operation not permitted)
WARN h264_mf    failed pre-flight: ffmpeg::Error(22: Invalid argument)
WARN h264_qsv   failed pre-flight: ffmpeg::Error(1313558101: Unknown error occurred)
WARN h264_amf   failed pre-flight: ffmpeg::Error(1313558101: Unknown error occurred)
WARN Using SOFTWARE H264 encoder (high CPU usage expected) encoder=libx264 1852x916 fps=60.0

nvEncodeAPI64.dll is present and the RTX 3070 is selected for D3D, so NVENC failing is
surprising. The bundled FFmpeg DLLs are dated Oct 2024. Software x264 at 60 fps also produced
sustained Failed to send decoded frame N: receiver dropped warnings during playback.

Possibly in scope of #976 (hardware encoding on Windows via Media Foundation) — h264_mf is
failing here with Invalid argument. Happy to split this into its own issue if you'd prefer.

Happy to provide
  • Full cap-desktop.log and cap-desktop-errors.log (793 lines)
  • The 74 MB minidump, on request
  • A full-memory dump — I've now enabled LocalDumps with DumpType=2, so I can capture one that
    actually contains the TP_WAIT object and name the owning module. Say the word and I'll
    reproduce and follow up.

Note: Cap ships Sentry (there's a sentry-transport thread), so you may already have aggregate
data on this crash bucket. WER bucket ID was 1840226820931017906, hashed bucket
4ef061879dbcc95bf989cc8b2fbd5cb2.

主要言語
Rust
スター
22.5k
フォーク
1.9k
平均マージ
6時間 33分
マージ済み PR(30日)
77

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

CapSoftware/Cap のほかの issue

CapSoftware/Cap の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。