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

Что означает сообщение "ошибка шины" и чем оно отличается от segfault?

Я хотел бы добавить простое объяснение для обоих: ошибка сегментации означает, что вы пытаетесь получить доступ к памяти, к которой вам не разрешено (например, это не часть вашей программы). Однако ошибка шины обычно означает, что вы пытаетесь получить доступ к несуществующей памяти (например, вы пытаетесь получить доступ к адресу на 12 ГБ, но у вас есть только 8 ГБ памяти) или если вы превышаете лимит полезной памяти.

xdevs23 03.10.2017 16:45

На какой платформе вы это видели? ПК? Mac? x86? 32/64?

Peter Mortensen 13.01.2020 16:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
282
2
335 453
15
Перейти к ответу Данный вопрос помечен как решенный

Ответы 15

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

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

-Адам

I believe the kernel raises SIGBUS when an application exhibits data misalignment on the data bus. I think that since most[?] modern compilers for most processors pad / align the data for the programmers, the alignment troubles of yore (at least) mitigated, and hence one does not see SIGBUS too often these days (AFAIK).

От: Здесь

Зависит от неприятных трюков, которые вы делаете со своим кодом. Вы можете вызвать ошибку шины / ловушку выравнивания, если сделаете что-то глупое, например, выполните математические вычисления с указателем, а затем приведете тип для доступа к проблемному режиму (т.е. вы настроили массив uint8_t, добавили один, два или три к указателю массива, а затем привели на short, int или long и попытайтесь получить доступ к нежелательному результату.) Системы X86 в значительной степени позволят вам это сделать, хотя и с реальным снижением производительности. НЕМНОГО Системы ARMv7 позволят вам это сделать, но большинство ARM, MIPS, Power и т. д. Будут ворчать на вас по этому поводу.

Svartalf 16.12.2014 21:39

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

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

Обычно это означает несогласованный доступ.

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

У моего i7 определенно есть MMU, но я все еще сталкивался с этой ошибкой при изучении C в OS X (передача неинициализированного указателя на scanf). Означает ли это, что OS X Mavericks глючит? Каким было бы поведение в ОС без ошибок?

Calvin Huang 17.02.2014 04:55

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

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

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

В случае, если у меня были данные [8]; Теперь это число кратно 4 в 32-битной архитектуре. Итак, он выровнен. Я все еще получаю сообщение об ошибке? Также, пожалуйста, объясните, является ли преобразование типов данных для указателей плохой идеей. Не приведет ли это к ошибкам совмещения в хрупкой архитектуре. Пожалуйста, уточните, это поможет мне.

dexterous 01.10.2013 16:49

Хех. Это не столько преобразование типов, сколько преобразование типов для указателя, для которого вы выполнили математические вычисления с указателем. Посмотрите осторожно на код выше. Компилятор тщательно выровнял ваш указатель для данных по двойному слову, а затем вы облажались с компилятором, сдвинув ссылку на ДВА и приведя тип к очень необходимому доступу, выровненному по двойному слову, к тому, что будет границей, отличной от двойного слова.

Svartalf 16.12.2014 21:28

«Хрупкий» - не то слово, которое я бы использовал для всего этого. Машины и код X86 уже некоторое время заставляют людей делать довольно глупые вещи, и это один из них. Если у вас возникли проблемы такого рода, переосмыслите свой код - для начала он не очень эффективен на X86.

Svartalf 16.12.2014 21:31

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

supercat 17.04.2015 23:35

@Supercat: Дело в том, что на X86 это сходит с рук. Вы попробуете это на ARM, MIPS, Power и т. д., И с вами будут происходить неприятные вещи. На ARM меньше, чем Arch V7, ваш код будет иметь сбой выравнивания, а на V7 вы можете, ЕСЛИ ваша среда выполнения настроена для этого, обработать его с СЕРЬЕЗНЫМ ударом производительности. Вы просто не хотите этого делать. Откровенно говоря, это плохая практика. : D

Svartalf 23.04.2015 21:15

@Svartalf: Мне хорошо известно, что платформы различаются в отношении обработки невыровненного доступа. Я бы хотел, чтобы стандарт C определял средства, с помощью которых исходный код мог бы указывать: «Я хочу, чтобы этот тип вел себя как указатель с выравниванием __, на целое число без знака, хранимое с использованием __ младших битов каждого из __ местоположений типа __ в __. -first format », и пусть компилятор сгенерирует любой машинный код, который потребуется для этого. Компилятору может потребоваться генерировать неприятный неэффективный код, но это не будет хуже, чем то, что программисту придется написать для переносимости. Разница...

supercat 23.04.2015 21:25

... было бы так, что на платформах, где заявленные требования совпадают с естественным поведением процессора, компилятор мог бы легко это использовать. Если, например, x86 программист запросил выравнивание MSB-first, процессору, возможно, придется добавить инструкции по замене байтов после загрузки и перед сохранением, но это все равно будет дешевле, чем четыре отдельных 8-битных хранилища.

supercat 23.04.2015 21:27
Ответ принят как подходящий

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

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

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

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

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

Они не редкость; Я только что выполняю упражнение 9 из раздела «Как усложнить трудный путь обучения C» и уже столкнулся с одним ...

11684 27.03.2013 00:12

Другая причина ошибок шины (в любом случае в Linux) - это когда операционная система не может поддерживать виртуальную страницу с физической памятью (например, в условиях нехватки памяти или нехватки огромных страниц при использовании огромной страничной памяти). Обычно mmap (и malloc) просто Зарезервируйте виртуальное адресное пространство, а ядро ​​назначает физическую память по запросу (так называемые программные ошибки страницы). Сделайте достаточно большой malloc, а затем запишите в него достаточное количество, и вы получите ошибку шины.

Eloff 14.07.2015 03:09

для меня раздел, содержащий /var/cache, был просто полным askubuntu.com/a/915520/493379

c33s 16.05.2017 01:08

В моем случае метод static_cast привязал параметр void * к объекту, который хранит обратный вызов (один атрибут указывает на объект, а другой - на метод). Затем вызывается обратный вызов. Однако то, что было передано как void *, было чем-то совершенно другим, и поэтому вызов метода вызвал ошибку шины.

Christopher K. 15.08.2018 16:04

@bltxd Вы знаете природу ошибок шины. то есть имеет ли сообщение на кольцевой шине какой-то механизм, при котором остановка на кольце также принимает сообщение, которое было отправлено ею, но в любой пункт назначения, поскольку оно предполагает, что оно прошло весь путь по кольцу и не было принято. Я предполагаю, что буфер заполнения строки возвращает статус ошибки, и когда он удаляется, он очищает конвейер и вызывает правильную микропрограмму исключения. Это в основном требует, чтобы контроллер памяти принимал все адреса в своем диапазоне, что предполагает, что при изменении BAR и т. д. Он должен будет внутренне

Lewis Kelsey 10.03.2019 08:00

изменить регистры в контроллере памяти, чтобы исключить этот диапазон адресов

Lewis Kelsey 10.03.2019 08:00

Мне это кажется неудобной операцией, поскольку память инициализируется при загрузке перед BAR, поэтому любое обновление BAR должно отражаться в контроллере памяти, что также означало бы, что тогда ему пришлось бы обновить свое внутреннее сопоставление с каналом RAM, модуль, ранг, IC, чип, банк, строка, столбец для всех остальных диапазонов

Lewis Kelsey 10.03.2019 08:11

Я также видел, как это происходит из моего основного приложения dotnet, когда диск был заполнен (с использованием io с отображением памяти). Возможно, это связано с комментарием @ Eloff.

John 06.05.2020 11:08

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

Это часто случается, когда я обновляю файл .so во время выполнения процесса.

poordeveloper 11.08.2015 05:05

Другая причина - если вы попытаетесь записать в mmap файл, размер которого превышает размер /dev/shm.

ilija139 22.03.2017 07:57

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

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

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

Хех ... если бы это было так, у вас были бы проблемы с ошибками шины вместо эксплойтов, которые вы постоянно читаете для Windows и других машин. Ошибки шины вызваны попыткой доступа к «памяти», к которой машина просто не может получить доступ из-за неправильного адреса. (Отсюда и термин «ошибка шины».) Это может быть связано с множеством сбоев, включая недопустимое выравнивание и т.п., пока процессор не может разместить адрес на линиях шины.

Svartalf 16.12.2014 21:35

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

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

Обратите внимание на использование «непреднамеренный» переменная 'i' в первый "цикл"?. Это то, что вызывает ошибку шины в этом случае.

Если m> = n, тогда внешний цикл будет выполняться один раз или не будет выполняться вообще, в зависимости от ранее существовавшего значения i. Если m <n, то он будет работать бесконечно с увеличением индекса j, пока вы не выйдете за пределы своего массива и, скорее всего, не вызовете ошибку сегментации, а не ошибку шины. Если этот код компилируется, тогда нет проблем с доступом к памяти самой переменной 'i'. Извините, но это неверный ответ.

itaych 17.05.2020 16:29

Конкретный пример ошибки шины, с которой я столкнулся при программировании 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 это дает ошибку шины. Почему? Я правда не знаю.

Вероятно, защита от переполнения стека вызывает ошибку шины.

Joshua 11.08.2015 05:06
"foo" хранится в сегменте памяти, доступном только для чтения, поэтому запись в него невозможна. Это не будет защита от переполнения стека, просто защита от записи в память (это дыра в безопасности, если ваша программа может перезаписывать себя).
Mark Lakata 21.06.2016 20:11

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

Я использую кросс-компилятор GCC ARM gnueabihf из 64-разрядной версии Ubuntu.

Как это отвечает на вопрос?

Peter Mortensen 13.01.2020 22:27

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 как:

Access to an undefined portion of a memory object.

mmap spec говорит, что:

References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object shall result in delivery of a SIGBUS signal.

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

The shared memory object has a size of zero.

Итак, в *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, я суммировал соответствующие документы немного дальше здесь.

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

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

Я согласен со всеми приведенными выше ответами. Вот мои 2 цента за ошибку АВТОБУСА:

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

Проверка, так ли это

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

Основная причина

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

Согласен, это самая частая причина ошибок шины в моем опыте.

itaych 17.05.2020 11:30

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