У меня есть очень простой код C++ здесь:
char *s = new char[100];
strcpy(s, "HELLO");
delete [] s;
int n = strlen(s);
Если я выполняю этот код от Visual C++ 2008 путем нажатия F5 (Start Debugging) это всегда приводит к катастрофическому отказу (Нарушение прав доступа.) Однако начинающий этот исполняемый файл вне IDE или использующий Ctrl+F5 IDE (Запускаются без Отладки) не приводит ни к какому катастрофическому отказу. Каково могло быть различие?
Я также хочу знать, возможно ли устойчиво воспроизвести катастрофический отказ Нарушения прав доступа, вызванный от доступа к удаленной области? Действительно ли это - вид катастрофического отказа, редкого в реальной жизни?
Доступ к памяти через удаленный указатель является неопределенным поведением. Вы не можете ожидать надежного / повторяемого поведения.
Скорее всего, это «работает» в одном случае, потому что строка все еще «сидит там» в теперь доступной памяти - = но вы не можете полагаться на это. VS заполняет память значениями отладки, чтобы ускорить сбои и найти эти ошибки.
Разница в том, что отладчик, и отладочные библиотеки, и код, собранный в режиме "отладки", любят ломать то, что должно ломаться. Ваш код должен ломаться (потому что он обращается к памяти, которая ему больше технически не принадлежит), поэтому он легче ломается, когда компилируется для отладки и запускается в отладчике.
В реальной жизни вы, как правило, не получаете таких незаметных уведомлений. Все эти вещи, которые заставляют вещи ломаться, когда они должны ломаться в отладчике... эти вещи дороги. Поэтому в релизе это проверяется не так строго. Вы можете в 99 случаях из 100 обойтись освобождением памяти и обращением к ней сразу после этого, потому что библиотеки времени выполнения не всегда сразу отдают память обратно в ОС. Но в сотый раз память либо исчезнет, либо ею завладеет другой поток, и вы получите длину строки, которая уже не строка, а 252462649-байтовый массив дерьма, устремляющийся в нераспределенную (а значит, несуществующую, насколько это должно волновать вас или среду выполнения) память. И почти ничего не говорит вам о том, что только что произошло.
Так что не делайте этого. Как только вы что-то удалили, считайте это мертвым и исчезнувшим. Иначе вы потратите полжизни, выслеживая жуков-хайзенбагов.
Исполняемый файл с отладочными символами способен обнаруживать некоторые случаи нарушений доступа. Код для обнаружения этого содержится в исполняемом файле, но по умолчанию не запускается.
Здесь вы найдете объяснение того, как вы можете контролировать поведение вне отладчика: http://msdn.microsoft.com/en-us/library/w500y392%28v=VS.80%29. aspx
Разыменование указателя после delete
является неопределенным поведением - может произойти что угодно, включая, помимо прочего:
точные результаты будут зависеть от множества факторов, большинство из которых находятся вне вашего контроля. Вам будет намного лучше вообще не запускать неопределенное поведение.
Я также хочу знать, возможно ли это стабильно воспроизводить доступ Сбой нарушения из-за доступа удаленная область?
Вместо простого delete
вы можете рассмотреть возможность использования встроенной функции, которая также устанавливает значение удаленного указателя на 0 / NULL. Обычно это приводит к сбою, если вы на него ссылаетесь. Однако он не будет жаловаться, если вы удалите его второй раз.
Редко ли такое падение в в реальной жизни?
Нет, этот вид сбоев, вероятно, стоит за большинством сбоев, которые мы с вами наблюдаем в программном обеспечении.
Обычно нет разницы в выделенной и освобожденной памяти с точки зрения процесса. Например, у процесса есть только одна большая карта памяти, которая увеличивается по запросу.
Нарушение прав доступа вызвано чтением / записью памяти, которая недоступна, обычно не выгружается в процесс. Различные служебные программы отладки памяти во время выполнения используют механизм разбиения по страницам для отслеживания недействительных обращений к памяти без серьезных потерь времени выполнения, которые могут возникнуть при проверке программной памяти.
В любом случае ваш пример доказывает только то, что ошибка иногда обнаруживается при запуске программы в одной среде, но не обнаруживается в другой среде, но это все равно ошибка, и поведение приведенного выше кода не определено.