Что такое ошибка шины?
-
03-07-2019 - |
Вопрос
Что означает сообщение "ошибка шины" и чем оно отличается от segfault?
Решение
Ошибки шины в настоящее время редки на x86 и возникают, когда ваш процессор обычно не может даже попытаться получить запрошенный доступ к памяти:
- использование инструкции процессора с адресом, который не удовлетворяет требованиям к выравниванию.
Ошибки сегментации возникают при доступе к памяти, которая не принадлежит вашему процессу, они очень распространены и обычно являются результатом:
- использование указателя на что-то, что было освобождено.
- использование неинициализированного, следовательно, поддельного указателя.
- используя нулевой указатель.
- переполнение буфера.
PS:Чтобы быть более точным, это не манипулирование самим указателем, которое вызовет проблемы, это доступ к памяти, на которую он указывает (разыменование).
Другие советы
Segfault обращается к памяти, к которой у вас нет доступа. Он доступен только для чтения, у вас нет разрешения и т. Д.
Ошибка шины при попытке доступа к памяти, которой там быть не может. Вы использовали адрес, который не имеет смысла для системы, или неправильный адрес для этой операции.
Я полагаю, что ядро вызывает SIGBUS когда приложение отображает данные рассогласование на шине данных.Я думаю что, поскольку большинство [?] современных компиляторов для большинства процессоров заполняют / выравнивают данные для программистов, проблемы с выравниванием прошлых лет (по крайней мере) смягчены, и, следовательно, никто не видит СИГБУС слишком часто в наши дни (AFAIK).
От: Здесь
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 и продолжающегося на len байт, на целые страницы, следующие за окончанием объекта, должны приводить к доставке сигнала SIGBUS.
И shm_open
говорит , что он генерирует объекты размером 0:
Объект общей памяти имеет нулевой размер.
Итак , в *map = 0
мы прикасаемся к концу выделенного объекта.
Доступ к памяти без выравнивания стека в ARMv8 aarch64
Об этом упоминалось на: Что такое ошибка шины? для SPARC, но здесь я приведу более воспроизводимый пример.
Все, что вам нужно, - это автономная программа aarch64:
.global _start
_start:
asm_main_after_prologue:
/* misalign the stack out of 16-bit boundary */
add sp, sp, #-4
/* access the stack */
ldr w0, [sp]
/* exit syscall in case SIGBUS does not happen */
mov x0, 0
mov x8, 93
svc 0
Затем эта программа запускает SIGBUS в Ubuntu 18.04 aarch64, ядро Linux 4.15.0 в Серверная машина ThunderX2.
К сожалению, я не могу воспроизвести это в пользовательском режиме QEMU v4.0.0, я не уверен почему.
Неисправность, по-видимому, является необязательной и контролируется SCTLR_ELx.SA
и SCTLR_EL1.SA0
поля, я обобщил соответствующие документы чуть дальше здесь.
Вы также можете получить SIGBUS, когда по какой-то причине невозможно вставить кодовую страницу.
Один классический случай ошибки шины - это некоторые архитектуры, такие как SPARC ( по крайней мере, некоторые SPARC, возможно, это было изменено), когда вы делаете неправильный доступ. Например:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
Этот фрагмент кода пытается записать 32-разрядное целочисленное значение 0xdeadf00d
по адресу, который (скорее всего) не выровнен должным образом, и сгенерирует ошибку шины на архитектурах, которые «разборчивы». в этой связи. Между прочим, Intel x86 не такой архитектуры, она позволила бы доступ (хотя и выполнять его медленнее).
Это зависит от вашей операционной системы, процессора, компилятора и, возможно, других факторов.
В общем случае это означает, что шина процессора не смогла выполнить команду или произошел конфликт, но это может означать целый ряд вещей в зависимости от среды и выполняемого кода.
-Адам
Обычно это означает неприсоединенный доступ.
Попытка получить доступ к памяти, которая физически отсутствует, также приведет к ошибке шины, но вы не увидите этого, если используете процессор с MMU и ОС, которая не глючит, потому что вы не будете иметь любую несуществующую память, сопоставленную с адресным пространством вашего процесса.
Конкретный пример ошибки шины, с которой я только что столкнулся при программировании 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 это дает ошибку шины. Зачем? Я действительно не знаю.
Я получал ошибку шины, когда корневой каталог был на 100%.
Моя причина ошибки шины в Mac OS X заключалась в том, что я попытался выделить около 1 МБ в стеке. Это работало хорошо в одном потоке, но при использовании openMP это приводит к ошибке шины, потому что Mac OS X имеет очень ограниченный размер стека для неосновных потоков .
Чтобы добавить то, что blxtd ответил выше, ошибки шины также возникают, когда ваш процесс не может попытаться получить доступ к памяти определенной «переменной» .
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
Обратите внимание на непреднамеренное использование переменной 'i' в first for for loop? Вот что в этом случае вызывает ошибку шины.
Я только что обнаружил, что на процессоре ARMv7 вы можете написать некоторый код, который выдает ошибку сегментации, когда не оптимизирован, но выдает ошибку шины при компиляции с -O2 (оптимизируйте больше). Я использую кросс-компилятор gcc arm gnueabihf из Ubuntu x64.
Я согласен со всеми ответами выше. Вот мои 2 цента относительно ошибки BUS:
Ошибка BUS не должна возникать из инструкций в коде программы. Это может произойти, когда вы запускаете двоичный файл и во время выполнения двоичный файл изменяется (перезаписывается сборкой или удаляется и т. Д.). Р>
Проверка, так ли это:
Простой способ проверить, является ли это причиной, - запустить запущенные экземпляры одного и того же двоичного файла и запустить сборку. Оба запущенных экземпляра завершатся с ошибкой SIGBUS
вскоре после завершения сборки и заменят двоичный файл (тот, который в данный момент запущен обоими экземплярами)
Основная причина Это связано с тем, что ОС меняет местами страницы памяти, а в некоторых случаях весь двоичный файл может находиться в памяти, и эти сбои происходят, когда ОС пытается извлечь следующую страницу из того же двоичного файла, но двоичный файл изменился с момента последнего чтения. р>
Типичное переполнение буфера, которое приводит к ошибке шины,
{
char buf[255];
sprintf(buf,"%s:%s\n", ifname, message);
}
Здесь, если размер строки в двойных кавычках (" ") больше размера буфера, это дает ошибку шины.