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

Почему этот небезопасный код генерирует исключение NullReferenceException?

Я играл с небезопасным кодом для проблемы с Code Golf,, и я нашел то, что не могу объяснить. Этот код:

unsafe
{
    int i = *(int*)0;
}

Сбой с нарушением доступа (Segfault), но этот код:

unsafe
{
    *(int*)0=0;
}

Выбрасывает исключение NullReferenceException. Мне кажется, что первый выполняет чтение, а второй выполняет запись. Исключение говорит мне, что что-то, где-то в CLR перехватывает запись и останавливает ее до того, как ОС уничтожит этот процесс. Почему это происходит при записи, но не на чтение? Это делает segfault для записи, если я делаю значение указателя достаточно большим. Означает ли это, что есть блок памяти, который знает CLR, и не будет даже пытаться писать? Почему же это позволяет мне попытаться прочитать из этого блока? Я что-то совершенно не понимаю?

Edit:

Интересно: System.Runtime.InteropServices.Marshal.WriteInt32(IntPtr.Zero, 0); Дает мне нарушение доступа, а не NullReference.

4b9b3361

Ответ 1

Первое исключение имеет смысл, конечно же - вы пытаетесь прочитать из адреса памяти 0. Второй интереснее.: P В С++ существует макрос/константа, называемый NULL, который имеет значение 0. Он используется для недопустимых адресов указателей - что очень похоже на нулевое значение в С# для ссылочных типов. Поскольку ссылки С# являются указателями внутри, исключение NullReferenceException возникает, когда вы пытаетесь прочитать/записать с этого адреса - адрес NULL или 0; на самом деле, адреса от 0 до 64K недействительны во всех процессах (в Windows), чтобы уловить ошибки программы. Точное исключение или ошибка может незначительно отличаться на компьютерном оборудовании или версии Windows/.NET Framework, но вы должны получить сообщение об ошибке с обоими фрагментами кода.

Что касается segfault при чтении/записи на случайные адреса, это связано с изоляцией ОС каждого процесса. Вы не можете возиться с кодом или данными других процессов - по крайней мере, не законно.