MicrosoftEdge / MicrosoftEdge/WebView2Feedback

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

Open
#5,672 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
PowerShell
Stars
526
Forks
67
PR merge metrics
No merged PRs in 30d

Description

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

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the attached MinesweeperWebViewProbe.zip and run RunProbe.cmd, then inspect probe_report/Report.txt and the 0x401 counters described in the issue. Compare the notification behavior with Chromium's base/message_loop/message_pump_win.cc; done means the 0x401 storm, renderer process growth, and handle growth no longer occur under the probe.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
desktop, operating-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.