GNU/Linux >> Tutoriales Linux >  >> Linux

¿Por qué fclose (NULL) de glibc causa una falla de segmentación en lugar de devolver un error?

fclose requiere como argumento un FILE puntero obtenido por fopen , uno de los flujos estándar stdin , stdout o stderr , o de alguna otra forma definida por la implementación. Un puntero nulo no es uno de estos, por lo que el comportamiento no está definido, al igual que fclose((FILE *)0xdeadbeef) sería. NULL no es especial Cía; Aparte del hecho de que está garantizado para comparar no es igual a cualquier puntero válido, es como cualquier otro puntero no válido, y usarlo invoca un comportamiento indefinido excepto cuando la interfaz lo está pasando a los documentos como parte de su contrato que NULL tiene un significado especial.

Además, regresar con un error sería válido (ya que el comportamiento no está definido de todos modos) pero sería un comportamiento dañino para una implementación, porque oculta el comportamiento indefinido . El resultado preferible de invocar un comportamiento indefinido es siempre un bloqueo, porque resalta el error y le permite corregirlo. La mayoría de los usuarios de fclose no verifique si hay un valor de retorno de error, y apuesto a que la mayoría de las personas son lo suficientemente tontas como para pasar NULL a fclose no van a ser lo suficientemente inteligentes como para comprobar el valor de retorno de fclose . Se podría argumentar que las personas deberían verifique el valor de retorno de fclose en general, ya que el vaciado final podría fallar, pero esto no es necesario para archivos que se abren solo para lectura, o si fflush fue llamado manualmente antes de fclose (que es un idioma más inteligente de todos modos porque es más fácil manejar el error mientras aún tiene el archivo abierto).


fclose(NULL) debería triunfar. free(NULL) tiene éxito, porque eso hace que sea más fácil escribir código de limpieza.

Lamentablemente, no es así como se definió. Por lo tanto, no puede usar fclose(NULL) en programas portátiles. (Por ejemplo, consulte http://pubs.opengroup.org/onlinepubs/9699919799/).

Como han mencionado otros, generalmente no desea que se devuelva un error si pasa NULL al lugar equivocado. Desea un mensaje de advertencia, al menos en las compilaciones de depuración/prueba. Eliminar la referencia a NULL le brinda un mensaje de advertencia inmediato y la oportunidad de recopilar un seguimiento que identifica el error de programación :). Mientras está programando, una falla de segmento es el mejor error que puede obtener. C tiene muchos errores más sutiles, que tardan mucho más en depurarse...

Es posible abusar de las devoluciones de error para aumentar la robustez frente a errores de programación. Sin embargo, si le preocupa que un bloqueo del software pueda perder datos, tenga en cuenta que puede ocurrir exactamente lo mismo, p. si su hardware pierde energía. Es por eso que tenemos guardado automático (desde los editores de texto de Unix con nombres de dos letras como ex y vi). Aún sería preferible que su software se bloquee visiblemente, en lugar de continuar con un estado inconsistente.


Los errores de los que habla la página del manual son errores de tiempo de ejecución, no errores de programación. No puedes simplemente pasar NULL en cualquier API que espera un puntero y espera que esa API haga algo razonable. Pasar un NULL puntero a una función documentada para requerir un puntero a datos es un error.

Pregunta relacionada:En C o C++, ¿debo verificar los parámetros del puntero con NULL/nullptr?

Para citar el comentario de R. sobre una de las respuestas a esa pregunta:

... parece estar confundiendo errores que surgen de condiciones excepcionales en el entorno operativo (fs full, out of memory, network down, etc.) con errores de programación. En el primer caso, por supuesto, un programa robusto necesita poder manejarlos con gracia. En este último, un programa robusto no puede experimentarlos en primer lugar.


Linux
  1. ¿Por qué se redirige Stderr a /dev/null de esta manera?

  2. Error de C++:referencia indefinida a 'clock_gettime' y 'clock_settime'

  3. ¿Por qué connect() daría EADDRNOTAVAIL?

  4. La forma más fácil de localizar una falla de segmentación

  5. ¿Por qué algunos programadores del kernel usan goto en lugar de bucles while simples?

Por qué uso exa en lugar de ls en Linux

¿Por qué ve el error:no se encontró el complemento "xyz"?

Linux vs Mac OS:15 razones por las que usar Linux en lugar de Mac OS

Error de segmentación cuando Qt QApplication se creó con new

¿Por qué Slack devuelve una falla de segmentación después de la actualización de Fedora 29?

¿Por qué mi interfaz ethernet se llama enp0s10 en lugar de eth0?