Regla 0x5001h: Los arreglos estáticos deben ser creados con un tamaño fijo en tiempo de compilación
Compilacion, preprocesador y seguridad (0x50XX)
0x5001h: Los arreglos estáticos deben ser creados con un tamaño fijo en tiempo de compilación¶
Enunciado normativo¶
DEBE declararse todo arreglo con un tamaño que sea una constante de tiempo de compilación (
#define,enumo literal entero). NO DEBE usarse un arreglo de longitud variable (VLA) cuyo tamaño dependa de un valor calculado en tiempo de ejecución.
¿Por qué existe esta regla?¶
El problema¶
Un VLA se reserva en la pila al entrar en el ámbito, con un tamaño que sólo
se conoce cuando el programa corre. Si el valor proviene del usuario o de una
cuenta previa, puede ser enorme, negativo o cero: o desborda el marco de pila
y aborta con SIGSEGV, o corrompe marcos vecinos sin avisar. Además, C11
degradó los VLA a característica opcional (__STDC_NO_VLA__).
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Compilación | -Wvla (GCC/Clang) advierte; en C90, -pedantic lo marca como error. |
| Comportamiento indefinido | Desborde de pila con tamaños grandes; corrupción si es negativo. |
| Bug silencioso | sizeof(vla) ya no es constante y se evalúa en runtime. |
| Portabilidad | Otro compilador sin VLA (__STDC_NO_VLA__) no compila el archivo. |
Fundamento en el estándar y en la cátedra¶
ISO/IEC 9899:2011 §6.7.6.2 describe el tipo «array de longitud variable» y
§6.10.8.3 define __STDC_NO_VLA__. La cátedra exige tamaño constante para que
el uso de pila sea predecible y reproducible en el sandbox de corrección.
Alcance y excepciones¶
Aplica a arreglos con almacenamiento automático o estático, incluidos los
parámetros declarados como int a[n] (decaen a puntero, pero el tipo sigue
siendo VLA si n no es constante). No aplica a miembros «flexible array
member» (int v[] como último campo de una struct), ni a memoria dinámica
reservada con malloc/calloc, que sí admite tamaño en runtime y se rige por
0x3001h: Siempre verificá la asignación exitosa de memoria dinámica, ni a dimensiones con #define, enum o sizeof.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — El tamaño lo decide el usuario¶
#include <stdio.h>
int main(void)
{
int cantidad;
scanf("%d", &cantidad);
int datos[cantidad];
datos[0] = 1;
return 0;
}Por qué falla: cantidad sólo se conoce en runtime; un valor como -1 o
2000000000 produce un VLA inválido y desborda la pila. El compilador no puede
proteger nada porque no conoce la cota.
❌ Contraejemplo 2 — const no es una constante de compilación¶
void cargar(size_t cantidad)
{
const size_t tope = cantidad;
int buffer[tope];
for (size_t i = 0; i < tope; i++) {
buffer[i] = 0;
}
}Por qué falla: en C, una variable const no es una expresión constante de
tiempo de compilación; sigue siendo un VLA. El calificativo const impide
modificarla, no la vuelve literal.
✅ Ejemplo conforme 1 — Dimensión con macro¶
#define MAX_DATOS 100
void cargar(void)
{
int datos[MAX_DATOS] = {0};
(void)datos;
}La dimensión es texto sustituido por el preprocesador antes de compilar, de modo que el compilador conoce el tamaño exacto y puede reservarlo en la pila.
✅ Ejemplo conforme 2 — Reserva dinámica cuando el tamaño es real¶
#include <stdlib.h>
int *reservar_datos(size_t cantidad)
{
int *datos = malloc(cantidad * sizeof(*datos));
if (datos == NULL) {
return NULL;
}
return datos;
}Cuando el tamaño depende de datos de entrada se usa memoria dinámica con
verificación de NULL (0x3001h: Siempre verificá la asignación exitosa de memoria dinámica); cuando es fijo, enum o #define. En
ningún caso un VLA.
⚠️ Casos límite¶
Tamaño cero:
int v[0]no es válido en C estándar (extensión de GNU);int v[sizeof(int) * 8];sí es constante.#definecon expresión:#define N (2 + 3)se expande a un literal constante; conviene protegerlo (ver 0x5013h: Protección obligatoria con paréntesis envolventes en expresiones de macroconstantes (#define)).Parámetro
int a[10]: decae aint *a; el10se ignora.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Reporta 0x5001h al detectar corchetes con expresión no constante. |
gcc / clang | gcc -std=c11 -Wall -Wextra -Werror -pedantic -Wvla archivo.c | error: variable length array 'datos' is used. |
Checklist de autocontrol¶
¿La dimensión de cada arreglo es un literal, un
#defineo unenum?¿Evité usar una variable
constlocal como tamaño?Si el tamaño es realmente variable, ¿usé
mallocy verifiquéNULL?¿El código compila con
-std=c11 -pedantic -Wvlasin advertencias?
Reglas relacionadas¶
0x3010h: Las variables que representan tamaños o índices de arreglos deben ser de tipo size_t — usá
size_tpara tamaños e índices de arreglos.0x3001h: Siempre verificá la asignación exitosa de memoria dinámica — si el tamaño es dinámico, reservá con
mallocy controláNULL.