筆者最近在從新整理和編譯 Nebula Graph 的第三方依賴,選出兩個比較有意思的問題給你們分享一下。linux
在編譯 Flex 過程當中,遇到了 Segmentation fault:c++
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:git
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
便可解決此問題。github
注:此問題不是必現,但編譯/連接選項 -pie 和 內核參數 kernel.randomize_va_space 有助於復現。數據庫
總結:bash
int
。前陣子,接到用戶反饋,在編譯 Nebula Graph 過程當中遭遇了編譯器非法指令的錯誤,詳見(#978)[https://github.com/vesoft-inc/nebula/issues/978]微信
錯誤信息大概是這樣的:app
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++ 自己使用了非法指令。爲了定位具體的非法指令集及其所屬模塊,咱們須要復現這個問題。幸運的是,下面的代碼片斷就能觸發:dom
#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
總結:
最後,若是你想嘗試編譯一下 Nebula 源代碼可參考如下方式:
bash> git clone https://github.com/vesoft-inc/nebula.git bash> cd nebula && ./build_dep.sh N
有問題請在 GitHub 或者微信公衆號上留言。