BUS_ADRERR в dlopen()

Что может быть причиной сигнала BUS_ADRERR во время dlopen()? Я получаю много таких отчетов о сбоях от разных пользователей.

Некоторые примечания:

  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 [email protected]
j  java.lang.ClassLoader$NativeLibrary.load()Z+53 [email protected]
j  java.lang.ClassLoader$NativeLibrary.loadLibrary(Ljava/lang/Class;Ljava/lang/String;Z)Z+216 [email protected]
j  java.lang.ClassLoader.loadLibrary0(Ljava/lang/Class;Ljava/io/File;)Z+46 [email protected]
j  java.lang.ClassLoader.loadLibrary(Ljava/lang/Class;Ljava/lang/String;Z)V+48 [email protected]
j  java.lang.Runtime.load0(Ljava/lang/Class;Ljava/lang/String;)V+57 [email protected]
j  java.lang.System.load(Ljava/lang/String;)V+7 [email protected]
<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)
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
731
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

SIGBUS очень редко встречается в системах Linux / x86.

Один из случаев, когда это происходит, — это когда файл mmaped усекается. Из карта человека:

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.

Дикая догадка: у вас есть состояние гонки, когда вы можете выполнять это извлечение из двух отдельных потоков одновременно.

Первый поток извлекает libswt-gtk-4922r22.so из ZIP-архива и dlopens его. dlopenmmaps файл, перемещает его и вызывает инициализатор библиотеки.

Во время работы инициализатора библиотеки второй поток решает, что библиотеку необходимо извлечь (это ошибка), и усекает файл .so перед записью в него нового (идентичного) содержимого. Как только truncate завершится, первый поток (все еще работающий инициализатор библиотеки) уничтожается с помощью SIGBUS.

Обычное исправление состоит в том, чтобы убедиться, что «проверить, существует ли файл, извлечь, если нет» в критическом разделе.

Спасибо, почти так и произошло. Я исправил ошибку вчера, но вы быстрее разместили ответ :) С той лишь разницей, что она была вызвана быстрым запуском двух процессов. Сначала увидел, что библиотека отсутствует, начал ее распаковывать, второй увидел частичную библиотеку на диске, загрузил ее и разбился. Критические разделы здесь не помогут, но я решил проблему, извлекая во временный файл и перемещая его, когда он будет полностью записан.

Codeguard 10.05.2019 10:12

Другие вопросы по теме