WebView2Feedback icon indicating copy to clipboard operation
WebView2Feedback copied to clipboard

[Problem/Bug]: Stability regression: v125 and up regularly crashing on select sites

Open RendijsSmukulis opened this issue 1 year ago • 7 comments

What happened?

  • A significant number of our users reporting a high number of crashes on sites, some examples being temu.com and ebay.com
  • We're able to reproduce the crash on newest stable SDK and Stable, Canary and Beta runtimes
  • ~We're able to reproduce this in both our app, and a "vanilla" new WPF project with just WebView2 added~ It appears the "vanilla" app crash was unrelated, and had a different stack in the dump.
WebView2 - Break instruction exception: null
  Module "ntdll!RtlUserThreadStart+0x28"
  Module "kernel32!BaseThreadInitThunk+0x1d"
  Module "msedgewebview2!__scrt_common_main_seh+0x106"
  Module "msedgewebview2!wWinMain+0x40d"
  Module "msedgewebview2!MainDllLoader::Launch+0x373"
  Module "msedge!ChromeMain+0x2c5"
  Module "msedge!ChromeMain+0x971"
  Module "msedge!ChromeMain+0x14c1"
  Module "msedge!ChromeMain+0x1bc9"
  Module "msedge!ChromeMain+0x101e0"
  Module "msedge!ChromeMain+0x10c8a"
  Module "msedge!ChromeMain+0x117a2"
  Module "msedge!IsSandboxedProcess+0x262bf02"
  Module "msedge!IsSandboxedProcess+0x1783851"
  Module "msedge!IsSandboxedProcess+0x1a2e218"
  Module "msedge!RelaunchChromeBrowserWithNewCommandLineIfNeeded+0x5e8d11"
  Module "msedge!RelaunchChromeBrowserWithNewCommandLineIfNeeded+0x3bb68f"
  Module "msedge!RelaunchChromeBrowserWithNewCommandLineIfNeeded+0x3bc702"
  Module "msedge!RelaunchChromeBrowserWithNewCommandLineIfNeeded+0x3bd06a"
  Module "msedge!IsSandboxedProcess+0x960a9"
  Module "msedge!IsSandboxedProcess+0xe3988"
  Module "msedge!IsSandboxedProcess+0x940e5"
  Module "msedge!IsSandboxedProcess+0x15bc41a"
  Module "msedge!CrashForExceptionInNonABICompliantCodeRange+0x566dc8"

Importance

Blocking. My app's basic functions are not working due to this issue.

Runtime Channel

Stable release (WebView2 Runtime), Prerelease (Edge Canary/Dev/Beta)

Runtime Version

125.0.2535.79

SDK Version

1.0.2535.41

Framework

WPF

Operating System

Windows 10, Windows 11

OS Version

No response

Repro steps

  • ~In a vanilla WPF app with WebView2, navigate to temu.com~
  • ~Sometimes it crashes immediately, sometimes you have to navigate around for a crash~

The crashes seen in the vanilla WPF app were different from the ones seen in our app. Currently working on a minimal repro for this exact crash. Dumps from our app will be sent to Microsoft email.

Repros in Edge Browser

No, issue does not reproduce in the corresponding Edge version

Regression

Regression in newer Runtime

Last working version (if regression)

124

AB#51481141

RendijsSmukulis avatar May 31 '24 10:05 RendijsSmukulis

Thank you for reporting the issue. Could you please attach dump file or send it to email

vbryh-msft avatar May 31 '24 16:05 vbryh-msft

@vbryh-msft , will email it to you (I've already sent it over to @nishitha-burman, @aluhrs13 & @liminzhu )

MarkIngramUK avatar May 31 '24 16:05 MarkIngramUK

We now have a minimal repro for this. In short - this is caused by some change in v125 onwards, which has impacted the stability of cross-origin request handling through the Fetch CDP API. I.e. when doing this pattern:

  Target.enable()
  Target.setDiscoverTargets(...)
  Target.setAutoAttach(autoAttach=T, waitForDebuggerOnStart=T, flatten=T)
  // call Fetch.enable() to enable network request handling on new targets (e.g. iframes to different origin), then runIfWaitingForDebugger to resume said target.
  Fetch.enable()
  Runtime.runIfWaitingForDebugger()
  • It can work fine for a few tens, hundreds or thousands of requests, however eventually crashes
  • It does not seem to be an issue when calling Fetch.continueRequest(), as the crash happens even with calls to Fetch.continueRequest() commented out (i.e. leaving the requests "hanging")

Minimal repro attached, just scroll around Temu a bit for a crash:

MainWindow.xaml

<Window x:Class="WebView2Wpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WebView2Wpf"
        xmlns:wpf="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="20" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" >
            <TextBox Name="urlToNavTo" HorizontalAlignment="Stretch" Width="300"/>
            <Button Name="Button" Click="Button_OnClick">go</Button>
        </StackPanel>
        <wpf:WebView2 Name="webview" Grid.Row="1" />
    </Grid>
</Window>

MainWindow.xaml.cs

using Microsoft.Web.WebView2.Core;
using System;
using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Windows;

namespace WebView2Wpf
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.webview.CoreWebView2InitializationCompleted += WebviewOnCoreWebView2InitializationCompleted;

            var options = new CoreWebView2EnvironmentOptions();
            var e = CoreWebView2Environment.CreateAsync(options: options).Result;
            this.webview.EnsureCoreWebView2Async(e);
        }

        private async void WebviewOnCoreWebView2InitializationCompleted(object? sender, CoreWebView2InitializationCompletedEventArgs e)
        {
            await webview.CoreWebView2.CallDevToolsProtocolMethodAsync("Target.setDiscoverTargets", "{\"discover\":true}");
            webview.CoreWebView2.GetDevToolsProtocolEventReceiver("Target.attachedToTarget").DevToolsProtocolEventReceived += OnAttachedToTarget;

            var autoAttachParams = JsonSerializer.Serialize(
                new SetAutoAttachParameters
                {
                    WaitForDebuggerOnStart = true,
                    Flatten = true,
                    AutoAttach = true
                }
            );

            await webview.CoreWebView2.CallDevToolsProtocolMethodAsync("Target.setAutoAttach", autoAttachParams);
            webview.CoreWebView2.GetDevToolsProtocolEventReceiver("Fetch.requestPaused").DevToolsProtocolEventReceived += OnRequestPaused;


            this.webview.CoreWebView2.Navigate("https://temu.com");
            this.webview.CoreWebView2.NavigationCompleted += CoreWebView2OnNavigationCompleted;
        }

        private async void OnRequestPaused(object? sender, CoreWebView2DevToolsProtocolEventReceivedEventArgs e)
        {
            try
            {
                var req = JsonSerializer.Deserialize<RequestIdWrapper>(e.ParameterObjectAsJson);

                var resp = JsonSerializer.Serialize(new RequestIdWrapper
                {
                    RequestId = req.RequestId
                });

                Debug.WriteLine($"+++> req handled: {resp}");
                await this.webview.CoreWebView2.CallDevToolsProtocolMethodForSessionAsync(e.SessionId, "Fetch.continueRequest", resp);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"+++> Failed handling: {ex}");
            }
        }

        private async void OnAttachedToTarget(object? sender, CoreWebView2DevToolsProtocolEventReceivedEventArgs e)
        {
            var attachedSession = JsonSerializer.Deserialize<AutoAttachedSession>(e.ParameterObjectAsJson);
            var sessionId = attachedSession.SessionId;

            Debug.WriteLine($"+++> Attached to target: {e.ParameterObjectAsJson}");

            await webview.CoreWebView2.CallDevToolsProtocolMethodForSessionAsync(sessionId, "Fetch.enable", "{\"patterns\":[{\"requestStage\":\"Request\"}]}");
            await webview.CoreWebView2.CallDevToolsProtocolMethodForSessionAsync(sessionId, "Runtime.runIfWaitingForDebugger", "{}");

            Debug.WriteLine($"+++> Fetch enabled");
        }

        private void CoreWebView2OnNavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e)
        {
            this.urlToNavTo.Text = this.webview.Source.OriginalString;
        }

        private void Button_OnClick(object sender, RoutedEventArgs e)
        {
            this.webview.CoreWebView2.Navigate(this.urlToNavTo.Text);
        }

        public record SetAutoAttachParameters
        {
            [JsonPropertyName("autoAttach")]
            public bool AutoAttach { get; init; }

            [JsonPropertyName("waitForDebuggerOnStart")]
            public bool WaitForDebuggerOnStart { get; init; }

            [JsonPropertyName("flatten")]
            [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
            public bool? Flatten { get; init; }
        }

        public record RequestIdWrapper
        {
            [JsonPropertyName("requestId")]
            public string RequestId { get; init; }
        }

        public record AutoAttachedSession
        {
            [JsonPropertyName("sessionId")]
            public string SessionId { get; init; }

            [JsonPropertyName("targetInfo")]
            public TargetInfo TargetInfo { get; init; }

            [JsonPropertyName("waitingForDebugger")]
            public bool WaitingForDebugger { get; init; }
        }

        public record TargetInfo
        {
            [JsonPropertyName("attached")]
            public bool Attached { get; init; }

            [JsonPropertyName("browserContextId")]
            public string BrowserContextId { get; init; }

            [JsonPropertyName("canAccessOpener")]
            public bool CanAccessOpener { get; init; }

            [JsonPropertyName("targetId")]
            public string TargetId { get; init; }

            [JsonPropertyName("title")]
            public string Title { get; init; }

            [JsonPropertyName("type")]
            public string Type { get; init; }

            [JsonPropertyName("url")]
            public string Url { get; init; }
        }
    }
}

RendijsSmukulis avatar Jun 05 '24 06:06 RendijsSmukulis

NB: This crash is also happening when using the WebView2's network request APIs, no need for CDP:

        private void WebviewOnCoreWebView2InitializationCompleted(object? sender, CoreWebView2InitializationCompletedEventArgs e)
        {
            this.webview.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All, CoreWebView2WebResourceRequestSourceKinds.All);
            this.webview.CoreWebView2.WebResourceRequested += CoreWebView2OnWebResourceRequested;
            this.webview.CoreWebView2.Navigate("https://temu.com");
        }

Edit: from additional debugging, it appears to be caused specifically by service_worker targets - might help you with finding the root cause.

RendijsSmukulis avatar Jun 05 '24 14:06 RendijsSmukulis

I feel like this Chromium bug is directly related to this issue. Considering that someone from Microsoft has filed it, do you have any updates or insight on the issue?

seldoff avatar Jul 02 '24 22:07 seldoff

Hi @seldoff, yes it is related to that Chromium bug. We suspect it's related to the Fetch.requestPaused but we're also seeking insight from Chromium. We will share more when we know more. Thanks!

peiche-ms avatar Jul 02 '24 22:07 peiche-ms

@peiche-jessica, I'm pretty sure that we have identified the Chromium commit that caused this regression. Please see my comment in the bug tracker.

seldoff avatar Jul 03 '24 18:07 seldoff

Closing this as it is resolved with the latest m127 runtime.

peiche-ms avatar Aug 22 '24 23:08 peiche-ms