¿Puedo confiar en que malloc devuelva NULL?

8 minutos de lectura

avatar de usuario
fredodesbordamiento

Leí eso 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 adelante generará un error. Dado que no puedo detectar un error de este tipo al verificar NULL, me pregunto qué tan útil es verificar NULL.

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 a malloc ¿así como?

  • Creo que no deberías usar malloc en C++: stackoverflow.com/questions/184537/…

    – lc2817

    30/10/2011 a las 21:15

  • @ lc2817 solo debe usar malloc si está escribiendo código con una interfaz C (es decir, funciones que se usarán desde C pero escritas en C ++) y el código C se encarga de liberar esa memoria.

    usuario142019

    30/10/2011 a las 21:17

  • @WTP gracias por esta precisión. Aunque, no sé si es el caso aquí.

    – lc2817

    30/10/2011 a las 21:21

  • @Dror K., no entiendo el propósito de la recompensa y una búsqueda rápida en Google no ayudó. La pregunta ya tiene una respuesta, ¿significa que está buscando otra respuesta mejorada?

    – gsamaras

    30 de enero de 2016 a las 21:21

  • @gsamaras Hola, seleccioné la opción que indica que una respuesta existente es digna de una recompensa. Entonces, la respuesta a su pregunta es que me gustaría recompensar una respuesta existente y no estoy buscando una nueva.

    – Dror K.

    30 de enero de 2016 a las 21:24

avatar de usuario
Antti Haapala — Слава Україні

citando manuales de linux:

De forma predeterminada, Linux sigue una estrategia de asignación de memoria optimista. Esto significa que cuando malloc() devuelve no-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 eliminará uno o más procesos. En caso de que Linux se emplee en circunstancias en las que sería menos deseable perder repentinamente algunos procesos elegidos al azar y, además, la versión del kernel es lo suficientemente reciente, se puede desactivar este comportamiento de compromiso excesivo mediante un comando como:

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

Deberías comprobar NULL volver, 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 pueden tener un espacio de direcciones utilizable de 2G – 3G en lugar de más de 4G de RAM total. En los sistemas de 64 bits, puede ser inútil comprobar el malloc código de retorno, pero podría considerarse una buena práctica de todos modos, y hace que su programa sea más portátil. Y, recuerde, la desreferenciación del puntero nulo ciertamente mata su proceso; un poco de intercambio podría no doler mucho en comparación con eso.

Si malloc sucede volver NULL cuando uno intenta asignar solo una pequeña cantidad de memoria, debe tener cuidado al intentar recuperarse de la condición de error como cualquier otra posterior. malloc también puede fallar, hasta que haya suficiente memoria disponible.

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

  • +1 por citar una buena diatriba sobre cómo es el valor predeterminado de Linux roto. Un buen programa siempre debe comprobar el valor de retorno de malloc. Si el usuario configuró mal su sistema (o lo dejó en una configuración predeterminada rota), entonces, por supuesto, esto puede no ayudar, pero no hay nada que pueda hacer y el bloqueo está fuera de su responsabilidad. Pero si no verifica el valor de retorno de mallocsu programa alcanzará el punto de equilibrio cuando se ejecute en sistemas donde el usuario/administrador realmente se preocupa por la corrección y ha deshabilitado la sobreasignación. El usuario entonces probablemente considerará que tu programa es una basura. 🙂

    – R.. GitHub DEJA DE AYUDAR A ICE

    30/10/2011 a las 21:54

  • Bueno, la verdad es un poco más complicada que eso. Hay agujeros en el espacio de direcciones del proceso; por ejemplo, es posible que el programa nunca toque todas las páginas en BSS, o cambie una página que está asignada en el segmento de datos. Un compromiso insuficiente suele ser un problema mayor en un sistema de escritorio/servidor que un compromiso excesivo. Y la partición de intercambio, si está habilitada, también proporciona algo de protección antes de que las cosas se pongan realmente mal.

    – Antti Haapala — Слава Україні

    30 de octubre de 2011 a las 22:02


  • Estoy en desacuerdo. Undercommit no es un problema porque siempre puedes lanzar más swap. En cualquier caso, si tiene páginas bss/data intactas, eso significa que tiene variables globales (no solo GOT/PLT allí), lo cual es un problema mayor. 🙂 Tal vez sean necesarios algunos, pero más de una página o dos es casi seguro que indica problemas de diseño…

    – R.. GitHub DEJA DE AYUDAR A ICE

    31 de octubre de 2011 a las 1:39

  • Sistema amigable para novatos 😉 La única vez que tuve que lidiar con OOM killer habría sido un proceso fuera de control que de todos modos detuvo el sistema por intercambio.

    – Antti Haapala — Слава Україні

    31 de octubre de 2011 a las 10:18

avatar de usuario
fred foo

En Linux, de hecho, no puede confiar en malloc regresando NULL si no hay suficiente memoria disponible debido a la estrategia de sobreasignación del kernel, pero aun así debe comprobarlo porque en algunas circunstancias malloc voluntad regreso NULL, por ejemplo, cuando solicita más memoria de la que está disponible en la máquina en total. el linux malloc(3) manpage llama a la sobreasignación “un error realmente malo” y contiene consejos sobre cómo apagarlo.

Nunca escuché que este comportamiento también ocurra 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 de intercambio en las instalaciones de Linux en una computadora portátil, ya que el comportamiento exacto que temes podría dañar el disco duro. Todavía me gustaría que los programas C/C++ que ejecuto verifiquen malloc devolver valores, dar mensajes de error apropiados y, cuando sea posible, limpiar después de ellos mismos.

  • El exceso de compromiso no es ni una característica ni un error, estrictamente hablando. Fue solo pereza histórica: comprometerse en exceso es mucho más fácil implementar que contabilizar el cargo de compromiso. Presumiblemente, algunas personas se acostumbraron y les gustó (por las razones perversas que sean) y algunos incluso comenzaron a escribir programas que malloc 1 gb como una matriz dispersa e incluso cosas más perversas, por lo que ahora nos quedamos con que esté activado de forma predeterminada…

    – R.. GitHub DEJA DE AYUDAR A ICE

    31 de octubre de 2011 a las 1:41

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

Cuando se llama con un argumento de 0 la norma permite malloc para devolver una especie de dirección única, que no es un puntero nulo y, sin embargo, no tiene derecho a acceder. Entonces, si solo prueba si el retorno es 0 pero no pruebes los argumentos para malloc, calloc o realloc es posible que encuentre una falla de segmento mucho más tarde.

Esta condición de error (memoria agotada) es bastante rara en entornos “alojados”. Por lo general, está en problemas mucho antes de molestarse con este tipo de error. (Pero si está escribiendo bibliotecas de tiempo de ejecución, es un pirata informático del kernel o un constructor 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 abarcan varias líneas, haciendo perror y cosas así, que pueden tener un impacto en la legibilidad del código.

Creo que esto de “verificar la devolución de malloc” está muy sobreestimado, a veces incluso defendido 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 programa se bloquee bien antes de que las cosas se pongan demasiado mal. miembros de puntero no inicializados en structLos s son una causa importante de errores que son difíciles de encontrar.
  • Siempre verifique el argumento para malloc and Co. si se trata de una constante de tiempo de compilación como sizof toto no puede haber un problema, pero siempre asegúrese de que su asignación de vectores maneje el caso cero correctamente.

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

  • Digamos que es mucho mejor decirle al usuario “Fuera del montón en la línea foo” que simplemente “excepción de puntero nulo en la barra”; para ello sería suficiente un envoltorio simple (¿macro?) para malloc. Esto en caso de que uno use cantidades ridículas de memoria y pueda esperar usar más de 2G en sistemas de 32 bits.

    – Antti Haapala — Слава Україні

    31 de octubre de 2011 a las 8:24

Para ver esto desde un punto de vista alternativo:

malloc puede devolver un puntero no NULL incluso si la memoria no está realmente disponible” no significa que siempre devuelva no NULL. Puede haber (y habrá) casos en los que se devuelva NULL (como ya dijeron otros), por lo que esta verificación es necesario sin embargo.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad