diff mbox series

[meta-oe] uim: Fix uim-module-manager segfault from a GC'd require filename

Message ID 20260804011152.1624318-1-khem.raj@oss.qualcomm.com
State New
Headers show
Series [meta-oe] uim: Fix uim-module-manager segfault from a GC'd require filename | expand

Commit Message

Khem Raj Aug. 4, 2026, 1:11 a.m. UTC
uim-module-manager crashes in uim_init() while requiring key.scm:

    #0  __strlen_evex ()
    #1  make_loaded_str (filename=0x7e)
    #2  scm_p_require ()
    ...
    #29 uim_init ()

scm_p_require() dereferences its FILENAME argument again after the
nested scm_load(), but nothing keeps a tagged ScmObj reference to it.
SigScheme's conservative collector only accepts properly tagged words
(within_heapp() / SCM_TAG_CONSISTENTP()), while the compiler keeps just
SCM_DROP_TAG(filename) and the interior char *, so the string is swept
and its cell recycled mid-load:

    before load: cell=0x7ffff7d5a090 obj_x=0x555555569180 "key.scm"
    after  load: cell=0x7ffff7d5a090 obj_x=0x7e            <- recycled

Whether it triggers is pure allocation timing, which is why uim-native
fell over while the cross-built uim ran the same scm files fine.

Add the patch to the common SRC_URI rather than the class-target one,
since it is uim-native that scm/Makefile runs at build time.

Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
---
 ...-protect-the-objects-used-by-require.patch | 103 ++++++++++++++++++
 meta-oe/recipes-support/uim/uim_1.9.6.bb      |   4 +-
 2 files changed, 106 insertions(+), 1 deletion(-)
 create mode 100644 meta-oe/recipes-support/uim/uim/0001-sigscheme-GC-protect-the-objects-used-by-require.patch
diff mbox series

Patch

diff --git a/meta-oe/recipes-support/uim/uim/0001-sigscheme-GC-protect-the-objects-used-by-require.patch b/meta-oe/recipes-support/uim/uim/0001-sigscheme-GC-protect-the-objects-used-by-require.patch
new file mode 100644
index 0000000000..1d2a829268
--- /dev/null
+++ b/meta-oe/recipes-support/uim/uim/0001-sigscheme-GC-protect-the-objects-used-by-require.patch
@@ -0,0 +1,103 @@ 
+From: Khem Raj <raj.khem@gmail.com>
+Date: Sun, 2 Aug 2026 00:00:00 +0000
+Subject: [PATCH] sigscheme: GC-protect the objects used by require
+
+uim-module-manager segfaults inside uim_init() while requiring key.scm:
+
+    #0  __strlen_evex ()
+    #1  make_loaded_str (filename=0x7e)
+    #2  scm_p_require ()
+    ...
+    #26 uim_scm_require_file ()
+    #29 uim_init ()
+
+scm_p_require() dereferences its FILENAME argument again after
+scm_require_internal() has run, and scm_require_internal() keeps
+LOADED_STR live across a nested scm_load().  Neither object is
+GC-protected.
+
+SigScheme's conservative collector only recognizes *tagged* ScmObj
+values: within_heapp() rejects any candidate word whose tag is not
+consistent with the cell it points to (SCM_TAG_CONSISTENTP()).  An
+optimizing compiler is free to keep only SCM_DROP_TAG(filename) and the
+interior "char *" returned by SCM_STRING_STR(), and gcc does exactly
+that here:
+
+    scm_p_require:
+        mov  %rdi,%rbp
+        and  $0xfffffffffffffff8,%rbp   # SCM_DROP_TAG(filename)
+        mov  0x0(%rbp),%r12             # SCM_STRING_STR(filename)
+        ...                             # no tagged copy is kept anywhere
+
+While the nested scm_load() runs, the string is therefore unreachable
+for the GC.  A cons allocation inside that load triggers a mark & sweep,
+the string cell is put on the free list (its body free()d by
+SCM_CELL_STRING_FIN()) and the cell is immediately recycled.  The
+following SCM_STRING_STR(filename) then returns whatever the new
+occupant stores in obj_x -- 0x7e above -- and strlen() faults:
+
+    before load: cell=0x7ffff7d5a090 obj_x=0x555555569180 "key.scm"
+    after  load: cell=0x7ffff7d5a090 obj_x=0x7e            <- recycled
+
+Whether this is hit depends purely on allocation timing, which is why it
+shows up for one build of uim and not for another built from the same
+sources on the same host.
+
+Protect the objects for as long as they are needed.
+
+Upstream-Status: Submitted [https://github.com/uim/uim/issues]
+
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+---
+ sigscheme/src/module-sscm-ext.c | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+--- a/sigscheme/src/module-sscm-ext.c
++++ b/sigscheme/src/module-sscm-ext.c
+@@ -224,11 +224,15 @@
+ {
+     ScmObj loaded_str;
+
+-    loaded_str = make_loaded_str(filename);
++    /* scm_load() below can trigger a GC and the conservative collector only
++     * recognizes tagged ScmObj values, so protect LOADED_STR explicitly. */
++    scm_gc_protect_with_init(&loaded_str, make_loaded_str(filename));
+     if (!scm_providedp(loaded_str)) {
+         scm_load(filename);
+         scm_provide(loaded_str);
+     }
++    scm_gc_unprotect(&loaded_str);
++
+     return NULL;
+ }
+
+@@ -242,15 +246,28 @@
+
+     ENSURE_STRING(filename);
+
++    /* FILENAME is dereferenced again below and its body is handed to
++     * scm_load() as a plain char *.  Optimizing compilers keep only
++     * SCM_DROP_TAG(filename) and SCM_STRING_STR(filename) live, and
++     * within_heapp() rejects both, so without this explicit protection the
++     * string is swept (and its body free()d) by a GC triggered from the
++     * nested load. */
++    scm_gc_protect(&filename);
++
+     scm_require_internal(SCM_STRING_STR(filename));
+
+ #if SCM_COMPAT_SIOD
+-    loaded_str = make_loaded_str(SCM_STRING_STR(filename));
++    scm_gc_protect_with_init(&loaded_str,
++                             make_loaded_str(SCM_STRING_STR(filename)));
+     retsym = scm_intern(SCM_STRING_STR(loaded_str));
+     SCM_SYMBOL_SET_VCELL(retsym, SCM_TRUE);
++    scm_gc_unprotect(&loaded_str);
++    scm_gc_unprotect(&filename);
+
+     return retsym;
+ #else
++    scm_gc_unprotect(&filename);
++
+     return SCM_TRUE;
+ #endif
+ }
diff --git a/meta-oe/recipes-support/uim/uim_1.9.6.bb b/meta-oe/recipes-support/uim/uim_1.9.6.bb
index 3e494e3338..1ea0f488ed 100644
--- a/meta-oe/recipes-support/uim/uim_1.9.6.bb
+++ b/meta-oe/recipes-support/uim/uim_1.9.6.bb
@@ -4,7 +4,9 @@  LICENSE = "BSD-3-Clause AND LGPL-2.0-or-later"
 LIC_FILES_CHKSUM = "file://COPYING;md5=ab2826b41ca0ff4030d38cc39791d1c8"
 SECTION = "inputmethods"

-SRC_URI = "https://github.com/uim/uim/releases/download/${PV}/uim-${PV}.tar.bz2"
+SRC_URI = "https://github.com/uim/uim/releases/download/${PV}/uim-${PV}.tar.bz2 \
+    file://0001-sigscheme-GC-protect-the-objects-used-by-require.patch \
+"
 SRC_URI:append:class-target = "\
     file://uim-module-manager.patch \
 "