Почему эта строка кода приводит к сбою компьютера? Что происходит на уровне памяти?
for(int *p=0; ;*(p++)=0)
;
Я нашел "ответ" на Everything2, но я хочу получить конкретный технический ответ.
Этот код просто формально устанавливает целочисленный указатель на нуль, а затем записывает в целое число, на которое указывает его 0, и увеличивает указатель, зацикливая навсегда.
Нулевой указатель не указывает на что-либо, поэтому запись 0 в него - неопределенное поведение (т.е. стандарт не говорит, что должно произойти). Также вам не разрешается использовать арифметику указателей за пределами массивов, и поэтому даже инкремент также является неопределенным поведением.
Неопределенное поведение означает, что авторам компилятора и библиотеки вообще не нужно заботиться об этих случаях, и все же система является действительной реализацией C/C++. Если программист делает что-то классифицированное как неопределенное поведение, то что бы ни случилось, и он/она не может обвинять авторов компилятора и библиотеки. Программист, входящий в неопределенное поведение, не может ожидать сообщения об ошибке или сбоя, но не может жаловаться на получение одного (еще один миллион выполненных инструкций позже).
В системах, где нулевой указатель представлен как нули, и нет поддержки для защиты памяти, эффект или такой цикл может начать очищать всю адресную память до тех пор, пока не будет повреждена какая-то жизненно важная часть памяти, например таблица прерываний, или до тех пор, пока код записывает нули в самом коде, саморазрушая. В других системах с защитой памяти (наиболее распространенные настольные системы сегодня) выполнение может вместо этого просто остановиться при первой операции записи.
Несомненно, причиной проблемы является то, что p
не был назначен разумный адрес.
Неправильно инициализируя указатель перед записью туда, где он указывает, вероятно, это будет делать Bad Things .
Это может быть просто segfault или может перезаписать что-то важное, например, адрес возврата функции, где segfault не произойдет, пока функция не попытается вернуться.
В 1980-х годах теоретик, с которым я работал, написал программу для 8086, один раз в секунду, написать одно слово случайных данных на случайном вычисляемом адресе. Компьютер был контроллером процесса с защитой сторожевого таймера и различными типами выходных данных. Вопрос состоял в следующем: как долго система будет работать до того, как она перестанет функционировать эффективно? Ответ был час и час ! Это была яркая демонстрация того, что большую часть памяти редко можно получить.
Это может привести к сбою ОС, или может привести к какому-либо другим вещам. Вы вызываете неопределенное поведение. У вас нет памяти по адресу 0
и вы не владеете ею. Вы просто опираетесь на память, которая не принадлежит вам.