dlopen()中的BUS_ADRERR

时间:2019-04-09 09:10:17

标签: java linux crash dlopen

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

一些注意事项:

  1. 这发生在不同的库中(我们的应用程序使用了一些库)
  2. 信号点的
  3. si_addr地址进入已加载的库。这真的让我感到困惑。
  4. 总是有足够的系统内存可用。
  5. 用户说该应用程序将在第二次尝试时正确启动。
  6. 我们的应用程序在加载之前从ZIP中提取库。
  7. 学习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)

1 个答案:

答案 0 :(得分:1)

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

发生这种情况的一种情况是将mmap版本的文件截断。来自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).
  

我们的应用程序在加载之前从ZIP中提取库。

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

第一个线程从ZIP存档中提取libswt-gtk-4922r22.so,并dlopen对其进行处理。 dlopen mmap保存文件,重新定位文件,然后调用库初始化程序。

在运行库初始化程序时,第二个线程决定必须提取该库(这是bug),并在将新的(相同的)内容写入其中之前截断.so文件。截断完成后,第一个线程(仍在运行的库初始化程序)将被SIGBUS杀死。

通常的解决方法是在关键部分中确保“检查文件是否存在,如果不存在,请提取”。