Почему присвоение 0 указателю является решением для висящего указателя?
Что делает OS/Debugger, когда указателю назначается 0?
8 ответов
Основная проблема, которую это решает, заключается в том, что не все процессоры реализуют одинаковую семантику разыменования памяти. В некоторых случаях невозможно выполнить разыменование адреса после того, как он был free()
во все, что выглядит как ошибка. Это особенно верно для встроенных процессоров. В других случаях распределителям может быть очень лениво возвращать освобожденную память операционной системе хоста по соображениям производительности.
По сути, разыменование такого указателя может привести к фактическому просмотру освобожденной области, просмотру обнуленной области, просмотру памяти, которая была возвращена при последующем выделении, или к возникновению исключения процессора. Поскольку такая возможность вполне обоснована, C++ назначил это условие как "неопределенное поведение".
Чтобы выйти из этой ситуации, вы хотите иметь способ различения значений указателей, которые были освобождены или распределены. Таким образом, C++ требует разыменования указателя, который был назначен 0
является ошибкой, и преобразование такого указателя в целое число также возвращает ноль.
Re: ваше текущее редактирование.
указатели не существуют для целей операционных систем. На самом низком уровне нет строк, целых чисел, чисел с плавающей точкой или указателей любого рода. только байты. Когда вы пишете программу на С ++, которая присваивает 0 значению указателя, операционная система просто не входит в уравнение. это полностью зависит от реализации компилятора.
С другой стороны, когда вы разыменовываете такой указатель в своей программе, C++ требует, чтобы это было ошибкой во время выполнения. На встроенных системах это практически не практично, 0 - это абсолютно правильный адрес памяти в таких системах, обычно SRAM находится рядом с этим адресом. Если компилятор строго реализует стандарт, он может вставлять проверку перед каждым разыменованием, чтобы увидеть, было ли оно нулевым, и переводить MCU в состояние ошибки, но это необычно, поскольку это замедлит и без того медленную систему и увеличит размер программы.
В более полнофункциональных системах, в тех, которые имеют модуль управления памятью, нулевой адрес в приложении обычно не отображается ни на одну физическую страницу, поэтому операционная система вам здесь помогает, вызывая ошибку в программе страницы, когда она пытается получить доступ к значению нулевого указателя.
Я предполагаю, что это более полезно для программиста, чем для OS/ отладчика.
OS/ debugger не волнует, куда указывает указатель.
Но полезно проверить, указывает ли указатель на что-то значимое.
Присвоение 0 (или NULL, или какому-либо предопределенному для вас в зависимости от вашего импорта) указателю является общим соглашением, используемым для указания того, что:
- указатель не используется (не указывает на интересующий адрес памяти),
- и что это НЕ должно быть разыменовано.
Указатель на 0 называется нулевым указателем и обычно используется для указания того, что он ни на что не указывает. Это может быть проверено отладчиком / средой выполнения / компилятором / чем угодно, чтобы убедиться, что у вас нет указателя на недопустимые данные. Это просто явное признание того, что указатель не должен указывать на что-либо прямо сейчас.
Просто, чтобы добавить к этому длинному списку ответов, среда выполнения назначит 0
, или же NULL
к указателю. Память на другом конце, если предварительно не освобождена (free()
или же operator delete
) если он был выделен динамически (malloc()
а также operator new
), или просто очистил автоматически, потому что это было auto
(все местные жители по умолчанию).
Назначение NULL
указатель, который имеет действительную память на другом конце, создает утечку памяти. Утечка памяти - это когда ОС думает, что процесс все еще использует некоторую память, но у процесса нет дескриптора памяти (он потерял адрес) и, следовательно, не имеет возможности освободить его или использовать. Память будет очищена после завершения процесса, но для долго выполняющихся процессов, или процессов, которые имеют многократную утечку, или, что хуже всего, программы, которые теряют большие объемы памяти, могут вызвать большие проблемы.
Если процесс теряет достаточно памяти, по крайней мере он замедлит работу системы и заставит пользователя убить ее, в худших обстоятельствах он вызовет убийцу OOM (в системах с одним) или, что еще хуже, вылетит из строя всю систему из-за нехватка памяти. Кроме того, если вы разыграете NULL
Указатель: в любой современной ОС вы вызовете ошибку segfault или bus, а в старой ОС вы можете уничтожить систему (например, DOS).
Отладчики могут уведомлять вас, если у них достаточно информации, вы также можете использовать инструменты статического анализа для обнаружения утечек памяти или инструменты времени выполнения, такие как valgrind. Утечки памяти - это одна из самых больших проблем для программ на C/C++, которую нужно тщательно изучить перед выпуском кода.
Why is assigning 0 to a pointer a solution to a dangling pointer?
@ wikipedia::
To expose dangling pointer errors, one common programming technique is to set
pointers to the null pointer or to an invalid address once the storage they
point to has been released. When the null pointer is dereferenced
(in most languages) the program will immediately terminate—there is no potential
for data corruption or unpredictable behavior. This makes the underlying
programming mistake easier to find and resolve.
This technique does not help when there are multiple copies of the pointer.
,
What does the OS/Debugger do when a pointer is assigned 0?
@ wikipedia::
though, that the physical address zero is often directly accessible by hardware (for
instance, it is directly accessible in x86 real mode, and it is where the interrupt
table is stored), but modern operating systems usually map virtual address spaces in
such a way that accessing address zero is forbidden.
Нулевой указатель важнее, чем просто соглашение. Вам разрешено освобождать nullptr и ничего не делать. Это также используется в качестве соглашения, что указатель еще ни на что не указывает.
Установка указателя на 0 не решает проблему висячих указателей. Если код считает, что висячий указатель (по определению недопустимый) является допустимым, установка в 0 и разыменование по-прежнему будет вызывать недопустимое поведение программы.
Если в коде перед разыменованием происходит проверка указателя на нулевое значение, то установка указателя на 0 может предотвратить недопустимое поведение.