Patriot vs Scud, da un piccolo errore a un disastro

Alle 20:40 del 25 febbraio 1991, un missile iracheno SCUD si abbatte su un accampamento di soldati statunitensi a Dhahran, sulla costa Est dell’Arabia Saudita. Il primo bilancio è tragico: 27 morti (diventeranno 28) e 98 feriti.
Appena il giorno prima è cominciata l’operazione Desert sabre, che porterà rapidamente alla fine della prima guerra del Golfo con la resa di Saddam Hussein, avvenuta il mattino del 28 febbraio.
A causare il disastro di Dhahran è stata la mancata attivazione del sistema difensivo degli alleati occidentali, basato sul missile PATRIOT. Lo SCUD è passato inosservato a causa di un errore di programmazione, ma anche per una cattiva gestione del progetto del software di controllo e una pessima comunicazione tra chi sviluppava e chi utilizzava il prodotto.
Seguendo il filo conduttore del tema di febbraio, cosa si può imparare da questa storia?


Il missile Scud

L’esercito iracheno utilizzò nella guerra del Golfo la variante Al-Hussein dell’originale progetto sovietico SCUD, a sua volta basato sugli studi balistici tedeschi effettuati durante la seconda guerra mondiale. Tra le altre modifiche, era stata ridotta la testata a vantaggio del propellente, per aumentare la gittata del missile, portandola a superare i 600km.
Il cilindro, di 12,46 metri per 88 centimetri di diametro (la foto di apertura dell’articolo mostra i resti di uno SCUD abbattuto), non era precisissimo, colpiva al 50% entro un raggio di 1km dall’obiettivo. La massima velocità raggiunta era di poco superiore a 1,5km al secondo.

La risposta statunitense: il PATRIOT

L’esercito statunitense rispondeva con il PATRIOT.
Il progetto, varato nel 1964 con sperimentazioni a partire dal 1976, era stato impostato come estremamente modulare, in modo da consentire che ciascuna componente potesse essere rinnovata, senza stravolgere l’intero complesso sistema.

SPC Daniel Nebrida of C Battery, 1st Battalion, 43rd Air Defense Artillery - part of the 35th ADA Brigade - in Osan, Korea, checks canister cable connections on a "live" Patriot missile system positioned toward North Korea.

La prima versione, il PAC-1, fu progettata per l’inseguimento e la distruzione di aerei in volo. Per poter intercettare missili balistici, molto più veloci, negli anni ’80 nacque la versione PAC-2, pronta per i test nel 1987 e in utilizzo a partire dal 1990. Oggi siamo alla versione PAC-3.

La base di lancio del PATRIOT PAC-2 utilizzava un sistema radar per rilevare la presenza di SCUD in volo.
Al primo avvistamento, la base di lancio ne determinava tipo (amico/nemico), posizione, direzione e velocità. Successivamente ne elaborava la posizione prevista dopo pochi secondi, e verificava l’effettiva presenza dello SCUD nell’area attesa, entro un raggio di circa 150m. In caso di conferma dell’avvistamento, veniva lanciato verso lo SCUD uno dei PATRIOT pronti per il lancio.

Il sistema di inseguimento dell’obiettivo utilizzato dai PATRIOT è denominato Track-via-missile: il radar di terra continua a illuminare l’obiettivo, un ricevitore radar sul missile rileva la posizione dell’obiettivo e la trasmette a terra. Dalla base vengono quindi inviati i controlli per correggere la rotta del missile verso l’obiettivo.
I principali vantaggi di questo sistema sono due: l’obiettivo non rileva (o meglio, non dovrebbe rilevare) la presenza del missile; la posizione dell’obiettivo viene rilevata con precisione crescente, man mano che si riduce la distanza tra missile e obiettivo.

Quando 24 bit sono pochi

La base di lancio dei PATRIOT utilizzava un computer multiprocessore a 24 bit. In una locazione di memoria composta da 24 bit possono essere essere memorizzati numeri:

  • interi tra -(223-1) = 8.388.607 e (223-1); il primo bit è infatti utilizzato per memorizzare il segno + o -;
  • reali con parte intera pari a 0 e parte decimale tra -(1-2-23) e (1-2-23), espressa con 23 bit.

Utilizzando due locazioni di memoria è possibile rappresentare un numero reale combinando la parte reale e la parte decimale. Poiché, però, basta memorizzare il segno una sola volta, la parte decimale recupera un bit e quindi può andare da -(1-2-24) e (1-2-24), espressa con 24 bit.

Il computer del sistema PATRIOT utilizzava un orologio interno che memorizzava il numero intero dei decimi di secondo trascorsi dal momento dell’accensione del computer stesso. Per calcolare le velocità (spazio ⁄ tempo), il contenuto dell’orologio veniva diviso per 10, o meglio moltiplicato per 1/10, per ottenere il tempo in secondi.

Nel sistema decimale frazioni come 1 ⁄ 3 hanno una rappresentazione periodica = 0.3333…, perché il denominatore ha un fattore primo (3) che non divide la base (10).
Nella notazione binaria accade la stessa cosa per la frazione 1 ⁄ 10, perché il fattore primo 5 non divide la base 2.

Si ha quindi:
1/10 = 0.00011001100110011001100 11001100 …
dove i primi 23 bit (in grassetto) sono quelli che effettivamente vengono memorizzati nella locazione di memoria.
Questo vuol dire approssimare 1 ⁄ 10 = 0.1 con 0.09999990463


Un sito molto utile per calcoli e conversioni è rapidtables.com. Ecco come utilizzarlo per verificare l’errore di troncamento commesso nel sistema PATRIOT.


Qual è l’effetto del troncamento?

L’errore di troncamento non comporta di per sé un problema concreto, fino a che tutti i tempi sono calcolati con la stessa base di riferimento e, quindi, con lo stesso errore. A porre le basi per il disastro fu invece un miglioramento introdotto nel PAC-2.

Per poter inseguire i missili balistici, molto più veloci degli aerei, fu deciso di migliorare la precisione del calcolo del tempo in secondi, memorizzando il valore 1 ⁄ 10 in una variabile reale, quindi con 24 bit a descrivere la parte decimale, invece di 23. L’approssimazione di 1 ⁄ 10 diventa allora 0.09999996423

In un progetto così delicato è importante limitare il numero di test di verifica necessari dopo ogni modifica. Molto saggiamente, quindi, la modifica fu affiancata all’esistente, introducendo una seconda funzione di calcolo del tempo. Tutte le applicazioni che non richiedevano maggiore precisione rimasero quindi immutate, senza necessitare di nuovi test.
Nella versione anti SCUD, quindi, fu necessario rivisitare il codice, per modificare tutti i punti in cui veniva chiamata  la funzione di calcolo del tempo, per puntare alla nuova funzione. E poi furono eseguiti i test previsti, che non rilevarono nessun problema.

I limiti del test, ovvero quando il diavolo ci mette la coda

Ahimè, non tutti i punti del codice furono corretti, con il risultato che il tempo veniva ad essere calcolato con due scale lievemente diverse tra loro, accumulando un errore che aumentava con il tempo trascorso dal momento dell’accensione del sistema.

In particolare, il primo avvistamento e la successiva verifica erano calcolati uno con la nuova funzione e l’altro con la vecchia.
Effetto: dopo 20 ore di funzionamento, l’errore faceva sì che il radar aspettasse lo SCUD nel posto sbagliato.

Perché i test non rilevarono il problema? Semplicemente perché ogni test faceva ripartire l’orologio del sistema da zero, e nessun test durava abbastanza per rendere l’errore rilevabile.

Quando la comunicazione funziona male

Qualche settimana prima, l’esercito israeliano, ovviamente coinvolto nel conflitto, aveva rilevato il problema e l’aveva prontamente segnalato agli alleati statunitensi.
Prima ancora di analizzare, individuare la root cause, correggere il bug, testare e rilasciare, fu diramata agli operativi al fronte la raccomandazione di non tenere in funzione continuativa i sistemi “per troppo tempo“.

Quanto tempo fosse “troppo” non veniva esplicitato nella comunicazione. Il suggerimento tecnico di riavviare il sistema ogni 8 ore si perse per strada e non arrivò al fronte.

Il 25 febbraio, a Dhahran il sistema era in funzione da 100 ore. La probabilità che il PATRIOT potesse confermare il primo avvistamento di uno SCUD era pari a zero.
Pochi minuti prima delle 20:40 il sistema di controllo dei PATRIOT rilevò la potenziale presenza di uno SCUD. La successiva verifica fu effettuata a poche centinaia di metri dal punto giusto, senza ovviamente trovare il potenziale bersaglio, e l’allarme fu automaticamente cancellato. Lo SCUD poteva continuare indisturbato la sua corsa.

Come si sarebbe potuto evitare il fatale errore software?

La realizzazione del progetto PATRIOT era avvenuta negli anni ’70, utilizzando l’Assembler come linguaggio di programmazione. Quindi, di fatto, il programma era scritto nel linguaggio nativo del processore (linguaggio macchina), anche se in una forma leggibile da un umano.


Al mio primo lavoro, nel 1977, mi trovai a programmare lo z80 della ZiLOG, il microprocessore che, insieme all’8080 dell’Intel e al 6502 della MOS Technology, hanno rivoluzionato l’informatica degli anni 80.
Dall’8080 dell’Intel discendono i processori dei pc Windows attuali, della MOS Technology non è rimasto nulla, se non il ricordo del Commodore 64. La ZiLOG è viva e produce ancora il processore z80, ormai quarantenne.

Il linguaggio che utilizzai era appunto l’assembler per z80. Un esempio: per scrivere il valore 0 nel registro accumulatore del processore, si utilizzava l’istruzione: « LD A,0 », tradotto in linguaggio macchina mediante due byte, « 3E 00 » in esadecimale.
Capitava, in emergenza, di dover modificare il programma direttamente in codice macchina, quindi avevamo mandato a memoria i codici più comuni. Tra i più gettonati meritano un ricordo particolare « 18 FE » (rimani in attesa qui) e « 28 FE » (rimani in attesa fino a che il flag 0 non si attivi).

Il problema è che l’emergenza era quotidiana, e non sempre si faceva un lavoro pulito nel riportare la modifica nel programma, documentando cosa si era fatto e perché.
A distanza di tempo, o semplicemente mettendo mano al lavoro effettuato da altri, la logica del codice era quindi spesso poco comprensibile, rendendo complicata la manutenzione.


Non esiste urgenza che non consenta di irrobustire un prodotto

L’azienda produttrice dei PATRIOT, la Raytheon, a fine anni ’80 aveva lo stesso problema. Il codice assembler prodotto e la relativa logica di funzionamento non erano sempre chiaramente documentati. A quel punto erano disponibili linguaggi più evoluti dell’assembler, e la best practice avrebbe suggerito di riscrivere con uno di questi linguaggi i componenti software più importanti. Cosa che fu fatta, ma solo negli anni ’90.

Si tratta di un errore frequente. La giustificazione che si adduce è spesso che non c’è stato tempo, il rilascio del prodotto era una faccenda urgente. Quasi di sicuro, però, si è persa l’occasione di approfittare di un precedente periodo di relativa calma, oppure non si è lanciato l’aggiornamento tecnologico come progetto parallelo.
Si tratta comunque di una questione delicata: più passa il tempo, più si accumulano modifiche e si rischia di perdere competenza sul prodotto (i progettisti si avvicendano, cambiano le aziende a cui vengono affidati parti del progetto e così via).

Al momento della modifica anti-SCUD, quindi, il codice, ancora una diretta derivazione del progetto originale, era difficilmente gestibile e non stupisce che sia sfuggita una correzione nell’introdurre la nuova funzione di calcolo del tempo.

Anche riporre troppa fiducia nei test non porta bene

Ecco un altro errore commesso troppo di frequente: utilizzare i test di prodotto per rilevare errori di progetto.
I test devono riprodurre al meglio le condizioni di utilizzo del prodotto. È importante quindi che vengano simulati i comportamenti dell’utilizzatore, anche i più improbabili, e le condizioni di funzionamenti possibili, anche le più estreme.

Ma un errore di programmazione può comunque passare tranquillamente inosservato in questi test. Nessun test di prodotto potrà sostituire efficacemente un buon lavoro di progettazione: capire il problema, descrivere la soluzione, realizzarla in modo pulito, comprensibile e documentato. E infine testarla prima ancora di integrarla nel prodotto.


Il caso del PATRIOT non è l’unico errore software che si è tradotto in un disastro.
Solo cinque anni dopo, il 4 giugno del 1996, un missile Ariane 5 lanciato dall’Agenzia Spaziale Europea esplodeva in volo, poche decine di secondi dopo il lancio.

La causa? la conversione di una variabile memorizzata come floating point a 64 bit, in un intero a 16 bit, forniva un risultato sballato quando la destinazione era troppo piccola per il numero originario.

Morale della storia: più attenzione nel programmare, e documentare quello che si fa. Raccontare per iscritto le cose aiuta a a scoprire una quantità incredibile di errori. Provare per credere.

Scritto da:

Pasquale

Mi chiamo Pasquale Petrosino, radici campane, da alcuni anni sulle rive del lago di Lecco, dopo aver lungamente vissuto a Ivrea.
Ho attraversato 40 anni di tecnologia informatica, da quando progettavo hardware maneggiando i primi microprocessori, la memoria si misurava in kByte, e Ethernet era una novità fresca fresca, fino alla comparsa ed esplosione di Internet.
Tre passioni: la Tecnologia, la Matematica per diletto e le mie tre donne: la piccola Luna, Orsella e Valentina.
Potete contattarmi scrivendo a: p.petrosino@inchiostrovirtuale.it