Отладка SIGBUS на x86 Linux

Что может вызвать SIGBUS (ошибка шины) в общем пользовательском приложении x86 в Linux? Все обсуждения, которые я смог найти в Интернете, касаются ошибок выравнивания памяти, которые, как я понимаю, на самом деле не относятся к x86.

(Мой код работает на Geode, если есть какие-то связанные с ним особенности процессора.)

Ответ 1

Вы можете получить SIGBUS из неуправляемого доступа, если вы включите неровную ловушку доступа, но обычно это отключено на x86. Вы также можете получить его от доступа к карте памяти, если есть какая-либо ошибка.

Лучше всего использовать отладчик для идентификации инструкции по сбою (SIGBUS является синхронным) и пытается увидеть, что он пытался сделать.

Ответ 2

SIGBUS может произойти в Linux по нескольким причинам, кроме ошибок выравнивания памяти - например, если вы попытаетесь получить доступ к области mmap за пределами отображаемого файла.

Используете ли вы что-либо вроде mmap, области разделяемой памяти или аналогичные?

Ответ 3

SIGBUS на x86 (включая x86_64) Linux - редкий зверь. Он может появиться из попытки доступа к концу файла mmap ed или некоторых других ситуаций, описанных в POSIX.

Но из-за аппаратных сбоев нелегко получить SIGBUS. А именно, неприглаженный доступ из любой команды - будь то SIMD или нет - обычно приводит к SIGSEGV. Переполнение стека приводит к SIGSEGV. Даже доступ к адресам, не находящимся в канонической форме, приводит к SIGSEGV. Все это из-за поднятия #GP, которое почти всегда отображается на SIGSEGV.

Теперь, вот некоторые способы получить SIGBUS из-за исключения процессора:

  • Включите бит AC в EFLAGS, затем выполните неровный доступ с помощью любой инструкции чтения или записи памяти. Подробнее см. обсуждение.

  • Выполняет каноническое нарушение через регистр указателя стека (rsp или rbp), генерируя #SS. Вот пример для GCC (скомпилируйте с gcc test.c -o test -masm=intel):

int main()
{
    __asm__("mov rbp,0x400000000000000\n"
            "mov rax,[rbp]\n"
            "ud2\n");
}

Ответ 4

О да, есть еще один странный способ получить SIGBUS.

Если ядро ​​не удается выполнить страницу на кодовой странице из-за давления памяти (необходимо отключить убийцу OOM) или сбой запроса IO, SIGBUS.

Ответ 5

Это было кратко упомянуто выше как "неудачный запрос ввода-вывода", но я немного расширю его.

Частым случаем является то, что вы лениво выращиваете файл, используя ftruncate, отображаете его в память, начинаете записывать данные и затем теряете пространство в своей файловой системе. Физическое пространство для сопоставленного файла выделяется при ошибках страницы, если их нет, процесс получает SIGBUS.

Если вам нужно, чтобы ваше приложение правильно восстановилось после этой ошибки, имеет смысл явно зарезервировать место до mmap с помощью fallocate. Обработка ENOSPC в errno после вызова fallocate намного проще, чем обработка сигналов, особенно в многопоточном приложении.

Ответ 6

Если вы запрашиваете отображение, подкрепленное огромными страницами с mmap и флагом MAP_HUGETLB, вы можете получить SIGBUS, если ядру не хватает выделенных огромных страниц и, следовательно, не может обработать ошибку страницы.

В этом случае вам нужно увеличить количество выделенных огромных страниц с помощью

  • /sys/kernel/mm/hugepages/hugepages-<size>/nr_hugepages или
  • /sys/devices/system/node/nodeX/hugepages/hugepages-<size>/nr_hugepages в системах NUMA.

Ответ 7

Общей причиной ошибки шины в x86 Linux является попытка разыменовать то, что на самом деле не является указателем, или является диким указателем. Например, если вы не инициализируете указатель или не назначаете произвольное целое число указателю, а затем пытаетесь разыменовать его, то обычно возникает либо ошибка сегментации, либо ошибка шины.

Согласование применяется к x86. Несмотря на то, что память на x86 байт-адресная (поэтому вы можете иметь указатель char на любой адрес), если у вас есть, например, указатель на 4-байтовое целое число, этот указатель должен быть выровнен.

Вы должны запустить свою программу в gdb и определить, какой доступ указателя вызывает ошибку шины, чтобы диагностировать проблему.

Ответ 8

Это немного от проторенного пути, но вы можете получить SIGBUS из неуравновешенной нагрузки SSE2 (m128).