Dev 日志 | 一次 Segmentation Fault 和 GCC Illegal Instruction 编译问题排查
摘要
笔者最近在重新整理和编译 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 过程中遭遇了编译器非法指令的错误,详见(#978)[https://github.com/vesoft-inc/nebula/issues/978]
错误信息大概是这样的:
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 或者微信公众号上留言。
附录
- Nebula Graph:一个开源的分布式图数据库
- GitHub:https://github.com/vesoft-inc/nebula
- 知乎:zhihu.com/org/nebulagraph/posts
- 微博:weibo.com/nebulagraph
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
java.nio包的分析(一)--Buffer类
什么是nio,看看百度百科的解释: 好的,下面来说一下,nio下的包的目录结构,总体来说,Nio算的上Java后来添加的一项高级属性了吧。 目录很清晰,通过目录名称也基本知道他的一些主要的功能分类,下面从上往下开始逐步的研究它的源代码,Java.nio下面直接的类为一堆的Buffer缓冲类,后面的各种Channel都是基于Buffer类进行操作的。 首先我们当然得先了解里面最最原始的类,Buffer的构成,才能明白后面衍生出的各种基本裂隙对于的Buffer 类 Buffer类的后续操作都是基于这几个值进行操作的,不信,接着往下看, 下面在来看看其中继承下来的一个类,IntBuffer,其他相应数据类型,与此相似,所以不做分析 里面主要有一些操作,比如put,get,还有一个比较的方法 另外在这个类里面还有一个比较奇葩的类MappedByteBuffe,内存映射Buffer: 原文转载自:https://blog.csdn.net/Androidlushangderen/article/details/39735101
- 下一篇
像用“数据库”一样使用“大数据”!华为宣布河图引擎开源
11 月 19 日,华为在深圳举办了 2019 全球数据基础设施论坛。华为 Cloud & AI 产品与服务总裁侯金龙宣布,面向鲲鹏计算产业,全面启动数据基础设施战略,并开源数据虚拟化引擎 HetuEngine(河图引擎),希望让伙伴像使用“数据库”一样使用“大数据”,让数据治理、使用更简单。 今年 9 月,华为在全联接大会上发布了“一云两翼双引擎”的鲲鹏计算产业布局,基于“鲲鹏+�N腾”双引擎,全面启航计算战略,为世界提供最强算力。今天华为又从数据角度对计算战略再一次进行了阐述。 侯金龙表示,华为公司的愿景与使命是:“把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界”。在智能世界,算力成为新生产力,数据成为新生产资料,“5G、AI、云”成为新生产工具,将使能千行百业迈入智能时代。 随着 5G、AI 和云的普及,数据量正以惊人的速度增长:从 1080P 到 4K、8K,视频数据量将提升 40 倍,从 4K 到 4K VR 要增加 6 倍以上;未来每辆自动驾驶汽车每天就会产生高达 64 TB 数据;深圳一个城市有超过 200 万摄像头,每天将产生 80 PB 数据...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Mario游戏-低调大师作品
- CentOS6,CentOS7官方镜像安装Oracle11G
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8编译安装MySQL8.0.19
- MySQL8.0.19开启GTID主从同步CentOS8