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¶
1 2 3 4 5 6 7 8int 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¶
1 2 3 4 5 6 7 8 9 10 11 12if (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¶
1 2 3 4 5 6 7 8 9 10 11FILE *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¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15bool 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.