Regla 0x1011h: Prohibición de saltos no estructurados goto fuera del patrón canónico de liberación de recursos
Estructuras de control y flujo (0x10XX)
0x1011h: Prohibición de saltos no estructurados goto fuera del patrón canónico de liberación de recursos¶
Enunciado normativo¶
ESTÁN PROHIBIDOS los saltos
gotohacia atrás, los que simulan lazos no estructurados y los que apuntan a etiquetas intermedias. SÓLO SE TOLERA elgotohacia adelante que salta a un bloque terminal único de liberación de recursos.
¿Por qué existe esta regla?¶
El problema¶
Un goto hacia atrás reconstruye a mano un lazo que el lenguaje ya ofrece y
obliga a rastrear el salto para saber cuántas veces se repite el código. Un
salto a una etiqueta intermedia fragmenta el flujo en pedazos que no
corresponden a ninguna estructura, y puede provocar dobles liberaciones.
El goto hacia adelante con un único bloque de limpieza es distinto: su forma
es reconocible, usa una sola etiqueta, salta siempre en la misma dirección y la
liberación vive en un único lugar. Por eso es el único patrón tolerado.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Código espagueti | Saltos cruzados que impiden leer el flujo linealmente. |
| Doble liberación | Un salto a una etiqueta intermedia puede liberar dos veces. |
| Mantenibilidad | Mover código puede dejar una etiqueta inalcanzable. |
Fundamento en el estándar y en la cátedra¶
ISO/IEC 9899:2011 §6.8.6.1 define goto; es legal en cualquier dirección. La
cátedra prohíbe el uso general en 0x1006h: No utilizar la instrucción goto y deja esta excepción acotada
para el patrón de limpieza, apoyada en 0x300Fh: Liberá la memoria en el orden inverso a su asignación y 0x3002h: Liberá siempre la memoria dinámica y asigná NULL al puntero para mitigar punteros colgantes.
Alcance y excepciones¶
Tolerado:
goto cleanup;hacia adelante, con una única etiqueta al final de la función que libera recursos y retorna.Prohibido:
gotohacia atrás,gotoa etiquetas intermedias ygotoque salta hacia adentro de un bloque.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — goto hacia atrás simulando un lazo¶
int i = 0;
repetir:
if (i < n)
{
procesar(valores[i]);
i++;
goto repetir;
}Por qué falla: el for equivalente es más corto y declara el avance en el
encabezado. El salto hacia atrás es exactamente el uso prohibido.
❌ Contraejemplo 2 — dos etiquetas intermedias de limpieza¶
if (paso_uno() != 0)
{
goto error_uno;
}
if (paso_dos() != 0)
{
goto error_dos;
}
error_dos:
liberar_dos();
error_uno:
liberar_uno();Por qué falla: las etiquetas intermedias obligan a razonar el orden de caída y pueden liberar dos veces. El patrón canónico usa un único bloque terminal.
✅ Ejemplo conforme 1 — sin goto, con guardas¶
FILE *archivo = fopen(ruta, "r");
if (archivo == NULL)
{
return false;
}
int *datos = malloc(TAMANO * sizeof(*datos));
if (datos == NULL)
{
fclose(archivo);
return false;
}Con pocos recursos ni hace falta goto: cada guarda libera lo suyo antes de
salir. Es la salida preferida cuando la función es corta.
✅ Ejemplo conforme 2 — goto hacia adelante a un único cleanup¶
bool exito = false;
int *datos = malloc(TAMANO * sizeof(*datos));
if (datos == NULL)
{
goto cleanup;
}
/* ... usar datos ... */
exito = true;
cleanup:
if (!exito)
{
free(datos);
datos = NULL;
}
return exito;Una sola etiqueta al final, siempre hacia adelante y con toda la liberación centralizada. Es el patrón canónico tolerado.
⚠️ Casos límite¶
Un solo recurso: no hace falta
goto; alcanza una guarda con limpieza antes delreturn(ver 0x2001h: Las funciones deben usar cláusulas de guarda y retornos anticipados para reducir la anidación profunda).Recursos anidados: liberar en orden inverso (ver 0x300Fh: Liberá la memoria en el orden inverso a su asignación).
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Regla 0x1011h: goto no canónico. |
| Búsqueda | grep -n "goto" archivo.c | Saltos hacia atrás o etiquetas intermedias. |
| Revisión manual | — | Más de una etiqueta o salto hacia atrás en la función. |
Checklist de autocontrol¶
¿Algún
gotosalta hacia atrás o a una etiqueta intermedia?Si uso el patrón de limpieza, ¿hay una única etiqueta terminal?
¿Los recursos se liberan en orden inverso y sin doble
free?
Reglas relacionadas¶
0x1006h: No utilizar la instrucción goto — prohibición general del
goto.0x2001h: Las funciones deben usar cláusulas de guarda y retornos anticipados para reducir la anidación profunda — retornos anticipados y limpieza centralizada.
0x300Fh: Liberá la memoria en el orden inverso a su asignación — liberar en orden inverso a la asignación.