Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Regla 0x7003h: No ignores valores de retorno que pueden indicar fallo

Robustez y manejo de errores (0x70XX)

Universidad Nacional de Río Negro

0x7003h: No ignores valores de retorno que pueden indicar fallo

Enunciado normativo

Todo valor de retorno de una función que pueda señalar un fallo (error, valor centinela, puntero NULL, conteo inesperado) DEBE ser examinado. Si el retorno no se puede manejar localmente, DEBE propagarse explícitamente; NO DEBE descartarse en silencio.

¿Por qué existe esta regla?

El problema

C expresa los errores por valor de retorno, no por excepciones. Cuando el retorno se ignora, el error se convierte en un dato inválido que circula silenciosamente hasta causar un fallo lejano, difícil de atribuir a su causa.

El descarte de retornos es además una de las fuentes más comunes de vulnerabilidades: una asignación de memoria fallida, una lectura truncada o una escritura parcial ignoradas derivan en desreferencias nulas y desbordamientos.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
Comportamiento indefinidoDesreferenciar un malloc que retornó NULL.
Datos corruptosUna lectura parcial se trata como completa.
Fallo tardíoEl error aparece lejos del punto que lo originó.
SeguridadEscrituras parciales silenciadas comprometen la integridad.

Fundamento en la cátedra

Es la regla general que las reglas 0x4002h, 0x3001h y 0x4008h aplican a casos concretos. El compilador colabora: -Wunused-result advierte cuando se descarta un retorno declarado warn_unused_result.

Alcance y excepciones

Aplica a funciones de biblioteca y a funciones propias que devuelvan un estado. No es obligatorio examinar retornos que por contrato nunca fallan (printf puede fallar, pero en el curso se admite ignorarlo en salida estándar) ni los de funciones de notificación sin efecto. La clave es documentar cuándo un retorno puede ignorarse.

Ejemplos exhaustivos

❌ Contraejemplo 1 — malloc ignorado

nodo_t *nuevo = malloc(sizeof(*nuevo));
nuevo->dato = valor;
nuevo->sig = lista;

Por qué falla: si la memoria se agota, malloc retorna NULL y el acceso a nuevo->dato desreferencia un puntero nulo. Viola 0x3001h: Siempre verificá la asignación exitosa de memoria dinámica.

❌ Contraejemplo 2 — Lectura ignorada

fread(buffer, sizeof(int), cantidad, archivo);
procesar(buffer, cantidad);

Por qué falla: fread puede leer menos elementos (fin de archivo o error). Procesar cantidad elementos usa datos no inicializados.

✅ Ejemplo conforme 1 — Verificación y propagación

nodo_t *nuevo = malloc(sizeof(*nuevo));
if (nuevo == NULL) {
    return NULL;
}

nuevo->dato = valor;
nuevo->sig = lista;

El fallo se detecta donde ocurre y se propaga como NULL, dejando la decisión al llamador.

✅ Ejemplo conforme 2 — Lectura verificada

size_t leidos = fread(buffer, sizeof(int), cantidad, archivo);
if (leidos != cantidad) {
    if (ferror(archivo)) {
        perror("fread");
    }
    return ERROR_LECTURA;
}

procesar(buffer, leidos);

Se usa el conteo real y se distingue error de fin de archivo.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gccgcc -Wall -Wextra-Wunused-result.
cppcheckcppcheck archivo.cRetornos ignorados.
kanedaauditoría de seguridadDescarto de retornos de funciones críticas.

Checklist de autocontrol

Reglas relacionadas

Antipatrón: Descarte del valor retornado por funciones de conversión numérica

Síntoma en el código del estudiante

Llamadas a strtol, atoi, strtod o scanf cuyo resultado se ignora, o que se usan sin comprobar errno ni el puntero endptr. El programa “lee el número” pero no distingue una cadena válida de una basura.

Diagnóstico

Mecanismo del defecto

strtol convierte la mayor cantidad posible de caracteres y deja de leer en el primer carácter inválido. Si la cadena empieza con letras, devuelve 0 y el llamador cree que el usuario ingresó un cero. Si el número excede el rango de long, la función satura en LONG_MAX o LONG_MIN y activa errno = ERANGE; si ese error se ignora, el valor saturado se usa como si fuera real.

El descarte del retorno es el mismo defecto que ignorar el de main: se tira información que el sistema puso a disposición. La regla 0x2012h: Tipo de retorno obligatorio ‘int’ en la función main() recuerda que el canal de retorno es la forma de reportar el resultado de la operación; acá ese canal es la tupla (valor, endptr, errno).

Consecuencia observable

Entradas inválidas se aceptan como cero o como el valor saturado, y el programa continúa con datos corruptos. No hay error de compilación; la falla es silenciosa y depende de la entrada.

Fundamento en el estándar C11

C11 declara strtol, strtoll, strtod y familia en <stdlib.h> (§7.22.1). La norma especifica que, si el valor no es representable, se devuelve LONG_MAX/LONG_MIN/LONG_LONG_MAX/LONG_LONG_MIN y se asigna ERANGE a errno (§7.22.1.4). También define errno en <errno.h> (§7.5). Corresponde al llamador decidir el comportamiento ante el error; ignorar el retorno es descartar la parte explícita del contrato de la función.

Corrección idiomática

❌ Código con el antipatrón
strtol(cadena, NULL, 10);
✅ Código refactorizado
#include <errno.h>
#include <limits.h>
#include <stdlib.h>

int convertir(const char *cadena, long *resultado)
{
    if (cadena == NULL || resultado == NULL) {
        return ERROR_PUNTERO_NULO;
    }

    char *endptr = NULL;
    errno = 0;
    long valor = strtol(cadena, &endptr, 10);

    if (endptr == cadena || *endptr != '\0') {
        return ERROR_FORMATO;
    }
    if (errno == ERANGE) {
        return ERROR_RANGO;
    }

    *resultado = valor;
    return OK;
}

Se verifica que la conversión haya consumido toda la cadena (*endptr == '\0'), que no esté vacía (endptr != cadena) y que no haya habido ERANGE. El llamador recibe un código de error con nombre simbólico (0x2007h: Los valores de retorno numéricos deben definirse como constantes de preprocesador o enums).

Errores típicos al compilar o ejecutar

# No hay error de compilación.
$ ./programa
Ingrese un numero: abc
Usted ingreso: 0        # el 0 viene del error, no de la entrada
$ ./programa
Ingrese un numero: 999999999999999999999999
Usted ingreso: 9223372036854775807   # valor saturado por ERANGE

Checklist de verificación

Reglas relacionadas