Ошибка шины при перекомпиляции двоичного файла - PullRequest
2 голосов
/ 10 марта 2011

Иногда в различных архитектурах Unix перекомпиляция программы во время ее работы вызывает сбой программы с «ошибкой шины».Кто-нибудь может объяснить, при каких условиях это происходит?Во-первых, как обновление двоичного файла на диске может повлиять на код в памяти?Единственное, что я могу себе представить, это то, что некоторые системы отображают код в память, и когда компилятор перезаписывает образ диска, это приводит к тому, что mmap становится недействительным.Каковы преимущества такого метода?Кажется очень неоптимальным иметь возможность сбой выполнения кода путем изменения исполняемого файла.

Ответы [ 2 ]

3 голосов
/ 10 марта 2011

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

Но если вы просто начнете переписывать его, тогда да, это mmap (3) 'ed. Когда блок перезаписывается, в зависимости от того, какие параметры mmap (3) использует динамический компоновщик, может произойти одно из двух:

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

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

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

Но DENYWRITE был отключен по соображениям безопасности, и COPY не реализована ни в одной из основных Unix-подобных систем.

0 голосов
/ 10 марта 2011

Ну, это немного сложный сценарий, который может происходить в вашем случае. Причиной этой ошибки обычно является проблема выравнивания памяти. Ошибка шины чаще встречается в системе, основанной на FreeBSD. Рассмотрим сценарий, что у вас есть что-то вроде структуры,

struct MyStruct { char ch [29]; // 29 байт int32 i; // 4 байта }

Таким образом, общий размер этой структуры будет 33 байта. Теперь рассмотрим систему с 32-байтовыми строками кэша. Эта структура не может быть загружена в одной строке кэша. Теперь рассмотрим следующие утверждения

Struct MyStruct abc; char * cptr = & abc; // символ указывает на начало структуры int32 * iptr = (cptr + 1) // iptr указывает на 2-й байт структуры.

Теперь общий размер структуры составляет 33 байта, ваши указатели на int указывают на 2 байта, так что вы можете прочитать данные из 32 указателей на int (потому что общий размер выделенной памяти составляет 33 байта). Но когда вы пытаетесь прочитать его и если структура размещена на границе строки кэша, ОС не сможет прочитать 32 байта за один вызов. Поскольку текущая строка кэша содержит только 31 байт данных, а оставшиеся 1 байт находятся на следующей строке кэша. Это приведет к неверному адресу и выдаст «Ошибка Buss». Большинство операционных систем обрабатывают этот сценарий, генерируя два вызова чтения из памяти внутри, но некоторые системы Unix не обрабатывают этот сценарий. Чтобы избежать этого, рекомендуется позаботиться о выравнивании памяти. В основном этот сценарий происходит, когда вы пытаетесь набрать приведение структуры к другому типу данных и попытаться прочитать память этой структуры.

Сценарий немного сложен, поэтому я не уверен, что смогу объяснить его проще. Я надеюсь, что вы понимаете сценарий.

...