Linux下C/CPP開發,函數符號衝突問題

原由

測試給我提了一個BUG,咱們的程序在鏈接HTTPS服務端後,莫名crash。
在還原測試環境後,經過gdb調試,發現crash在libcurl的curl_easy_platform這個函數裏面,因而開啓了漫長的debug之旅,最終發現是函數符號衝突所致。curl

還原函數符號衝突情景

首先準備三個模塊

靜態庫libA.a
動態庫libB.so
可執行二進制test.bin

靜態庫libA.a

靜態庫A主要導出一個函數接口TestFunc
主要代碼:函數

extern "C" void TestFunc(std::string const& strData)
{
    std::cout<<"This is libtestA"<<std::endl;
    std::cout<<strData<<std::endl;
}

動態庫libB.so

動態庫B導出兩個函數接口,一個TestFunc,另外一個函數調用靜態庫A的TestFunc 主要代碼:測試

extern "C" __attribute__((visibility("default"))) void TestFunc(std::string const& strData)
void TestFunc(std::string const& strData)
{
    std::cout<<"This is libtestB"<<std::endl;
    std::cout<<strData<<std::endl;
}
extern "C" __attribute__((visibility("default"))) void TestFunc_Ex()
{
    //寫一個測試類,經過類裏面Test函數調用靜態庫A的TestFunc函數
    TestClass _t;
    _t.Test();
}

可執行二進制test.bin

test.bin調用動態庫B裏面的兩個函數接口
主要代碼:編碼

int main()
{
    TestFunc("hoho");
    TestFunc_Ex();

    return 0;
}

輸出結果:

This is libtestB
hoho
This is libtestB
TestClass::Test

若是將靜態庫A導出的函數的參數修改成空,那麼從新編譯後,再運行test.bin,就復現了crash。url

This is libtestB
hoho
This is libtestB
Segmentation fault (core dumped)

結果分析

理想中的結果應該是:.net

This is libtestB
hoho
This is libtestA
TestClass::Test

出現這個問題的緣由是:
在Linux下,全部同名函數,都會被第一個加載的函數符號所代替,因此test.bin調用的時候,所有都走了動態庫B的TestFunc函數。debug

結語

遇到這種函數符號衝突的問題,編譯器一般不會給你任何提示。出現crash,只能經過gdb和經驗來一步一步排查。
解決方法能夠經過編譯傳參數來指定導出函數來解決,但我不建議這種方法。在大型項目中添加多餘的編譯參數及文件是一種很挫的作法。我仍是建議在編碼中注意規範,多檢查、多用命名空間來約束、避免這類問題。調試

示例代碼Demo下載地址code

相關文章
相關標籤/搜索