Повреждает ли память (ptr), где ptr - NULL?

113

Теоретически могу сказать, что

free(ptr);
free(ptr); 

- это повреждение памяти, поскольку мы освобождаем уже освобожденную память.

А вдруг

free(ptr);
ptr=NULL;
free(ptr); 

Поскольку ОС будет вести себя неопределенным образом, я не могу получить фактический теоретический анализ происходящего. Что бы я ни делал, это повреждение памяти или нет?

Действителен ли освобождение нулевого указателя?

Виджай
источник
1
не уверен в бесплатном стандарте C, но в C ++ delete (NULL) вполне допустимо, поэтому я думаю, что free (NULL) также должен быть.
Приянк Болия
14
@Pryank: delete NULLнедопустим в C ++. delete может применяться к значениям нулевого указателя конкретного типа, но не к NULL. delete (int*) NULLзаконно, но не delete NULL.
AnT
значит, если указатель указывает на NULL, free ничего не выполняет. это значит !!!!!! каждый раз в нашем коде, если вы хотите освободить память, можно просто заменить свободную (ptr) на ptr = NULL?
Виджай,
3
Нет. Если ptrуказывает на память, а вы не обращаетесь к freeней, память будет протекать. Установка этого значения NULLпросто теряет контроль над памятью и дает утечку. Если ptr случаетсяNULL , вызывающий freeне представляет никакой операции.
GManNickG
1
@benjamin: А? Что заставило вас сделать вывод, что вы можете заменить free(ptr)на ptr = NULL. Никто ничего подобного не сказал.
AnT

Ответы:

225

7.20.3.2 freeФункция

Синопсис

#include <stdlib.h> 
void free(void *ptr); 

Описание

freeФункция вызывает пространство , на который указывает ptrна освобождаться, то есть сделал для дальнейшего распределения. Если ptrэто пустой указатель, никаких действий не происходит.

См. ISO-IEC 9899 .

При этом, глядя на разные кодовые базы в дикой природе, вы заметите, что люди иногда делают:

if (ptr)
  free(ptr);

Это связано с тем, что некоторые среды выполнения C (я точно помню, что это было в случае с PalmOS) зависали при освобождении NULLуказателя.

Но в настоящее время я считаю, что можно с уверенностью предположить, free(NULL)что это не так, как указано в стандарте.

Грегори Пакош
источник
29
Нет, ptr = NULL никоим образом не заменяет бесплатную (ptr), обе совершенно разные
Prasoon Saurav
7
НЕТ, это означает , что free(ptr)где ptrнаходится нуль не имеет побочных эффектов. Но в любом случае каждая память, выделенная с использованием malloc()или calloc()должна быть впоследствии освобождена с использованиемfree()
Грегори Пакош
4
ptr = NULL гарантирует, что даже если вы случайно вызовете free (ptr), ваша программа не перестанет работать с ошибкой.
Prasoon Saurav
2
Обратите внимание, что хотя стандарт C говорит, что это не работает, это не означает, что каждая C-библиотека обрабатывает это так. Я видел сбои бесплатно (NULL), поэтому лучше вообще не звонить бесплатно.
Derick
6
@WereWolfBoy, он имеет в виду избежать free(NULL), проверяя указатель NULLперед вызовомfree()
Грегори Пакош
22

Все совместимые со стандартами версии библиотеки C трактуют свободный (NULL) как неработающий.

Тем не менее, в свое время были некоторые версии бесплатного ПО, которые вылетали из-за бесплатного использования (NULL), поэтому вы можете увидеть, что рекомендуют некоторые методы защитного программирования:

if (ptr != NULL)
    free(ptr);
R Самуэль Клатчко
источник
8
-1 [необходима ссылка]. Изменение стиля кода из-за некоторой теории реализации устаревших слухов - плохая идея.
Tomas
41
@Tomas - Я никогда не рекомендовал менять стиль, я просто объяснил, почему вы все еще можете видеть эту рекомендацию в некоторых стилях.
R Samuel Klatchko
5
@Tomas 3BSD ( winehq.org/pipermail/wine-patches/2006-October/031544.html ) и PalmOS для двоих (вторая рука для обоих).
Дуглас Лидер,
7
@Tomas: проблема была в Unix версии 7. Когда я учился, free (xyz), где xyz == NULL был рецептом мгновенной катастрофы на машине, на которой я учился (ICL Perq, работающий под PNX, который был основан на версии 7 Unix с некоторыми дополнениями System III). Но я так давно не кодил.
Джонатан Леффлер,
2
Netware также дает сбой при освобождении NULL ... (только что отладил сбой на нем ...)
Calmarius
13

Если ptr равен NULL, никакая операция не выполняется.

говорит документация.

Михаил Крелин - хакер
источник
Вы имеете в виду, что taht free ничего не выполнит?
Виджай,
2
Бенджамин, именно это и означает. Что бы вы ожидали от него, если бы он знал об отсутствии аргумента?
Михаил Крелин - хакер
12

Я помню, как работал над PalmOS, где произошел free(NULL)сбой.

jlru
источник
4
Интересно, что вторая платформа (после 3BSD) дает сбой.
Дуглас Лидер,
2
Если я правильно помню, на Palm стандартной библиотеки C не существовало. Вместо этого был почти неподдерживаемый файл заголовка, который отображал вызовы стандартных библиотек через SDK для Palm OS. Многое произошло неожиданно. Сбои при работе NULLбыли одним из больших отличий панели инструментов Palm от стандартной библиотеки.
Стивен Фишер,
8
free(ptr);
ptr=NULL;
free(ptr);/*This is perfectly safe */

Вы можете безопасно удалить ПУСТОЙ указатель. В этом случае никакая операция выполняться не будет. Другими словами, free () ничего не делает с указателем NULL.

Prasoon Saurav
источник
8

Рекомендуемое использование:

free(ptr);
ptr = NULL;

Видеть:

man free

     The free() function deallocates the memory allocation pointed to by ptr.
     If ptr is a NULL pointer, no operation is performed.

Когда вы устанавливаете указатель на NULLпосле, free()вы можете вызвать free()его снова, и никакая операция выполняться не будет.

stefanB
источник
3
Это также помогает обнаруживать ошибки с помощью отладчика. Очевидно, что segfault в p-> do () с p = 0 - это кто-то, использующий освобожденный указатель. Менее очевидно , когда вы видите р = 0xbfade12 в отладчике :)
нейро
6

free(NULL)совершенно законно в С, а также delete (void *)0и delete[] (void *)0являются законными в C ++.

Кстати, двойное освобождение памяти обычно вызывает какую-то ошибку времени выполнения, поэтому ничего не портит.

n0rd
источник
2
delete 0недопустима в C ++. deleteявно требует выражения типа указателя. Допустимо применять deleteк типизированному значению нулевого указателя, но не к 0(и не к NULL).
AnT
1
Вы также не можете удалить void*: P Какие деструкторы следует запускать?
GManNickG
1
@GMan: вы можете удалить, void *если это нулевой указатель.
AnT
Хорошо, достаточно честно. Я забыл, что мы имеем дело только с null.
GManNickG
обычно ничего не портит, но не гарантируется. ASLR делает это довольно маловероятным, но все же не невозможным: buf1=malloc(X); free(buf1);buf2=malloc(X);free(buf1); - здесь, если вам не повезло, buf2 получил тот же адрес, что и buf1, и вы случайно освободили buf1 дважды, поэтому на втором этапе, свободном от buf1, вы фактически освободили buf2 тихо, без причинения вреда. любая (имитация) ошибка / сбой / что угодно. (но у вас все равно, вероятно, произойдет сбой в следующий раз, когда вы попытаетесь использовать buf2 - и этот сценарий очень маловероятен, если вы работаете на ASLR)
hanshenrik
3

free(ptr)сохраняется в C, если ptrесть NULL, однако большинство людей не знают, что он NULLне обязательно должен быть равен 0. У меня есть хороший пример старой школы: на C64 по адресу 0 есть порт ввода-вывода. Если вы написали программу на C, обращающуюся к этому порту, вам понадобится указатель со значением 0. Соответствующая библиотека C должна будет различать 0 и NULLзатем.

С уважением.

andi8086
источник
Интересный факт, застал меня врасплох. Я почувствовал себя обязанным отправиться в путешествие по вопросам / ответам с указателем NULL.
членистоногие
0

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

Павел Радзивиловский
источник
-3

ptr указывает на некоторую ячейку памяти, скажем, 0x100.

Когда вы освобождаете (ptr), в основном вы разрешаете диспетчеру памяти использовать 0x100 для других действий или процессов, и простыми словами это освобождение ресурсов.

Когда вы делаете ptr = NULL, вы указываете ptr на новое место (не беспокойтесь о том, что такое NULL). При этом вы потеряли данные памяти 0x100 - вот что такое утечка памяти.

Поэтому не рекомендуется использовать ptr = NULL для действительного ptr.

Вместо этого вы можете выполнить некоторую безопасную проверку, используя:

if (ptr! = NULL) {бесплатно (ptr);}

Когда вы освобождаете (ptr), где ptr уже указывает на NULL, он не выполняет никаких операций, поэтому это безопасно.

Кишанп
источник