Regla 0x7004h: No llamés exit() en funciones de biblioteca: propagá el error
Robustez y manejo de errores (0x70XX)
0x7004h: No llamés exit() en funciones de biblioteca: propagá el error¶
Enunciado normativo¶
Las funciones de biblioteca o de módulo NO DEBEN terminar el proceso con
exit()niabort()ante un error. DEBEN informar el fallo mediante su valor de retorno (o un parámetro de salida) y dejar que el llamador decida cómo reaccionar. Sólomain(o una función de nivel de aplicación documentada) puede terminar el proceso.
¿Por qué existe esta regla?¶
El problema¶
Una función de biblioteca que llama a exit() le quita el control al
llamador. Ese llamador podría haber querido reintentar, informar el error,
liberar recursos o seguir procesando otros datos; en cambio, el proceso muere
sin posibilidad de respuesta.
Además, exit() cierra el programa sin devolver la memoria ni cerrar
recursos de forma ordenada en todos los casos, y vuelve a la función
imposible de probar de forma aislada: cualquier test que dispare el error
mata al proceso de pruebas.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Testabilidad | No se puede probar el camino de error sin terminar el test. |
| Reutilización | La función sólo sirve para un programa que siempre aborta. |
| Recursos | Se pierden datos sin guardar y recursos abiertos. |
| Diseño | Se mezcla la política de la aplicación con la lógica del módulo. |
Fundamento en la cátedra¶
Separa la capa de biblioteca (que informa) de la capa de aplicación (que decide). Se apoya en 0x7003h: No ignores valores de retorno que pueden indicar fallo (verificar y propagar retornos) y en 0x2005h: Cada función debe tener una única responsabilidad (Principio de Responsabilidad Única) (responsabilidad única).
Alcance y excepciones¶
Aplica a funciones de módulos y TDAs. exit() es aceptable únicamente en
main o en una rutina de arranque documentada, y ante condiciones
irrecuperables explícitas. En un TAD, jamás.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — El TAD decide abortar¶
pila_t *pila_crear(size_t capacidad)
{
pila_t *p = malloc(sizeof(*p));
if (p == NULL) {
fprintf(stderr, "Sin memoria\n");
exit(EXIT_FAILURE);
}
/* ... */
return p;
}Por qué falla: la pila no puede crearse y mata todo el proceso. El llamador no puede informar el error de otra forma ni continuar sin pila.
❌ Contraejemplo 2 — Validación que aborta¶
void pila_apilar(pila_t *p, int valor)
{
if (pila_llena(p)) {
fprintf(stderr, "Pila llena\n");
exit(EXIT_FAILURE);
}
/* ... */
}Por qué falla: apilar en una pila llena es una condición previsible que el programa de aplicación podría manejar (descartar, avisar, redimensionar), pero el TAD decide por él.
✅ Ejemplo conforme 1 — Retornar el error¶
pila_t *pila_crear(size_t capacidad)
{
pila_t *p = malloc(sizeof(*p));
if (p == NULL) {
return NULL;
}
/* ... */
return p;
}El llamador decide si aborta, avisa o reintenta.
✅ Ejemplo conforme 2 — Estado de retorno¶
typedef enum {
PILA_OK,
PILA_LLENA,
PILA_VACIA
} pila_resultado_t;
pila_resultado_t pila_apilar(pila_t *p, int valor)
{
if (pila_llena(p)) {
return PILA_LLENA;
}
/* ... */
return PILA_OK;
}main traduce el estado a un mensaje y decide la salida:
if (pila_apilar(p, valor) != PILA_OK) {
fprintf(stderr, "No se pudo apilar\n");
pila_destruir(p);
return EXIT_FAILURE;
}⚠️ Casos límite¶
Condiciones irrecuperables: quedarse sin memoria para una estructura global de arranque puede justificar
exit()enmain, documentado.assert: aborta en fallos de programación (no de entrada), y está pensado para depuración; no es una alternativa aexit()en producción.Manejo de errores en
main: es el lugar natural para reportar y terminar.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
grep | buscar exit(/abort( fuera de main | Llamadas en módulos. |
cppcheck | cppcheck archivo.c | Uso de exit en bibliotecas. |
Checklist de autocontrol¶
¿Mi función de módulo termina el proceso por su cuenta?
¿Puedo probar el camino de error sin matar el test?
¿El error se informa por retorno o parámetro de salida?
¿Sólo
maindecide la política de salida?
Reglas relacionadas¶
0x4003h: Utilizá errno, perror y strerror para reportar fallos del sistema operativo de manera precisa — reporte preciso de errores.
0x7003h: No ignores valores de retorno que pueden indicar fallo — propagación de retornos.
0x2005h: Cada función debe tener una única responsabilidad (Principio de Responsabilidad Única) — responsabilidad única del módulo.
0x2007h: Los valores de retorno numéricos deben definirse como constantes de preprocesador o enums — códigos de retorno como constantes o
enum.