На каком уровне компьютера определен нулевой указатель? - PullRequest
4 голосов
/ 12 марта 2011

Сырой компьютер в основном просто имеет память с физическими адресами, начинающимися с 0, верно? Тогда кто-то может написать код сборки (например, BIOS) и фактически установить значение в 0.

Теперь, если есть BIOS, который запускает компьютер, тогда кто-то может написать загрузчик для операционной системы. Может ли этот человек решить переместить фактические значения в позицию 0 в памяти на ассемблере?

Что если они используют C или C ++? Могут ли они иметь указатель со значением 0 и использовать его для доступа к первой ячейке памяти? Для этого нужен специально адаптированный компилятор?

И тогда операционная система выходит на сцену. Он имеет диспетчер памяти, который вызывается malloc, чтобы получить больше памяти. Может ли быть написана операционная система, которая может просто использовать нулевые указатели в качестве обычных указателей, но в остальном ведет себя точно так же, как Linux, и тогда, если кто-то скомпилирует программу на C с обычным неизмененным GCC для нее, нулевой указатель не приведет к сегментации неисправность?

Ответы [ 4 ]

2 голосов
/ 12 марта 2011

Прочитайте это Почему Linux программирует, что разыменования (char *) 0 не всегда segfault? это как минимум половина вашего ответа :-) И это http://wiki.debian.org/mmap_min_addr Первая часть, оуязвимости, которые были возможны до «исправления» mmap_min_addr.И это http://eparis.livejournal.com/606.html, с историей уязвимости.

Так что да, можно сопоставить страницу с адресом 0 и поместить туда код.Ваша система будет слабее ошибок в программах, но «идеальные» программы будут работать так же, как и раньше.Что касается вопроса "что произойдет, если программа получит доступ к сегменту 0" ... Ну ... Что бы вы ни хотели ...

Но я думаю, что вы не совсем понимаете, как защищена память "современные "процессоры работают.Каждый процесс может видеть отдельный блок памяти, сопоставленный с адресом, и некоторые процессы могут «записывать» на эту страницу, а некоторые могут только «читать» (а некоторые могут выполняться).

2 голосов
/ 12 марта 2011

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

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

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

2 голосов
/ 12 марта 2011

Хотя указатель NULL представлен в C исходном коде как 0, не требуется, чтобы базовый битовый шаблон действительно был равен 0. Он просто должен отличаться от ненулевогоуказатели.Есть примеры архитектур, в которых он не равен нулю под прикрытием.

Сама реализация C определяет, что такое NULL.

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

1 голос
/ 12 марта 2011

Linux (или любые «нормальные» процессы и ОС с виртуальной памятью) оставляют самые низкие адреса неизменными, особенно для обнаружения ошибок с нулевым указателем. рассмотрим следующий пример:

#include <unistd.h>
#include <sys/mman.h>
int main() {
    char *p = mmap(0,4096,PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_SHARED|MAP_FIXED,-1,0);
    if (p == MAP_FAILED) return 1;
    p[0] = 'x';
    p[1] = '\n';
    write(1,0,2);
    return 0;
}

это работает в системах, предшествующих selinux (выводит "x"), хотя на моем рабочем столе с отключенным selinux работает только как пользователь root, а не обычный пользователь. но дело в том, что вы обычно контролируете все в своем виртуальном адресном пространстве. если вы действительно хотите поместить что-то в 0, вы можете, хотя можете столкнуться, например, с кодом, который отказывается иметь дело со строкой в ​​0.

...