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.