1. 程式人生 > 其它 >std::cout segmentation fault

std::cout segmentation fault

dlopen,std::cout,segmentation fault,coredump

今天測試功能,發現一個奇怪的問題,std::cout導致崩潰。呼叫過程如下圖:

gdb除錯coredump檔案,堆疊資訊如下圖:

定位具體崩潰日誌,發現std::basic_ostream物件沒有初始化,如圖

通過谷歌查資料,發現有一個報錯跟我類似,根據答覆,發現問題出在ios_base::Init沒有初始化,

ios_base::Init用於構造此成員型別的物件,確保標準流物件(cin,cout,cerr,clog,cin,cout,cerr和clog)被構造和正確初始化。
根據答覆,只需要include <iostream>便可以保證ios_base::Init初始化
在C++03中,std::ios_base::Init是未指定的,我們需要確保在輸入main()時,標準流已初始化。
C++11修復這個問題,#include <iostream>的每個例項都跟著static std::ios_base::Init __unspecified_name__,這樣可以自動保證流可以使用。
我檢查程式,發現程式中已經#include <iostream>,應該不存在ios_base::Init沒有初始化這種情況
懷疑是dlopen的操作機制影響了ios_base::Init的初始化

函式定義 void * dlopen(const char* pathName, int mode);
pathName 指的是db檔案或listDB.so檔案在實機環境中的位置, mode指的是開啟資料庫的模式
mode在linux下,按功能有以下幾種
解析方式
RTLD_LAZY:
    暫緩決定,在dlopen返回前,對於動態庫中的未定義的符號不執行解析,只對函式引用有效,對於變數引用總是立即解析。這種模式有一個優勢,
例如動態庫中的某些函式引用了其他第三方庫,有些沒有,那麼呼叫沒有引用第三方庫的函式時,可以不用把第三方庫的檔案放在LD_LIBRARY_PATH下面 RTLD_NOW: 立即決定,在dlopen返回前,解析出所有未定義的符號,如果解析不出來,在dlopen會返回NULL,錯誤為 undefined symbol:XXX... 作用範圍 RTLD_GLOBAL: 動態庫中定義的符號可被其後開啟的其他庫重定位 RTLD_LOCAL: 與RTLD_GLOBAL作用相反,動態庫中定義的符號不能被其後開啟的其他庫重定位。如果沒有指明是RTLD_GLOBAL還是RTLD_LOCAL,那麼預設是RTLD_LOCAL。 作用方式 RTLD_NODELETE:在dlclose()期間不解除安裝庫,並且在以後使用dlopen()重新載入庫時不初始化庫中的靜態變數。這個flag不是POSIX
-2001標準。 RTLD_NOLOAD: 不載入庫,可用於測試庫是否已經載入(dlopen()返回NULL說明未載入,否則說明載入),也可用於改變已載入庫的flag,
如:先前載入庫的flag為RTLD_LOCAL,用dlopen(RTLD_NOLOAD
|RTLD_GLOBAL)後flag將變成RTLD_GLOBAL.這個flag不是POSIX-2001標準 RTLD_DEEPBIND:在搜尋全域性符號前先搜尋庫內的符號,避免同名符號的衝突,這個flag不是POSIX-2001標準

當dlopen中使用RTLD_DEEPBIND特性,可能會遮蔽全域性std::ios_base::Init變數,導致iostream物件沒有初始化,

經過實驗,在dlopen中取消RTLD_DEEPBIND,崩潰問題得到解決。