【问题标题】:Segmentation Fault before main() when using glut, and std::string?使用 glut 和 std::string 时 main() 之前的分段错误?
【发布时间】:2015-10-13 06:42:27
【问题描述】:

在 64 位 Ubuntu 14.04 LTS 上,我正在尝试编译一个使用 glut 的简单 OpenGL 程序。在 main 中执行任何代码行之前,我遇到了分段错误 (SIGSEV);即使在一个非常精简的测试程序上。这是什么原因造成的?

我的命令行:

g++ -Wall -g main.cpp -lglut -lGL -lGLU -o main

我的简单测试用例:

#include <GL/gl.h>                                                                                                                                         
#include <GL/glu.h>
#include <GL/glut.h>

#include <string>
#include <cstdio>

int main(int argc, char** argv){
    printf("Started\n");                                                                                                   
    std::string dummy = "hello";
    glutInit(&argc, argv);
    return 0;
}

当我运行程序时,main 开头的 printf 不会在段错误之前执行。 在 GDB 下,我在段错误之后得到这个回溯

#0  0x0000000000000000 in ?? ()
#1  0x00007ffff3488291 in init () at dlerror.c:177
#2  0x00007ffff34886d7 in _dlerror_run (operate=operate@entry=0x7ffff3488130 <dlsym_doit>, args=args@entry=0x7fffffffddf0) at dlerror.c:129
#3  0x00007ffff3488198 in __dlsym (handle=<optimized out>, name=<optimized out>) at dlsym.c:70
#4  0x00007ffff702628e in ?? () from /usr/lib/nvidia-352/libGL.so.1
#5  0x00007ffff6fd1aa7 in ?? () from /usr/lib/nvidia-352/libGL.so.1
#6  0x00007ffff7dea0fd in call_init (l=0x7ffff7fd39c8, argc=argc@entry=1, argv=argv@entry=0x7fffffffdf48, env=env@entry=0x7fffffffdf58) at dl-init.c:64
#7  0x00007ffff7dea223 in call_init (env=<optimized out>, argv=<optimized out>, argc=<optimized out>, l=<optimized out>) at dl-init.c:36
#8  _dl_init (main_map=0x7ffff7ffe1c8, argc=1, argv=0x7fffffffdf48, env=0x7fffffffdf58) at dl-init.c:126
#9  0x00007ffff7ddb30a in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
#10 0x0000000000000001 in ?? ()
#11 0x00007fffffffe2ba in ?? ()
#12 0x0000000000000000 in ?? ()

这是踢球者。如果我注释掉 either gluInit 行或 std::string 虚拟行,程序编译并运行得很好。直到我注意到这一点,我认为我的 GLUT 有问题(尽管我已经尝试过我正在调试的原始程序(我精简到这个例子))几个系统都没有成功。我在这里有点不知所措。

编辑:我尝试了 gmbeard 的建议。关闭优化 (-O0) 并没有改变 gdb 生成的调用堆栈。

在程序上运行 ldd 给了我:

linux-vdso.so.1 =>  (0x00007ffe3b7f1000)
libglut.so.3 => /usr/lib/x86_64-linux-gnu/libglut.so.3 (0x00007f04978fa000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f04975f6000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f04973e0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f049701b000)
libGL.so.1 => /usr/lib/nvidia-352/libGL.so.1 (0x00007f0496cec000)
libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f04969b7000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f04966b1000)
libXi.so.6 => /usr/lib/x86_64-linux-gnu/libXi.so.6 (0x00007f04964a1000)
libXxf86vm.so.1 => /usr/lib/x86_64-linux-gnu/libXxf86vm.so.1 (0x00007f049629b000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0497b44000)
libnvidia-tls.so.352.21 => /usr/lib/nvidia-352/tls/libnvidia-tls.so.352.21 (0x00007f0496098000)
libnvidia-glcore.so.352.21 => /usr/lib/nvidia-352/libnvidia-glcore.so.352.21 (0x00007f0493607000)
libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007f04933f5000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f04931f1000)
libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f0492fd2000)
libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f0492dce000)
libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f0492bc8000)

然后,在确定了我正在使用的 libGL 之后,我在其上运行了 ldd

linux-vdso.so.1 =>  (0x00007ffc55df8000)
libnvidia-tls.so.352.21 => /usr/lib/nvidia-352/tls/libnvidia-tls.so.352.21 (0x00007faa60d83000)
libnvidia-glcore.so.352.21 => /usr/lib/nvidia-352/libnvidia-glcore.so.352.21 (0x00007faa5e2f2000)
libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007faa5dfbd000)
libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007faa5ddab000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007faa5d9e6000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007faa5d7e2000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007faa5d4dc000)
libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007faa5d2bd000)
/lib64/ld-linux-x86-64.so.2 (0x00007faa612b5000)
libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007faa5d0b9000)
libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007faa5ceb3000)

但快速浏览并没有发现任何问题。

【问题讨论】:

  • 我认为这是因为您没有通过任何参数尝试添加这些行,因为 printf argc = 1; argv[0] = "test"; 抱歉,我无法测试它,因为我在火车上。
  • 不,如果我通过命令行参数,它仍然会中断。因为它在 main 执行之前就崩溃了,所以无论如何都没有多大意义。
  • 试试LD_DEBUG=all ./mainLD_DEBUG=all LD_DEBUG_OUTPUT=log.txt ./main。可能它可以解释ld.so 在崩溃之前正在做什么。
  • 它确实提供了大量信息。将近9000行。它打印出来的最后一件事是:“ 20863: symbol=__pthread_key_create;lookup in file=/usr/lib/x86_64-linux-gnu/libXdmcp.so.6 [0]” 除此之外,我不确定要做什么搜索;因此,有 8559 行可供筛选,以找到我目前无法识别的内容。
  • 好吧,首先,试一试。使用g++ -pthread -Wall -g main.cpp -lglut -lGL -lGLU -o main 构建您的项目

标签: c++ opengl glut glu


【解决方案1】:

所以你在 LD_DEBUG 输出中看到:

最后打印出来的是:" 20863: symbol=__pthread_key_create; 在文件中查找=/usr/lib/x86_64-linux-gnu/libXdmcp.so.6 [0]

这意味着 ld.so id 正在寻找 __pthread_key_create,因为您的某个库需要它[并且您最好找到该符号需要什么库,它可能会回答什么库需要 libpthread.so]。

所以 __pthread_key_create 必须在 libpthread.so 中,但您的 ldd 输出中没有 libpthread.so。正如您在下面看到的,您的程序可能在 init() 中使用 __pthread_key_create 时崩溃。顺便你也可以试试

LD_PRELOAD=/lib64/libpthread.so.0 ./main

为了确保 pthread_key_create 在其他符号之前加载。

所以lgut 不太可能成为问题。它只是在初始化时调用 dlsym ,这是绝对正确的行为。但是程序崩溃了:

#0  0x0000000000000000 in ?? ()
#1  0x00007ffff3488291 in init () at dlerror.c:177
#2  0x00007ffff34886d7 in _dlerror_run (operate=operate@entry=0x7ffff3488130 <dlsym_doit>, args=args@entry=0x7fffffffddf0) at dlerror.c:129

此回溯显示,调用了一个地址为 0x00000000 的函数(我猜它是 __pthread_key_create 的未解析地址),这是一个错误。调用了什么函数?查看来源:

这是 dlerror.c:129(第 2 帧):

int
internal_function
_dlerror_run (void (*operate) (void *), void *args)
{
  struct dl_action_result *result;

  /* If we have not yet initialized the buffer do it now.  */
  __libc_once (once, init);

(第 1 帧):

/* Initialize buffers for results.  */
static void
init (void)
{
  if (__libc_key_create (&key, free_key_mem))
    /* Creating the key failed.  This means something really went
       wrong.  In any case use a static buffer which is better than
       nothing.  */
    static_buf = &last_result;
}

它必须是__libc_key_create 是一个宏,它在glibc 中有不同的定义。如果你为 POSIX 构建,它被定义了

/* Create thread-specific key.  */
#define __libc_key_create(KEY, DESTRUCTOR) \
  __libc_ptf_call (__pthread_key_create, (KEY, DESTRUCTOR), 1)

我让你用:

g++ -pthread -Wall -g main.cpp -lpthread -lglut -lGL -lGLU -o main

为了确保__libc_key_create 实际上调用__pthread_key_create 并且lpthread 在-lglut 之前被初始化。但是如果你不想使用 -pthread 那么你可能需要分析帧 #1

#1  0x00007ffff3488291 in init () at dlerror.c:177

例如,您可以将第 1 帧的反汇编添加到您的问题中

【讨论】:

  • 非常感谢!我刚醒来并根据您的建议尝试了解决方法。我找到了我的 libpthread.so 并尝试了“LD_PRELOAD=/lib/x86_64-linux-gnu/libpthread.so.0 ./main”,它奏效了!所以错误是你建议的;出于某种原因需要 libpthread,但没有链接,也不能通过简单地使用 -lpthread 或 -pthread 来链接。
  • 我添加了第二个解决方法,不需要 LD_PRELOAD,通过让编译器/链接器相信我确实需要 libpthread:我将此添加到我的 main.cpp `#include void* simpleFunc(void*) { return NULL; } 无效 forcePThreadLink() { pthread_t t1; pthread_create(&t1, NULL, &simpleFunc, NULL); }' 这很愚蠢,但它有效。现在这里的程序是什么:我应该按原样接受这个答案(因为它导致了一种解决方法),并提出一个新问题,为什么在我明确需要它之前我无法链接到 pthread 直到写一些愚蠢的黑客?
  • 我不确定程序。但您可以随时发布自己的答案并接受它,如果它是最佳答案
  • -pthread-lpthread 都需要吗? GCC 文档似乎说 -pthread 为预处理器和链接器设置了标志。
【解决方案2】:

您的程序和 libGL 可能链接到或使用了第三个库(可能是 libc?)的两个冲突版本。根据您提供的详细信息很难诊断。您可以禁用优化 (-O0) 并查看 GDB 是否放弃任何进一步的线索。您可以通过运行 ldd 查看您的程序和 libGL 的依赖关系——这显示了编译时依赖关系。抱歉,我只能提供建议 - 出现这些类型的运行时问题可能有多种原因。

【讨论】:

  • 感谢您的建议,我尝试了您的两个建议(并更新了原始帖子的详细信息);但我认为我还没有接近破解这个谜团。 libc 在 libGL 和我的程序之间似乎是相同的(尽管内存地址有所不同,但路径是相同的)。还有其他想法吗?
【解决方案3】:

我遇到了类似的问题,但LD_PRELOAD=/lib/x86_64-linux-gnu/libpthread.so.0 ./main 并非总是有效。这个问题发生在 NVIDIA GPU 上,OpenGL 链接到 /usr/lib/nvidia-352/libGL.so.1,在不同的计算机上测试后,我发现将 g++ 版本更改为 g++-5 可以工作,或者链接到另一个 OpenGL 实现“mesa/libGL.so”,@987654323 @。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 2017-07-16
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 2013-04-28
    相关资源
    最近更新 更多