Czy free (ptr), gdzie ptr to NULL uszkodzona pamięć?


112

Teoretycznie mogę to powiedzieć

free(ptr);
free(ptr); 

to uszkodzenie pamięci, ponieważ zwalniamy pamięć, która została już zwolniona.

Ale co gdyby

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

Ponieważ system operacyjny będzie zachowywał się w nieokreślony sposób, nie mogę uzyskać faktycznej teoretycznej analizy tego, co się dzieje. Cokolwiek robię, czy to uszkodzenie pamięci, czy nie?

Czy zwolnienie wskaźnika NULL jest prawidłowe?


1
nie jestem pewien co do standardu C, ale w C ++ metoda delete (NULL) jest całkowicie poprawna, więc myślę, że wolny (NULL) również powinien być.
Priyank Bolia

14
@Pryank: delete NULLnie działa w C ++. delete można zastosować do wartości wskaźnika null określonego typu, ale nie do NULL. delete (int*) NULLjest legalne, ale nie delete NULL.
AnT

więc oznacza to, że jeśli wskaźnik wskazuje na NULL free, nic nie wykonuje. czy to oznacza !!!!!! za każdym razem w naszym kodowaniu, jeśli chcesz zwolnić pamięć, możesz po prostu zamienić free (ptr) na ptr = NULL?
Vijay

3
Nie. Jeśli ptrwskazuje na pamięć, a ty jej nie wywołasz free, to pamięć wycieknie. Ustawienie go NULLtak, aby po prostu utraciło dostęp do pamięci i przecieki. Jeśli ptr tak się stanieNULL , wywołanie freejest bez operacji.
GManNickG

1
@benjamin: Hę? Co skłoniło Cię do wniosku, że można zastąpić free(ptr)z ptr = NULL. Nikt nic takiego nie powiedział.
AnT

Odpowiedzi:


225

7.20.3.2 freeFunkcja

Streszczenie

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

Opis

freeFunkcja powoduje miejsca wskazywanego przez ptrbyć zwalniane, czyli udostępnione do dalszej alokacji. Jeśli ptrjest pustym wskaźnikiem, żadna akcja nie jest wykonywana.

Zobacz ISO-IEC 9899 .

Biorąc to pod uwagę, patrząc na różne bazy kodów na wolności, zauważysz, że ludzie czasami robią:

if (ptr)
  free(ptr);

Dzieje się tak, ponieważ niektóre środowiska wykonawcze C (na pewno pamiętam, że miało to miejsce na PalmOS) ulegały awarii podczas zwalniania NULLwskaźnika.

Ale obecnie uważam, że można bezpiecznie założyć, że free(NULL)jest to nop zgodnie z instrukcją zawartą w normie.


29
Nie, ptr = NULL nie jest w żaden sposób zamiennikiem za darmo (ptr), oba są zupełnie inne
Prasoon Saurav

7
NIE, oznacza to, że free(ptr)gdzie ptrjest zero, nie ma skutków ubocznych. Ale w każdym razie każda pamięć przydzielona przy użyciu malloc()lub calloc()musi zostać zwolniona później za pomocąfree()
Gregory Pakosz

4
ptr = NULL zapewnia, że ​​nawet jeśli przypadkowo wywołasz free (ptr), Twój program nie przejdzie do segfaultów.
Prasoon Saurav

2
Proszę zauważyć, że chociaż standard C mówi, że nie jest to operacja, nie oznacza to, że każda biblioteka C obsługuje to w ten sposób. Widziałem awarie za darmo (NULL), więc w pierwszej kolejności najlepiej unikać dzwonienia pod numer bezpłatny.
Derick,

6
@WereWolfBoy ma na myśli unikanie free(NULL), testując wskaźnik NULLprzed wezwaniemfree()
Gregory Pakosz

22

Wszystkie zgodne ze standardami wersje biblioteki C traktują darmową (NULL) jako no-op.

To powiedziawszy, kiedyś istniało kilka wersji darmowych, które ulegały awarii na darmowym (NULL), dlatego możesz zobaczyć niektóre obronne techniki programowania:

if (ptr != NULL)
    free(ptr);

8
-1 [potrzebne źródło]. Zmiana stylu kodu ze względu na jakąś teorię archaicznej implementacji pogłosek to zły pomysł.
Tomas

41
@Tomas - Nigdy nie polecałem zmiany stylu, po prostu wyjaśniłem, dlaczego nadal możesz zobaczyć tę rekomendację w niektórych stylach.
R Samuel Klatchko

5
@Tomas 3BSD ( winehq.org/pipermail/wine-patches/2006-October/031544.html ) i PalmOS dla dwojga (drugie rozdanie dla obu).
Douglas Leeder

7
@Tomas: problem dotyczył rzeczy takich jak wersja 7 Unix. Kiedy się uczyłem, free (xyz), gdzie xyz == NULL było przepisem na natychmiastową katastrofę na maszynie, na której się uczyłem (ICL Perq z PNX, który był oparty na wersji 7 Unix z kilkoma dodatkami z Systemu III). Ale od dawna nie koduję w ten sposób.
Jonathan Leffler

2
Netware również ulega awarii podczas
uwalniania

13

Jeśli ptr ma wartość NULL, nie jest wykonywana żadna operacja.

mówi dokumentacja.


czy masz na myśli to, że taht free nic nie wykona?
Vijay

2
benjamin, właśnie to oznacza. Czego spodziewałbyś się, że wykona, jeśli jest świadomy nieważności argumentu?
Michael Krelin - haker

12

Pamiętam, jak pracowałem na PalmOS, gdzie się free(NULL)zawiesił.


4
Ciekawe - to sprawia, że ​​druga platforma (po 3BSD) ulega awarii.
Douglas Leeder

2
Jeśli dobrze pamiętam, na Palm nie istniała standardowa biblioteka C. Zamiast tego istniał w większości nieobsługiwany plik nagłówkowy, który mapował wywołania biblioteki standardowej do pakietu Palm OS SDK. Wiele rzeczy zadziałało nieoczekiwanie. Awaria NULLbyła jedną z największych różnic w działaniu zestawu narzędzi Palm w porównaniu ze standardową biblioteką.
Steven Fisher

8
free(ptr);
ptr=NULL;
free(ptr);/*This is perfectly safe */

Możesz bezpiecznie usunąć wskaźnik NULL. W takim przypadku żadna operacja nie zostanie wykonana, innymi słowy free () nie robi nic na wskaźniku NULL.


8

Zalecane użycie:

free(ptr);
ptr = NULL;

Widzieć:

man free

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

Jeśli ustawisz wskaźnik na NULLafter free(), możesz free()go ponownie wywołać i żadna operacja nie zostanie wykonana.


3
Pomaga to również w wykrywaniu segfaultów za pomocą debuggera. Jest oczywiste, że segfault w p-> do () z p = 0 to ktoś używający zwolnionego wskaźnika. Mniej widoczne, gdy zobaczysz p = 0xbfade12 w debugerze :)
neuro

6

free(NULL)jest całkowicie legalny w C, jak również delete (void *)0i delete[] (void *)0jest legalny w C ++.

Przy okazji, dwukrotne zwolnienie pamięci zwykle powoduje jakiś błąd w czasie wykonywania, więc niczego nie psuje.


2
delete 0nie jest legalne w C ++. deletejawnie wymaga wyrażenia typu wskaźnika. Dozwolone jest stosowanie deletedo wpisanej wartości wskaźnika null, ale nie do 0(i nie do NULL).
AnT

1
Nie możesz usunąć void*: P Które destruktory ma działać?
GManNickG,

1
@GMan: Użytkownik może usuwać void *tak długo, jak jest to null pointer.
AnT

Ok, w porządku. Zapomniałem, że mamy do czynienia tylko z null.
GManNickG

zazwyczaj niczego nie psuje, ale nie ma gwarancji. ASLR sprawia, że ​​jest to raczej mało prawdopodobne, ale nadal nie jest to niemożliwe: buf1=malloc(X); free(buf1);buf2=malloc(X);free(buf1); - tutaj, jeśli masz pecha, buf2 ma dokładnie ten sam adres, co buf1 i przypadkowo zwolniłeś buf1 dwa razy, więc na drugim miejscu wolnym od buf1 faktycznie zwolniłeś buf2 po cichu, bez casuowania jakikolwiek (natychmiastowy) błąd / awaria / cokolwiek. (ale prawdopodobnie nadal będziesz mieć awarię następnym razem, gdy spróbujesz użyć buf2 - a ten scenariusz jest bardzo mało prawdopodobny, jeśli używasz ASLR)
hanshenrik

3

free(ptr)jest zapisany w C, jeśli ptrjest NULL, jednak większość ludzi nie wie, że NULLnie musi być równa 0. Mam ładny, oldschoolowy przykład: na C64, pod adresem 0, znajduje się port IO. Jeśli napisałeś program w C, który uzyskuje dostęp do tego portu, potrzebujesz wskaźnika o wartości 0. Odpowiednia biblioteka C musiałaby rozróżniać od 0 do tego portu NULL.

Z poważaniem.


Ciekawostka, zaskoczyła mnie. Sprawiło, że poczułem się zmuszony wybrać się na wycieczkę po NULL wskaźnikowych pytaniach / odpowiedziach.
stawonogi


-3

ptr wskazuje na jakąś lokalizację w pamięci, powiedzmy 0x100.

Kiedy zwalniasz (ptr), w zasadzie pozwalasz, aby 0x100 był używany przez menedżera pamięci do innych działań lub procesów, a mówiąc prosto, jest to zwolnienie zasobów.

Kiedy robisz ptr = NULL, ustawiasz ptr na nową lokalizację (nie martwmy się tym, czym jest NULL). W ten sposób straciłeś kontrolę nad danymi pamięci 0x100. To właśnie jest wyciek pamięci.

Dlatego nie jest zalecane używanie ptr = NULL na prawidłowym ptr.

Zamiast tego możesz przeprowadzić bezpieczną kontrolę, używając:

if (ptr! = NULL) {free (ptr);}

Kiedy zwolnisz (ptr), gdzie ptr już wskazuje na NULL, nie wykonuje żadnej operacji, więc jest to bezpieczne.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.