Что означает "двойная свобода"?

Как видно из названия, я новичок в 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)