1. 程式人生 > >Dev 日誌 | 一次 Segmentation Fault 和 GCC Illegal Instruction 編譯問題排查

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

相關推薦

Dev 日誌 | Segmentation Fault GCC Illegal Instruction 編譯問題排查

摘要 筆者最近在重新整理和編譯 Nebula Graph 的第三方依賴,選出兩個比較有意思的問題給大家分享一下。 Flex Segmentation Fault——Segmentation fault (core dumped) 在編譯 Flex 過程中,遇到了 Segmentation fault: m

動態規劃分治法,貪心算法以及遞歸的再深刻理解體會

規劃 動態 分治法 每次體會算法都有新的感覺,刷題越多,對算法的理解感覺也就越深刻。下面我們來重新體會下分治法,動態規劃,貪心法,遞歸的理解。1.分治法: 將問題分成單獨的階段,每個階段互相不幹擾很獨立,如10米長的木棍,切成10段,每段去解決每一段的問題。(階段沒有關系)2.貪心法 站

用不到1000美元攢臺深度學習用的電腦深度學習便宜硬體的探奇

從上世紀80年代後我就再沒攢過電腦。我也相當擔心花好幾百塊,最終搞一堆我自己裝不出來的零件(或是攢出來了,但可能沒法正常工作)。不過我要告訴你,攢機是可以的!另外,整個過程也很好玩。最後你能擁有一臺通用的電腦,並能做預測,同時比筆記本快20多倍。下面是購買清單和一些細節建議:主機板主機板有不同的尺寸規格。因為

劍指offer-41:陣列中只出現的數字為S的連續正數序列

題目描述 小明很喜歡數學,有一天他在做數學作業時,要求計算出9~16的和,他馬上就寫出了正確答案是100。但是他並不滿足於此,他在想究竟有多少種連續的正數序列的和為100(至少包括兩個數)。沒多久,他就得到另一組連續正數和為100的序列:18,19,20,21,22。現在把問題交給你,你

讓天下沒有難用的資料庫 » 記not in minus的優化

優化前: select count(t.id)   from test t  where t.status = 1    and t.id not in (select distinct a.app_id                       from test2 a             

【MongoDb】關於OracleMongoDb的插入查詢效能測試

本次實驗是在筆者上學期期末一次課程實習中的一部分,現在整理出來以供參考。 本次資料用的是不同數量級別上的資料分別在Oracle和MongoDb中進行實驗的。 其中兩者的表結構一樣,都是如下欄位:

Centos檢視系統最近啟動時間執行時間

1.uptime命令  [[email protected] Log_Data]$ uptime 09:18:01 up 20:17, 1 user, load average: 0.13, 0.12, 0.14 2.檢視/proc/uptime檔案計算系統啟

Linux中xargs命令的重要作用------順便分享面試經歷實戰經歷

        在某公司的某次面試中, 被問到這樣一個題目:如何刪除當前目錄和子目錄下所有的.txt檔案?  如果對linux命令不熟悉, 則看到題目就會有點傻眼。 當然, 如果你清楚xargs命令的作用, 那就好說了。 一句話:xagrs會接收管道傳過來的引數, 並傳給管

跨域nginx配置問題

請求 The per mozilla 訪問限制 clas ocs -type head 問題描述 請求是跨域請求,從a.mycompony.com到b.mycompony.com;後端設置了如下參數,表示前端允許post和get方式跨域請求 response.setHe

“背鍋”“解鍋”後的反思

  中秋過的真快,還沒體會到就到最後一天了。今天在圖書館,突然想寫篇與技術無關的,但是我們工作中經常發生的事情。本來不想寫這種型別的文章,怕這種文章降低自己形象顯得太low。但是一來想鍛鍊下自己的文筆敘事能力,越怕這怕那越不敢動筆,越不動筆越沒長進,總要開個頭來個正向刺激迴圈;二來相比技術型別的文章,故事型別

線上 OOM 效能優化

大家好,我是鴨血粉絲(大家會親切的喊我 「阿粉」),是一位喜歡吃鴨血粉絲的程式設計師,回想起之前線上出現 OOM 的場景,畢竟當時是第一次遇到這麼 緊髒 的大事,要好好記錄下來。 1 事情回顧 在某次週五,通過 Grafana 監控,發現線上環境突然出現CPU和記憶體飆升的情況: 但是看到網路輸出和輸入流

關於線上DDOS攻擊阿里雲DDOS防護相關內容

## 問題 最近我們的一臺阿里雲伺服器 (ECS,有公網IP,Nginx 伺服器,開放了80,443),遭受到了DDOS攻擊,主要攻擊的行為是 攻擊我們443 埠。發起大量的請求。 ![image-20200604140131494](https://djxblog.oss-cn-shenzhen.ali

mysql中文字符亂碼的問題排查

mysql mysql中文亂碼 mysql字符集 今天開發反應兩樣的程序往一個庫裏面插入數據正常,往另外一個庫裏面插入數據有亂碼。第一反應就是兩個數據庫關於字符集的配置不一樣。在兩個庫分別查看參數:show variables like "%char%";+--------------------

線上伺服器inode打滿的事故排查

早晨來到公司收到線上伺服器磁碟/目錄滿了的報警,於是登到伺服器上,使用df -h檢視磁碟情況: # df -h Filesystem Size Used Avail Use% Mounted on /dev/vda2 36G 36G 0

MongoDB 佔用 CPU 過高問題的排查

1. 引言 今天檢視監控無意間突然發現自己的伺服器上,CPU 佔用率飆升到 100%,load 升到 10 以上,登入的響應已經達到半分鐘。 馬上執行 top,發現主要是 mongodb 佔用了大量

(轉載)生產系統 Full GC 問題分析與排查總結

一次生產系統 Full GC 問題分析與排查總結   轉載請註明 AIQ - 最專業的機器學習大資料社群  http://www.6aiq.com AIQ 機器學習大資料 知乎專欄 點選關注 一次生產系統 Full GC 問題分

yarn導致cpu飆高的異常排查經歷

yarn就先不介紹了,這次排坑經歷還是有收穫的,從日誌到堆疊資訊再到原始碼,很有意思,下面聽我說 問題描述: 叢集一臺NodeManager的cpu負載飆高。 程序還在但是看日誌已經不再向ResourceManager傳送心跳,不斷重複下文2的動作。 心跳停止一段時間後會重連上RM但是cpu仍然很高,再過

讓天下沒有難用的資料庫 » 資料庫上雲遷移效能下降的排查

背景介紹: 某客戶目前正在將本地的業務系統遷移上雲,測試過程中發現後臺運營系統,在rds上執行時間明顯要比線下PC上自建資料庫執行時間要慢1倍,導致客戶系統割接延期的風險。使用者線下一臺PC伺服器的效能居然還比頂配的RDS跑的快,這讓使用者對RDS的效能產生了質疑,需要立刻調查原因。 問題分析: 通

JVM效能分析 | 生產系統Full GC問題分析與排查總結

一次生產系統Full GC問題分析與排查總結 背景 最近某線上業務系統生產環境頻頻CPU使用率過低,頻繁告警,通過重啟可以緩解,但是過了一段時間又會繼續預警,線上兩個服務節點相繼出現CPU資源緊張,導致伺服器卡死不可用,通過告警資訊可以看到以下問題:

JVM成長之路,記錄記憶體溢位導致頻繁FGC的問題排查及解決

  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC  0.00  18.29  97.31  50.26  97.42  95.25