• 3 min de lectura
Pruebas inestables llevaron a Buildkite a un error de memoria en Redis
Buildkite rastreó pruebas inestables hasta un uso después de liberar (use-after-free) en la extensión C hiredis del cliente de Redis tras una actualización de la gema.

Imagen: Hacker News
Un conjunto de pruebas inestables resultó ser algo mucho más profundo: un error de corrupción de memoria en la biblioteca redis-client.
Buildkite dice que el problema apareció por primera vez cuando el manager de ingeniería David vio varias fallas en las pruebas y las señaló en Slack. En 15 minutos, el equipo trató las fallas como lo bastante graves para bloquear despliegues y eliminó temporalmente las pruebas para desbloquear main. Al mirar la puntuación de fiabilidad del Test Engine de Buildkite, David notó que las tres peores pruebas habían pasado de aproximadamente 100% de fiabilidad a inestables entre 2 y 4 días antes. Un cambio reciente destacaba: una actualización de la gema de Redis realizada el viernes por la tarde anterior.
Al principio, el equipo sospechó de una condición de carrera ordinaria. Las pruebas que fallaban estaban en una suite de pruebas de características que usaba RSpec, un navegador sin cabeza Selenium, un servidor web/API, una base de datos y Redis—exactamente el tipo de configuración donde los problemas de sincronización son comunes. Incluso intentaron insertar pausas para comprobar si los mensajes WebSocket retrasados eran la causa.
Esa teoría no se sostuvo. Para el lunes siguiente, más pruebas en el mismo archivo fallaban de forma esporádica. Después de construir un caso reproducible más fiable—que aún podía tardar hasta 30 minutos en fallar—el equipo limitó el problema a las interacciones entre ActionCable y Redis. Los registros adicionales mostraron que un comando subscribe llegaba a ActionCable pero nunca alcanzaba a Redis. Los desarrolladores también informaron fallos de WebSocket en desarrollo, lo que sugería que el problema iba más allá del entorno de pruebas.
El avance llegó después de que apareciera un extraño error del asignador de memoria:

Recomendado
Por qué los datos de robótica empezaron a parecerse a YouTube
malloc: doble liberación de objeto
Unos días más tarde, otra compilación desencadenó un fallo de segmentación y generó un volcado de núcleo. Ese artefacto existió gracias a un plugin interno que otro desarrollador había creado para subir automáticamente volcados de núcleo de ejecuciones de prueba fallidas. El exingeniero de Buildkite Rian lo usó para inspeccionar el fallo y encontró que había ocurrido dentro de hiredis, la extensión C incluida en la gema redis-client.
Cómo ASAN expuso el fallo
Rian rastreó el fallo hasta una llamada a la función C memmove. Los punteros de origen y destino parecían válidos, pero el campo de tamaño era 0x00a0ffffffffffb6—unos 45 petabytes. Combinado con el comportamiento extraño observado después de la actualización de la gema, eso sugería fuertemente corrupción de memoria.
Rian entonces ejecutó el caso reproducible en una versión de Ruby compilada con ASAN tras ver una charla de conferencia ese mismo año, “Finding and fixing memory safety bugs in C with ASAN.” Tardó un par de horas en ponerlo en marcha, y en 30 minutos ASAN informó de un uso de heap después de liberar (heap use-after-free).
La causa raíz: en algunos casos, el hilo lector de hiredis liberaba el búfer del escritor. Hiredis usa dos hilos por conexión, uno para leer y otro para escribir.
Una vez que Buildkite supo de dónde venía la corrupción, la solución fue relativamente sencilla. Rian desactivó la extensión C para las conexiones Redis en pruebas, desarrollo y producción y creó un caso reproducible para reportarlo aguas arriba. Buildkite afirma que ningún dato de producción resultó dañado.
Enterprise Editor
Marcus follows the money. He covers enterprise software, cloud architecture, and the tectonic shifts in Big Tech strategy. He translates dense earnings calls and complex M&A activity into actionable insights about where the industry is actually heading. If a tech giant makes a silent pivot, Marcus is usually the first to notice.
vía Hacker News


