¿Free() establece errno?

7 minutos de lectura

avatar de usuario
Pablo

Si buf es un malloc() búfer de caracteres asignado, no free(buf) establecer/restablecer errno?

Digamos que quiero escribir el búfer en un archivo y luego liberarlo, ya que ya no lo necesito.

Digamos que la política de error para el código es devolver -1 en caso de error.

¿Es esta una forma adecuada de escribir el búfer y la verificación de errores sin perder memoria?

fputs(buf, somefile);
free(buf);
if (errno) return -1;

¿O debo considerar la posibilidad de establecer libremente errno, como en…

fputs(buf, somefile);
if (errno){ 
    free(buf);
    return -1;
}
free(buf);

o, horror de los horrores,

do { 
  fputs(buf, somefile);
  int save_errno = errno;
  free(buf);
  errno = save_errno;
  if (errno) return -1;
} while(0);  

donde el uso de un bloque permite que exista un save_errno local en varios lugares en caso de que sea necesario reutilizarlo.

Todo esto parecería depender de si free() establece errno.

los página de manual de linux gratis () es también la página del manual para malloc()etc. Menciona malloc() configurando errno, pero no free().

los Página del manual de GNU C Library para liberar memoria dinámica no menciona si free() establece errno.

Así que escribí un programa corto para forzar un error de escritura para poder ver si free() reset errno, y no lo hace. Me pregunto si debería confiar en este resultado y en el hecho de que free() es tan esencial que “por supuesto que no establece errno”.

# See if free() resets errno on a bad write
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
  char * buf = malloc(256);
  snprintf(buf,256,"%s\n", "Hello, World!");

  FILE *badfile;

  badfile = fopen("/dev/null","r");

  fputs(buf, badfile);
  free(buf);
  printf("%d\n", errno);
  printf("%s\n", strerror(errno));
}

  • A una buena referencia debería ayudar.

    – Un tipo programador

    1 de junio de 2015 a las 9:32

  • Asimismo, el valor de errno no está definido después de llamar a funciones que no lo configuran explícitamente, y eso incluye llamadas a funciones que no fallan. En otras palabras, no verifique errno a menos que el anterior la llamada falló explícitamente.

    – Un tipo programador

    1 de junio de 2015 a las 9:34

  • “Mal uso” de freecomo intentar liberar el mismo puntero dos veces, no tener estrellarse, es simplemente indefinido. Aunque el comportamiento indefinido en muchos casos conduce a bloqueos.

    – Un tipo programador

    1 de junio de 2015 a las 9:35


  • pubs.opengroup.org/onlinepubs/9699919799/functions/…

    – Werner Henze

    1 de junio de 2015 a las 11:17

  • No es necesario recurrir a un do {...} while(0); construir, también puede crear bloques con llaves simples {...}.

    – Quintín

    1 de junio de 2015 a las 12:38

avatar de usuario
Sander De Dycker

POSIX no define free establecer errno (aunque POSIX actualmente no lo prohíbe, por lo que una implementación podría hacerlo; consulte la respuesta de @ArjunShankar para obtener más detalles). Pero eso no es realmente relevante para su preocupación.

La forma en que está comprobando los errores es incorrecta. Debe comprobar el valor de retorno de fputsy compruebe si es más pequeño que 0. Si es así, entonces puedes comprobar errno para averiguar qué causó la falla, pero eso es opcional (y debe hacerse antes de llamar a otras funciones).

Entonces, algo como esto debería hacer el truco:

int result = fputs(buf, somefile);
/* optionally read errno here if result < 0 (before the free call) */
free(buf);
return (result < 0) ? -1 : 0;

  • Cita relevante de la errno página man: Its value is significant only when the return value of the call indicated an error (i.e., -1 from most system calls; -1 or NULL from most library functions); a function that succeeds is allowed to change errno.

    – Marca

    1 de junio de 2015 a las 23:06

  • @Mark: Dato curioso: logré observar eso execvp() cambios errno sobre el éxito

    – Josué

    5 sep 2021 a las 20:44

avatar de usuario
ArjunShankar

Un compatible con POSIX free podría establecer errno Este Dia pero esto va a cambiar para mejor en el futuro. Detalles:

  1. los The Open Group Base Especificaciones Edición 7 definicion de errno establece lo siguiente:

Ninguna función en este volumen de POSIX.1-2008 establecerá errno en 0. La configuración de errno después de una llamada exitosa a una función no se especifica a menos que la descripción de esa función especifique que errno no se modificará.

  1. La definición de free en sí no especifica qué free hace con errno.

Lo que esto significa es que un compatible free la implementación nunca se restablecerá errno a 0. Pero puede o no establecerlo en un valor distinto de cero.

Sin embargo, el número 8 (un trabajo en progreso) de la especificación requerir free para garantizar específicamente que no establecerá errno cuando se pasa una entrada válida.

glibc ya se está preparando para cumplir con este nuevo requisito.

  • ¿Bajo qué circunstancias podría liberar establecer errno cuando se pasa una entrada válida?

    – Aleatorio832

    1 de junio de 2015 a las 12:34

  • @ Random832 Eso dependería de la implementación. Tal vez algunos no se tocan errno. Mire el informe de error de glibc (pero para ser claros, esto aún no es un error, ya que POSIX aún no se ha revisado) al que vinculé en la última línea de mi respuesta, para obtener detalles sobre cómo puede suceder en la implementación de glibc de free.

    – ArjunShankar

    1 de junio de 2015 a las 12:41


  • @Random832 Imagine una implementación malloc/free que intentara reducir el montón cuando fuera posible, utilizando llamadas al sistema adecuadas al sistema operativo subyacente, por ejemplo, mmap(), sbrk(), etc. Si estas llamadas al sistema fallan, se establecería errno.

    – Kyle Jones

    1 de junio de 2015 a las 16:43

  • @ Random832, es perfectamente válido que una función se establezca incondicionalmente errno al error más común y luego use el valor de retorno para indicar si realmente ocurrió ese error.

    – cjm

    1 jun 2015 a las 19:45

avatar de usuario
Vlad de Moscú

No se dice nada sobre errno en la descripción de free en el Estándar C. Por lo tanto, no puede confiar en esta característica.

Según el Estándar C (7.5 Errores <errno.h>)

3… El valor de errno puede establecerse en distinto de cero mediante una llamada de función de biblioteca, haya o no un error, siempre que el uso de errno no esté documentado en la descripción de la función en esta Norma Internacional.

y el uso de errno no está documentado en la descripción de free en el C Standard como ya he dicho anteriormente.

avatar de usuario
molbdnilo

Si la referencia no dice que una función devuelve un código de error en errno en caso de falla, no lo hará.

Funciones que configuran errno a un código de error (casi) siempre señalan de otra manera que errno contiene el código de error actual: las funciones de asignación de memoria regresan NULLmuchas otras funciones devuelven cero o un número negativo, y así sucesivamente.
Estas funciones no son necesarias para modificar errno de ninguna manera si tienen éxito, y por lo general no lo hacen.

Por lo general, no puede inspeccionar errno para determinar si algo salió mal; solo está destinado a recuperar más información una vez que sepa que ha habido un error.

Una excepción a la regla final es la strto{l, d, ul} familia, pero el primer párrafo también es válido para ellos.
Y tampoco necesariamente establecen errno excepto cuando fallan, por lo que primero debe borrarlo o puede contener un código de error obsoleto.

Sí, free() puede bloquear el error en varios sistemas. gnulib evita este problema reemplazando free() en dichas plataformas, que actualmente documenta como: “glibc 2.32, Mac OS X, FreeBSD, NetBSD, OpenBSD 4.4, Minix, AIX, HP-UX, IRIX, Cygwin, mingw, MSVC”

avatar de usuario
usuario4531555

puede usar RAII para liberar memoria mallocada y verificar el valor de retorno de fputs. Ese será el código de gracia.

//if malloc successfully
AutoFree af(buf);
if (fputs(buf, somefile)) {
LOG("something err:%s", strerror(errno));
}
return 0;

¿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