【问题标题】:Why does linking against both sdl2 and udev cause a segmentation fault?为什么链接 sdl2 和 udev 会导致分段错误?
【发布时间】:2015-12-30 17:23:31
【问题描述】:

我有以下非常愚蠢的 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 中的任何内容,如您的第一个示例所示,那么您为什么要链接该库?
  • @JohnBollinger 这是一个最小的例子,我的实际项目确实需要这两个库。
  • @JohnBollinger 仅供参考, -ludev 就足够了 - 似乎不是 -lusb 应该受到责备(但它确实在途中引入了 udev)。
  • 很奇怪,这看起来像是一个非常特定于环境的问题。根据您使用台面的回溯 - 'loader_get_pci_id_for_fd' 函数是查找要为您的硬件引入哪个驱动程序的函数。有趣的是 mesa 实际上使用 dlopen() 来加载 libudev.so;您需要检查库路径以确保它加载的路径与您链接的相同!

标签: c linux linker sdl-2 udev


【解决方案1】:

如果一个程序的行为仅取决于它的链接方式而有所不同,那么这一定是由于不同的函数实现在一种情况和另一种情况下[动态]链接。除此之外,要详细回答需要检查所有所涉及的库的详细信息。

尽管如此,在这一点上,我倾向于观察到您显然严重依赖 RPATH,这是非常值得怀疑的。尤其值得怀疑的是,您似乎是通过 RPATH 解析 C 标准库(从回溯的第一行可以明显看出)而不是使用系统的版本。

最好通过配置动态链接器来影响动态链接,而不是通过在程序或库中嵌入 RPATH。如果目标是使用与系统默认不同的库,那么您可能会发现建立一个可以运行您的程序的替代 chroot 环境很有用。在任何情况下,请确保编译器、静态链接器、动态链接器、程序所依赖的所有库以及程序本身都同意使用每个库的哪个版本。

【讨论】:

  • -rpath 的东西正是我从pkg-config --libs 得到的,但这对于在 NixOS 中的打包方式来说是相当标准的。不过我会更深入地研究它。
  • 我已经简化了 GCC 调用,但仍然会发生同样的情况,所以至少我调用 gcc 的方式似乎不是这样。
  • 这个答案为我指明了正确的方向,正如@kepstin 提到的那样 - mesa 使用 dlopen 打开 udev。这里真正的问题是我正在构建的环境与当前运行 udev 的系统链接到一个不同的 udev。如果我链接的版本与正在运行的版本完全相同,那么一切都很好。我必须找到一种方法来正确设置我的构建环境,但感谢上帝,我们终于找到了问题!
猜你喜欢
  • 2015-06-29
  • 1970-01-01
  • 2021-07-18
  • 2020-04-15
  • 1970-01-01
  • 2011-07-07
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
相关资源
最近更新 更多