Segmentation Fault 和 GCC Illegal Instruction 编译问题排查

ywz888
发布于 2022-10-12 11:28
浏览
0收藏


摘要


笔者最近在重新整理和编译 Nebula Graph 的第三方依赖,选出两个比较有意思的问题给大家分享一下。


Flex Segmentation Fault

Segmentation fault (core dumped)



在编译 Flex 过程中,遇到了 Segmentation fault:

Segmentation Fault 和 GCC Illegal Instruction 编译问题排查-鸿蒙开发者社区

使用 gdb 查看 coredump:

Segmentation Fault 和 GCC Illegal Instruction 编译问题排查-鸿蒙开发者社区

可以看到,问题出在了 allocate_array 函数。因为 reallocarray 返回指针,返回值应该使用 64 bit 寄存器rax,但 allocate_array 调用 reallocarray 之后,检查的却是 32 bit 的 eax,同时使用 cltq 指令将 eax 符号扩展 到 rax

原因只有一个:allocate_array 看到的 reallocarray 的原型,与 reallocarry 的实际定义不符。翻看编译日志,确实找到了 implicit declaration of function 'reallocarray' 相关的警告。configure 阶段添加 CFLAGS=-D_GNU_SOURCE 即可解决此问题。


注:此问题不是必现,但编译/链接选项 -pie 和 内核参数 kernel.randomize_va_space 有助于复现。


总结:

  • 隐式声明的函数在 C 中,返回值被认为是 int
  • 关注编译器告警,-Wall -Wextra 要打开,开发模式下最好打开 -Werror。


GCC Illegal Instruction



前阵子,接到用户反馈,在编译 Nebula Graph 过程中遭遇了编译器非法指令的错误,详见(#978)[https://github.com/vesoft-inc/nebula/issues/978]


错误信息大概是这样的:

Segmentation Fault 和 GCC Illegal Instruction 编译问题排查-鸿蒙开发者社区

既然是 internal compiler error,想必是 g++ 本身使用了非法指令。为了定位具体的非法指令集及其所属模块,我们需要复现这个问题。幸运的是,下面的代码片段就能触发:

Segmentation Fault 和 GCC Illegal Instruction 编译问题排查-鸿蒙开发者社区

非法指令一定会触发 SIGILL,又因为 g++ 只是编译器的入口,真正干活的是 cc1plus。我们可以使用 gdb 来运行编译命令,抓住子进程使用非法指令的第一现场:

Segmentation Fault 和 GCC Illegal Instruction 编译问题排查-鸿蒙开发者社区

Bingo!mulx 属于 BMI2 指令集,报错机器 CPU 不支持该指令集。


仔细调查,引入该指令集的是 GCC 的依赖之一,GMP。默认情况下,GMP 会在 configure 阶段探测当前机器的 CPU 具体类型,以期最大化利用 CPU 的扩展指令集,提升性能,但却牺牲了二进制的可移植性。


解决方法是,在 configure 之前,使用代码目录中的 configfsf.guess configfsf.sub 替换或者覆盖默认的 config.guess 和 config.sub


总结:

  • 某些依赖可能因为性能或者配置的原因,造成二进制的不兼容。
  • 缺省参数下,GCC 为了兼容性,不会使用较新的指令集。
  • 为了平衡兼容性和性能,你需要做一些额外的工作,比如像 glibc 那样在运行时选择和绑定某个具体实现。



文章转载自公众号:Nebula Graph Community

标签
已于2022-10-12 11:28:33修改
收藏
回复
举报
回复
    相关推荐