MicrosoftEdge / MicrosoftEdge/WebView2Feedback

[Problem/Bug]: WPF: GraphicsItemD3DImage.Dispose(bool) disposes managed _device outside the if (disposing) block

Open
#5,636 2 comments 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?

In Microsoft.Web.WebView2.Wpf (used by WebView2CompositionControl), the internal class Microsoft.Web.WebView2.Wpf.GraphicsItemD3DImage implements the standard Dispose(bool disposing) pattern, but the call to _device?.Dispose() is placed outside the if (disposing) block.

Decompiling Microsoft.Web.WebView2.Wpf.dll shows (simplified):

protected virtual void Dispose(bool disposing)
{
    if (_disposed)
        return;

    if (disposing)
    {
        // other managed cleanup...
    }

    _device?.Dispose(); // <-- BUG: managed object disposed unconditionally

    _disposed = true;
}

_device is a managed IDisposable object. Per the standard .NET dispose pattern, managed objects must only be disposed when disposing == true (i.e. when called from Dispose()), never on the finalizer path (Dispose(false)).

Why this is a problem:

When GraphicsItemD3DImage is collected without an explicit Dispose() call and its finalizer runs:

  • Dispose(false) still calls _device?.Dispose() on the finalizer thread.
  • At that point _device may already have been finalized itself (finalization order between reachable-from-finalizable objects is undefined), so this can touch an already-reclaimed object.
  • It also invokes D3D device teardown from the finalizer thread rather than the thread that owns the device, which is unsafe for D3D11 objects and can cause intermittent ObjectDisposedException, access violations, or device-context corruption that are very hard to diagnose in host applications.

Expected behavior:

_device?.Dispose() should be moved inside the if (disposing) block, so it is only executed on the explicit dispose path:

if (disposing)
{
    // other managed cleanup...
    _device?.Dispose();
}
Importance

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

Runtime Channel

Stable release (WebView2 Runtime)

Runtime Version

No response

SDK Version

1.0.4078.44

Framework

WPF

Operating System

Windows 11

OS Version

No response

Repro steps

This is a code-level defect, observable by inspection:

  1. Reference Microsoft.Web.WebView2 1.0.4078.44.
  2. Decompile Microsoft.Web.WebView2.Wpf.dll (e.g. with ILSpy).
  3. Inspect Microsoft.Web.WebView2.Wpf.GraphicsItemD3DImage.Dispose(bool).
  4. Observe _device?.Dispose() outside the if (disposing) block, so it also runs on the finalizer path.

https://github.com/Hannott/WebView2CompositionControl

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 by inspecting Microsoft.Web.WebView2.Wpf.GraphicsItemD3DImage.Dispose(bool) in Microsoft.Web.WebView2.Wpf.dll, using the decompilation described in the issue. Confirm that _device?.Dispose() is only reached on the explicit dispose path, then verify the resulting behavior against the standard Dispose pattern; no specific test file is named.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
desktop
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.