Skip to content

[Problem/Bug]: WebView2 UWP (EmbeddedBrowserWebView.dll) self-perpetuating 0x401/WM_USER+1 message loop -> handle leak -> renderer process explosion #5672

Description

@OnlyANoob

What happened?

Summary

In UWP/AppContainer hosts, EmbeddedBrowserWebView.dll (WebView2 Runtime) notifies its UI thread of queued work by posting PostMessageW(hwnd, 0x401, 0, 0) (0x401 = WM_USER+1 = Chromium kMsgHaveWork). The posting site (RVA 0xE0E0C) has no CAS deduplication, so while producers (AppTaskRunner::PostTask) keep enqueueing during the drain, the drain re-posts on exit and the loop becomes self-sustaining at ~100–165 msgs/sec.

Each pass leaks kernel handles (Event ×27 / Section ×31). Handle growth itself consumes no significant memory — the memory impact is indirect: sustained handle growth makes renderers crash and WebView2 restarts them, until 400–717 msedgewebview2.exe processes exhaust free RAM (~98%) and freeze the machine. In contrast, during the 60 s probe run the handle count grows at the same rate while free RAM stays essentially flat — confirming the memory drain comes from the renderer process explosion, not from the handles themselves.

MinesweeperWebViewProbe.zip

Root cause: the missing CAS dedup at 0xE0E0C (point A) lets the task notification loop self-perpetuate. Proven by patch: memory-patching 0xE0E0C (callmov eax,1) stops 0x401 completely, the process count stops growing and a 5-minute handle sample is completely stable — single root cause, no independent second leak. This is an SDK-level defect, not app-specific (HIT was reproduced on Windows 10/11 × Runtime 113/151 with a clean-room probe). Detailed analysis in the collapsible section below.

Detailed root-cause analysis (disassembly evidence) — click to expand

Mechanism (static + dynamic)

queue non-empty & flag==0
  -> post_fn_A: PostMessageW(hwnd, 0x401, 0, 0)      @0xE0E0C  (no CAS dedup)
  -> UI thread WndProc 0x260BD0 handles 0x401
  -> 0x260E00 COM wrapper -> vtable dispatch -> drain 0xE14CB
  -> drain clears head/tail (real consume)
  -> producers keep enqueueing during drain
  -> drain exit: head != tail -> re-post 0x401         @0xE16A7
  -> infinite loop

Comparison with upstream Chromium (base/message_loop/message_pump_win.cc)

Dynamic counters (WinDbg, 1 min) — point A 0xE0E0C: 837 | point B 0x3962F9: 0 | normal-play baseline: 6,109/min (~102/s)

Causal proof (patch of point A, 1 min)PostMessageW 0x401 counter grew by just +1 in the minute after the patch — a real stop, not a slowdown (the storm normally runs at hundreds of posts/min, so +1 means it fully ceased) | process count: growing → stable | 5-min handle sample: completely stable

Self-feeding ratio (per-thread PostTask, 1 min) — UI thread (0x401 chain): 40,570 (99.4%) | other threads: 242 (0.6%)

Impact — resource-exhaustion DoS (system freeze), not memory corruption, no sandbox escape.

Related: #5290 — crash in EmbeddedBrowserWebView with TaskRunner::PostTask on the stack; different symptom (abort crash vs memory-exhaustion process explosion) but likely the same AppTaskRunner task-dispatch subsystem.

Importance

Important. My app's user experience is significantly compromised.

Runtime Channel

Stable release (WebView2 Runtime)

Runtime Version

151.0.4129.78

SDK Version

1.0.1108.44

Framework

WinUI2/UWP

Operating System

Windows 10, Windows 11

OS Version

10.0.19045,10.0.26200

Repro steps

Primary repro — standalone probe (no original host needed)

Attached MinesweeperWebViewProbe.zip: a minimal native C++/CX UWP app (UWP AppContainer + WebView2 SDK) that IAT-hooks PostMessageW and counts 0x401.

  1. Extract the zip, double-click RunProbe.cmd (approve the UAC prompt).
  2. Wait ~60 seconds.
  3. Open probe_report\Report.txt → read the VERDICT line: HIT = 0x401 growing at ~110–165/s.

Works on any machine with WebView2 Runtime build ≥ 1108 (the script auto-installs/updates the Evergreen runtime only when the runtime is missing or older than build 1108, and reverts all system changes afterwards).

Background — natural repro in the original host (Microsoft Minesweeper, UWP)

Play normally for ~5–40 minutes; msedgewebview2.exe count and system RAM grow until the machine freezes.

Cross-machine probe results (60 s sampling, all HIT)

Machine OS Runtime 0x401 rate
Dev machine Windows 11 26200 151.0.4129.78 ~165/s
Machine A Windows 10 19045 113.0.1774.50 ~110/s
Machine B Windows 10 19045 151.0.4129.78 ~141/s

Expected vs actual

Expected: the task notification is deduplicated (at most one pending kMsgHaveWork), as upstream Chromium does.

Actual: the notification is posted unconditionally while the drain runs, creating a self-perpetuating message storm that leaks handles and explodes the renderer process tree.

Repros in Edge Browser

No, issue does not reproduce in the corresponding Edge version

Regression

No, this never worked

Last working version (if regression)

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions