c error-handling shared-libraries signals errno

¿Debería mi biblioteca manejar SIGSEGV en la entrada de un puntero malo?



error-handling shared-libraries (6)

Estoy escribiendo una pequeña biblioteca que toma un puntero ARCHIVO * como entrada.

Si reviso inmediatamente este puntero ARCHIVO * y descubro que conduce a una segfault, ¿es más correcto manejar la señal, establecer errno y salir con gracia? o para no hacer nada y usar el controlador de señal instalado del llamador, si tiene uno?

La sabiduría prevaleciente parece ser "las bibliotecas nunca deberían causar un bloqueo". Pero mi pensamiento es que, dado que esta señal particular es ciertamente culpa de quien llama, entonces no debería intentar ocultarle esa información. Es posible que tenga su propio controlador instalado para reaccionar al problema a su manera. La misma información PUEDE recuperarse con errno, pero la disposición predeterminada para SIGSEGV fue establecida por una buena razón, y pasar la señal respeta esta filosofía al forzar a la persona que llama a manejar sus errores, o al estrellarse y protegerlo de daños mayores. .

¿Estaría de acuerdo con este análisis o ve alguna razón convincente para manejar SIGSEGV en esta situación?


La sabiduría prevaleciente parece ser "las bibliotecas nunca deberían causar un bloqueo".

No sé de dónde sacaste eso: si pasan un puntero no válido, deberías colgar. Cualquier biblioteca lo hará.


Esta es una pregunta subjetiva, y posiblemente no apta para SO, pero presentaré mi opinión:

Piénselo de esta manera: si tiene una función que toma una cadena char * terminada en char * y está documentada como tal, y la persona que llama pasa una cadena sin el terminador nulo, ¿debería captar la señal y abofetear a la persona que llama en la muñeca? ¿O debería dejar que se bloquee y hacer que el programador incorrecto con su API corrija su código?

Si su código toma un puntero FILE * y su documentación dice "pase cualquier FILE * abierto FILE * ", y pasan un objeto FILE * cerrado o invalidado, han roto el contrato. La comprobación de este caso ralentizaría el código de las personas que usan correctamente su biblioteca para acomodar a las personas que no lo hacen, mientras que dejar que se cuelgue mantendrá el código lo más rápido posible para las personas que lean la documentación y escriban un buen código.

¿Espera que alguien que pasa un puntero inválido FILE * compruebe y maneje correctamente un error? ¿O es más probable que continúen ciegamente, causando otro choque más tarde, en cuyo caso el manejo de este bloqueo puede disfrazar el error?


Hacerse cargo de los manipuladores no es un asunto de la biblioteca, diría que es algo ofensivo a menos que se lo pida explícitamente. Para minimizar los bloqueos, la biblioteca puede validar su entrada en cierta medida. Más allá de eso: basura en la basura.


Los kernels no deberían bloquearse si les das un puntero malo, pero las bibliotecas probablemente deberían hacerlo. Eso no significa que no debe hacer ninguna comprobación de errores; un buen programa muere inmediatamente ante datos irracionalmente malos. Preferiría que una biblioteca llamara a fianza con assert (f! = NULL) que simplemente seguir adelante y, finalmente, desreferenciar el puntero NULL.


Consideraría razonable verificar el caso especial de un puntero NULL . Pero más allá de eso, si pasan basura, violaron el contrato de la función y se estrellan.


Lo sentimos, pero las personas que dicen que una biblioteca debe fallar son simplemente perezosas (quizás en tiempo de consideración, así como en esfuerzos de desarrollo). Las bibliotecas son colecciones de funciones. El código de la biblioteca no debería "simplemente bloquearse" más de lo que otras funciones en su software deberían "simplemente colapsar".

Por supuesto, las bibliotecas pueden tener algunos problemas sobre cómo pasar los errores a través de los límites de la API, si varios lenguajes o funciones de lenguaje (relativamente) exóticas como excepciones normalmente estarían involucradas, pero no hay nada demasiado especial al respecto. En realidad, es solo parte de la carga de escribir bibliotecas, a diferencia del código en la aplicación.

Excepto donde realmente no se puede justificar la sobrecarga, cada interfaz entre sistemas debe implementar la comprobación de la cordura, o mejor, el diseño por contrato, para evitar problemas de seguridad, así como errores.

Hay varias maneras de manejar esto. Lo que probablemente debería hacer, en orden de preferencia, es uno de los siguientes:

  1. Utilice un lenguaje que admita excepciones (o mejor, diseño por contrato) dentro de las bibliotecas, e incluya una excepción o permita que el contrato falle.

  2. Proporcione un mecanismo de gestión de errores / ranura / gancho / devolución de llamada, y llame a cualquier controlador registrado. Requerir que, cuando se inicialice su biblioteca, se registre al menos un controlador de errores.

  3. Soporte para devolver algún código de error en cada función que podría fallar, por cualquier motivo. Pero esta es la forma antigua y relativamente loca de hacer cosas desde C (en oposición a C ++) días.

  4. Establezca algunos valores globales "se ha producido un error en el indicador", y permita borrar ese indicador antes de las llamadas. Esto también es antiguo y completamente loco, principalmente porque traslada la carga del mantenimiento del estado de error a la persona que llama, Y no es seguro cuando se trata de enhebrar.