2017-05-31 89 views
3

我爲離線渲染3D模型做了一個C++工具。渲染是使用OSMesa庫完成的。lib OSMesa離屏上下文創建在C++中失敗,但僅在靜態鏈接時才生效

這個軟件在一年多的時間裏工作得非常完美,我停下來做了6個月前的更新。與此同時,我的開發環境多次更新。

現在我再次編譯它,發現一個意外的錯誤。

該軟件的普通版本仍按預期工作,但靜態鏈接的版本是segfaulting。

我假設錯誤是在OSmesa配置/編譯/鏈接過程中的,而不是在庫代碼中,但任何有關更好的調試分段錯誤的建議,我們都很感激。

在嘗試了編譯過程的衆多變體而沒有成功之後,我現在很困惑。 任何人都可以在下面描述的某些步驟中看到我正在做的一些愚蠢的事情?


我重新編譯OSmesa庫靜態版本的共享庫的相同版本的工作在我的系統(12.0.6),禁止所有非必要的功能(使用的是基於Ubuntu系統, OSmesa LIB的無靜電版本可從資料庫):

 
./configure \ 
    --disable-xvmc \ 
    --disable-glx \ 
    --disable-dri \ 
    --with-dri-drivers="" \ 
    --with-gallium-drivers="" \ 
    --disable-shared-glapi \ 
    --disable-egl \ 
    --with-egl-platforms="" \ 
    --enable-osmesa \ 
    --enable-gallium-llvm=no \ 
    --disable-gles1 \ 
    --disable-gles2 \ 
    --enable-static \ 
    --disable-shared 

這是我離屏渲染工具的編譯命令:

 
g++ -std=c++11 -Wall -O3 -g -static -static-libgcc -static-libstdc++ ./src/measure_model.cpp model.o thumbnail.o -o measure_model_debug -pthread -lOSMesa -ldl -lm -lpng -lz -lcrypto 

這是我是一個警告通過使用OSMesa靜態編譯得到,它甚至一年前存在與工作靜態二進制:

 
/home/XXX/XXX/backend/lambda/mesa/mesa-12.0.6/src/mesa/main/dlopen.h:52: warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking 

這是我從運行該工具得到:

 
Segmentation fault (core dumped) 

但沒有分割故障如果製作我只是跳過OSmesa上下文創建步驟(顯然所有的3D渲染)

這是回溯:

 
#0 0x0000000000000000 in ??() 
#1 0x00000000004af20a in mtx_init (type=4, mtx=0xe10f70) at ../../include/c11/threads_posix.h:215 
#2 _mesa_NewHashTable() at main/hash.c:135 
#3 0x000000000052f295 in _mesa_alloc_shared_state ([email protected]=0xdcc9b0) at main/shared.c:67 
#4 0x000000000046e717 in _mesa_initialize_context ([email protected]=0xdcc9b0, [email protected]=API_OPENGL_COMPAT, visual=, [email protected]=0x0, [email protected]=0x7fffffffcd40) at main/context.c:1192 
#5 0x000000000046c870 in OSMesaCreateContextAttribs ([email protected]=0x7fffffffd290, sharelist=) at osmesa.c:834 
#6 0x000000000046ccdc in OSMesaCreateContextExt (format=, depthBits=, stencilBits=, accumBits=, sharelist=) at osmesa.c:660 
#7 0x0000000000468742 in generate_thumbnail(Model*, Json::Value)() 
#8 0x0000000000401c7d in main (argc=, argv=) at ./src/measure_model.cpp:107 

靜態鏈接二進制是一個嚴格的要求。

分段錯誤發生在我用於編譯工具的同一臺機器上(OSmesa靜態庫也編譯在同一臺機器上),但在同一工具的非靜態鏈接版本中沒有分段錯誤。

+1

請運行gdb下的故障程序;在segv發佈後輸出'bt','info reg','frame 1; disassemble'。 ['mtx_init'使用了一些pthread](https://github.com/anholt/mesa/blob/master/include/c11/threads_posix.h#L200)mutex/mutex_attr函數,你在靜態線程中使用pthread有一些問題程式。這可能是一個壞主意,試圖改變你的需求的嚴格性(動態鏈接到glibc和pthread,爲了在較早的操作系統中運行,使用自己的glibc + pthreads和rpath來鏈接它們)。 – osgx

+0

謝謝osgx,我打算做這個額外的調試,並將更新問題。使用帶有靜態鏈接程序的pthread有任何已知問題? – pangon

+1

太好了,經過一番測試,結果證明實際上是導致問題的靜態鏈接的pthread庫。我的實際用例需要靜態鏈接大多數庫,但不是核心庫。可以將dl和pthread聯繫起來,解決我的問題。非常感謝。我對C++二進制文件鏈接到pthread的方式看到這個限制感到失望!我希望通過研究我可以在網上看到的案例來找出這種pthread限制的意義。再次感謝@osgx,如果你可以發佈這個問題的答案,我會將其標記爲正確的,給你賞金:) – pangon

回答

2

這是我從運行該工具得到: Segmentation fault (core dumped)

但沒有分割故障,如果我直接跳過了OSmesa上下文創建步驟(顯然所有的3D渲染)所產生

因此,OSmesa的創建存在一些問題。通過回溯,我們可以看到top函數是從零的EIP執行的(跳到NULL/NULL的調用),所以在作爲OS Mesa上下文創建的一部分的mtx_init中有一些函數的調用。

#0 0x0000000000000000 in ??() 
#1 0x00000000004af20a in mtx_init (type=4, mtx=0xe10f70) at ../../include/c11/threads_posix.h:215 
#2 _mesa_NewHashTable() at main/hash.c:135 
#3 0x000000000052f295 in _mesa_alloc_shared_state ([email protected]=0xdcc9b0) at main/shared.c:67 
#4 0x000000000046e717 in _mesa_initialize_context ([email protected]=0xdcc9b0, [email protected]=API_OPENGL_COMPAT, visual=, [email protected]=0x0, [email protected]=0x7fffffffcd40) at main/context.c:1192 
#5 0x000000000046c870 in OSMesaCreateContextAttribs ([email protected]=0x7fffffffd290, sharelist=) at osmesa.c:834 
#6 0x000000000046ccdc in OSMesaCreateContextExt (format=, depthBits=, stencilBits=, accumBits=, sharelist=) at osmesa.c:660 
#7 0x0000000000468742 in generate_thumbnail(Model*, Json::Value)() 
#8 0x0000000000401c7d in main (argc=, argv=) at ./src/measure_model.cpp:107 

這是什麼功能?據online sources of include/c11/threads_posix.h: mtx_init() on github,只有調用pthread_mutex_initpthread_mutexattr_init等幾個互斥相關功能的libpthread的(-lpthread)。

爲什麼會產生調用NULL而不是真正的函數?可能是由於使用了glibc和/或libpthread的靜態鏈接。 現在確切的問題仍然不明確(我能夠發現靜態鏈接libpthread.a報告到一些共享庫,這是不正確的,將永遠不會工作)。

你的情況存在的pthread_mutex_init僅別名(強之一)的glibc/NPTL/pthread_mutex_init.c(線150)strong_alias (__pthread_mutex_init, pthread_mutex_init)並有可能在glibc的本身,可能是未初始化的符號的一些薄弱的別名。在鏈接選項或/和ld有些錯誤的想法,他沒有找到/鏈接nptl/pthread_mutex_init.o(它是libpthread.a歸檔的一部分)與真正的符號到最終的可執行文件(ld經常跳過.a檔案的未使用/不需要的對象並且不要將它們鏈接到最終的可執行文件中),將重定位指針保持爲NULL。一些glibc的專家可能知道,Employed Russian是SO上的專家之一。

我建議靜態鏈接只到你的內部庫或也可能正常非系統庫類似檯面(您可能use -Wl,-Bstatic -lyour_lib -Wl,-Bdynamic選項來臨時更改聯動靜態的庫之間的上市;或使用-l:金手指選項爲-l:libYour_lib.afound by Radek在同樣的問題)。但不要靜態鏈接到像libc,libpthread,librt等glibc的大多數基本庫(當使用nss時,在glibc的靜態鏈接中存在一些問題:目標系統必須具有完全相同版本的動態glibc才能使nss工作)。

如果你想收拾舊機器的應用程序,你需要的glibc你也可以嘗試收拾自己與應用程序共享的glibc庫版本的一些功能;把它們放到一些子目錄中,添加rpath鏈接器選項來更改庫搜索路徑,也可以將INTERP section from default ABI ld-linux.so.2加載程序從您的glibc版本更改爲您自己的ld-linux.so.2副本,並且您仍然會遇到問題舊的內核,因爲新的glibcs​​需要一些相當新的內核的一些現代功能(系統調用,結構)。

或者你可以收拾你的應用程序成某種像泊塢窗,或其他一些isolation溶液(或chroot的?)容器中始終有你的庫版本...

更新:只是found類似BT的報告用NULL而不是從NPTL互斥執行:https://bugzilla.redhat.com/show_bug.cgi?id=163083「靜態鏈接的C++程序使用並行線程將段錯誤」(2005-2007)pthread_mutex_init(&lock, NULL);g++ -g -static foo.cpp -o foo -lpthreadwhere #0 0x00000000 in ??() #1 0x08048232 in main() at foo.cpp:7

這顯然是由於不被包括在所述輸出可執行某些pthreads函數。這個錯誤可能會重複#115157,如果是這樣,我很抱歉,但希望包含的測試用例會有用。

附加信息:

的建議在#115157強制在所有的libpthreads.a的鏈接是一個有效的解決方法。

https://bugzilla.redhat.com/show_bug.cgi?id=115157 「與/usr/lib/nptl/libpthread.a靜態鏈接可執行失敗」 - 2004-2009 CLOSED WONTFIX

的Jakub耶利內克2004-10-29 5時26分10秒EDT

首先,如果可以的話,應該避免使用-static,這隻會造成問題, 兩者的便攜性和其他問題。

如果你真的需要用-lpthread 聯在創建靜態連接程序,然後只是使用的-Wl,--whole-archive -lpthread -Wl,--no-whole-archive 代替-pthread。其他任何事情都有很多問題。

相關問題