News · OpenAI ha ricondotto i crash della ricerca in ChatGPT a un host Azure difettoso e a una race condition di 18 anni in libunwind

May, 274 min di lettura
Piattaforma

OpenAI ha ricondotto i crash della ricerca in ChatGPT a un host Azure difettoso e a una race condition di 18 anni in libunwind

Come un'analisi a livello di popolazione su un anno di core dump ha separato due bug non collegati che si erano mascherati da un unico fallimento impossibile

Due crash con lo stesso travestimento

Il protagonista è Rockset, il sistema di ricerca e analisi cloud-native che OpenAI ha acquisito nel 2024 e che oggi usa per mantenere aggiornato l'indice della knowledge base di un workspace per ChatGPT. Il suo layer di esecuzione è scritto in C++, e qualche mese prima del post ha iniziato a generare crash che sembravano fisicamente impossibili: una funzione normale sembrava terminare per poi tornare a un indirizzo fittizio, a volte in uno slot di return-address a NULL, a volte con lo stack pointer %rsp sfasato esattamente di 8 byte.

Nessuno dei due sintomi è compatibile con del codice applicativo normale. Una scrittura vagante che colpisce esattamente un return-address salvato è estremamente improbabile, e disallineare %rsp di 8 byte senza assembly inline, setcontext o longjmp — nessuno dei quali usato da Rockset — è ancora più strano, perché il codice compilato tocca quel registro solo nel prologo e nell'epilogo di una funzione. Ogni ipotesi proposta dal team o da ChatGPT aveva forti evidenze contrarie. Il motivo, si è scoperto, era che stavano fissando due bug non collegati contemporaneamente: una corruzione hardware silenziosa su un singolo host Azure, e una race condition di 18 anni in GNU libunwind.

Una finestra di cento picosecondi, e la stima di Fermi che l'ha rese credibile

L'host difettoso è stato messo in denylist, e i suoi crash con stack disallineato sono scomparsi, anche se il team non è mai riuscito a riprodurre la corruzione dei registri in settimane di stress test. Rimosso quel cluster, i restanti core return-to-null si verificavano tutti durante l'unwinding delle eccezioni C++. GNU libunwind sintetizza una ucontext_t sullo stack e la passa a una routine interna, _Ux86_64_setcontext, le cui istruzioni finali spostano %rsp sul nuovo fondo dello stack prima che un'istruzione successiva legga l'instruction pointer di destinazione dalla stessa struct. Una volta spostato %rsp, la struct non è più protetta dalla red zone, quindi un segnale ricevuto in quella finestra permette al kernel di costruire il proprio signal frame proprio su quella memoria e azzerare l'instruction pointer ripristinato.

La finestra vulnerabile è una singola istruzione — circa cento picosecondi su una CPU out-of-order moderna — che sembrava troppo ristretta per spiegare più di una dozzina di crash return-to-null al giorno. Una stima di Fermi ha colmato il divario: una finestra di 10⁻¹⁰ secondi contro un SIGUSR2 in arrivo ogni 10⁻² secondi di tempo CPU dà a ogni handler di cleanup circa una probabilità di 10⁻⁸ di perdere la race; un host che genera 10⁴ eccezioni al secondo per la contropressione sull'ingest fallisce quindi circa una volta ogni poche ore, il che a livello di flotta è più che sufficiente.

Rockset era anomalo su tutti e tre gli assi che determinano il tasso di crash. Genera eccezioni di frequente come controllo del sovraccarico, invia SIGUSR2 in modo inusualmente frequente tramite il suo coarse_thread_cputime_clock, e all'inizio dell'anno aveva aggiunto una chiamata a timer_getoverrun che faceva consumare più stack al signal handler — abbastanza da raggiungere e sovrascrivere la ucontext_t obsoleta. Prima di quella modifica, i crash non comparivano affatto. Il bug di 18 anni era sempre stato presente; era il prodotto tra tasso di eccezioni, tasso di segnali e uso dello stack dell'handler ad aver appena superato la soglia che lo rendeva visibile.

L'instrumentazione come vera soluzione

La mitigazione immediata è stata passare da GNU libunwind all'unwinder di libgcc — un buon compromesso a prescindere, dato che libgcc ha ricevuto più lavoro per ridurre la contesa sui lock nelle VM di grandi dimensioni — e OpenAI ha contribuito upstream un reproducer autonomo e una fix a GNU libunwind. Per il guasto hardware, il team ha migliorato il gestore dei segnali fatali per registrare lo stato dei registri, così una recidiva può essere rilevata solo dai log senza bisogno di un core dump, e ha modificato il control plane per riutilizzare le VM invece di riciclarle, il che rende più facile individuare i nodi difettosi.

La lezione fondamentale non è nessuno dei dettagli su ABI, DWARF o meccanismi delle eccezioni emersi dall'indagine. È che la confusione è persistita solo perché due fenomeni erano mescolati in un'unica narrazione, e si è dissolta nel momento in cui il dataset è diventato pulito e completo. Questo è il punto da portare in altri team infrastrutturali: quando un bug sembra impossibile, il pezzo mancante è spesso un dato di popolazione accurato, non una diagnosi più intelligente sul singolo caso.

La reliability non riguarda solo la correzione dei bug dopo che si verificano: riguarda la costruzione di dati, workflow e competenze che trasformano i problemi impossibili in problemi diagnosticabili e risolvibili.Montana Labs

Find this story relevant to you?

Contact us to find a unique solution

Contact us

Cerchi un partner di ingegneria AI capace di costruire davvero?

Aiutiamo le aziende a integrare l AI nei prodotti, automatizzare i flussi di lavoro ad alto valore e modernizzare i sistemi software che sostengono la crescita.

Get in touch

Letture correlate

Altre analisi su delivery di prodotto, IA operativa e il lavoro sui sistemi che fa reggere il deployment alla prova dei fatti.

Jul, 134 minuti di lettura
Piattaforma

Doppel automatizza la rimozione dei contenuti di phishing con una pipeline in cinque fasi basata su GPT-5 e RFT

Jul, 134 min di lettura
Piattaforma

L'espansione di Meta a 5GW in Louisiana viene annunciata con i bonus agli insegnanti, non con i teraflops

Jul, 94 min di lettura
Piattaforma

Il GPT-5 di OpenAI arriva come router su più modelli, non come modello unico