Как в glibc обнаруживаются двойные освобождения?

* glibc detected ./load: double free or corruption (!prev): ADDRESS **

При использовании glibc как он узнает, что я дважды освобождаюсь? Отслеживает ли все, что я искал и освободил? Содержится ли оно в метаданных, например, как свободный знает, сколько места нужно освободить ( Как свободный знает, сколько свободного места?)

4 ответа

Решение

Для каждого выделения менеджер памяти хранит некоторый "заголовок" (наиболее вероятный узел дерева или связанный список). Когда вы передали на освобождение что-то, что не содержит действительного заголовка - ну, это не могло быть правильно освобождено. Что касается того, где хранится эта информация - это зависит от реализации, но обычно она размещается прямо перед адресом, который вы получили от malloc, - однако размер и структура, скорее всего, неизвестны, но, по крайней мере, это дает представление о том, насколько легко этот заголовок может быть сломанным / испорченным / перезаписанным / и т.д.

Когда вы что-то делаете malloc, вы получаете указатель на блок памяти. Вы уже знаете это ^^. Управление памятью также резервирует (скрытый) заголовок перед * вашим блоком (который, например, отслеживает размер блока). Когда вы освобождаете свой указатель, заголовок красного цвета, чтобы проверить, является ли он действительным указателем. Свободная операция также стирает заголовок. Если вы освободите дважды, заголовок больше не будет действительным на втором бесплатном. Отсюда и обнаружение.

Память, выделенная malloc(), calloc() или же realloc() есть метаданные для распределения, которые используются free() для выделения выделенной памяти.

Однако не следует делать какие-либо предположения о том, как или обнаруживается двойное освобождение, поскольку поведение не определено в стандарте, как указано ниже.

free() освобождает пространство памяти, на которое указывает ptrкоторый должен был быть возвращен предыдущим вызовом malloc(), calloc() или же realloc(), В противном случае, или если free(ptr) уже был вызван ранее, происходит неопределенное поведение. Если ptr NULL, операция не выполняется.

Стандарт языка Си говорит, что освобождение указателя во второй раз - неопределенное поведение. То, что вы видите в glibc, является одним конкретным случаем этого неопределенного поведения - полезным - когда выдается сообщение. Большинство распределителей отслеживают то, что выделено, и до определенной суммы оно может отслеживать то, что было освобождено. Но вы не можете рассчитывать на это поведение.

Программе переменного тока также разрешается молча аварийно завершать работу или игнорировать ситуацию (или любое другое действие, которое она считает необходимым).

Другие вопросы по тегам