fix(decorated-window-tao): load GTK with RTLD_LOCAL to stop sqlite interposition#368
Merged
Conversation
…mbol interposition The Linux CSD shadow helper (new in 2.1.0) dlopen()s GTK with RTLD_GLOBAL at every decorated-window creation. On distros where GTK's dependency closure includes libsqlite3 (NixOS: gtk3 -> tinysparql -> sqlite), the system sqlite enters the global symbol scope and lazily-bound sqlite3_* PLT entries of androidx/Room's bundled-sqlite JNI library resolve to the system copy from then on. Entry points first called after the window opened then operate on statements created by the bundled copy and segfault (SIGSEGV in sqlite3VdbeMemGrow via bindText) — reads bound before the window kept working, which matched the reported symptom. Switch every GTK-family dlopen (shadow + widget helpers) to RTLD_LOCAL. All symbols are fetched via dlsym() on the explicit handles — nothing uses dlsym(RTLD_DEFAULT) — so no global visibility is needed, and GTK's own modules link libgtk directly. Includes an e2e repro (SqliteReproMain.kt + runSqliteRepro task): recreate the NixOS closure on any distro with a patchelf'ed libgtk-3.so.0 that adds libsqlite3.so.0 as DT_NEEDED, open a bundled-sqlite DB and read before the window, then bindText-write after it. Crashes with RTLD_GLOBAL, passes with RTLD_LOCAL while the shadow theme stamp stays functional. Fixes #366
…gression test Replaces the manual runSqliteRepro task (hardcoded /tmp shim path) with a JUnit test: it builds the patched-GTK shim itself in a temp dir (patchelf --add-needed libsqlite3.so.0), forks a JVM on the repro main — a SIGSEGV kills the whole process, so the outcome must be observed from outside — and asserts exit 0, a functional GTK shadow theme stamp (guards against a vacuous pass where GTK never loaded) and the completed write. Skips instead of failing wherever the scenario can't run: non-Linux, no DISPLAY/WAYLAND_DISPLAY, no patchelf, no system libgtk-3/libsqlite3. Verified both ways locally: passes with RTLD_LOCAL natives, fails with RTLD_GLOBAL ones.
kdroidFilter
force-pushed
the
fix/tao-linux-gtk-rtld-local
branch
from
July 18, 2026 18:21
d4957c9 to
6d27d3a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
libsqlite3.so(sqlite3VdbeMemGrow) on Linux when a Room/androidx bundled-sqlite write runs after a Tao decorated window opened (regression 2.0.7 → 2.1.0, NixOS).nucleus_tao_linux_shadow.c) dlopen()s GTK withRTLD_GLOBALat every window creation. On NixOS, GTK3's closure pullslibsqlite3(gtk3 → tinysparql → sqlite), so the system sqlite enters the global symbol scope. The bundled-sqlite JNI lib binds itssqlite3_*PLT entries lazily: entry points first called after the window opened resolve to the system copy but operate on statements created by the bundled copy → segfault. This is exactly why reads (bound before the window) kept working while writes crashed.RTLD_GLOBAL→RTLD_LOCALfor all GTK-family dlopen sites (shadow + widget helpers). Safe: every symbol is fetched viadlsym()on the explicit handles, nothing relies ondlsym(RTLD_DEFAULT), and GTK's own modules linklibgtk-3.sovia their ownDT_NEEDED.nucleus_tao_egl.c/nucleus_tao_linux_popup.c(EGL/GL/X11/wayland — no sqlite in their closures) are deliberately left untouched.tao-demo(SqliteReproMain.kt+runSqliteReprotask), same pattern as the Sandboxing: make extract-and-load native libraries (System.load from temp) work in store builds without upstream changes #317 probe. The NixOS closure is recreated on any distro with a patched GTK copy:mkdir /tmp/gtk-shim && cp /usr/lib/x86_64-linux-gnu/libgtk-3.so.0 /tmp/gtk-shim/ patchelf --add-needed libsqlite3.so.0 /tmp/gtk-shim/libgtk-3.so.0 ./gradlew :examples:tao-demo:runSqliteReproTest plan
nativeBindText(androidx bundled JNI) → systemlibsqlite3.so.0→ SIGSEGV in the sqlite allocatorbindTextwrite + read-back succeed, no crashRTLD_LOCALin the same process (nativeShadowThemeStamp()→Yaru-blue-dark|1)grep RTLD_DEFAULTover native sources: no consumer of the global scope