Что такое ошибка шины?

Что означает сообщение об ошибке шины и чем оно отличается от сегфоута?

20 ответов

Решение

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

  • использование инструкции процессора с адресом, который не удовлетворяет его требованиям выравнивания.

Ошибки сегментации возникают при доступе к памяти, которая не принадлежит вашему процессу, они очень распространены и обычно являются результатом:

  • используя указатель на что-то, что было освобождено.
  • используя неинициализированный, следовательно, фиктивный указатель.
  • используя нулевой указатель.
  • переполнение буфера.

PS: если быть более точным, это не манипулирование самим указателем, который вызовет проблемы, это доступ к памяти, на которую он указывает (разыменование).

Segfault получает доступ к памяти, к которой у вас нет доступа. Это только для чтения, у вас нет разрешения и т.д...

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

mmapминимальный пример POSIX 7

"Ошибка шины" происходит, когда ядро ​​отправляет SIGBUS к процессу.

Минимальный пример, который производит это, потому что ftruncate был забыт:

#include <fcntl.h> /* O_ constants */
#include <unistd.h> /* ftruncate */
#include <sys/mman.h> /* mmap */

int main() {
    int fd;
    int *map;
    int size = sizeof(int);
    char *name = "/a";

    shm_unlink(name);
    fd = shm_open(name, O_RDWR | O_CREAT, (mode_t)0600);
    /* THIS is the cause of the problem. */
    /*ftruncate(fd, size);*/
    map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    /* This is what generates the SIGBUS. */
    *map = 0;
}

Бежать с:

gcc -std=c99 main.c -lrt
./a.out

Проверено в Ubuntu 14.04.

POSIX описывает SIGBUS как:

Доступ к неопределенной части объекта памяти.

Спецификация mmap говорит, что:

Ссылки в пределах диапазона адресов, начинающиеся с pa и продолжающиеся для длинных байтов до целых страниц, следующих за концом объекта, должны привести к доставке сигнала SIGBUS.

А также shm_open говорит, что генерирует объекты размером 0:

Объект общей памяти имеет нулевой размер.

Так что в *map = 0 мы дотрагиваемся до конца выделенного объекта.

Я согласен со всеми ответами выше. Вот мои 2 цента относительно ошибки шины:

Ошибка шины не должна возникать из инструкций в коде программы. Это может произойти, когда вы запускаете двоичный файл и во время выполнения двоичный файл изменяется (перезаписывается сборкой или удаляется и т. Д.).

Проверка, так ли это: Простой способ проверить, является ли это причиной, - запустить запущенные экземпляры одного и того же двоичного файла и запустить сборку. Оба запущенных экземпляра зависнут с SIGBUS ошибка вскоре после завершения сборки и замены двоичного файла (тот, который в настоящее время работают оба экземпляра)

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

Я полагаю, что ядро ​​вызывает SIGBUS, когда приложение демонстрирует смещение данных на шине данных. Я думаю, что, поскольку большинство [?] Современных компиляторов для большинства процессоров дополняют / выравнивают данные для программистов, проблемы выравнивания прошлого (по крайней мере) смягчаются, и, следовательно, в наши дни SIGBUS не видят слишком часто (AFAIK).

От: Здесь

Вы также можете получить SIGBUS, если по какой-то причине невозможно вставить кодовую страницу.

Конкретный пример ошибки шины, с которой я только что столкнулся при программировании C на OS X:

#include <string.h>
#include <stdio.h>

int main(void)
{
    char buffer[120];
    fgets(buffer, sizeof buffer, stdin);
    strcat("foo", buffer);
    return 0;
}

Если вы не помните документы strcat добавляет второй аргумент к первому, изменяя первый аргумент (переверните аргументы, и все работает нормально). В Linux это дает ошибку сегментации (как и ожидалось), но в OS X это дает ошибку шины. Зачем? Я действительно не знаю.

Один классический случай ошибки шины возникает в некоторых архитектурах, таких как SPARC (по крайней мере, некоторые SPARC, возможно, это было изменено), когда вы делаете неправильный доступ. Например:

unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;

Этот фрагмент пытается записать 32-разрядное целочисленное значение 0xdeadf00d к адресу, который (скорее всего) не выровнен должным образом и вызовет ошибку шины на архитектурах, которые "разборчивы" в этом отношении. Intel x86, кстати, не такая архитектура, она позволила бы доступ (хотя и выполнял его медленнее).

Я получал ошибку шины, когда корневой каталог был на 100%.

Во-первых, SIGBUS и SIGSEGV не являются конкретным типом ошибок, а представляют собой группы или семейства ошибок. Вот почему вы обычно видите номер сигнала (si_no) и код сигнала (si_code).

Они также зависят от операционной системы и архитектуры относительно того, что именно может их вызвать.

В целом можно так сказать. SIGSEGV связан с отображениями памяти (разрешениями, без отображения), то есть с ошибкой mmu.

SIGBUS - это когда отображение памяти выполнено успешно и вы столкнулись с проблемой с базовой системой памяти (нет памяти в этом месте, выравнивание, smmu предотвращает доступ и т. Д.), То есть ошибка шины.

SIGBUS также может быть с MMAP-файлами, если файл исчезает из системы, например, вы используете MMAP-файл на съемном носителе, и он отключается.

Хорошее место для поиска на платформе - заголовок siginfo.h, чтобы получить представление о подтипах сигналов. например, для linux На этой странице представлен обзор. https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/siginfo.h#L245

      /*
 * SIGSEGV si_codes
 */
#define SEGV_MAPERR 1   /* address not mapped to object */
#define SEGV_ACCERR 2   /* invalid permissions for mapped object */
#define SEGV_BNDERR 3   /* failed address bound checks */
#ifdef __ia64__
# define __SEGV_PSTKOVF 4   /* paragraph stack overflow */
#else
# define SEGV_PKUERR    4   /* failed protection key checks */
#endif
#define SEGV_ACCADI 5   /* ADI not enabled for mapped object */
#define SEGV_ADIDERR    6   /* Disrupting MCD error */
#define SEGV_ADIPERR    7   /* Precise MCD exception */
#define SEGV_MTEAERR    8   /* Asynchronous ARM MTE error */
#define SEGV_MTESERR    9   /* Synchronous ARM MTE exception */
#define NSIGSEGV    9

/*
 * SIGBUS si_codes
 */
#define BUS_ADRALN  1   /* invalid address alignment */
#define BUS_ADRERR  2   /* non-existent physical address */
#define BUS_OBJERR  3   /* object specific hardware error */
/* hardware memory error consumed on a machine check: action required */
#define BUS_MCEERR_AR   4
/* hardware memory error detected in process but not consumed: action optional*/
#define BUS_MCEERR_AO   5
#define NSIGBUS     5

Последнее замечание: все сигналы также могут быть сгенерированы пользователем, например, kill. Если он сгенерирован пользователем, то si_code- SI_USER. Таким образом, специальные источники получают отрицательные si_codes.

      /*
 * si_code values
 * Digital reserves positive values for kernel-generated signals.
 */
#define SI_USER     0       /* sent by kill, sigsend, raise */
#define SI_KERNEL   0x80        /* sent by the kernel from somewhere */
#define SI_QUEUE    -1      /* sent by sigqueue */
#define SI_TIMER    -2      /* sent by timer expiration */
#define SI_MESGQ    -3      /* sent by real time mesq state change */
#define SI_ASYNCIO  -4      /* sent by AIO completion */
#define SI_SIGIO    -5      /* sent by queued SIGIO */
#define SI_TKILL    -6      /* sent by tkill system call */
#define SI_DETHREAD -7      /* sent by execve() killing subsidiary threads */
#define SI_ASYNCNL  -60     /* sent by glibc async name lookup completion */

#define SI_FROMUSER(siptr)  ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr)    ((siptr)->si_code > 0)

Обычно это означает неприсоединенный доступ.

Попытка получить доступ к памяти, которая физически отсутствует, также приведет к ошибке шины, но вы не увидите этого, если используете процессор с MMU и ОС, которая не глючит, потому что у вас не будет никаких -существующая память сопоставлена ​​с адресным пространством вашего процесса.

Это зависит от вашей ОС, процессора, компилятора и, возможно, других факторов.

В целом это означает, что шина ЦП не смогла выполнить команду или столкнулась с конфликтом, но это может означать целый ряд вещей в зависимости от среды и кода, который выполняется.

-Адам

Причиной ошибки шины в Mac OS X было то, что я попытался выделить около 1 МБ в стеке. Это работало хорошо в одном потоке, но при использовании openMP это приводит к ошибке шины, потому что Mac OS X имеет очень ограниченный размер стека для неосновных потоков.

Одна из заметных причин заключается в том, что SIGBUS возвращается, если вы пытаетесь mmap область /dev/mem, к которой пользовательскому пространству не разрешен доступ.

Я только что обнаружил, что на процессоре ARMv7 вы можете написать некоторый код, который выдает ошибку сегментации, когда не оптимизирован, но дает ошибку шины при компиляции с -O2 (оптимизируйте больше). Я использую кросс-компилятор gcc arm gnueabihf из Ubuntu x64.

Для меня я случайно вызвал «Ошибка шины», не объявив, что моя сборка возвращается в .textраздел. Это могло показаться очевидным, но на какое-то время я поставил в тупик.

Например.

      .globl _myGlobal # Allocate a 64-bit global with the value 2
.data
.align 3
_myGlobal:
.quad 2
.globl _main # Main function code
_main:
push %rbp

Отсутствовала текстовая директива при возврате к коду из данных:

      _myGlobal:
.quad 2
.text # <- This
.globl _main
_main:

Надеюсь, это кому-то поможет

Я пытался освободить строку, случайно оказавшуюся в стеке:

      #include <stdlib.h>

int main(void)
{
    char *str = "foo";
    free(str);
    return (EXIT_SUCCESS);
}

Мое исправление состояло в том, чтобыstrdup()строка в стеке:

      #include <stdlib.h>
#include <string.h>

int main(void)
{
    char *str = strdup("foo");
    free(str);
    return (EXIT_SUCCESS);
}

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

for (j = 0; i < n; j++) {
                for (i =0; i < m; i++) {
                        a[n+1][j] += a[i][j];
                }
        }

Заметили "непреднамеренное" использование переменной "i" в первом "цикле for"? Вот что в этом случае вызывает ошибку шины.

Типичное переполнение буфера, которое приводит к ошибке шины,

{
    char buf[255];
    sprintf(buf,"%s:%s\n", ifname, message);
}

Здесь, если размер строки в двойных кавычках ("") больше размера буфера, это дает ошибку шины.

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

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