Подтвердить что ты не робот

Что означает 0xdeadbeef в адресе 0x0?

Я только что увидел в коде следующую строку:

#define ERR_FATAL( str, a, b, c ) {while(1) {*(unsigned int *)0 = 0xdeadbeef;} }

Я знаю, что 0xdeadbeef означает ошибку, но что означает это значение, когда оно находится в адресе 0? Какой адрес 0 представляет?

4b9b3361

Ответ 1

Адрес 0x0 распознается компилятором как NULL pointer и будет реализация определила неверный адрес памяти, на некоторых системах буквально находится в первом адресном месте в системной памяти, а на других это просто местозаполнитель кода для некоторого общего недопустимого адреса памяти. С точки зрения кода C мы не знаем, какой адрес будет, только то, что он недействителен для доступа к нему. По сути, этот фрагмент кода пытается сделать, это написать "незаконный" адрес памяти со значением 0xdeadbeef. Само по себе значение - это какой-то гекс, который выражает "мертвую говядину", что указывает на то, что программа мертвая говядина (т.е. Проблема), если вы не являетесь носителем английского языка, я вижу, как это может быть не так ясно:). Идея заключается в том, что это вызовет ошибку сегментации или аналогичную информацию с намерением сообщить вам о том, что существует проблема, немедленно прекратив работу программы без каких-либо операций очистки или других операций, выполняемых промежуточным (имя макроса ERR_FATAL намекает на это), Большинство операционных систем не предоставляют программам прямой доступ ко всей памяти в системе, и код предполагает, что операционная система не позволит вам напрямую обращаться к памяти, расположенной по адресу 0x0. Учитывая, что вы отметили этот вопрос тегом linux, это поведение, которое вы увидите (поскольку linux не разрешает доступ к этому адресу памяти). Обратите внимание: если вы работаете над чем-то вроде встроенной системы, где нет такой гарантии, это может вызвать множество проблем, поскольку вы можете переписать что-то важное.

Обратите внимание, что там будут лучшие способы сообщить о проблемах, чем это, которые не зависят от определенных типов поведения undefined, вызывающих определенные побочные эффекты. Использование таких вещей, как assert, скорее всего, станет лучшим выбором. Если вы хотите завершить программу с помощью abort(), это лучший выбор, как в стандартной библиотеке, и делает именно то, что вы хотите. См. Ответ от ComicSansMS для получения дополнительной информации о том, почему это предпочтительнее.

Ответ 2

Полагая это значение (или любое значение, имеющее значение) в адресе 0, должно немедленно прекратить работу программы.

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

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

Обратите внимание, что C уже предоставляет стандартную библиотечную функцию для этой цели: abort(). Вызов abort был бы предпочтительным для этой цели по ряду причин:

  • Запись на адрес 0 не гарантирует завершение работы программы. Это неоправданно ограничивает переносимость кода и может иметь разрушительные последствия в случае, если код действительно перекомпилируется и выполняется на платформе, где запись в адрес 0 приводит к фактической операции сохранения в памяти.
  • Вызов abort() более понятен кому-то, читающему код. Ваш вопрос доказывает, что многие разработчики не поймут, что должен делать этот код. Хотя имя макроса и значение deadbeef дают некоторые подсказки, он по-прежнему неоправданно скрыт. Также обратите внимание, что имя макроса не будет видно при просмотре дизассемблированного кода в отладчике.
  • Вызов более строгих сигналов вызова abort(). Это справедливо не только для самого кода, но и для наблюдаемого поведения двоичного кода. Предполагая, что операция выполняется по назначению на машине Unix, в результате вы получите SIGSEGV, что является сигналом, указывающим на повреждение памяти. abort(), с другой стороны, вызывает SIGABRT, который указывает на ненормальное завершение программы. Если причина фатальной ошибки действительно не была повреждением памяти, бросание SIGSEGV в этом случае скрывает, почему программа терпит неудачу и может ввести в заблуждение разработчика, пытающегося выследить ошибку. Это особенно деликатно, если вы считаете, что сигнал не может быть захвачен отладчиком, а автоматическим обработчиком сигналов, который затем может вызвать недопустимый код для обработки ошибок.

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

Ответ 3

Вывод неверного указателя (который является тем, что пытается выполнить вышеприведенный код) приводит к Undefined Поведение. Таким образом, система могла бы что-либо сделать - она ​​могла потерпеть крах, она ничего не могла сделать, или демоны могут вылететь из вашего носа. Эта страница является отличной страницей, о которой должен знать каждый программист C о Undefined Behavior.

Таким образом, приведенный выше код является неправильным способом вызвать сбой. Как отметил координатор, было бы лучше позвонить abort().