Що означає повідомлення про "помилку шини" та як воно відрізняється від сегмента?
Що означає повідомлення про "помилку шини" та як воно відрізняється від сегмента?
Відповіді:
Помилки шини в наш час рідкісні для x86 і трапляються, коли ваш процесор навіть не може спробувати запит на доступ до пам'яті, як правило:
Помилки сегментації виникають під час доступу до пам'яті, яка не належить до вашого процесу, вони є дуже поширеними і, як правило, є результатом:
PS: Якщо бути точнішим, це не маніпулювання самим покажчиком, що спричинить проблеми, це доступ до пам’яті, на яку він вказує (перенаправлення).
/var/cache
був просто повний askubuntu.com/a/915520/493379
static_cast
редагує void *
параметр об'єкту, який зберігає зворотний виклик (один атрибут вказує на об'єкт, а інший на метод). Тоді викликається зворотний дзвінок. Однак те, що було передано як void *
щось зовсім інше, і, таким чином, виклик методу викликав помилку в шині.
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
ми торкаємося кінця виділеного об'єкта.
Неузгоджений доступ до пам'яті стека в 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, коли програма демонструє невідповідність даних на шині даних. Я думаю, що оскільки більшість [?] Сучасних компіляторів для більшості процесорів вкладають / вирівнюють дані для програмістів, проблеми з вирівнюванням ще (принаймні) пом'якшені, і, отже, в ці дні SIGBUS не бачить занадто часто (AFAIK).
З: Ось
Конкретний приклад помилки шини, з якою я щойно стикався під час програмування 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 це помилка шини. Чому? Я справді не знаю.
"foo"
зберігається в сегменті пам'яті, доступному лише для читання, тому писати до нього неможливо. Це не буде захистом від переповнення стека, а лише захистом від пам'яті (це отвір для безпеки, якщо програма може переписати себе).
Класичний екземпляр помилки шини - це для певних архітектур, таких як SPARC (принаймні деякі SPARC, можливо, це було змінено) - це коли ви робите неправильно узгоджений доступ. Наприклад:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
Цей фрагмент намагається записати 32-бітне ціле значення 0xdeadf00d
на адресу, яка (швидше за все) не є належним чином вирівняна, і створить помилку шини в архітектурах, які є "вибагливими" в цьому плані. Intel x86, до речі, не така архітектура, вона дозволила б отримати доступ (хоч і виконувати його повільніше).
Це залежить від вашої ОС, процесора, компілятора та, можливо, інших факторів.
Взагалі це означає, що шина процесора не могла виконати команду або зазнала конфлікту, але це може означати цілу низку речей залежно від середовища та коду, який виконується.
-Адам
Зазвичай це означає неузгоджений доступ.
Спроба отримати доступ до пам'яті, яка фізично не присутня, також призведе до помилки шини, але ви цього не побачите, якщо ви використовуєте процесор з MMU та ОС, яка не є помилкою, оскільки у вас не буде жодної -існуюча пам'ять, відображена в адресному просторі вашого процесу.
scanf
). Чи означає це, що OS X Mavericks баггі? Якою була б поведінка в ОС, що не бажає на помилки?
Моя причина помилки в шині на Mac OS X полягала в тому, що я намагався виділити близько 1 Мб на стеці. Це добре працювало в одному потоці, але при використанні openMP цей диск приводить до помилки шини, оскільки Mac OS X має дуже обмежений розмір стека для не головних потоків .
Я згоден з усіма відповідями вище. Ось мої 2 центи щодо помилки BUS:
Помилка BUS не повинна виникати з інструкцій в коді програми. Це може статися, коли ви виконуєте бінарний файл і під час виконання двійковий файл модифікується (перезаписується збіркою або видаляється тощо).
Перевірка, чи це так:
Простий спосіб перевірити, чи не є причиною цього, запустивши запущені екземпляри одного і того ж бінарного файлу та запустивши збірку. Обидва запущені екземпляри збилися б із SIGBUS
помилкою незабаром після закінчення збірки та замінили двійковий (той, який зараз запущені обидва екземпляри)
Основна причина: Це тому, що ОС обмінюється сторінками пам'яті, а в деяких випадках двійковий файл може бути не повністю завантажений в пам'ять, і ці збої відбудуться, коли ОС намагається отримати наступну сторінку з того ж бінарного файлу, але бінарний файл змінився з моменту останнього читати.
Щоб додати те, на що відповів blxtd, вище, помилки шини трапляються також тоді, коли ваш процес не може намагатися отримати доступ до пам'яті певної змінної .
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
Помічаєте " ненавмисне " використання змінної "i" у першому "for loop"? Ось що викликає помилку в шині в цьому випадку.
Я щойно з'ясував важкий шлях, що на процесорі ARMv7 ви можете написати якийсь код, який дає помилку сегментації, коли неоптимізований, але він дає вам помилку шини при компіляції з -O2 (оптимізуйте більше).
Я використовую перехресний компілятор GCC ARM gnueabihf з Ubuntu 64 біт.
Типовий перелив буфера, що призводить до помилки шини,
{
char buf[255];
sprintf(buf,"%s:%s\n", ifname, message);
}
Тут, якщо розмір рядка в подвійних лапки ("") перевищує розмір buf, це дає помилку шини.