Dev 日志 | 一次 Segmentation Fault 和 GCC Illegal Instruction 编译问题排查

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 本文记录了 Segmentation fault (core dumped) 和 internal compiler error: Illegal instruction 两个错误信息的 Debug 过程

摘要

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

Flex Segmentation Fault——Segmentation fault (core dumped)

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

make[2]: Entering directory '/home/dutor/flex-2.6.4/src'
./stage1flex   -o stage1scan.c ./scan.l
make[2]: *** [Makefile:1696: stage1scan.c] Segmentation fault (core dumped)

使用 gdb 查看 coredump:

Core was generated by `./stage1flex -o stage1scan.c ./scan.l'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  flexinit (argc=4, argv=0x7ffd25bea718) at main.c:976
976             action_array[0] = '\0';
(gdb) disas
Dump of assembler code for function flexinit:
   0x0000556c1b1ae040 <+0>:     push   %r15
   0x0000556c1b1ae042 <+2>:     lea    0x140fd(%rip),%rax        # 0x556c1b1c2146
   ...
   0x0000556c1b1ae20f <+463>:   callq  0x556c1b1af460 <allocate_array> #这里申请了buffer
   ...
=> 0x0000556c1b1ae24f <+527>:   movb   $0x0,(%rax) # 这里向buffer[0]写入一个字节,地址非法,挂掉了
   ...
(gdb) disas allocate_array
Dump of assembler code for function allocate_array:
   0x0000556c1b1af460 <+0>:     sub    $0x8,%rsp
   0x0000556c1b1af464 <+4>:     mov    %rsi,%rdx
   0x0000556c1b1af467 <+7>:     xor    %eax,%eax
   0x0000556c1b1af469 <+9>:     movslq %edi,%rsi
   0x0000556c1b1af46c <+12>:    xor    %edi,%edi
   0x0000556c1b1af46e <+14>:    callq  0x556c1b19a100 <reallocarray@plt> # 调用库函数申请内存
   0x0000556c1b1af473 <+19>:    test   %eax,%eax # 判断是否为 NULL
   0x0000556c1b1af475 <+21>:    je     0x556c1b1af47e <allocate_array+30># 跳转至NULL错误处理
   0x0000556c1b1af477 <+23>:    cltq   # 将 eax 符号扩展至 rax,造成截断
   0x0000556c1b1af479 <+25>:    add    $0x8,%rsp
   0x0000556c1b1af47d <+29>:    retq
   ...
End of assembler dump.

可以看到,问题出在了 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——internal compiler error: Illegal instruction

前阵子,接到用户反馈,在编译 Nebula Graph 过程中遭遇了编译器非法指令的错误。

错误信息大概是这样的:

Scanning dependencies of target base_obj_gch
[ 0%] Generating Base.h.gch
In file included from /opt/nebula/gcc/include/c++/8.2.0/chrono:40,
from /opt/nebula/gcc/include/c++/8.2.0/thread:38,
from /home/zkzy/nebula/nebula/src/common/base/Base.h:15:
/opt/nebula/gcc/include/c++/8.2.0/limits:1599:7: internal compiler error: Illegal instruction
min() _GLIBCXX_USE_NOEXCEPT {
    return FLT_MIN; }
^~~
0xb48c5f crash_signal
../.././gcc/toplev.c:325
Please submit a full bug report,
with preprocessed source if appropriate.

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

#include <thread>
int main() 
{
    return 0;
}

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

$ gdb --args /opt/nebula/gcc/bin/g++ test.cpp
gdb> set follow-fork-mode child
gdb> run
Starting program: /opt/nebula/gcc/bin/g++ test.cpp
[New process 31172]
process 31172 is executing new program: /opt/nebula/gcc/libexec/gcc/x86_64-pc-linux-gnu/8.2.0/cc1plus
Thread 2.1 "cc1plus" received signal SIGILL, Illegal instruction.
[Switching to process 31172]
0x00000000013aa0fb in __gmpn_mul_1 ()
gdb> disas
...
0x00000000013aa086 <+38>: mulx (%rsi),%r10,%r8
...

Bingo!mulx 属于 BMI2 指令集,报错机器 CPU 不支持该指令集。
仔细调查,引入该指令集的是 GCC 的依赖之一,GMP。默认情况下,GMP 会在 configure 阶段探测当前机器的 CPU 具体类型,以期最大化利用 CPU 的扩展指令集,提升性能,但却牺牲了二进制的可移植性。解决方法是,configure 之前,使用代码目录中的 configfsf.guess configfsf.sub 替换或者覆盖默认的 config.guess 和 config.sub

总结:

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

最后,如果你想尝试编译一下 Nebula 源代码可参考以下方式:

bash> git clone https://github.com/vesoft-inc/nebula.git
bash> cd nebula && ./build_dep.sh N

有问题请在 GitHub 或者微信公众号上留言。

附录

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
Linux C语言 Python
Linux C-完美解决segmentation fault (core dumped)
在Linux下进行C语言编程时,遇到一个错误,网上说的都很复杂,看都看不懂,其实就是你对指针进行直接操作之前,没有对它进行分配地址空间。 所以在运行的时候,它不知道在那里操作(比如赋值,取值),所以才报了这个错误。
44009 0
|
编译器 Go 开发工具
常见问题之Golang——cgo: C compiler &quot;gcc&quot; not found: exec: &quot;gcc&quot;: executable file not found in %PATH%错误
本文主要是对我日常在使用golang时遇到的一些问题与解决方式进行的汇总,在此提供给大家便于排查一些遇到的问题,其中有更好的解决方案可在评论区留言。
1224 0
常见问题之Golang——cgo: C compiler &quot;gcc&quot; not found: exec: &quot;gcc&quot;: executable file not found in %PATH%错误
|
5月前
|
Python
Jetson 错误(一):Illegal instruction (core dumped)解决
在NVIDIA Jetson平台上运行Python时遇到"Illegal instruction (core dumped)"错误的解决方法,包括设置环境变量和确保软件包版本兼容性。
656 0
|
10月前
MTK在编译10A的target时报错:make: *** [mmi_feature_check]
MTK在编译10A的target时报错:make: *** [mmi_feature_check]
45 0
|
Python
Python 库配置问题:“Couldn‘t find ffmpeg or avconv - defaulting to ffmpeg, but may not work“. 解决办法
Python 库配置问题:“Couldn‘t find ffmpeg or avconv - defaulting to ffmpeg, but may not work“. 解决办法
1070 0
Python 库配置问题:“Couldn‘t find ffmpeg or avconv - defaulting to ffmpeg, but may not work“. 解决办法
在处理时有错误发生: trousers tpm-tools E: Sub-process /usr/bin/dpkg returned an error code (1)
在处理时有错误发生: trousers tpm-tools E: Sub-process /usr/bin/dpkg returned an error code (1)
在处理时有错误发生: trousers tpm-tools E: Sub-process /usr/bin/dpkg returned an error code (1)
|
程序员 iOS开发 开发者
iOS开发:程序打包提示Ignoring file XXX missing required architecture arm7 in file XXX错误
前段时间在开发过程中遇到一个iOS打包报错Ignoring file XXX missing required architecture arm7 in file XXX的问题,然后回想了一下问题所在,是因为集成了ijk播放器插件,然后ijk三方库不支持arm7造成的报错。
211 0
iOS开发:程序打包提示Ignoring file XXX missing required architecture arm7 in file XXX错误
编译OpenJDK11:configure: error: Target CPU mismatch. We are building for x86_64 but CL is for “版“; exp
编译OpenJDK11:configure: error: Target CPU mismatch. We are building for x86_64 but CL is for “版“; exp
189 0
|
C++ Windows
全网首发:编译ffmpeg: error: ‘VFW_E_NOT_FOUND‘ undeclared ; did you mean ‘NTE_NOT_FOUND‘?
全网首发:编译ffmpeg: error: ‘VFW_E_NOT_FOUND‘ undeclared ; did you mean ‘NTE_NOT_FOUND‘?
166 0
缺少链接库报错:ld: symbol(s) not found for architecture x86_64
缺少链接库报错:ld: symbol(s) not found for architecture x86_64
269 0