为什么同时链接sdl2和udev会导致分段错误?

4

我有一个非常愚蠢的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

如果您的程序不依赖于libusb中的任何内容,就像您的第一个示例所展示的那样,那么为什么要链接该库呢? - John Bollinger
@JohnBollinger 这只是一个最简单的例子,我的实际项目确实需要这两个库。 - ocharles
@JohnBollinger 只是提供信息,-ludev 就足够了 - 似乎不是 -lusb 的问题(但它确实会带来 udev)。 - ocharles
1
非常奇怪,这看起来像是一个非常特定于环境的问题。根据回溯信息,您正在使用Mesa - 'loader_get_pci_id_for_fd'函数是查找要为您的硬件引入哪个驱动程序的函数。有趣的是,Mesa实际上使用dlopen()加载libudev.so;您需要检查库路径以确保它加载了与您链接的相同的库! - kepstin
1个回答

1
如果一个程序的行为只是因为它被链接的方式不同而有所不同,那么这必须是由于在一种情况下动态链接了不同的函数实现而在另一种情况下链接了其他实现。除此之外,要详细回答需要检查所有涉及的库的细节。
尽管如此,我倾向于观察你显然严重依赖RPATH,这是非常可疑的。特别是你似乎通过RPATH解析C标准库(从你的回溯的第一行可以看出),而不是使用系统的版本。
最好通过配置动态链接器来影响动态链接,而不是将RPATH嵌入到程序或库中。如果目标是使用不同于系统默认值的库,则您可能会发现在其中运行程序的替代chroot环境很有用。在所有情况下,请确保编译器、静态链接器、动态链接器、程序所依赖的所有库以及程序本身都同意使用每个库的哪个版本。

1
“-rpath” 的内容只是我从 pkg-config --libs 获取的,但这在 NixOS 中打包东西时相当标准。不过我会深入研究一下的。 - ocharles
我简化了GCC调用,但仍然出现相同的问题,因此至少看起来不是我调用gcc的方式所导致的。 - ocharles
1
这个答案指引了我正确的方向,正如@kepstin所提到的 - mesa使用dlopen打开udev。真正的问题在于我构建的环境链接到了与当前运行udev不同的不同版本 udev。如果我链接到与正在运行的完全相同的版本,则一切都很好。我必须找到一种方法来正确设置我的构建环境,但感谢上帝,我们终于找到了问题! - ocharles

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接