Skip to content

fix(webview): stop Pi 2/3 blank screen from gcc NEON alignment SIGBUS - #3184

Merged
vpetersson merged 9 commits into
masterfrom
fix/webengine-armhf-neon-alignment-blank
Jul 13, 2026
Merged

fix(webview): stop Pi 2/3 blank screen from gcc NEON alignment SIGBUS#3184
vpetersson merged 9 commits into
masterfrom
fix/webengine-armhf-neon-alignment-blank

Conversation

@vpetersson

@vpetersson vpetersson commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Issues Fixed

Blank screen on Raspberry Pi 2 (forum report: https://forums.screenly.io/t/screen-stays-blank/6732). Same armv7 root cause underlies the intermittent malloc(): unaligned tcache crash tracked in issue 3022.

Description

The Qt5 WebEngine viewer crash-loops on the Pi 2 (any armv7/Cortex-A board), leaving a permanent blank screen. AnthiasViewer SIGBUSes on an unaligned 64-bit NEON store — vst1 {q8},[rN:64] — that modern Debian gcc (12–16, verified first-hand) emits for struct zero-init/copy of 8-byte-aligned types via its arm_block_set_aligned_vect block-move expander. Chromium/Qt hand some of those pointers 4-byte-aligned addresses, so the :64 alignment assertion faults on the Cortex-A7; the ARM kernel can't fix up NEON, so SIGBUS → blank.

gcc considers this correct codegen (GCC PR 93031, WONTFIX). The regression was the Linaro→Debian gcc toolchain switch (PR 3070), not the Qt 5.15.19 bump (PR 3121) — the old prebuilt toolchain only escaped it because it predated gcc-14. Bisecting Qt versions and newer gcc (13/14/15/16) does not help; this is the fix Yocto's Chromium recipes ship.

Fix (both parts required):

  • Append arm_use_neon=false to QtWebEngine's Chromium gn args → general C++ compiles -mfpu=vfpv3-d16 (no NEON block store); libvpx/Skia re-add NEON per-file with runtime detection, so HW SIMD video decode is preserved.
  • Wrap the armhf cross gcc/g++ with -mno-unaligned-access so both the qmake-built Qt libs (libQt5Core/Gui/Qml/Quick) and Chromium's gn build lower the block move to 4-byte-safe vstr. arm_use_neon=false alone leaves Qt's own libs faulting.

Also makes the Qt5 toolchain rebuildable on Debian trixie / Python 3.13 (a prerequisite): imp/pipes/cgi shims for stdlib modules Chromium 87's build tooling still imports, a distro-six overwrite for grit's broken vendored six, and python3-six/setuptools installs.

Validated on real hardware. Unfixed builds crash-loop with a blank screen (kernel Unhandled fault: alignment exception (0x801)) on both a Pi 2 (Cortex-A7) and a native 32-bit Pi 3 (Cortex-A53). Built with this toolchain, the viewer is stable — no respawn loop, renders webpage/image/video with 0 alignment traps across a multi-hour soak, including the CPU-heavy native signage apps. Binary-level: the fixed libQt5WebEngineCore.so strips the alignment-asserted NEON block stores ~27× (pi2 159, pi3 157 vs 4251 unfixed). The pi2 toolchain was also clean-rebuilt from scratch (no ccache / no Docker cache) and reproduces the fix.

Toolchain release (done). The WebView-v2026.07.1 release is published with the validated pi2 + pi3 tarballs (verified downloadable at the build URL, sha256-matched): https://github.com/Screenly/Anthias/releases/tag/WebView-v2026.07.1 . The one-line qt5_toolchain_url bump merged separately, so master already consumes the fixed toolchain at runtime; this PR brings the toolchain source fix (build_qt5.sh + the py3.13 rebuild shims) so the source can reproduce that release.

Checklist

  • I have performed a self-review of my own code.
  • New and existing unit tests pass locally and on CI with my changes. (All 10 CI checks green; the WebView-v2026.07.1 toolchain release is published so the pi2/pi3 viewer image build resolves the toolchain instead of 404ing.)
  • I have done an end-to-end test for Raspberry Pi devices. (Real Pi 2 (A7) and a native 32-bit Pi 3 (A53): unfixed = blank-screen crash-loop; fixed = stable viewer rendering webpage/image/video with 0 alignment traps over a multi-hour soak.)
  • I have tested my changes for x86 devices. (N/A — armhf pi2/pi3 Qt 5 toolchain only; x86 installs Qt 6 from Debian apt.)
  • I added documentation for the changes I have made. (src/anthias_webview/README.md updated, plus extensive inline comments in build_qt5.sh, the pyshim modules, and Dockerfile.qt5-webview-builder.j2.)

The Qt5 WebEngine viewer crash-loops on the Pi 2 (and any armv7/Cortex-A
board), leaving a permanent blank screen: AnthiasViewer SIGBUSes on an
unaligned 64-bit NEON store (vst1 {q8},[rN:64]) that modern Debian gcc
(12-16) emits for struct zero-init/copy of 8-byte-aligned types via its
arm_block_set_aligned_vect block-move expander. Chromium/Qt hand some of
those pointers 4-byte-aligned addresses, so the :64 alignment assertion
faults on the Cortex-A7; the kernel can't fix up NEON, so it SIGBUSes.
gcc treats this as correct codegen (GCC PR 93031, WONTFIX); the previously
shipped toolchain only escaped it because it predated the Linaro->Debian
gcc switch.

Fix (both required):
- Append arm_use_neon=false to QtWebEngine's Chromium gn args (the fix
  Yocto's meta-chromium / meta-lgsvl-browser ship) so general C++ compiles
  -mfpu=vfpv3-d16; codec/graphics (libvpx, Skia) re-add NEON per-file with
  runtime detection, preserving HW SIMD decode.
- Wrap the armhf cross gcc/g++ with -mno-unaligned-access so BOTH the
  qmake-built Qt libs and Chromium's gn build lower the block move to
  4-byte-safe vstr. arm_use_neon=false alone doesn't cover Qt's own libs.

Also makes the Qt5 toolchain rebuildable on Debian trixie (Python 3.13),
which dropped stdlib modules Chromium 87's build tooling still imports:
imp/pipes/cgi shims (src/anthias_webview/pyshim/) installed into python3
site-packages, a distro-six overwrite for grit's vendored six, and
python3-six/setuptools installs.

Validated on a real Pi 2: 0 alignment traps, stable viewer, renders
image/video/webpage, on the latest Qt 5.15.19 + Debian gcc-14.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@vpetersson
vpetersson requested a review from a team as a code owner July 10, 2026 19:54
@vpetersson vpetersson self-assigned this Jul 10, 2026
@vpetersson
vpetersson requested a review from Copilot July 10, 2026 19:54

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Updates the Qt 5 WebView toolchain build to avoid ARMv7 (Pi 2/3) alignment SIGBUS crashes in QtWebEngine/Chromium builds with modern Debian GCC, and modernizes the legacy Chromium 87 build tooling for Debian trixie’s Python 3.13 removals.

Changes:

  • Bump the pinned Qt5 toolchain release URL used by the image builder to WebView-v2026.07.1.
  • Add Python 3.12/3.13 stdlib shims (imp, pipes, cgi) to keep Chromium 87 tooling working on trixie.
  • Harden the Qt 5 toolchain build to avoid NEON-alignment faults by forcing -mno-unaligned-access via compiler wrapping and setting arm_use_neon=false in QtWebEngine’s Chromium GN args.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tools/image_builder/utils.py Updates the pinned Qt5 toolchain release tag used during viewer image builds.
src/anthias_webview/pyshim/pipes.py Provides pipes.quote compatibility via shlex.quote for Python 3.13+.
src/anthias_webview/pyshim/imp.py Provides a minimal imp shim for Python 3.12+ to satisfy Chromium 87 build tooling imports.
src/anthias_webview/pyshim/cgi.py Provides cgi.escape compatibility for Python 3.13+ to satisfy Chromium 87 build tooling imports.
src/anthias_webview/build_qt5.sh Adds Python-compat setup and build-flag/toolchain wrapping to prevent ARMv7 alignment traps and keep the toolchain rebuildable on trixie.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tools/image_builder/utils.py Outdated
Comment thread src/anthias_webview/build_qt5.sh Outdated
Comment thread src/anthias_webview/build_qt5.sh
Comment thread src/anthias_webview/build_qt5.sh
Comment thread src/anthias_webview/build_qt5.sh
Comment thread src/anthias_webview/pyshim/imp.py
Comment thread src/anthias_webview/pyshim/imp.py
Comment thread src/anthias_webview/pyshim/cgi.py
vpetersson and others added 2 commits July 10, 2026 19:58
The imp/pipes/cgi shims run only inside the Qt 5 toolchain builder image
to satisfy Chromium 87's Python-2-era build tooling on trixie's Python
3.13; they emulate removed-stdlib APIs, so the app's strict typing and
formatting rules don't apply. Same treatment as the sibling
sysroot-relativelinks.py already gets.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
… wrapper

Copilot review follow-ups on the Qt 5 toolchain build:
- Drop the `2>/dev/null || true` swallowing on the pyshim copy and the
  six/setuptools installs — these are required on Python 3.13, so a real
  failure should abort the build (set -e) instead of surfacing later as a
  confusing ImportError inside a Chromium gn/ninja action.
- Make the -mno-unaligned-access compiler wrapper recursion-proof: move
  the original aside to <tool>.real before writing the wrapper, so it can
  never exec itself if arm-linux-gnueabihf-{gcc,g++} is a real binary
  rather than an alternatives symlink.
- imp shim: correct the docstring (copied into site-packages, not
  PYTHONPATH) and give NullImporter.find_module the optional legacy
  `path` argument.
- cgi shim: document that escape() deliberately mirrors the stdlib
  cgi.escape (double-quote only), not html.escape.
- utils: fix the stale WebView-v2026.07.0 comment (now 07.1).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Comment thread src/anthias_webview/build_qt5.sh Outdated
Comment thread src/anthias_webview/build_qt5.sh Outdated
Comment thread src/anthias_webview/build_qt5.sh Outdated
Comment thread tools/image_builder/utils.py Outdated
- pyshim copy: guard on the glob matching real files so an empty/absent
  dir doesn't hand cp a literal `*.py` and abort under set -e.
- -mno-unaligned-access wrapper: only wrap when the tool exists and isn't
  already wrapped (idempotent; doesn't pre-empt fetch_cross_compile_tool's
  own presence check).
- arm_use_neon=false: grep-guard the common.pri append so a rebuild in the
  same workdir can't duplicate the line.
- Bump the remaining WebView-v2026.07.0 references (docs, scripts, github
  release-filter test fixtures) to 07.1 for consistency with the pinned
  toolchain release.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 2 comments.

Comment thread src/anthias_webview/build_qt5.sh
Comment thread src/anthias_webview/build_qt5.sh
The Qt5 builder image installs python3 but not python3-pip, so the
`|| pip3 install ...` fallback for six/setuptools could never actually
run — if the apt install fails the pip3 call just errors with
command-not-found. Install via apt only and let a real failure abort the
build (set -e), which is the honest behaviour.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 1 comment.

Comment thread src/anthias_webview/pyshim/imp.py
find_module() computed a file handle from spec.origin unconditionally; for
built-in/frozen modules origin is the sentinel 'built-in'/'frozen' (and
None for namespace packages), so open() would fail. Only open a genuine
file-backed origin.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 1 comment.

Comment thread src/anthias_webview/build_qt5.sh Outdated
The vendored-six overwrite swallowed all errors (2>/dev/null || true).
six is installed earlier in the script so the import can't fail, and a
silently-failed overwrite would only resurface later as the exact
"No module named 'six.moves'" grit crash this step exists to prevent.
Drop the swallowing and fold the two finds into one.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 1 comment.

Comment thread tools/image_builder/utils.py

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 2 comments.

Comment thread src/anthias_webview/pyshim/imp.py
Comment thread src/anthias_webview/pyshim/imp.py Outdated
… handling

Address Copilot review round 7 on the Python 3.13 `imp` shim:

- find_module() now resolves built-in and frozen modules the way the
  historical stdlib imp did when called with no explicit path: check
  sys.builtin_module_names / FrozenImporter first (no import side
  effects) and return C_BUILTIN / PY_FROZEN with a None pathname
  instead of leaking importlib's 'built-in'/'frozen' sentinel through
  as a fake filename. PathFinder alone never surfaced these (they're on
  no path), so it previously raised ImportError for e.g. `sys`.
- load_module() no longer assumes every PKG_DIRECTORY has an
  __init__.py: namespace packages (which find_module also classifies as
  PKG_DIRECTORY) now fall through to importlib.import_module instead of
  exec'ing a non-existent <dir>/__init__.py and raising.

Verified against built-in (sys), frozen (_frozen_importlib), regular
package (json), source module, and a synthetic namespace package.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated no new comments.

@vpetersson

Copy link
Copy Markdown
Contributor Author

Validated end-to-end on real 32-bit Raspberry Pi 3 hardware

Reproduced the bug and confirmed the fix on a native 32-bit Raspberry Pi OS (Raspbian trixie, armv7l) Pi 3 (Cortex-A53) — installed via the standard installer (dogfooded; it pulls all dependencies itself).

Unfixed (latest-pi3 from master):

  • AnthiasViewer crash-loops (respawns every ~6s)
  • Blank screen with a kernel alignment-fault dump on HDMI
  • dmesg: repeated Unhandled fault: alignment exception (0x801) / Alignment trap: not handling instruction f9400adf (14+ and climbing)

This is the "screen stays blank" forum report reproduced end-to-end on the A53.

Fixed (this PR's toolchain — Qt5 runtime rebuilt with arm_use_neon=false + the -mno-unaligned-access compiler wrapper):

  • 0 alignment traps
  • AnthiasViewer stable (no respawn), 4 QtWebEngineProcess render processes
  • Renders webpages (Wikipedia fullscreen) and the native signage apps
  • 8-minute native-app stress soak (clock, world-clock, weather, moon, rss, quotes, word, on-this-day + Wikipedia at 15–20s each, constant WebEngine teardown/init): 0 alignment traps, 0 respawns, 0 restarts. A multi-hour soak is ongoing.

This confirms the binary-level analysis: the pi3-stream libQt5WebEngineCore.so has the alignment-asserted NEON block stores stripped identically to the pi2 build (157 vs 4,251 in the unfixed master build). It is not a pi2-only fix — the same change in build_qt5.sh fixes pi3/A53 as well; no separate pi3 fix is needed.

Separately, the pi2 toolchain was clean-rebuilt from scratch (no ccache / no Docker cache) and reproduces the fix (150 faulting stores), and the pi2 viewer soaks clean on real hardware.

Still required before merge (unchanged): build + upload the pi2/pi3 toolchain tarballs to the WebView-v2026.07.1 release so CI's pi2/pi3 image builds resolve. Both tarballs are built and validated.

@vpetersson

Copy link
Copy Markdown
Contributor Author

Toolchain release is live: WebView-v2026.07.1https://github.com/Screenly/Anthias/releases/tag/WebView-v2026.07.1

Both validated tarballs are attached and downloadable at the exact URL the viewer image build fetches (verified HTTP 200, unauthenticated):

  • qt5-5.15.19-trixie-pi2.tar.gz (+ .sha256) — clean-rebuilt from scratch, 150 faulting NEON stores
  • qt5-5.15.19-trixie-pi3.tar.gz (+ .sha256) — 157 faulting stores; the build used to validate on real 32-bit Pi 3

This clears the last pre-merge blocker — CI's pi2/pi3 viewer image builds resolve the toolchain instead of 404ing.

…-neon-alignment-blank

# Conflicts:
#	tools/image_builder/utils.py
@vpetersson

Copy link
Copy Markdown
Contributor Author

Merged master and resolved the utils.py conflict.

Context: the toolchain-URL bump merged first (#3185), so master already consumes WebView-v2026.07.1 — users get the fix at runtime via the pre-built toolchain tarball. Both that PR and this one edited the same qt5_toolchain_url line; resolved by taking master's version, so utils.py is effectively unchanged here.

This PR still needs to land to bring the toolchain source fix to master: build_qt5.sh (arm_use_neon=false + the -mno-unaligned-access cross-compiler wrap) and the Python 3.13 rebuild shims (pyshim/). Without it, rebuilding the toolchain from master would produce an unfixed tarball and could overwrite the released WebView-v2026.07.1.

Verified post-merge: build_qt5.sh carries the fix (9 refs), pyshim/ present, utils.py pinned to .07.1.

@sonarqubecloud

Copy link
Copy Markdown

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants