起初是发现 Fedora 38 RISC-V 在执行 gnome-shell --list-modes
时出现 segfault 的情况,便对这一问题展开了调查
在干净的 Fedora 38 RISC-V 上安装 gnome-shell,并测试 gnome-shell --list-modes
确实有问题,随后下载了该包的 debugsource 和 debuginfo 并使用 gdb 分析
查看后发现 strstr 传入了一个空指针,遂追踪空指针何时被传入,追踪到 shell_introspection_init()
时发现找不到 g_strsplit()
函数,后来发现此函数是在 maybe_add_rpath_introspection_paths()
里调用到的,而这个函数应该是被 gcc 优化为 shell_introspection_init()
的内联函数了
可以看到
for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; dyn++)
{
if (dyn->d_tag == DT_RPATH)
rpath = dyn;
else if (dyn->d_tag == DT_RUNPATH)
runpath = dyn;
else if (dyn->d_tag == DT_STRTAB)
strtab = (const char *) dyn->d_un.d_val;
}
if ((!rpath && !runpath) || !strtab)
return;
if (rpath)
paths = g_strsplit (strtab + rpath->d_un.d_val, ":", -1);
else
paths = g_strsplit (strtab + runpath->d_un.d_val, ":", -1);
此处调用了 g_strsplit()
,而 strtab 出自上面的 for 循环
在 gdb 里打印 strtab 的值会发现该值为 0x4d50,不像是一个地址,同时在 x86 下的 gnome-shell 测试中,strtab 的值就是一个正确的指针,那么可以推断出是 strtab 指向了一个不存在的地址导致后续问题
搜索过程中发现 gnome-shell 的 gitlab 中已经有人提出了 相关issue
根据他们的说法,glibc 对于 MIPS 和 RISC-V 的 .dynamic 段因为是只读的默认没有开启 reallocate,导致获取的地址仅仅只是 offset 而非实际地址,因此在 该commit中 简单判断了 strtab 是否小于 link_map->l_addr,如果是,则相加,相当于手动偏移地址
在应用该补丁后问题得到解决
感谢 U2FsdGVkX1 在解决此问题时提供的帮助