Skip to content

fix(desktop): skip community view transition on Linux WebKitGTK to avoid UI-process segfault - #5768

Open
oso0x34 wants to merge 2 commits into
block:mainfrom
oso0x34:fix/linux-webkitgtk-vt-crash
Open

fix(desktop): skip community view transition on Linux WebKitGTK to avoid UI-process segfault#5768
oso0x34 wants to merge 2 commits into
block:mainfrom
oso0x34:fix/linux-webkitgtk-vt-crash

Conversation

@oso0x34

@oso0x34 oso0x34 commented Aug 13, 2026

Copy link
Copy Markdown

Summary

Switching communities crashes the Buzz UI process on many Linux machines,
100% of the time (#3488, #4142). The root cause is a WebKitGTK 2.52 bug:
when a view transition is the first thing to demand accelerated
compositing and the accelerated backing store could not be created, the
UI process dereferences a null AcceleratedBackingStore. The guard for
that case is a debug ASSERT, which release builds compile out — so
users get a bare SIGSEGV instead of an assertion.

This PR detects Linux WebKitGTK by user agent in
runCommunityViewTransition and takes the existing
no-startViewTransition fallback path. The community switch still
happens — instantly, without the cross-fade — until a fixed WebKitGTK
ships. Two tests added, no other behavior touched.

Why the FORCE_SHM heuristic doesn't cover this

webkit_rendering.rs (the #3654 fix) sets
WEBKIT_DMABUF_RENDERER_FORCE_SHM=1 on NVIDIA/AppImage. That does not
prevent this crash. We wrote a ~100-line repro outside Buzz — plain
GTK + WebKitWebView whose page just calls document.startViewTransition()
in a loop — and ran it with a scrubbed environment (env -i), one
variable at a time, on Ubuntu 24.04 / GNOME-X11 / NVIDIA / WebKitGTK
2.52.3:

Environment Result
no WebKit vars at all SIGSEGV, segfault at 48, offset fd69b2
WEBKIT_DMABUF_RENDERER_FORCE_SHM=1 (what Buzz ships) SIGSEGV, identical
WEBKIT_DISABLE_DMABUF_RENDERER=1 (legacy) SIGSEGV, identical
ViewTransitions WebKit feature disabled clean — Buzz's own fallback path works

segfault at 48 is m_surfaceID at offset 0x48 read through a null
this, matching the symbolized analysis by @shawnyeager in #3488 exactly.
The null store is the default state on this X11 box — no env var
needed to get there — so no rendering env tweak can fix it. The only
app-side mitigation is not entering the view-transition compositing path.

Why a UA check instead of isLinuxPlatform()

#4276 proposes the same guard via shared/lib/platform.ts's
isLinuxPlatform(), which reads navigator.platform. Node ≥ 21 defines
navigator.platform === "Linux x86_64" under plain Node on Linux, so
that guard also fires inside the unit-test runner: the three existing
communityViewTransition transition-path tests then take the fallback
branch and fail on any Linux dev box or CI runner (they pass on macOS,
which hides it locally).

The UA check here (Linux + AppleWebKitChrome) targets WebKitGTK
specifically — Node's UA (Node.js/24) and Chromium dev-server sessions
on Linux keep the real transition path, and the suite stays green.

Related issue

Fixes #3488. Fixes #4142.

Searched for duplicates — the closest existing PR is #4276 (same call
site, motivated by the #3931 updateCallbackDone hang on community
removal). It bundles unrelated agent-UI changes and trips the unit-test
issue above. Maintainers should feel free to take whichever they prefer;
the goal is just to stop the Linux crashes. This guard very likely also
resolves #3931, since it skips the same API on the same platform — but we
only verified the segfault, not the hang, so it isn't claimed here.

Also related: #3654 (the env-var mechanism this bypasses).

Testing

  • pnpm test (desktop): 4763 pass / 0 fail, including 2 new tests —
    a UA detection matrix, and "Linux WebKitGTK runs the update without
    calling startViewTransition".
  • pnpm typecheck clean; pnpm check clean.
  • On an affected machine: stock Buzz crashed on every community
    switch. Running the same build with the ViewTransitions WebKit
    feature disabled — which routes through the identical fallback branch
    this PR selects — community switching has been 100% stable since.
  • The standalone C repro crashes reliably without the transition path
    skipped and runs clean with it skipped; source and full matrix
    available if useful for CI or for the upstream report.

No screenshots: the visible change on Linux is the absence of the
cross-fade (an instant switch), and the "before" state is the app
disappearing. Happy to attach a screen recording of both if a maintainer
wants it.

Upstream

Filed against WebKitGTK with the minimal repro attached and a proposed
ASSERT → runtime-null-check patch for the three unguarded call sites in
WebKitWebViewBase.cpp:
https://bugs.webkit.org/show_bug.cgi?id=321683

Revert condition

Once Buzz's minimum WebKitGTK carries that upstream fix, this guard can be
removed.

@Chessing234

Copy link
Copy Markdown
Contributor

two things about isLinuxWebKitGtk.

the platform half is already available without sniffing: shared/lib/platform.ts:16 exports isLinuxPlatform(), which goes through the real platform rather than the UA string. worth composing with that and keeping the UA test for the WebKitGTK-vs-other-engine question only.

more importantly the heuristic fails open. this guards a UI-process segfault, so the cost of not matching is a crash, and !userAgent.includes("Chrome") is the fragile part — a UA that ever gains a Chrome-ish token silently disables the workaround and the segfault comes back with nothing pointing at this line. on tauri, linux means WebKitGTK anyway, so skipping the transition on isLinuxPlatform() alone fails closed: the worst case is a missing animation on some hypothetical non-WebKitGTK linux build, instead of a crash on a real one.

@Chessing234 Chessing234 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the linux half of this already exists — shared/lib/platform.ts exports isLinuxPlatform(), used in AppearanceSettingsControls.tsx:173 and notifications/lib/desktop.ts. it's also the more careful test: it keys off navigator.platform and excludes android explicitly, where userAgent.includes("Linux") would match an android webview string if one ever turned up without a Chrome token. isLinuxPlatform() && !/Chrome/.test(navigator.userAgent) reuses the vetted half rather than adding a second definition of "linux" in a feature file.

fwiw i checked the thing that would have sunk the UA approach outright — tauri.conf.json sets no custom user agent, so the webview does report the stock WebKitGTK string. nice repro table.

@oso0x34

oso0x34 commented Aug 15, 2026

Copy link
Copy Markdown
Author

Thanks — you're right on both counts, and I took the stronger of the two options you offered.

isLinuxWebKitGtk() is gone. The guard is now shouldSkipCommunityViewTransition(), which is just isLinuxPlatform() from shared/lib/platform.ts. No user-agent engine test at all, so there is no heuristic left to silently stop matching. Pushed in 7912051.

export function shouldSkipCommunityViewTransition(): boolean {
  return isLinuxPlatform();
}

I kept your framing in the comment above it, because the reasoning is the part worth preserving for whoever reads this next: it guards a UI-process segfault, so it has to fail closed, and the cost of over-matching is a missing cross-fade rather than a crash.

Deliberate consequence, worth stating plainly: Chromium on Linux now skips the transition too — that includes dev-server sessions and Playwright runs on Linux CI. I traced the call sites first; runCommunityViewTransition is only reached from useCommunityNavigationTransitions.ts:57 and :109, and no E2E spec asserts on the transition, so nothing breaks. But it does mean the animated path is covered at unit level rather than end-to-end on Linux. If you would rather keep the animation for Chromium, an isTauri() conjunct would do it — I left it out on purpose, since it re-introduces a way for the guard to be wrong in the direction that segfaults. Happy to add it if you disagree.

One gotcha the tests turned up, in case it bites someone else: Node 22 sets navigator.platform to "Linux x86_64", so on Linux CI every pre-existing test in communityViewTransition.test.mjs silently started taking the skip path. The transition tests now pin a MacIntel navigator in installBrowser() and restore the real one in afterEach, so they keep exercising the animated path. The guard itself is covered directly for Linux WebKit, Linux Chromium, macOS, Android (Linux platform string, correctly excluded), and absent-navigator.

Verification at 7912051f062df87818f8eb30ccd19e21b840c20b, merged up to 0.5.14:

  • pnpm test — 4956 pass, 0 fail
  • pnpm typecheck — clean
  • pnpm check — clean (the two Biome warnings are pre-existing, in unrelated files)

I also had an independent model review the change cold, with no steer toward what I expected it to find; it approved and flagged only the Linux-Chromium E2E coverage tradeoff noted above, which is why I am surfacing it here rather than leaving it implicit.

Also worth linking from here: per @HolgerHatGarKeineNode's analysis in #3488, the crash is now fixed for the population that hit it through Buzz's own WEBKIT_DISABLE_DMABUF_RENDERER=1 heuristic, since #4505 landed in 0.5.6. This PR is for the residual case — machines where AcceleratedBackingStore::create() returns null regardless of env vars, which is the configuration I reproduced with a scrubbed environment. Those still crash on 0.5.14, and the engine-side fix (https://bugs.webkit.org/show_bug.cgi?id=321683) is still unassigned upstream.

nole214 and others added 2 commits August 25, 2026 21:05
…oid UI-process segfault

WebKitGTK 2.52 dereferences a null AcceleratedBackingStore when a view
transition is the first thing to demand accelerated compositing and the
backing store could not be created (X11 sessions, dmabuf transport
disabled or unavailable). The guard is a debug ASSERT that release
builds compile out, so every community switch segfaults the UI process
on affected machines — 100% reproducible, including with the
WEBKIT_DMABUF_RENDERER_FORCE_SHM=1 heuristic applied.

Detect Linux WebKitGTK by user agent and take the existing
no-startViewTransition fallback path: the community switch still runs,
just without the cross-fade, until a fixed WebKitGTK ships.

Fixes block#3488
Fixes block#4142

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: oso0x <getdtms@gmail.com>
…user agent

Review feedback: the previous heuristic failed open. It sniffed the user
agent and required the absence of a "Chrome" token, so a webview whose UA
ever gained a Chrome-ish token would silently disable the workaround and
bring back a UI-process segfault, with nothing pointing at the call site.

Use the existing isLinuxPlatform() helper instead, which reads the real
platform rather than the UA string. On Tauri, Linux means WebKitGTK, so
this fails closed: the worst case is a missing cross-fade in a Linux
browser session rather than a crash on a real one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: oso0x <getdtms@gmail.com>
@kvncrw

kvncrw commented Sep 2, 2026

Copy link
Copy Markdown

Independent verification on a different environment — the fix works.

Repro (pre-fix): Buzz 0.5.19 AppImage, Debian 13, X11, NVIDIA RTX PRO 6000 (GB202). Launcher sets WEBKIT_DMABUF_RENDERER_FORCE_SHM=1 (the #3654 NVIDIA workaround), so the accelerated backing store is unavailable. Switching community from the rail crashed the UI process on the first switch, every time — kernel log shows one identical frame across four crashes: segfault at 48 ... error 4 in libwebkit2gtk-4.1.so.0[...+fd69b2] (AppImage-bundled WebKit, same offset every crash).

Post-fix: built main + this PR (7912051 onto 1c8321c) as an AppImage via linux-canary.yml's recipe. Drove 9 community switches via the rail (buzz ⇄ second workspace), including 6 rapid alternations. Process alive throughout, zero new segfaults in dmesg, buzz-active-community-id flipping correctly per click.

Two extra data points for the thread:

  • The crash is not specific to the bundled WebKit or to NVIDIA — this repro is a third GPU vendor (Blackwell) on the bundled-lib X11 path, matching the Arch/system-WebKitGTK and AMD reports above.
  • 0.5.20 does not fix it: the bundled libwebkit2gtk-4.1.so.0 is byte-identical between 0.5.19 and 0.5.20 (md5 6ea71136be354a08d723219edde47fb5), so Linux users on the auto-update channel have no fix in flight except this PR. The updater feed (buzz-desktop-latest/latest.json) still serves 0.5.19 as of 2026-09-02.

Happy to run additional matrix (Wayland session, different compositing flags) on this box if useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants