lib OSMesa离屏上下文创建在C++中失败,但仅在静态链接时才生效

问题描述:

我为离线渲染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

这是我从运行该工具得到: 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。其他任何事情都有很多问题。