]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
fix(ulibc): add null-pointer guards in __libc_init_array/fini_array
authorTulio A M Mendes <[email protected]>
Thu, 16 Apr 2026 05:36:47 +0000 (02:36 -0300)
committerTulio A M Mendes <[email protected]>
Thu, 16 Apr 2026 05:36:47 +0000 (02:36 -0300)
In a PIC shared library build, linker-generated symbols like
__init_array_start, __fini_array_end, and _init may remain
SHN_UNDEF (value 0) when the library has no .init_array/.fini_array
sections. The GOT entries for these resolve to 0.

Added null-pointer checks using volatile pointers (to prevent the
compiler from assuming the address is always non-null) for all
init/fini array pointers and for _init/_fini function pointers.
This prevents crashes when these symbols are unresolved.

user/ulibc/src/init_fini.c

index d409d0439577d14ffb3862597de6be9bf6ffa403..91aed6a9cda3ecf38d30c64ff95af369d50f9e6c 100644 (file)
  * The symbols __preinit_array_start, __init_array_start, __init_array_end,
  * __fini_array_start, __fini_array_end are defined by the linker script.
  * _init() and _fini() come from crti.o/crtn.o (GCC CRT files).
+ *
+ * In a shared-library build these linker-generated symbols may remain
+ * SHN_UNDEF (value 0) when the library has no .init_array / .fini_array
+ * sections.  We guard against that by checking the GOT entries for NULL.
  */
 
 #include <stddef.h>
 
 typedef void (*init_func)(void);
 
-extern init_func __preinit_array_start[];
-extern init_func __preinit_array_end[];
-extern init_func __init_array_start[];
-extern init_func __init_array_end[];
-extern init_func __fini_array_start[];
-extern init_func __fini_array_end[];
+/* These are resolved via the GOT in PIC mode; their values come from
+ * GLOB_DAT relocations.  When the linker doesn't define them they
+ * resolve to 0.  We read them through a volatile pointer so the
+ * compiler cannot assume they are non-null. */
+extern init_func *volatile __preinit_array_start[];
+extern init_func *volatile __preinit_array_end[];
+extern init_func *volatile __init_array_start[];
+extern init_func *volatile __init_array_end[];
+extern init_func *volatile __fini_array_start[];
+extern init_func *volatile __fini_array_end[];
 
 extern void _init(void);
 extern void _fini(void);
 
+/* Read _init/_fini through volatile to allow null check.
+ * In PIC shared libs, these resolve via GOT and may be 0. */
+static volatile init_func _init_ptr = _init;
+static volatile init_func _fini_ptr = _fini;
+
 void __libc_init_array(void) {
     size_t count, i;
+    init_func *s, *e;
 
-    count = (size_t)(__preinit_array_end - __preinit_array_start);
-    for (i = 0; i < count; i++)
-        __preinit_array_start[i]();
+    s = (init_func*)__preinit_array_start;
+    e = (init_func*)__preinit_array_end;
+    if (s && e) {
+        count = (size_t)(e - s);
+        for (i = 0; i < count; i++)
+            s[i]();
+    }
 
-    _init();
+    {
+        init_func fn = _init_ptr;
+        if (fn) fn();
+    }
 
-    count = (size_t)(__init_array_end - __init_array_start);
-    for (i = 0; i < count; i++)
-        __init_array_start[i]();
+    s = (init_func*)__init_array_start;
+    e = (init_func*)__init_array_end;
+    if (s && e) {
+        count = (size_t)(e - s);
+        for (i = 0; i < count; i++)
+            s[i]();
+    }
 }
 
 void __libc_fini_array(void) {
     size_t count;
+    init_func *s, *e;
 
-    count = (size_t)(__fini_array_end - __fini_array_start);
-    while (count-- > 0)
-        __fini_array_start[count]();
+    s = (init_func*)__fini_array_start;
+    e = (init_func*)__fini_array_end;
+    if (s && e) {
+        count = (size_t)(e - s);
+        while (count-- > 0)
+            s[count]();
+    }
 
-    _fini();
+    {
+        init_func fn = _fini_ptr;
+        if (fn) fn();
+    }
 }