¿Free (ptr) donde ptr es NULL daña la memoria?

112

Teóricamente puedo decir que

free(ptr);
free(ptr); 

es una corrupción de la memoria ya que estamos liberando la memoria que ya se ha liberado.

Pero que si

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

Como el sistema operativo se comportará de una manera indefinida, no puedo obtener un análisis teórico real de lo que está sucediendo. Lo que sea que esté haciendo, ¿es esto una corrupción de memoria o no?

¿Es válido liberar un puntero NULL?

Vijay
fuente
1
No estoy seguro acerca del estándar libre de C, pero en C ++ delete (NULL) es perfectamente válido, así que supongo que free (NULL) también debería serlo.
Priyank Bolia
14
@Pryank: delete NULLno es válido en C ++. delete se puede aplicar a valores de puntero nulo de tipo concreto, pero no a NULL. delete (int*) NULLes legal, pero no delete NULL.
el AnT
lo que significa que si un puntero apunta a NULL free no realiza nada. ¿Eso significa? cada vez en nuestra codificación, si desea liberar una memoria, simplemente puede reemplazar una libre (ptr) con ptr = NULL?
Vijay
3
No. Si ptrapunta a la memoria y no la llama free, la memoria se perderá. Configurarlo en NULLsimplemente pierde el control de la memoria y se filtra. Si ptr resulta serNULL , llamar freees una no operación.
GManNickG
1
@benjamin: ¿Eh? ¿Qué le hizo concluir que puede reemplazar free(ptr)con ptr = NULL. Nadie dijo nada de eso.
el AnT

Respuestas:

224

7.20.3.2 La freefunción

Sinopsis

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

Descripción

La freefunción hace que el espacio al que apunta ptrse desasigne, es decir, se ponga a disposición para una asignación posterior. Si ptres un puntero nulo, no se produce ninguna acción.

Consulte ISO-IEC 9899 .

Dicho esto, al mirar diferentes bases de código en la naturaleza, notará que las personas a veces lo hacen:

if (ptr)
  free(ptr);

Esto se debe a que algunos tiempos de ejecución de C (seguro que recuerdo que fue el caso en PalmOS) se bloquean al liberar un NULLpuntero.

Pero hoy en día, creo que es seguro asumir que free(NULL)es un nop según las instrucciones del estándar.

Gregory Pakosz
fuente
29
No, ptr = NULL no es un reemplazo gratis (ptr), ambos son completamente diferentes
Prasoon Saurav
7
NO, significa que free(ptr)donde ptres nulo no tiene efectos secundarios. Pero en cualquier caso, cada memoria asignada usando malloc()o calloc()debe liberarse luego usandofree()
Gregory Pakosz
4
ptr = NULL asegura que incluso si accidentalmente llama a free (ptr), su programa no fallará.
Prasoon Saurav
2
Tenga en cuenta que aunque el estándar C dice que es una operación no operativa, eso no significa que todas las bibliotecas C lo manejen así. He visto bloqueos gratis (NULL), por lo que es mejor evitar llamar al free en primer lugar.
Derick
6
@WereWolfBoy quiere decir evitar free(NULL)probando el puntero NULLantes de llamarfree()
Gregory Pakosz
22

Todas las versiones de la biblioteca C que cumplen con los estándares tratan gratis (NULL) como no operativo.

Dicho esto, en un momento hubo algunas versiones de free que fallarían en free (NULL), por lo que es posible que vea algunas técnicas de programación defensiva recomendadas:

if (ptr != NULL)
    free(ptr);
R Samuel Klatchko
fuente
8
-1 [cita requerida]. Cambiar el estilo del código debido a alguna teoría de una implementación arcaica de rumores es una mala idea.
Tomas
41
@Tomas: nunca recomendé cambiar de estilo, simplemente expliqué por qué es posible que todavía veas esta recomendación en algunos estilos.
R Samuel Klatchko
5
@Tomas 3BSD ( winehq.org/pipermail/wine-patches/2006-October/031544.html ) y PalmOS para dos (2da mano para ambos).
Douglas Leeder
7
@Tomas: el problema estaba en cosas como la versión 7 de Unix. Cuando estaba aprendiendo, gratis (xyz) donde xyz == NULL era una receta para un desastre instantáneo en la máquina donde aprendí (ICL Perq ejecutando PNX, que estaba basado en la versión 7 de Unix con algunos extras de System III). Pero no he codificado de esa manera durante mucho tiempo.
Jonathan Leffler
2
Netware también se bloquea al liberar NULL ... (acaba de depurar un bloqueo en él ...)
Calmarius
13

Si ptr es NULL, no se realiza ninguna operación.

dice la documentación.

Michael Krelin - hacker
fuente
¿Quieres decir que el libre albedrío no realiza nada?
Vijay
2
benjamin, eso es exactamente lo que significa. ¿Qué esperaría que realizara si tuviera conocimiento de la nulidad del argumento?
Michael Krelin - hacker
12

Recuerdo trabajar en PalmOS donde se free(NULL)bloqueó.

jlru
fuente
4
Interesante: eso crea una segunda plataforma (después de 3BSD) que se bloquea.
Douglas Leeder
2
Si mal no recuerdo, en Palm, la biblioteca estándar de C no existía. En su lugar, había un archivo de encabezado en su mayoría no compatible que asignaba las llamadas de biblioteca estándar al SDK de Palm OS. Muchas cosas actuaron inesperadamente. El bloqueo NULLfue una de las grandes diferencias de ejecución de la caja de herramientas de Palm en comparación con la biblioteca estándar.
Steven Fisher
8
free(ptr);
ptr=NULL;
free(ptr);/*This is perfectly safe */

Puede eliminar de forma segura un puntero NULL. En ese caso, no se realizará ninguna operación. En otras palabras, free () no hace nada en un puntero NULL.

Prasoon Saurav
fuente
8

Uso recomendado:

free(ptr);
ptr = NULL;

Ver:

man free

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

Cuando coloque el puntero en NULLdespués free(), podrá free()volver a llamarlo y no se realizará ninguna operación.

StefanB
fuente
3
Eso también ayuda a detectar segfaults con un depurador. Es evidente que segfault en p-> do () con p = 0 es alguien que usa un puntero liberado. Menos evidente cuando ves p = 0xbfade12 en el depurador :)
neuro
6

free(NULL)es perfectamente legal en C así como delete (void *)0ydelete[] (void *)0 son legales en C ++.

Por cierto, liberar memoria dos veces suele causar algún tipo de error en tiempo de ejecución, por lo que no corrompe nada.

n0rd
fuente
2
delete 0no es legal en C ++. deleteRequiere explícitamente una expresión de tipo puntero. Es legal aplicar deletea un valor de puntero nulo escrito, pero no a 0(y no a NULL).
el AnT
1
Tampoco puede eliminar void*: P ¿Qué destructor (es) debería ejecutar?
GManNickG
1
@GMan: puede eliminar void *siempre que sea un puntero nulo.
el AnT
OK bastante justo. Olvidé que solo estamos tratando específicamente con null.
GManNickG
generalmente no corrompe nada, pero no se garantiza que lo haga. ASLR hace que esto sea bastante improbable, pero aún no imposible: buf1=malloc(X); free(buf1);buf2=malloc(X);free(buf1); - aquí, si no tiene suerte, buf2 obtuvo exactamente la misma dirección que buf1, y accidentalmente liberó buf1 dos veces, por lo que en la segunda liberación de buf1 realmente liberó buf2 en silencio, sin casu cualquier error (inmediato) / accidente / lo que sea. (pero es probable que la próxima vez que intente usar buf2 aún tenga un bloqueo, y este escenario es muy poco probable si se ejecuta en ASLR)
hanshenrik
3

free(ptr)is save in C if ptris NULL, sin embargo, lo que la mayoría de la gente no sabe es que NULLno tiene por qué ser igual a 0. Tengo un buen ejemplo de la vieja escuela: en el C64, en la dirección 0, hay un puerto IO. Si escribió un programa en C para acceder a este puerto, necesitaría un puntero cuyo valor sea 0. La biblioteca C correspondiente tendría que distinguir entre 0 y NULLluego.

Saludos cordiales.

andi8086
fuente
Dato interesante, me tomó por sorpresa. Me hizo sentir obligado a hacer un viaje alrededor de preguntas / respuestas de puntero NULL.
artrópodo
0

no la corrupción de la memoria, pero el comportamiento depende de la implementación. Por norma, debería ser un código legal.

Pavel Radzivilovsky
fuente
-3

ptr apunta a alguna ubicación de memoria, digamos 0x100.

Cuando libera (ptr), básicamente está permitiendo que el administrador de memoria use 0x100 para otra actividad o proceso y, en palabras simples, es la desasignación de recursos.

Cuando hace ptr = NULL, está haciendo que ptr apunte a una nueva ubicación (no nos preocupemos por lo que es NULL). Al hacer esto, perdió la pista de los datos de la memoria 0x100. Esto es lo que es la pérdida de memoria.

Por lo tanto, no es recomendable utilizar ptr = NULL en un ptr válido.

En su lugar, podría hacer una verificación segura usando:

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

Cuando liberas (ptr) donde ptr ya apunta a NULL, no realiza ninguna operación, por lo que es seguro hacerlo.

kishanp
fuente