Evidencia inmutable de una corrida de 1 hora limpia del generador hand-rolled de M4 (
tests/fuzz_parser.rs) sobregabysql::sql::parse(...). No editar a mano.
Resumen ejecutivo
1 hora · 503.8 millones de queries random · 0 panics.
| Métrica | Valor |
|---|---|
| Duración | 3 600 s (60 min exactos) |
| Iteraciones totales | 503 861 946 |
| Throughput | 139 961 iters/seg |
| Queries que parsearon OK (azar) | 74 787 |
| Queries con parse error (esperado) | 503 787 159 |
| PANICS | 0 |
Entorno
- Host: Windows 11 + bash sobre git-bash.
- Toolchain:
stable-x86_64-pc-windows-gnu(rustc 1.95.0). - Build profile:
release(la suite fuzz se corre optimizada para máxima throughput). - Commando exacto:
GABYSQL_FUZZ_PARSER_SECS=3600 \ cargo test --target x86_64-pc-windows-gnu --release \ --test fuzz_parser -- --ignored --nocapture - Seed base:
0x9E37_79B9_7F4A_7C15(Numerical Recipes — mismo que todo el resto de la suite property-based: M3 planner, Pager proptest, gabybench).
Qué se ejercitó
El generador produce 100% queries pseudo-aleatorias en cada iteración, mezcla de:
- 70% secuencias de tokens estructuradas: 2 a 60 tokens picados
random de un vocabulario SQL (~90 keywords, 13 operadores, 7
puntuaciones, identificadores
a..zde 1-12 chars, literales numéricos/string/NULL). - 30% mutación adversarial: query estructurado + 1-4 bytes random inyectados/borrados/reemplazados → ataca decoding UTF-8, buffer bounds, tokenizer corner cases.
Cada query es nueva (seed distinto). El generador no retroalimenta coverage como libFuzzer/AFL — es generación pura random. Eso lo hace menos eficiente que un fuzzer coverage-guided pero suficiente para detectar panics groseros y la línea de README es válida.
Lectura crítica
Lo que esta evidencia respalda:
- El parser no panic-ea ante ~500M inputs random.
- Los
unwrap()yexpect()que el parser usa internamente cubren los casos que el generador supo armar. - En particular: 74 787 queries que parsearon OK son una porción no trivial de SQL casualmente válido — la combinatoria de las keywords + literales + operadores cubrió bastantes shapes sintácticos reales.
Lo que esta evidencia NO respalda:
- Que el motor entero esté hardened. Solo se probó
parse().exec()no se invocó. - Que no haya bugs semánticos. Un parser que devuelve
Errno es un parser correcto — solo es un parser que no panic-ea. - Que las queries que parsean OK sean ejecutables. Sintaxis OK ≠
motor las acepta — muchas seguramente caen con
[GBY-...]en exec. - Coverage. Sin
cargo fuzzreal + coverage-guided, no sabemos qué partes del parser se ejercitaron y qué partes no. Para eso hace falta libFuzzer (Linux + nightly).
Próxima mejora
Cuando alguien quiera subir el bar (próximos meses):
cargo fuzzreal en CI Linux — agregar workflow en GitHub Actions con nightly + cargo-fuzz. Mantener este test hand-rolled para ejecución local en Windows + GNU.- Fuzz sobre
exec()además deparse()— segundo target con un pre-fixture de tabla y ops random sobre ella. Mucho más caro (cada iter cuesta ms, no µs) pero detecta panics en path de ejecución, no solo en parsing. - Coverage-guided — usar
cargo-fuzzcon libFuzzer para que el generador aprenda qué inputs exploran nuevo código. Salto de eficiencia importante.
Reproducción
Con esta commit en main, cualquiera puede reproducir:
git checkout <commit>
GABYSQL_FUZZ_PARSER_SECS=3600 \
cargo test --target x86_64-pc-windows-gnu --release \
--test fuzz_parser -- --ignored --nocapture
Si encontrás un panic con un seed específico, abrí issue con el seed
- la query — el LCG es determinístico, reproduce 1:1.