fix(webview): stop Pi 2/3 blank screen from gcc NEON alignment SIGBUS - #3184
Conversation
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]>
There was a problem hiding this comment.
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-accessvia compiler wrapping and settingarm_use_neon=falsein 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.
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]>
- 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]>
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]>
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]>
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]>
… 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]>
Validated end-to-end on real 32-bit Raspberry Pi 3 hardwareReproduced the bug and confirmed the fix on a native 32-bit Raspberry Pi OS (Raspbian trixie, Unfixed (
This is the "screen stays blank" forum report reproduced end-to-end on the A53. Fixed (this PR's toolchain — Qt5 runtime rebuilt with
This confirms the binary-level analysis: the pi3-stream 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 |
|
Toolchain release is live: WebView-v2026.07.1 — https://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):
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
|
Merged Context: the toolchain-URL bump merged first (#3185), so This PR still needs to land to bring the toolchain source fix to master: Verified post-merge: |
|



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 tcachecrash 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.
AnthiasViewerSIGBUSes 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 itsarm_block_set_aligned_vectblock-move expander. Chromium/Qt hand some of those pointers 4-byte-aligned addresses, so the:64alignment 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):
arm_use_neon=falseto 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.gcc/g++with-mno-unaligned-accessso both the qmake-built Qt libs (libQt5Core/Gui/Qml/Quick) and Chromium's gn build lower the block move to 4-byte-safevstr.arm_use_neon=falsealone leaves Qt's own libs faulting.Also makes the Qt5 toolchain rebuildable on Debian trixie / Python 3.13 (a prerequisite):
imp/pipes/cgishims for stdlib modules Chromium 87's build tooling still imports, a distro-six overwrite for grit's broken vendored six, andpython3-six/setuptoolsinstalls.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 fixedlibQt5WebEngineCore.sostrips 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.1release 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-lineqt5_toolchain_urlbump merged separately, somasteralready 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
WebView-v2026.07.1toolchain release is published so the pi2/pi3 viewer image build resolves the toolchain instead of 404ing.)src/anthias_webview/README.mdupdated, plus extensive inline comments inbuild_qt5.sh, the pyshim modules, andDockerfile.qt5-webview-builder.j2.)