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 0x200Bh: Prohibición de retornar la dirección de una variable local de stack

Funciones, contratos y modularizacion (0x20XX)

Universidad Nacional de Río Negro

0x200Bh: Prohibición de retornar la dirección de una variable local de stack

Enunciado normativo

NO DEBE devolverse la dirección de una variable automática (&local) ni de un arreglo local. Si la función debe entregar memoria, DEBE reservarla en el heap con malloc/calloc y documentar quién la libera.

¿Por qué existe esta regla?

El problema

Las variables locales viven en el marco de pila y mueren cuando la función retorna. Devolver su dirección produce un puntero colgante: el número sigue existiendo, pero el objeto apuntado ya no está vivo, y desreferenciarlo es comportamiento indefinido.

Lo engañoso es que a menudo “funciona”: el valor viejo sigue ahí hasta que otra llamada pisa el marco. El fallo aparece tarde, como bug intermitente.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
Comportamiento indefinidoDesreferenciar el puntero es UB según §6.2.4 y §6.5.3.2.
Bug intermitenteEl valor “correcto” sobrevive hasta que otra función pisa el marco.
SeguridadUn atacante puede controlar el contenido de la pila reutilizada.

Fundamento en el estándar y en la cátedra

C11 establece que la duración de un objeto automático termina al salir del bloque (§6.2.4). Acceder a él por puntero después es comportamiento indefinido, y la norma incluye el uso de una dirección cuya vida terminó (§6.5.3.2). La cátedra lo prohíbe: si el dato debe sobrevivir, se reserva en el heap (0x3001h: Siempre verificá la asignación exitosa de memoria dinámica) o se copia al llamador.

Alcance y excepciones

Cubre cualquier retorno por puntero hacia un objeto local, incluidos:

Excepción legítima: devolver un puntero a un objeto con duración estática (static o global) es válido respecto de la vida útil, pero prohibido por 0x2004h: No se permite el uso de variables globales por el estado compartido. Devolver memoria de malloc es la solución correcta.

Ejemplos exhaustivos

❌ Contraejemplo 1 — Retorno de dirección local

int *crear_valor(void)
{
    int x = 10;
    return &x;
}

Por qué falla: x vive en el marco de crear_valor; al retornar, el marco se destruye y el llamador recibe una dirección que la próxima llamada reutilizará.

❌ Contraejemplo 2 — Retorno de arreglo local

char *nombre_por_defecto(void)
{
    char buffer[32] = "sin nombre";
    return buffer;
}

Por qué falla: buffer decae a char * y se devuelve la dirección de la pila local. Aunque la cadena sea válida un instante, ya no lo es al volver. Es un error clásico que el compilador suele advertir con -Wreturn-local-addr.

✅ Ejemplo conforme 1 — Reserva en el heap con propiedad documentada

/**
 * @brief Crea un valor inicializado en 10.
 * @return Puntero a un int en el heap, o NULL si falla malloc.
 * @post El llamador es dueño del bloque y debe liberarlo con free().
 */
int *crear_valor(void)
{
    int *p = malloc(sizeof(*p));
    if (p == NULL) {
        return NULL;
    }
    *p = 10;
    return p;
}

La memoria sobrevive a la función y el contrato dice quién la libera. La reserva usa sizeof(*p), conforme a 0x300Bh: Usá siempre sizeof en las asignaciones de memoria dinámica, prefiriendo sizeof(*ptr).

✅ Ejemplo conforme 2 — Copia al búfer del llamador

int copiar_por_defecto(char *destino, size_t cap)
{
    if (destino == NULL || cap == 0) {
        return ERROR_PUNTERO_NULO;
    }

    const char *origen = "sin nombre";
    if (strlen(origen) + 1 > cap) {
        return ERROR_ESPACIO;
    }

    strcpy(destino, origen);
    return OK;
}

El llamador aporta el almacenamiento; la función solo escribe en él. No hay memoria que sobreviva a un marco destruido.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gcc / clanggcc -Wall -Wextra -Wreturn-local-addr -std=c11 ...“function returns address of local variable”.
gaffgaff check archivo.creturn &local; o retorno de arreglo local.

Checklist de autocontrol

Reglas relacionadas