BUS_ADRERR 在 dlopen() 中

BUS_ADRERR in dlopen()

dlopen() 期间可能导致 BUS_ADRERR 信号的原因是什么?我收到了很多来自不同用户的此类崩溃报告。

一些注意事项:

  1. 它发生在不同的库中(我们的应用程序使用了一些)
  2. si_addr 信号指向加载库的地址。这让我很困惑。
  3. 总是有足够的系统内存可用。
  4. 用户说应用程序将在第二次尝试时正确启动。
  5. 我们的应用程序在加载它们之前从 ZIP 中提取库。
  6. 学习 journalctl 没有任何兴趣。

典型的崩溃报告(由Java生成):

Stack: [0x00007f284919b000,0x00007f284939c000],  sp=0x00007f2849397258,  free space=2032k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [ld-linux-x86-64.so.2+0x1fa6f]
C  [ld-linux-x86-64.so.2+0x8ffc]

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  java.lang.ClassLoader$NativeLibrary.load0(Ljava/lang/String;Z)Z+0 java.base@10.0.1
j  java.lang.ClassLoader$NativeLibrary.load()Z+53 java.base@10.0.1
j  java.lang.ClassLoader$NativeLibrary.loadLibrary(Ljava/lang/Class;Ljava/lang/String;Z)Z+216 java.base@10.0.1
j  java.lang.ClassLoader.loadLibrary0(Ljava/lang/Class;Ljava/io/File;)Z+46 java.base@10.0.1
j  java.lang.ClassLoader.loadLibrary(Ljava/lang/Class;Ljava/lang/String;Z)V+48 java.base@10.0.1
j  java.lang.Runtime.load0(Ljava/lang/Class;Ljava/lang/String;)V+57 java.base@10.0.1
j  java.lang.System.load(Ljava/lang/String;)V+7 java.base@10.0.1
<snip>

siginfo: si_signo: 7 (SIGBUS), si_code: 2 (BUS_ADRERR), si_addr: 0x00007f27deec7880

<snip>

7f27dec43000-7f27decc1000 r-xp 00000000 08:08 1054117 <snip>/libswt-gtk-4922r22.so
7f27decc1000-7f27deec0000 ---p 0007e000 08:08 1054117 <snip>/libswt-gtk-4922r22.so
7f27deec0000-7f27deec8000 rw-p 0007d000 08:08 1054117 <snip>/libswt-gtk-4922r22.so
7f27deec8000-7f27deecb000 r-xp 00285000 08:08 1054117 <snip>/libswt-gtk-4922r22.so

<snip>

Memory: 4k page, physical 3902428k(1540768k free), swap 3998716k(3998716k free)

SIGBUS 在 Linux / x86 系统上非常罕见。

发生这种情况的一种情况是 mmaped 文件被截断。来自 man mmap:

SIGBUS Attempted access to a portion of the buffer that does not
       correspond to the file (for example, beyond the end of the
       file, including the case where another process has truncated
       the file).

Our application extracts the libraries from ZIP before loading them.

一个疯狂的猜测:你有一个竞争条件,你可以同时从两个单独的线程执行这个提取。

第一个线程从 ZIP 压缩包中提取 libswt-gtk-4922r22.so,然后 dlopen 保存它。 dlopen mmaps 文件,重新定位它,并调用库初始化程序。

虽然库初始化程序是 运行,但第二个线程决定必须提取库(这是错误),并在将新的(相同的)内容写入其中之前截断 .so 文件.一旦截断完成,第一个线程(仍然是 运行 库初始化器)就会被 SIGBUS.

杀死

通常的解决方法是确保 "check that the file exists, extract if not" 在关键部分完成。