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 0x300Ch: Verificá siempre los límites de los arreglos antes de acceder a sus elementos

Memoria, punteros y tipos (0x30XX)

Universidad Nacional de Río Negro

0x300Ch: Verificá siempre los límites de los arreglos antes de acceder a sus elementos

Enunciado normativo

Todo acceso a un elemento de arreglo DEBE estar precedido por la verificación de que el índice está dentro de [0, cantidad). La verificación DEBE usar el mismo tipo sin signo que la cantidad (size_t) y NO DEBE confiar en que el llamador envió un índice válido.

¿Por qué existe esta regla?

El problema

En C, arreglo[i] es azúcar para *(arreglo + i): el lenguaje no comprueba el índice ni en compilación ni en ejecución. Un índice fuera de rango lee o escribe memoria vecina y el resultado va desde un dato incorrecto hasta un SIGSEGV o una vulnerabilidad explotable. La validación convierte el acceso inválido en una decisión controlada y es responsabilidad de la función, no del llamador.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
Comportamiento indefinidoAcceso fuera de límites (C11 §6.5.6 no da garantías).
CorrupciónEscritura en memoria vecina que altera otras variables o el heap.
SeguridadDesbordamiento de buffer explotable.

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

C11 §6.5.6 regula la aritmética de punteros: sólo está definida dentro del mismo objeto arreglo, y un punto más allá del final. Cualquier índice mayor es comportamiento indefinido. La cátedra exige la validación explícita junto con 0x3010h: Las variables que representan tamaños o índices de arreglos deben ser de tipo size_t: si la cantidad es size_t, comparar contra un índice int puede fallar por conversiones de signo.

Alcance y excepciones

Aplica a accesos indexados v[i] y a aritmética de punteros p + i. No aplica a arreglos cuyo índice está garantizado por construcción, como el recorrido canónico for (size_t i = 0; i < cantidad; i++), donde la propia condición del lazo es la verificación. Tampoco exime de validar entradas que provienen del usuario, de archivos o de parámetros.

Ejemplos exhaustivos

❌ Contraejemplo 1 — Índice del llamador sin validar

void guardar(int valores[], size_t cantidad, int indice, int nuevo)
{
    valores[indice] = nuevo;
}

Por qué falla: indice puede ser cualquier cosa, incluido un valor mayor o igual a cantidad. La función escribe fuera del arreglo. El contrato debe validar indice < cantidad o documentar la precondición y confiar en el llamador, pero la cátedra prefiere la validación explícita.

❌ Contraejemplo 2 — Off-by-one en la condición del lazo

for (int i = 0; i <= cantidad; i++)
{
    suma += valores[i];
}

Por qué falla: la condición i <= cantidad permite i == cantidad, un punto más allá del último elemento válido. La iteración final lee memoria ajena. El error es particularmente peligroso porque el lazo parece correcto a simple vista.

✅ Ejemplo conforme 1 — Validación explícita con size_t

bool guardar(int valores[], size_t cantidad, size_t indice, int nuevo)
{
    if (indice >= cantidad)
    {
        return false;
    }
    valores[indice] = nuevo;
    return true;
}

El índice es size_t y se compara contra la cantidad sin conversiones de signo. La función devuelve false ante un índice inválido en lugar de corromper memoria. El contrato queda claro para el llamador.

✅ Ejemplo conforme 2 — Recorrido canónico con cota simple

size_t contar_positivos(const int valores[], size_t cantidad)
{
    size_t positivos = 0;
    for (size_t i = 0; i < cantidad; i++)
    {
        if (valores[i] > 0)
        {
            positivos++;
        }
    }
    return positivos;
}

La condición i < cantidad es la verificación de límites para cada acceso. El tipo size_t evita el desbordamiento de signo y la comparación es directa. Es el patrón que también recomienda 0x100Dh: Prohibición de condiciones de parada compuestas complejas en lazos for.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gaffgaff check archivo.cAcceso indexado sin validación previa del índice.
gcc / clanggcc -Wall -Wextra -std=c11 -Warray-bounds -fsanitize=bounds ...array subscript is above array bounds.
valgrindvalgrind ./programaInvalid read/write of size N fuera del bloque.

Checklist de autocontrol

Reglas relacionadas