Вопрос о разделе назначения NULL-указателя в адресном пространстве процесса - PullRequest
3 голосов
/ 22 ноября 2010

Я читаю , а ниже приводится цитата:

Виртуальное адресное пространство каждого процесса разделить на перегородки. На 32-битной x86 Windows, раздел 0x00000000 - 0x0000FFFF (включительно) называется Раздел назначения с нулевым указателем. Этот раздел выделен, чтобы помочь программисты ловят NULL-указатель задания. Если нить в вашем процесс пытается прочитать или записать в адрес памяти в этом раздел, нарушение доступа поднял.

Мне интересно, почему мы должны использовать диапазон адресного пространства вместо только значение 0 , чтобы поймать NULL-указатель присваивания? AFAIK, NULL равно 0. Итак, что стоит за этим дизайном? Есть ли что-то еще в этом диапазоне, что пользователь не должен касаться? Или NULL не обязательно равен 0?

Большое спасибо.

Ответы [ 4 ]

4 голосов
/ 22 ноября 2010

Все современные операционные системы хитро реализуют проверку разыменования нулевого указателя без каких-либо накладных расходов при использовании аппаратного обеспечения управления виртуальной памятью. Страница 0-й 4 КБ (или в данном случае 0-15-й страницы (всего 64 КБ)) настроена таким образом, что любое чтение или запись данных или выполнение инструкции по адресу 0 (или 0x00000FFF или 0x0000FFFF в этом отношении) мгновенно приводит к доступу исключение нарушения.

Позвольте мне сказать по-другому. Преобразование разыменования нулевого указателя в 0, но разрешение ссылок на данные, скажем, по адресу 1, будет непомерно дорогим - поскольку вы не можете использовать аппаратное обеспечение VM с гранулярностью страницы, вместо этого потребуется выполнить сравнение нулевого указателя и последовательность ветвлений до многих указателей разыменования. Сделав первую или несколько первых страниц недоступными, эту проверку можно выполнить «бесплатно» в оборудовании виртуальной машины. Недостатком является то, что вы не можете использовать эти первые страницы ни для чего другого.

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

Так почему раздел назначения пустых указателей в Windows (после Win98) составляет 64 КБ вместо минимально необходимых 4 КБ? Ответ Вайзарда также хорошо подходит для обнаружения ошибок индекса массива нулевых указателей.

* Позднее обновление: RE: почему 64 КБ? - Я спросил кого-то, кто должен знать о команде Windows Core, и они сказали, что это, вероятно, область размером 64 КБ, потому что Windows сохраняет определенные структуры управления памятью с гранулярностью выделения 64 КБ. Это почему? Я не знаю, но, возможно, у Раймонда Чена есть ответ: http://blogs.msdn.com/b/oldnewthing/archive/2003/10/03/55239.aspx. Ух ты. *

3 голосов
/ 22 ноября 2010

В языке C или C ++ NULL всегда равен 0, но 0 в качестве значения указателя в исходном коде не обязательно соответствует всем нулевым битам в скомпилированном двоичном файле. Однако в Windows я считаю, что нулевой указатель - это все нулевые биты.

Зарезервированное пространство, вероятно, поможет поймать такие вещи, как myarray[n], где myarray равно нулю, или mystruct->myfield, где mystruct равно нулю. Адрес, к которому осуществляется доступ, не обязательно совпадает с указателем, он может находиться где-то после него.

0 голосов
/ 22 ноября 2010

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

struct Foo {
    int a;
    inb b;
}* Bar = 0;

Bar->b = 0;

В int = 32-битных компиляторах член 'b' будет 4 байта в структуре, поэтому Bar-> b попытается получить доступ к адресу 0x00000004.

0 голосов
/ 22 ноября 2010

Диапазон необходим для облегчения обнаружения ошибок, вызванных разыменованием нулевых и близких к нулевым указателям.Например:

int startOffset = 1000; //start at 1000th element;
char* buffer = obtain();// happens to be null
for( int i = startOffset; buffer[i] != 0; i++ ) {
   //do stuff
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...