Что означает "двойная свобода"?
Как видно из названия, я новичок в C и в скором времени появляюсь в среднесрочной перспективе. В настоящее время я пересматриваю прошлые документы, а повторяющаяся тема - двойная свободная проблема. Я понимаю, что это процесс вызова free()
в одном месте памяти дважды, но у меня есть несколько вопросов, на которые я не уверен на 100%, как ответить:
Вопрос 1: Каков результат двойного свободного в C и почему это такая проблема?
Это приведет к двойному освобождению:
char* ptr = malloc(sizeof(char));
*ptr = 'a';
free(ptr);
free(ptr);
Моим ответом на это было бы, вернет ли он адрес памяти 0x0 и вызовет системную нестабильность/сбой. Кроме того, если я правильно помню, двойной бесплатный может фактически вызвать malloc
дважды, что приводит к переполнению буфера, что делает систему уязвимой.
Каким будет лучший способ кратко подвести этот вопрос?
Вопрос 2: Опишите ситуацию, в которой особенно легко ввести
двойной свободный в C?
Я думал, что при прохождении указателей вокруг вы можете случайно освободить его в одной функции, а также освободить его снова, не понимая?
Опять же, что такое "лучший" способ подвести итог?
Ответы
Ответ 1
Двойной свободный в C, с технической точки зрения, приводит к поведению undefined. Это означает, что программа может вести себя совершенно произвольно, и все ставки отключены от того, что происходит. Это, конечно, плохой случай! На практике двойное освобождение блока памяти приведет к повреждению состояния диспетчера памяти, что может привести к повреждению существующих блоков памяти или к будущим распределениям в случае непредвиденных действий (например, одна и та же память, получаемая на двух разные последовательные вызовы malloc
).
Двойное освобождение может происходить во всех случаях. Достаточно распространенный случай, когда несколько разных объектов имеют указатели друг на друга и начинают очищаться вызовами free
. Когда это произойдет, если вы не будете осторожны, вы можете free
указать один и тот же указатель несколько раз при очистке объектов. Однако есть и другие случаи.
Надеюсь, это поможет!
Ответ 2
Поскольку free() будет консолидировать соседние регионы, управляя информацией, хранящейся в тегах перед каждым регионом. Это что-то вроде управления двойным связанным списком. Таким образом, было бы опасно, если буфер, в котором указатель ptr
был перезаписан строкой атаки, в которую могут быть введены поддельные теги.
Ответ 3
Согласно опубликованному стандарту C11, вызов free
в уже free
ячейке памяти приводит к поведению undefined. Это может привести к причудливым ситуациям, таким как память, не получающая выделение, даже когда она доступна, куча становится коррумпированной, то же место памяти распределяется между разными mallocs и т.д. В принципе, это undefined и может быть чем угодно.
ANSI C11 std можно найти здесь. https://www.iso.org/obp/ui/#iso:std:iso-iec:9899:ed-3:v1:en
EDIT: изменен NULL на уже free
d, на основе комментариев. также ссылка теперь указывает на ISO/IEC 9899: 2011 (ru)