在BUS_ADRERR
期间可能引起dlopen()
信号的原因是什么?我收到了许多来自不同用户的崩溃报告。
一些注意事项:
si_addr
地址进入已加载的库。这真的让我感到困惑。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)
答案 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
杀死。
通常的解决方法是在关键部分中确保“检查文件是否存在,如果不存在,请提取”。