Сегментация Ошибка перед main() при использовании перенасыщения и std::string?
В 64-битном Ubuntu 14.04 LTS я пытаюсь скомпилировать простую программу OpenGL, которая использует перенасыщение. Я получаю ошибку сегментации (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;
}
Когда я запускаю программу, printf в начале main не запускается перед segfault.
В GDB я получаю эту обратную трассировку после segfault
#0 0x0000000000000000 in ?? ()
#1 0x00007ffff3488291 in init () at dlerror.c:177
#2 0x00007ffff34886d7 in _dlerror_run ([email protected]=0x7ffff3488130 <dlsym_doit>, [email protected]=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, [email protected]=1, [email protected]=0x7fffffffdf48, [email protected]=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 ?? ()
И вот кикер. Если я прокомментирую либо строку 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)
Но быстрый взгляд не показывает ничего плохого.
Ответы
Ответ 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, но у вас нет libpthread.so
в вашем ldd
выходном файле. Как вы можете видеть ниже, ваша программа вылетает, возможно, при использовании __pthread_key_create в init(). Кстати, вы также можете попробовать
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 ([email protected]=0x7ffff3488130 <dlsym_doit>, [email protected]=0x7fffffffddf0) at dlerror.c:129
Эта обратная трассировка показывает, что была вызвана функция с адресом 0x00000000 (мой догадка, что это еще неразрешенный адрес __pthread_key_create), и это ошибка. Какую функцию вызывали? Посмотрите на источники:
Это dlerror.c: 129 (frame # 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 к вашему вопросу
Ответ 2
Возможно ли, что ваша программа и libGL связаны или используют две противоречивые версии третьей библиотеки (возможно, libc?). Трудно диагностировать данные, которые вы предоставили. Вы можете отключить оптимизацию (-O0
) и посмотреть, дает ли GDB какие-либо дополнительные подсказки. Вы могли видеть, какие зависимости и ваша программа и libGL имеют, запуская ldd
- это показывает зависимости времени компиляции. Извините, я могу только давать предложения - эти типы проблем выполнения могут возникать по нескольким причинам.
Ответ 3
Я встретил аналогичную проблему, но LD_PRELOAD=/lib/x86_64-linux-gnu/libpthread.so.0 ./main
не всегда работал. Эта проблема возникла на графическом процессоре NVIDIA, OpenGL связан с /usr/lib/nvidia-352/libGL.so.1
, после тестирования на разных компьютерах, я нахожу замену версии g++ на g++ - 5, или ссылку на "mesa/libGL.so", другую реализацию OpenGL, на g++ main.cpp -o main -Wl, --rpath /usr/lib/x86_64-linux-gnu/mesa -lGLU -lGL -lglut
.