You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

libdl中link_map是什么?为何引发应用动态加载崩溃?

动态加载库时的空指针崩溃问题

问题现象与根源

最近构建的复杂C++应用编译成功后,启动时出现非法内存访问崩溃,经排查是空指针带偏移访问导致。崩溃发生在通过dlopen动态加载libXcursor.so库的过程中,核心原因是link_map->l_versions为空指针,但elf_machine_rela函数(尤其是其中的RESOLVE_MAP宏)在重定位时未对该指针做非空检查,触发崩溃的代码行是map->l_versions[ndx]:

ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
                 &map->l_versions[ndx],
                 (void *) (l_addr + r->r_offset), skip_ifunc);

需要注意的是,这个出现问题的link_map并非libXcursor.so自身的依赖描述,而是libgthread库的DSO,且该依赖未完成初始化。

问题代码路径追踪

libgthread的link_map是从dl_open_worker中传入进行重定位的:

_dl_relocate_object (l, l->l_scope, reloc_mode, 0);

它是通过以下逻辑被收集到待重定位的依赖列表中的:

l = new;
do
{
  if (! l->l_real->l_relocated)
    maps[nmaps++] = l;
  l = l->l_next;
}
while (l != NULL);

上述代码中的new是libXcursor.so对应的link_map。这段逻辑存在异常,因为其他依赖的初始化是通过以下代码完成的,其中包含了版本检查的步骤:

/* Load that object's dependencies.  */
_dl_map_object_deps (new, NULL, 0, 0,
                     mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT));

/* So far, so good.  Now check the versions.  */
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
  if (new->l_searchlist.r_list[i]->l_real->l_versions == NULL)
    (void) _dl_check_map_versions (new->l_searchlist.r_list[i]->l_real,
                                   0, 0);

疑问与修复需求

  1. 为什么会在重定位时传入另一组未正确初始化的依赖列表,且系统加载器的关键流程中没有添加必要的非空检查?
  2. 针对当前glibc 2.27版本,该如何修复这个崩溃问题?

环境信息

使用的libdl版本为/lib64/libdl-2.27.so,对应glibc版本为glibc-2.27-38.fc28.x86_64。

补充说明

该问题已在后续glibc的多个提交中修复,目前无法复现,即使使用glibc 2.27版本编写小型测试应用,也无法触发原崩溃场景。


内容的提问来源于stack exchange,提问作者Anton Astafiev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 11:47:44