Почему связывание как с sdl2, так и с udev вызывает ошибку сегментации?

У меня есть следующая действительно тупая программа на C:

#include <SDL2/SDL.h>

int main () {
  SDL_Init(SDL_INIT_VIDEO);
}

Если я скомпилирую его и свяжу с sdl2, все будет хорошо:

[nix-shell:~/work/on-the-limit]$ gcc oddity.c -lSDL2 -o oddity

[nix-shell:~/work/on-the-limit]$ ./oddity 

Однако, если я также свяжусь с udev...

[nix-shell:~/work/on-the-limit]$ gcc oddity.c -lSDL2 -ludev -o oddity

[nix-shell:~/work/on-the-limit]$ ./oddity 
Segmentation fault

... происходит ошибка сегментации.

gdb говорит следующее:

[nix-shell:~/work/on-the-limit]$ gdb ./oddity 
GNU gdb (GDB) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./oddity...done.
(gdb) run
Starting program: /home/ollie/work/on-the-limit/oddity 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/nix/store/npfsi1d9ka8zwnxzn3sr08hbwvpapyk7-glibc-2.21/lib/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff736b36a in strlen () from /nix/store/483br9kb3f5igsgmb6aqsjhl2ipj2bxr-glibc-2.21/lib/libc.so.6
(gdb) bt
#0  0x00007ffff736b36a in strlen () from /nix/store/483br9kb3f5igsgmb6aqsjhl2ipj2bxr-glibc-2.21/lib/libc.so.6
#1  0x00007ffff7fbb54b in strpcpy () from /nix/store/m3k7v0cy7zh6qbjqhrxgd36p105qqf0q-systemd-217/lib/libudev.so.1
#2  0x00007ffff7fbb6b3 in strscpy () from /nix/store/m3k7v0cy7zh6qbjqhrxgd36p105qqf0q-systemd-217/lib/libudev.so.1
#3  0x00007ffff7fb8f3d in device_new_from_parent.isra.7.lto_priv () from /nix/store/m3k7v0cy7zh6qbjqhrxgd36p105qqf0q-systemd-217/lib/libudev.so.1
#4  0x00007ffff7fb6140 in udev_device_get_parent () from /nix/store/m3k7v0cy7zh6qbjqhrxgd36p105qqf0q-systemd-217/lib/libudev.so.1
#5  0x00007ffff4c9b85a in loader_get_pci_id_for_fd () from /run/opengl-driver/lib/libGL.so.1
#6  0x00007ffff4c9be68 in loader_get_driver_for_fd () from /run/opengl-driver/lib/libGL.so.1
#7  0x00007ffff4c95126 in dri2CreateScreen () from /run/opengl-driver/lib/libGL.so.1
#8  0x00007ffff4c748d4 in __glXInitialize () from /run/opengl-driver/lib/libGL.so.1
#9  0x00007ffff4c70c1b in GetGLXPrivScreenConfig.part.2 () from /run/opengl-driver/lib/libGL.so.1
#10 0x00007ffff4c70d4d in glXChooseVisual () from /run/opengl-driver/lib/libGL.so.1
#11 0x00007ffff7b92288 in X11_GL_LoadLibrary () from /nix/store/qcf0jg20x3fnb09p4xc1y5dsbz84m7h9-SDL2-2.0.3/lib/libSDL2-2.0.so.0
#12 0x00007ffff7b89567 in SDL_CreateWindow_REAL () from /nix/store/qcf0jg20x3fnb09p4xc1y5dsbz84m7h9-SDL2-2.0.3/lib/libSDL2-2.0.so.0
#13 0x00007ffff7b89180 in SDL_VideoInit_REAL () from /nix/store/qcf0jg20x3fnb09p4xc1y5dsbz84m7h9-SDL2-2.0.3/lib/libSDL2-2.0.so.0
#14 0x00007ffff7ac8317 in SDL_Init_REAL () from /nix/store/qcf0jg20x3fnb09p4xc1y5dsbz84m7h9-SDL2-2.0.3/lib/libSDL2-2.0.so.0
#15 0x00000000004008b6 in main () at oddity.c:4

person ocharles    schedule 30.12.2015    source источник
comment
Если ваша программа ни от чего не зависит в libusb, как показывает ваш первый пример, то почему вы связываетесь с этой библиотекой?   -  person John Bollinger    schedule 30.12.2015
comment
@JohnBollinger Это минимальный пример, моему реальному проекту нужны обе библиотеки.   -  person ocharles    schedule 30.12.2015
comment
@JohnBollinger К вашему сведению, -ludev достаточно - кажется, что виноват не -lusb (но он действительно вызывает udev по пути).   -  person ocharles    schedule 30.12.2015
comment
Очень странно, это похоже на очень специфичную для среды проблему. Основываясь на трассировке, которую вы используете mesa, функция loader_get_pci_id_for_fd ищет, какой драйвер использовать для вашего оборудования. Интересно, что mesa фактически использует dlopen() для загрузки libudev.so; вам нужно проверить пути библиотеки, чтобы убедиться, что она загрузила ту же, что и вы связали!   -  person kepstin    schedule 30.12.2015


Ответы (1)


Если поведение программы различается только в зависимости от того, как она связана, то это должно быть результатом того, что разные реализации функций [динамически] связаны в одном и другом случаях. Кроме того, для подробного ответа потребуется изучить сведения обо всех всех задействованных библиотеках.

Тем не менее, на данный момент я склонен заметить, что вы, по-видимому, сильно полагаетесь на RPATH, что весьма сомнительно. Особенно сомнительно, что вы, кажется, разрешаете стандартную библиотеку C через RPATH (как видно из первой строки вашей обратной трассировки), а не используете версию системы.

Было бы лучше влиять на динамическую компоновку, настроив динамический компоновщик, а не встраивая RPATH в вашу программу или библиотеки. Если цель состоит в том, чтобы использовать библиотеки, отличные от системных по умолчанию, вам может оказаться полезным установить альтернативную среду chroot, в которой могла бы работать ваша программа. При любых обстоятельствах убедитесь, что компилятор, статический компоновщик, динамический компоновщик, все библиотеки, на которые опирается ваша программа, и сама программа согласны с тем, какую версию каждой библиотеки следует использовать.

person John Bollinger    schedule 30.12.2015
comment
Материал -rpath - это то, что я получаю от pkg-config --libs, но это довольно стандартно для того, как все упаковано в NixOS. Хотя я посмотрю глубже. - person ocharles; 30.12.2015
comment
Я упростил вызовы GCC, и то же самое все еще происходит, так что, по крайней мере, это не похоже на то, как я вызываю gcc. - person ocharles; 30.12.2015
comment
Этот ответ указал мне правильное направление, и, как упоминает @kepstin, mesa использует dlopen для открытия udev. Настоящая проблема здесь в том, что среда, которую я создавал, была связана с отличным udev от систем, в которых в настоящее время работает udev. Если я ссылаюсь на ту же версию, что и работающая, то все в порядке. Мне придется найти способ правильно настроить среду сборки, но, слава богу, мы наконец нашли проблему! - person ocharles; 30.12.2015