¿Puedo confiar en que Malloc devolverá NULL?

Leí que en los sistemas Unix, malloc puede devolver un puntero que no sea NULL, incluso si la memoria no está realmente disponible, e intentar usar la memoria más tarde provocará un error. Como no puedo detectar ese error al buscar NULL, me pregunto qué tan útil es verificar NULL en absoluto.

En una nota relacionada, Herb Sutter dice que manejar los errores de memoria de C ++ es inútil, porque el sistema entrará en espasmos de paginación mucho antes de que realmente ocurra una excepción. ¿Esto se aplica también a malloc ?

Citando los manuales de Linux :

Por defecto, Linux sigue una estrategia de asignación de memoria optimista. Esto significa que cuando malloc() no devuelve NULL no hay garantía de que la memoria esté realmente disponible. Este es un error realmente malo. En caso de que el sistema se quede sin memoria, el infame asesino OOM matará uno o más procesos. En caso de que Linux se emplee en circunstancias en las que sería menos conveniente perder repentinamente algunos procesos elegidos al azar, y además la versión del kernel es suficientemente reciente, uno puede desactivar este comportamiento excesivo mediante un comando como:

 # echo 2 > /proc/sys/vm/overcommit_memory 

Debería comprobar el retorno NULL , especialmente en sistemas de 32 bits, ya que el espacio de direcciones del proceso podría agotarse mucho antes que la RAM: en Linux de 32 bits, por ejemplo, los procesos de usuario podrían tener espacio de direcciones utilizable de 2G – 3G en lugar de más de 4G de RAM total. En los sistemas de 64 bits podría ser inútil verificar el código de retorno malloc , pero podría considerarse una buena práctica de todos modos, y hace que su progtwig sea más portátil. Y, recuerde, desreferenciar el puntero nulo mata su proceso ciertamente; algunos intercambios pueden no doler mucho en comparación con eso.

Si malloc pasa a devolver NULL cuando uno intenta asignar solo una pequeña cantidad de memoria, entonces hay que tener cuidado al intentar recuperarse de la condición de error ya que cualquier malloc posterior también puede fallar, hasta que haya suficiente memoria disponible.

El operador predeterminado de C ++ new es a menudo un contenedor sobre los mismos mecanismos de asignación empleados por malloc() .

En Linux, no puede confiar en que malloc devuelva NULL si no hay suficiente memoria disponible debido a la estrategia de sobreasignación del kernel, pero igual debe verificarlo porque en algunas circunstancias malloc devolverá NULL , por ejemplo, cuando solicita más memoria de la que está disponible en la máquina en total. La página de malloc(3) Linux malloc(3) llama a la sobreasignación “un error realmente malo” y contiene consejos sobre cómo desactivarlo.

Nunca he escuchado sobre este comportamiento que también está ocurriendo en otras variantes de Unix.

En cuanto a los “espasmos de paginación”, eso depende de la configuración de la máquina. Por ejemplo, tiendo a no configurar una partición swap en las instalaciones de laptop de Linux, ya que el comportamiento exacto que teme podría matar el disco duro. Todavía me gustaría que los progtwigs C / C ++ que ejecuto comprueben los valores de retorno de malloc , den los mensajes de error apropiados y, cuando sea posible, limpien ellos mismos.

Verificar la devolución de malloc no le ayuda mucho por sí solo para hacer que sus asignaciones sean más seguras o menos propensas a errores. Incluso puede ser una trampa si esta es la única prueba que implementa.

Cuando se invoca con un argumento de 0 el estándar permite a malloc devolver un tipo de dirección única, que no es un puntero nulo y al que no tiene derecho de acceder, sin embargo. Entonces, si solo prueba si el retorno es 0 pero no prueba los argumentos a malloc , calloc o realloc , puede encontrar un segfault mucho más tarde.

Esta condición de error (memoria agotada) es bastante rara en entornos “alojados”. Por lo general, tienes problemas mucho antes de que te molestes con este tipo de error. (Pero si está escribiendo librerías de tiempo de ejecución, si es un hacker de kernel o un generador de cohetes, esto es diferente, y allí la prueba tiene mucho sentido).

Luego, la gente tiende a decorar su código con capturas complicadas de esa condición de error que abarca varias líneas, haciendo perror y cosas así, que pueden tener un impacto en la legibilidad del código.

Creo que esta “comprobación del retorno de malloc ” está muy sobreestimada, a veces incluso defendida de manera bastante dogmática. Otras cosas son mucho más importantes:

  • siempre inicializar variables, siempre. para las variables de puntero esto es crucial, deje que el progtwig se cuelgue bien antes de que las cosas se pongan feas. los miembros punteros no inicializados en struct s son una causa importante de errores que son difíciles de encontrar.
  • siempre verifique el argumento en malloc y Co. si esto es una constante de tiempo de comstackción como sizof toto no puede haber un problema, pero siempre asegúrese de que su asignación vectorial maneje la caja cero correctamente.

Una cosa fácil de comprobar para el retorno de malloc es terminar con algo como memset(malloc(n), 0, 1) . Esto simplemente escribe un 0 en el primer byte y falla muy bien si malloc tuvo un error o n fue 0 para comenzar.

Para ver esto desde un punto de vista alternativo:

malloc puede devolver un puntero no nulo incluso si la memoria no está realmente disponible” no significa que siempre devuelve un valor no nulo. Puede haber (y habrá) casos en los que se devuelve NULL (como ya se dijo), por lo que este control es necesario.