un approccio per la software fault injection in sistemi ...e' necessario comprendere che...

152
Facoltà di Ingegneria Corso di Studi in Ingegneria Informatica tesi di laurea specialistica Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti Anno Accademico 2008/2009 relatore Ch.mo prof. Domenico Cotroneo correlatore Ing. Roberto Natella candidato Stefano Rago matr. 885/215 1

Upload: others

Post on 25-Aug-2020

8 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Facoltà di IngegneriaCorso di Studi in Ingegneria Informatica

tesi di laurea specialistica

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Anno Accademico 2008/2009

relatoreCh.mo prof. Domenico Cotroneo

correlatoreIng. Roberto Natella

candidatoStefano Ragomatr. 885/215

1

Page 2: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Alla mia grande famiglia

2

Page 3: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Indice Introduzione................................................................................................................................... 1

Organizzazione della trattazione............................................................................................... 3Capitolo 1: Introduzione alla Software Fault Injection................................................................... 4

1.1 Concetti sulla dependability dei sistemi informatici............................................................. 41.1.1 Attributi della dependability......................................................................................... 61.1.2 Minacce alla dependability.......................................................................................... 71.1.3 Mezzi per ottenere e stimare la dependability............................................................. 8

1.2 Software Faults............................................................................................................. 101.3 Stato dell'arte nell'iniezione di Software Faults............................................................. 18

Capitolo 2: Coflight - un caso di studio di sistema Fault Tolerant ............................................... 252.1 Introduzione a CARDAMOM ........................................................................................ 262.2 Fault Tolerance Service................................................................................................ 322.3 Load Balancing Service ............................................................................................... 342.4 COFLIGHT ................................................................................................................... 362.5 Modellazione a stati del sistema................................................................................... 40

Capitolo 3: Progettazione di campagne di testing basate su Software Fault Injection ...............513.1 Obiettivi, definizioni e metriche di valutazione.............................................................. 51

3.1.1 Il caso di studio COFLIGHT...................................................................................... 543.2 Misure e raccolta dati ................................................................................................... 563.3 Analisi dei dati............................................................................................................... 61

3.3.1 Il caso di studio COFLIGHT...................................................................................... 63Capitolo 4: Valutazione sperimentale basata sullo stato dell'arte................................................ 69

4.1 Entrambi i facade faulty.................................................................................................... 694.1.1 Copertura degli stati.............................................................................................. 69

4.2 Facade primario faulty (esplorazione del modello in senso orizzontale e verticale).........744.2.1 Copertura degli stati (esplorazione in senso orizzontale)...................................... 744.2.2 Copertura degli stati (esplorazione in senso verticale).......................................... 77

4.3 Facade primario faulty (workload con diversificazione delle richieste).............................804.3.1 Copertura degli stati ............................................................................................. 81

4.4 Processing server faulty.................................................................................................... 834.5 Vulnerabilità scoperte....................................................................................................... 85

Capitolo 5: Iniezione di guasti di concorrenza ............................................................................ 875.1 Definizione del modello dei guasti ............................................................................... 915.2 Iniezione dei guasti .................................................................................................... 1135.3 Attivazione dei guasti ................................................................................................. 1155.4 Implementazione......................................................................................................... 118

5.4.1 Algoritmo per la determinazione dei percorsi.......................................................... 1195.4.2 Tecnica di controllo dello scheduling....................................................................... 121

Capitolo 6: Valutazione sperimentale basata sull'iniezione di guasti di concorrenza ..............1246.1 Copertura degli stati ................................................................................................... 1246.2 Vulnerabilità scoperte................................................................................................. 138

Conclusioni e sviluppi futuri....................................................................................................... 139Appendice A: Modellazioni alternative del sistema................................................................... 142Bibliografia................................................................................................................................. 146

III

Page 4: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Indice delle figureIllustrazione 1: Tecniche per la Fault Tolerance................................................................................. 9Illustrazione 2: Una classificazione dei Software Faults.................................................................. 11Illustrazione 3: Trend dei Bohrbugs e degli Heisenbugs.................................................................. 12Illustrazione 4: I bugs e le relative contromisure.............................................................................. 14Illustrazione 5: Spettro delle metodologie di analisi dei difetti software...........................................16Illustrazione 6: La tecnica G-SWFIT................................................................................................. 23Illustrazione 7: I Pluggable Services di Cardamom.......................................................................... 28Illustrazione 8: Struttura di Cardamom............................................................................................. 31Illustrazione 9: Fault Tolerance in Cardamom.................................................................................. 33Illustrazione 10: Load Balancing in modalità round robin................................................................. 35Illustrazione 11: I tipi di dato di un FDP definiti dal progetto Avenue............................................... 37Illustrazione 12: Architettura di Coflight............................................................................................ 40Illustrazione 13: Modello a stati finiti del sistema............................................................................. 47Illustrazione 14: Un esempio di sequenza di messaggi applicata al modello..................................49Illustrazione 15: Sequence Diagram di un caso d'uso..................................................................... 50Illustrazione 16: Predicati e modello di comportamento................................................................... 56Illustrazione 17: Tool utilizzato per analizzare i log del sistema....................................................... 67Illustrazione 18: Workload ad esplorazione orizzontale................................................................... 70Illustrazione 19: Classificazione dei test........................................................................................... 71Illustrazione 20: Distribuzione dei fallimenti nello scenario con entrambi i Facade faulty................72Illustrazione 21: Classificazione dei test per lo scenario con entrambi i Facade faulty....................73Illustrazione 22: Distribuzione dei fallimenti nello scenario con singolo Facade faulty ed esplorazione orizzontale................................................................................................................... 75Illustrazione 23: Classificazione dei test per lo scenario con singolo Facade faulty ed esplorazione orizzontale........................................................................................................................................ 76Illustrazione 24: Workload ad esplorazione verticale....................................................................... 77Illustrazione 25: Distribuzione dei fallimenti nello scenario con singolo Facade faulty ed esplorazione verticale....................................................................................................................... 78Illustrazione 26: Classificazione dei test per lo scenario con singolo Facade faulty ed esplorazione verticale............................................................................................................................................ 79Illustrazione 27: Distribuzione dei fallimenti nello scenario con singolo Facade faulty e diversificazione delle richieste.......................................................................................................... 81Illustrazione 28: Classificazione dei test per lo scenario con singolo Facade faulty e diversificazione delle richieste.......................................................................................................... 82Illustrazione 29: Le semplificazioni rimosse dal modello.................................................................. 87Illustrazione 30: Nuova versione del modello a stati finiti................................................................. 88Illustrazione 31: Processo di definizione del fault model................................................................ 113Illustrazione 32: Esempio di percorso per l'attivazione di un conflitto............................................ 120Illustrazione 33: Esmpio di scheduling per l'attivazione di un conflitto........................................... 121Illustrazione 34: Risultati della campanga di concurrency fault injection.......................................135

IV

Page 5: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Introduzione

Questo lavoro di tesi si colloca nel contesto dei sistemi software critici e della software

fault injection come strumento per studiare e validare tali sistemi. I sistemi critici sono

presenti in numerosi ambiti, fra cui quello militare, dell'aeronautica, dei sistemi per cure

mediche, dei sistemi per la gestione economica. Questi sistemi, notevolmente differenti

dal punto di vista delle funzionalità offerte, condividono un insieme di caratteristiche che

da un lato li rendono particolarmente sofisticati e complessi e dall'altro comportano la

necessità di massima affidabilità.

Con il termine dependability, più avanti esemplificato in questa trattazione, si intende un

insieme di attributi di qualità di un sistema ed è il punto di partenza di numerosi studi e

ricerche effettuati negli ultimi anni. La dependability è il requisito principale dei sistemi

critici, che, malgrado gli sforzi più attenti, sono soggetti alla presenza di difetti, o fault

nella terminologia di questo contesto.

Uno dei mezzi per studiare e migliorare la dependability di un sistema è la fault tolerance,

che, contemplando l'occorrenza di determinati tipi di fault, si occupa di contrastarne le

conseguenze, facendo in modo che il sistema, seppur affetto da tali difetti, risponda

comunque ai requisiti previsti.

Anche la fault tolerance, tuttavia, è soggetta a difetti per cui diventa cruciale verificare che

i meccanismi di fault tolerance di un sistema funzionino nella maniera prevista.

Un modo per validare la fault tolerance di un sistema è la fault injection che emulando, a

tempo di esecuzione, la presenza di opportuni fault, scelti sulla base di statistiche e studi

approfonditi, si occupa di favorirne l'attivazione, al fine di studiare la reazione del sistema

in tali circostanze.

In questo lavoro sono state studiate e valutate due tecniche di fault injection: una tecnica

allo stato dell'arte ed una tecnica innovativa. Tali tecniche sono state applicate ad un caso

di studio particolarmente incline a questo tipo di lavoro: un sistema per la gestione dei

piani di volo, parte di un sistema ATC (Air Traffic Control).

1

Page 6: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un contributo di questo lavoro è stato quello di fornire una modellazione del sistema

basata sugli stati al fine di supportare lo studio e la valutazione di entrambe le tecniche.

Fra le diverse alternative analizzate, è stato adottato un modello a stati finiti che tenesse in

conto le variabili di maggior interesse. Modellare il sistema in questo modo permette di

comprendere le condizioni di funzionamento maggiormente sensibili all'attivazione di

fault, poiché generalmente le conseguenze dei fault non hanno gli stessi effetti in

qualunque condizione. Questo tipo di discernimento è utile per concentrare gli sforzi e

approfondire meglio i casi che più lo richiedono, poiché studi di questo tipo comportano

tempi e costi notevoli.

La tecnica allo stato dell'arte, nota come G-SWFIT (Generic Software Fault Injection

Technique) è stata approfonditamente valutata, applicandola alle entità del sistema

maggiormente critiche. Sono stati proposti differenti scenari d'uso del sistema (workload)

attraverso in quali è stato possibile evidenziare i diversi meriti e difetti di una tale tecnica.

Il risultato fondamentale è che questa tecnica non permette di testare efficacemente tutti

gli stati previsti dal modello. Inoltre, tale tecnica sembra maggiormente idonea

all'emulazione di una tipologia di guasti che sono già sufficientemente affrontati e rimossi

durante la fase di sviluppo e testing del sistema, diversi dal tipo di guasti che la fault

tolerance contempla e che, quindi, si vuole emulare con la fault injection. L'obiettivo,

infatti, è quello di riprodurre quei difetti che sfuggono alla fase di testing e che si attivano,

con conseguenze più o meno gravi, nella fase operativa di un sistema.

Da queste premesse è nata la tecnica proposta, nello sforzo di emulare una categoria di

guasti maggiormente rappresentativi e utili allo scopo. Dapprima è stata individuata, sulla

base di lavori precedenti, la tipologia di guasti più frequente all'interno di questa categoria

– quella degli errori di programmazione concorrente – dopodiché è stata individuata una

metodologia in grado non solo di emularli, ma di fare in modo che potessero essere attivati

in maniera deterministica e controllata.

Questo tipo di guasti, infatti, hanno una modalità di attivazione che li rende

particolarmente difficili da riprodurre, poiché spesso, proprio nel tentativo di

comprenderne le cause, “scompaiono”, ossia, vengono alterate le condizioni che ne

2

Page 7: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

favoriscono la manifestazione. Lo sviluppo della tecnica proposta è stato motivato anche

da queste considerazioni: se la tecnica precedente ha lasciato degli stati scoperti,

presumibilmente il sistema ha attraversato quegli stati affetto da tali difetti, ma questi non

si sono manifestati.

La tecnica proposta ha permesso di completare la copertura di tutti gli stati del modello,

dimostrandosi complementare all'altra tecnica. Inoltre, collateralmente alla valutazione

delle tecniche, sono state scoperte delle vulnerabilità nei meccanismi di fault tolerance del

sistema testato, illustrate nel corso della trattazione.

Organizzazione della trattazione

Il resto di questo testo è organizzato come segue. Il Capitolo 1 introduce la Software Fault

Injection, descrivendone gli aspetti principali e le tecniche presenti in letteratura, mentre il

Capitolo 2 illustra il caso di studio attraverso il quale sono state valutate le tecniche di

fault injection. Le due tecniche di fault injection sono illustrate seguendo una struttura

simile: prima da un punto progettuale e implementativo (rispettivamente nei Capitolo 3 e

5) e poi sono presentati i risultati (rispettivamente nei Capitoli 4 e 6).

3

Page 8: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Capitolo 1Introduzione alla Software Fault Injection

1.1 Concetti sulla dependability dei sistemi informatici

Negli ultimi anni, la necessità e la richiesta di sistemi informatici complessi, mission e

safety critical, sono cresciute molto rapidamente. Contestualmente sono aumentati gli

ambiti in cui tali sistemi sono richiesti e la criticità degli stessi. Di conseguenza il requisito

fondamentale per questo tipo di sistemi è l'affidabilità.

Come constatato da Gray in [4] e da altri autori in diversi lavori ([16], [20], [21]), la

maggior parte dei problemi riscontrati nei moderni sistemi viene attribuita al software. Ciò

è dovuto, in parte, alla maggiore consolidazione che ha raggiunto la tecnologia hardware,

in parte alla natura stessa del software e al maggiore spettro di possibilità che offre. Sono

numerosi gli esempi in cui problemi di tipo software hanno dato luogo a fallimenti di

sistema, in ambiti che vanno dai sistemi per cure mediche a sistemi per la gestione

economica, a sistemi militari, per menzionarne solo alcuni. Tali fallimenti comportano

conseguenze di tipo diverso, che possono essere più o meno gravi a seconda dei criteri

adottati per classificarle, ma che tuttavia indicano, nella loro stessa definizione,

l'occorrenza di un evento inammissibile. Il duplice intento dello studio della dependability

è appunto quello di capire, da un lato, quanto si può essere confidenti che, dato un certo

sistema, determinati eventi non accadano e, dall'altro, come conferire al sistema

caratteristiche che consentano una certa confidenza.

Avendo menzionato una classe di eventi “inammissibili” è il caso di specificare ed

esemplificare tale classe. E' necessario comprendere che produrre software privo di errori

è molto difficile. L'attività di sviluppo del software, infatti, è spesso condizionata, oltre

che dalle difficoltà tecniche, da vincoli di mercato, che costringono a contenere, o a

ridurre, i tempi di sviluppo e da vincoli economici. Tutto ciò comporta dunque notevoli

difficoltà nel garantire l'assenza di difetti.

4

Page 9: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Ciò che si vuole ottenere, con lo studio della dependability, è la possibilità di ammettere la

presenza di difetti, eventualmente quantificandoli e prevedendoli, ma fare in modo che

questi non impediscano al sistema di rispondere a determinati requisiti.

In quest'ottica, il ciclo di sviluppo dei sistemi software si modifica, includendo delle fasi

incentrate allo studio della dependability del sistema, sia in stadio progettuale, sia in stadio

implementativo.

Formalmente, il concetto di dependability ha visto attribuirsi, in letteratura, diverse

definizioni. Una delle prime, fra le più accreditate, è dovuta a Laprie che, nel 2001, definì

la dependability come “la capacità di fornire un servizio che possa essere considerato, a

buona ragione, affidabile”. Lo stesso Laprie, tre anni dopo, diede una nuova definizione

del termine, introducendo un concetto di misurabilità della dependability: “la capacità di

evitare fallimenti che siano più frequenti e più gravi di quanto si possa accettare”. Queste

definizioni scaturiscono da approfondite discussioni su termini e definizioni, che sono

documentate in un libro del 1992 edito dallo stesso Laprie [6]. Tale libro contiene, tra

l'altro un glossario dei termini con le rispettive traduzioni in lingua Italiana, Francese,

Tedesca e Giapponese.

Un altro lavoro che ha contribuito alla definizione di dependability e all'organizzazione e

chiarificazione dei concetti ad essa collegati è l'articolo di Avizienis et al. [7]. In questo

lavoro, il concetto di security viene integrato maggiormente tra gli aspetti della

dependability, assumendo maggiore importanza rispetto al lavoro di Laprie [6].

Evidentemente, il differente contesto storico-tecnologico in cui è stato concepito il lavoro

di Avizienis ha indotto il concetto di security ad assumere un'importanza ed una maturità

tale da essere inclusa all'interno dello studio della dependability.

Di seguito si riportano le definizioni di alcuni concetti basilari per poter, in seguito,

definire i diversi aspetti della dependability, le minacce alla stessa e i mezzi per ottenerla:

• sistema: è un'entità che interagisce con altre entità

• servizio: è ciò che fa il sistema, così come percepito dall'utilizzatore. L'utilizzatore può

5

Page 10: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

essere a sua volta un sistema.

Un servizio è corretto se conforme alle specifiche del sistema

• interfaccia: è il confine tra il sistema e i suoi utilizzatori

1.1.1 Attributi della dependability

La dependability è un attributo di qualità di un sistema composto dai seguenti sotto-

attributi:

• availability: disponibilità a fornire un servizio corretto. In altre parole è la probabilità

che, in un certo istante, il sistema fornirà un servizio corretto

• reliability: continutità nel fornire un servizio corretto. In altre parole è la probabilità

che, in un certo intervallo di tempo, il sistema fornirà un servizio corretto

• safety: assenza di conseguenze gravi per gli utilizzatori e per l'ambiente circostante il

sistema. Il concetto di gravità si basa su attività di risk analysis

• integrity: assenza di alterazioni improprie del sistema

• maintainability: capacità di essere sottoposto a modifiche e correzioni

• performability: metrica per valutare le prestazioni di un sistema in presenza di

fallimenti

• security: è, a sua volta un attributo composto, che comprende:

◦ availability: in questo contesto è la disponibilità di servizio per i soli utilizzatori

autorizzati a fruirne

◦ confidentiality: assenza di divulgazione non autorizzata di informazioni

◦ integrity: in questo contesto è l'assenza di alterazioni non autorizzate del sistema

In letteratura sono stati formulati una serie di parametri sintetici che caratterizzano

determinate misure della dependability, fra cui il Mean Time To Failure (MTTF), che è il

tempo medio che trascorre prima che il sistema sia soggetto ad un failure, il Mean Time

Between Failure (MTBF), ossia il tempo medio che trascorre tra due failure, il Mean Time

To Repair (MTTR), tempo impiegato mediamente a ripristinare il sistema in uno stato di

corretto funzionamento, il Mean Down Time (MDT), ossia il tempo medio in cui un sistema

6

Page 11: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

non è funzionante, in un determinato intervallo di riferimento.

1.1.2 Minacce alla dependability

Un servizio corretto si ha quando il servizio implementa la funzione del sistema in

conformità alle specifiche. In corrispondenza di un evento in cui un servizio cessa di

essere corretto, si ha un system failure. L'intervallo di tempo in cui il servizio fornito non è

corretto viene detto service outage, mentre il ritorno alla correttezza del servizio è detta

service restoration. Un servizio può divenire non corretto in diversi modi, chiamati failure

modes. Si definisce errore la parte dello stato del sistema che non risulta corretta, mentre

la causa di un errore, addotta o ipotizzata, viene detta fault.

Esiste una catena di propagazione delle minacce che mette in correlazione fault, errori e

failure. Secondo tale catena, quando il sistema fornisce un servizio corretto, può contenere

un fault (o più di uno) che, finchè non viene attivato, viene detto dormiente. Il fault viene

attivato nel momento in cui produce un errore, che può essere, a sua volta, in uno stato di

non attivazione e viene detto latente, oppure rilevato. Il tipo di fault di cui si è parlato

finora è di tipo interno, in contrapposizione al caso in cui il fault venga “iniettato” nel

componente dall'esterno (ad es. come input da un altro componente). L'attivazione di un

fault consiste in una combinazione di input al sistema (o ad un suo componente), non

necessariamente univoca, che va a sollecitare il fault. Quando un errore si propaga

all'interfaccia del sistema (o di un componente di esso) si ha un failure. La propagazione di

un errore può, peraltro, ingenerare ulteriori errori.

Il tempo che intercorre prima che il fault si attivi viene detto fault dormancy, mentre

l'intervallo di tempo tra l'attivazione e il rilevamento dell'errore è chiamato latency

dell'error detection. Si noti che, poiché un fault può essere introdotto in una qualunque

delle fasi di sviluppo, possono esistere dei fault anche nelle specifiche del sistema, che

consistono nell'omissione o l'alterazione di determinati requisiti, effettivamente voluti da

chi commissiona lo sviluppo del sistema. Questo è un punto ancor più delicato se si

considera che un fallimento viene considerato tale sulla base delle specifiche di sistema.

7

Page 12: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

1.1.3 Mezzi per ottenere e stimare la dependability

Nell'intento di far fronte alla necessità di sviluppo di sistemi critici affidabili, sono state

realizzate numerose tecniche e metodologie, che possono essere distinte in quattro

categorie:

• fault prevention: finalizzate alla prevenzione dei fault

• fault tolerance: contemplano la possibilità della presenza di fault, nell'intento di evitare

che degenerino in failure

• fault removal: hanno lo scopo di eliminare i fault o ridurne la gravità delle

conseguenze

• fault forecasting: si propongono di stimare l'incidenza dei fault, quantificandoli e

prevedendone le conseguenze

Le prime tre categorie sono accomunate dall'intento di conferire al sistema un certo grado

di confidenza, mentre la restante è finalizzata a quantificare tale confidenza, motivandola.

Alternativamente si può effettuare una classificazione di questi approcci a seconda che

questi tollerino o meno la presenza di fault:

• fault intolerance: hanno l'obbiettivo di ridurre l'eventualità di occorrenza di fault.

Come evidenziato in precedenza, seppur con sforzi notevoli, è molto difficile garantire

la totale assenza di fault, che possono, prima o poi, causare dei failure

• fault tolerance: reagiscono all'occorrenza di fault mascherandoli, completamente o

parzialmente, e comunque facendo in modo che questi non possano, entro certi limiti,

provocare dei failure.

La fault tolerance e i meccanismi di supporto ad essa sono particolarmente rilevanti in

questo lavoro poiché lo studio effettuato si è concentrato sulla valutazione di diverse

tecniche per la fault injection, che è finalizzata, a sua volta, proprio allo studio e alla

valutazione dei meccanismi di fault tolerance. Come accennato, un sistema fault tolerant è

progettato per tollerare l'occorrenza di guasti, purchè questi rientrino nell'insieme di guasti

contemplati in fase di progetto. Le tecniche più diffuse si basano sul concetto di

ridondanza che può essere intesa sia in senso spaziale che temporale. Un esempio di

8

Page 13: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

ridondanza temporale consiste, a fronte di un'operazione che ha prodotto risultati non

previsti, nel ripetere l'operazione. La ridondanza spaziale, invece, consiste nel replicare

entità o moduli del sistema per far fronte al fallimento di una copia principale, oppure per

comparare i risultati di copie differenti.

Come evidenzia la Figura 1, preliminari alle azioni per tollerare un guasto, vi sono le

attività di detection degli errori (conseguenti ai guasti) e di recovery. La detection si

occupa di verificare la presenza di uno o più errori mentre la recovery è finalizzata a

ripristinare lo stato corretto del sistema e prevenire la successiva riattivazione di un fault

[7].

Fra i mezzi per migliorare la dependability che sono stati citati, la fault removal merita un

maggiore approfondimento poiché è, insieme alla fault tolerance, il punto di partenza per

la fault injection.

Infatti quest'ultima, se da un lato mira a validare i meccanismi di fault tolerance, dall'altro

9

Illustrazione 1: Tecniche per la Fault Tolerance

Page 14: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

può essere utilizzata per fornire un feedback per la fase di sviluppo evidenziando le

vulnerabilità del sistema al fine di correggerle opportunamente. Ad ogni modo la fault

removal comprende anche altre attività, non ultima quella di testing che tradizionalmente

ha da sempre costituito la tecnica basilare per la produzione di software di qualità.

Un importante concetto, legato a quelli appena esposti, è quello della fault coverage, che

consiste nella probabilità che il sistema gestisca correttamente il guasto dato un fault.

Esiste un'interessante relazione che connette i diversi approcci per la dependability e che

evidenzia la necessità di un approccio combinato. Poiché, infatti, non è possibile credere

di poter produrre sistemi assolutamente privi di difetti anche a mezzo di notevoli sforzi

(fault prevention) si rende necessaria l'eliminazione di tali difetti (fault removal). Ma tale

attività è essa stessa soggetta ad imperfezioni, per cui bisogna essere in grado di stimare

quantitativamente la probabilità di occorrenza di eventuali fault “superstiti” e, altrettanto

importante, di capire quali conseguenze tali fault possano avere (fault forecasting). A

questo punto, si vuole avere, comunque la possibilità che tali fault non diano luogo a

failure, per cui si ricorre alla fault tolerance. Tuttavia le tecniche di fault tolerance sono, a

loro volta, suscettibili agli errori, e anche per queste sono quindi necessarie tutte le

considerazioni fatte per il sistema di partenza.

1.2 Software Faults

Secondo la classificazione di Avizienis et al. in [7], esistono 13 classi di software faults, di

cui solo 5 riguardano fault introdotti in fase di sviluppo del sistema. Lo studio della

software dependability è concentrato proprio su queste classi di fault, che vengono

comunemente chiamati difetti o bug. Il motivo di ciò è, come accennato in precedenza, la

preponderanza di questi fault fra le cause di failure dei sistemi. I moderni sistemi, inoltre,

sono spesso basati sull'utilizzo di COTS (Components Off-The-Shelf) che sono sviluppati

da terze parti e di cui spesso non si ha a disposizione né il codice sorgente, né alcun tipo di

parametro in merito alla dependability del componente stesso. Inoltre, spesso i sistemi

10

Page 15: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

integrano, fra l'altro, componenti o sottosistemi legacy, che eventualmente, così come i

COTS, sono stati sviluppati senza tenere in conto la possibilità di integrazione con altri

sistemi. Tutto ciò conferisce al sistema complessivo un grado di impredicibilità, in termini

di dependability, che rende necessario uno studio particolarmente attento.

E' opportuno chiarire che, sebbene le cause di software failure sono sempre permanenti,

per la natura stessa dei difetti software, il processo che conduce al failure dipende spesso

da una quantità di fattori tale che può essere considerato non deterministico. Le condizioni

dell'ambiente in cui si trova ad operare il sistema possono essere, in molti casi,

difficilmente riproducibili a causa, ad esempio, della programmazione concorrente, race

conditions e altri problemi simili.

Tuttavia i difetti software possono essere permanenti anche nella modalità con cui si

manifestano: la maggior parte di questi difetti vengono scoperti in fase di testing del

sistema ed eliminati. I difetti di questo tipo quindi, detti solid o hard faults, difficilmente

raggiungono la fase operazionale del sistema, in quanto, essendo facilmente riproducibili,

è altrettanto semplice studiare il contesto in cui si manifestano e risalire alla soluzione del

problema. Quando invece i fault hanno una modalità di manifestazione non deterministica,

11

Illustrazione 2: Una classificazione dei Software Faults

Page 16: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

raramente vengono scoperti e, quand'anche ciò accade, poiché non si riescono a riprodurre

le condizioni per la loro manifestazione, il lavoro di eliminazione del difetto si complica

notevolmente. Per tale ragione i fault di questo tipo vengono chiamati elusive fault. Come

si riscontra dalla figura 3, il numero di elusive fault scoperti, in percentuale, cresce

gradualmente, dalla fase di sviluppo, in cui sono praticamente assenti, fino alla fase

operazionale, in cui, poiché il sistema è in esecuzione, eventualmente in un un gran

numero di istanze e nelle più disparate circostanze di utilizzo, aumenta la probabilità di

manifestazione del difetto. Inversamente, i solid bug che, all'inizio della fase di sviluppo

sono, percentualmente, molto maggiori degli elusive bug, sottoposti ad attività di testing,

revisione ed eventualmente di patching, decrescono asintoticamente. In realtà, nel caso di

patching, si ha un andamento a dente di sega per la curva relativa agli hard bug:

solitamente una patch introdotta per eliminare un fault, ne introduce altri. Si noti che le

curve descritte sono unicamente di tipo qualitativo, in quanto non è possibile disporre di

dati concreti a riguardo.

In letteratura, gli hard fault sono anche detti bohrbug, con riferimento al modello atomico

12

Illustrazione 3: Trend dei Bohrbugs e degli Heisenbugs

Page 17: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

di Bohr, che è chiaro e ben conosciuto. Analogamente, gli elusive bugs sono anche

chiamati mandelbug con riferimento a Benoît Mandelbrot, noto ricercatore nel campo

della geometria frattale. Gli elusive bug sono stati definiti anche heisenbug, in allusione al

Principio di Indeterminazione di Heisenberg, che afferma che non si può calcolare allo

stesso tempo e con certezza la quantità di moto e la posizione di una particella. Questa

definizione richiama il fatto che le condizioni di manifestazione degli heisenbug sono

talmente complesse che anche il solo fatto di cercare di riprodurle e registrarne le

conseguenze ne preclude l'attivazione.

Con riguardo ai modelli a stati finiti, un sistema affetto da mandelbug può essere

modellato attraverso una macchina a stati deterministica, mentre se è affetto da heisenbug

si può modellare come una macchina a stati non deterministica.

Vi è un'altra categoria di bug software che è il caso di menzionare ed è quella degli aging

related bugs. Sebbene questi fault siano di tipo permanente, vengono modellati come un

sottoinsieme dei guasti transienti e la loro modalità di manifestazione è correlata

all'uptime del sistema. E' noto che spesso i sistemi software in esecuzione in maniera

continuata, all'aumentare dell'uptime (tempo di attività continuata) tendono ad esibire un

peggioramento delle prestazioni ed un aumento del tasso di fallimento. Questo è un

fenomeno noto col nome di software aging ed è recentemente diventato un importante

campo di studio e ricerca. I sintomi che questo tipo di fault produce sono particolarmente

difficili da studiare, in quanto i failure a cui danno luogo sono frutto di un'accumulazione

di condizioni d'errore. Normalmente, infatti, secondo la catena di propagazione dei fault,

una volta che questi sono attivati dando luogo ad uno o più errori, possono, prima o poi,

degenerare in failure. Per gli aging related bug l'intervallo di tempo che intercorre tra

l'attivazione del fault e il failure, è di solito talmente lungo che diventa molto complicato

risalire alle condizioni di attivazione del fault stesso perchè, in quell'intervallo di tempo,

gli eventi relativi al sistema, inclusi gli input e le transizioni tra i vari stati possono

facilmente deviare la diagnosi. Per tali motivazioni, gli aging related bug rientrano nella

13

Page 18: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

categoria degli heisenbug. Le cause più frequenti di software aging sono il mancato

rilascio di porzioni di memoria precedentemente allocata, il mancato rilascio di risorse di

sincronizzazione precedentemente acquisite, errori di round off, etc. Per combattere i

software fault appartenenti alle categorie citate si hanno differenti metodologie, sia in fase

di sviluppo che in fase operativa, e vengono sintetizzate nella figura 4.

Come accennato in precedenza, la fase di testing, che appartiene allo stadio di sviluppo del

sistema, tende a rimuovere, prevalentemente, i bohrbug, poiché raramente si riescono ad

attivare, in questa fase, le condizioni di attivazione di elusive fault.

Per quanto riguarda, invece, gli heisenbug, la difficile riproducibilità di questi, se da un

lato rappresenta un elemento di difficoltà per la rimozione del bug, al contempo

rappresenta una caratteristica di cui è possibile servirsi per tollerare l'occorrenza del bug:

se si attiva il fault in un dato momento, difficilmente, eseguendo nuovamente il flusso di

esecuzione che ha attivato il fault, ciò accadrà di nuovo. A maggior ragione, riavviando

l'applicazione faulty oppure l'intero sistema, sarà ancora meno probabile l'occorrenza di

una nuova attivazione. Queste ultime due tecniche sono valide anche per scongiurare

14

Illustrazione 4: I bugs e le relative contromisure

Page 19: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

l'occorrenza di failure dovuti ad aging related bug: in questo caso si parla di software

rejuvenation.

Uno tra i maggiori contributi al tentativo di conferire un approccio scientifico alla

classificazione dei software fault è la metodologia che va sotto il nome di ODC

(Orthogonal Defect Classification) [9], nata con l'obbiettivo di fornire agli sviluppatori un

feedback efficace in tempi contenuti. Allo stato dell'arte, prima dell'introduzione

dell'ODC, le tecniche tradizionali difficilmente avevano la capacità di fornire un livello di

dettaglio sufficiente per una comprensione a grana fine del processo di sviluppo, per il

quale, in molti casi, le decisioni erano guidate dall'intuizione e dall'esperienza, piuttosto

che da misure, analisi ed altri approcci tipicamente ingegneristici. In questo l'ODC

possiede il principale elemento di innovazione, assistendo i processi decisionali sulla base

di misurazioni e studi analitici. Lo sforzo principale di questa metodologia consiste nel

ricavare da un insieme di informazioni molto ampio e ricco dal punto di vista semantico

(vengono raccolti i difetti software in tutte le fasi del sistema, dallo sviluppo alla fase

operativa), poche informazioni essenziali effettivamente utili, incentrate sul concetto di

difetto.

A differenza dell'hardware, un difetto software ha una natura piuttosto amorfa e c'è una

difficoltà intrinseca nel dare a questo una definizione chiara, univoca e non ambigua.

Tuttavia, per gli scopi dell'ODC, il concetto di difetto software viene inteso in maniera

molto semplice e sintetica: è la necessità di una modifica al software. Posto in quest'ottica,

il difetto si rende più facilmente identificabile e tracciabile di quanto non possa essere un

fault, un errore o un failure.

Nello spettro delle metodologie di analisi dei difetti, dunque, l'ODC si colloca al centro tra

due estremi opposti: da un lato i metodi puramente quantitativi (matematici, statistici) che

hanno, ad esempio, lo scopo di stimare il tempo di completamento o i costi di garanzia;

dall'altro i metodi di analisi puramente qualitativa, come la Root Cause Analysis. La figura

seguente riassume questo concetto.

15

Page 20: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Secondo tale approccio, i fault sono raggruppati in classi ortogonali, ossia non

sovrapposte, in base a due attributi fondamentali: i defect type e i defect trigger.

I defect type, sono definiti in un'ottica molto vicina a quella dello

sviluppatore/programmatore, da cui la consistente utilità del feedback dei risultati, in

particolare vengono definiti in base alla correzione necessaria a risolverli. L'ODC classica

prevede i seguenti defect type:

• Function. Un difetto di questo tipo condiziona significativamente le capacità del

sistema, le interfacce di programmazione a livello applicativo (API), strutture dati

globali, caratteristiche di interfacciamento con l'utente o con l'architettura hardware.

Richiede una modifica formale al progetto.

• Assignment. A differenza del caso precedente, questo tipo di difetto riguarda poche

linee di codice, come l'inizializzazione di strutture dati o istruzioni di controllo.

• Interface. Riguarda l'interazione con altri componenti, moduli, driver di periferiche,

etc.

• Checking. Rientra in questa classe la mancata validazione di dati e valori prima che

questi vengano utilizzati.

• Timing/Serialization. Questi difetti vengono corretti migliorando la gestione di risorse

condivise e real-time.

• Build/Package/Merge. Sono difetti nelle libreria di sistema, nella gestione delle

modifiche o nel controllo delle versioni.16

Illustrazione 5: Spettro delle metodologie di analisi dei difetti software

Page 21: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

• Documentation. Tali difetti riguardano la documentazione del prodotto, le note di

rilascio o le note per la manutenzione.

• Algorithm. Riguardano problemi di efficienza o correttezza degli algoritmi e possono

essere risolti modificandoli o implementandoli nuovamente, senza comportare una

modifica formale del progetto.

Se il concetto di defect type non è una peculiarità dell'ODC, in quanto è presente già nella

letteratura precedente, quello di defect trigger è stato introdotto ex-novo, per rispondere

alle esigenze della particolare metodologia. In questo contesto, il termine trigger può

essere reso in Italiano con l'espressione causa scatenante in quanto rappresenta ciò che

permette l'attivazione di un fault. Da questo punto di vista, conoscere i defect trigger è

utile per migliorare la comprensione degli aspetti di verifica del processo di sviluppo.

Poiché, infatti, i software fault più problematici sono quelli che sfuggono alle attività di

testing in fase di sviluppo, tali attività potrebbero beneficiare notevolmente delle

informazioni circa i defect trigger perchè queste consentono di capire le modalità con cui

testare il sistema al fine di scoprire il difetto. Per modalità si intende un concetto più

ampio della semplice enumerazione degli input o dei diversi flussi di esecuzione,

includendo anche le condizioni dell'ambiente in cui si esegue il sistema. I defect trigger

sono raggruppati in tre classi, corrispondenti ai diversi processi di testing che avvengono

nel ciclo di sviluppo:

• review – è un processo passivo, in cui si verifica il sistema quando non è in

esecuzione, mediante la documentazione ed il codice

• unit/function test – viene controllata attivamente l'implementazione, mediante

esecuzione del codice

• system test – si simula l'utilizzo effettivo da parte del cliente

Nel processo di review, i trigger consistono nell'attività da parte di un soggetto che riflette

sul prodotto, esamina il progetto, discute l'implementazione. Quando invece il prodotto

viene testato, il trigger consiste propriamente nella causa per cui è stato scritto il test case,

l'idea che ha portato a considerarlo.

17

Page 22: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Per lo scopo di questo lavoro, i trigger più interessanti sono quelli che appartengono al

processo di system testing. Questi possono essere esemplificati come segue:

• Recovery/Exception handling. Un tale evento comporta l'esecuzione di codice di

“emergenza” causato dagli input provenienti dal workload.

• System startup and restart. Questi trigger riguardano le fasi di avvio o di spegnimento

del sitema, in condizioni ordinarie.

• Workload volume/stress. In questi casi il sistema è sottoposto a notevoli sforzi, sia in

termini di risorse che di capacità prestazionali.

• Hardware/software configuration. Questi trigger sono legati a cambiamenti che

avvengono nell'ambiente operativo del sistema.

• Normal mode. I trigger di questo tipo avvengono in condizioni ordinarie del sistema.

1.3 Stato dell'arte nell'iniezione di Software Faults

Come evidenziato in precedenza, le tecniche di fault tolerance utilizzate per migliorare la

dependability di un sistema, sono, a loro volta, suscettibili di errori e incorrettezze. Si pone

dunque il problema di verificare che tali tecniche rispondano in maniera adeguata ai

requisiti. Nel testing dei meccanismi di tolleranza ai guasti ci si pone l'obbiettivo di

verificare che, in presenza di determinati fault, questi siano tollerati opportunamente,

ossia, non degenerino in failure, essendo mascherati, corretti o, ove possibile, ignorati. Se

ciò non è possibile, l'obbiettivo diventa comprendere l'incidenza dei danni conseguenti al

mancato successo delle tecniche. Quando il testing consiste nella deliberata alterazione del

sistema in modo da provocare artificialmente l'occorrenza di fault, per studiare la reazione

del sistema, si parla di fault injection.

Poiché i sistemi in considerazione sono spesso notevolmente complessi, le fault location,

ossia le parti del sistema in cui è possibile iniettare guasti, possono riguardare i più

disparati aspetti del sistema stesso. Una prima, importante distinzione, riguarda l'iniezione

di tipo hardware o software. Nel primo caso, si può agire sia a livello fisico, intervenendo

18

Page 23: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

direttamente sulle componenti elettroniche del sistema, soprattutto se queste sono

progettate tenendo in conto l'obbiettivo della verificabilità (design for testability), sia a

livello logico (che è la tecnica più diffusa), ad esempio emulando gli hardware fault via

software (SWIFI – Software Implemented Fault Injection).

Negli ultimi anni però, vista la maggiore complessità del software e la preponderanza dei

guasti software come cause di fallimenti, la tendenza si è spostata e gli studi si sono

concentrati maggiormente sul software. Anche restringendo le location al solo livello

software, si presentano diverse tecniche alternative, ognuna delle quali presenta differenti

caratteristiche.

In [1] viene fatta una distinzione tra le tecniche basate sull'esecuzione e quelle basate sulla

simulazione.

Nel primo caso, gli esperimenti riguardano il sistema nel suo stadio finale, quando è

considerato ultimato e pronto per l'utilizzo. Con tali tecniche è possibile valutare

concretamente gli attributi di dependability del sistema, ma difficilmente i risultati ottenuti

possono guidare attività di revisione o modifica.

Nel secondo caso invece, viene formulato un modello del sistema, utile a condurre

simulazioni di esperimenti. I fault, infatti, vengono introdotti nel modello piuttosto che nel

sistema stesso, e permettono di comprendere gli effetti degli stessi nei riguardi del

comportamento operativo del sistema. Queste tecniche, intrinsecamente più lente, hanno il

vantaggio di fornire un feedback per la fase di sviluppo.

Un'ulteriore alternativa consiste nel concentrare l'attività di fault injection su un prototipo

del sistema. Tale modalità permette di testare il sistema senza che questo sia

necessariamente completato, e soprattutto senza fare le assunzioni sul sistema necessarie, a

causa delle astrazioni di alto livello, per le tecniche basate su modelli.

Un altro criterio per diversificare le tecniche di fault injection software è il momento in cui

avviene l'iniezione: a tempo di compilazione oppure a runtime. Nel primo caso, il codice

del programma (sorgente o macchina) deve essere modificato prima che l'immagine di

19

Page 24: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

questo sia caricata ed eseguita. Questo metodo non richiede software aggiuntivi a runtime,

né causa perturbazioni al sistema al momento dell'esecuzione. Inoltre, poiché il fault è

cablato nel codice, può essere utilizzato per emulare fault permanenti. Lo svantaggio è che

non è possibile controllare l'iniezione a tempo di esecuzione.

Nel secondo caso, invece, di iniezione a runtime, si rende necessario un meccanismo di

triggering del fault, che faccia cioè innescare l'attivazione del fault (per un

approfondimento sul concetto di trigger si veda il paragrafo sull'ODC). Le tecniche di

triggering includono strumenti di time-out, che possono ad esempio generare degli

interrupt per invocare l'iniezione. Questa tecnica non richiede modifiche all'applicazione

target, né al workload dell'esperimento. Poiché questo metodo inietta i fault su una base

temporale piuttosto che in corrispondenza di eventi specifici o stati del sistema, produce

effetti e comportamenti non predicibili, ma è utile per emulare fault transienti ed

intermittenti.

Alternativamente ai meccanismi di time-out, si può ricorrere ad una tecnica basata sulle

eccezioni (o trap), che, via hardware o via software, possono essere utilizzate per trasferire

il controllo ad un modulo di iniezione.

L'ultima delle alternative di iniezione a runtime, simile alla tecnica di modifica del codice,

consiste nell'inserire istruzioni aggiuntive al programma target che permettono

l'esecuzione di codice per l'iniezione, prima di una particolare istruzione. A differenza del

metodo delle interruzioni, il modulo di iniezione può essere parte del programma target ed

essere eseguito in user mode piùttosto che in system mode.

Un'altra tecnica diffusa nel testing di componenti COTS e dei sistemi operativi, consiste

nell'iniettare i fault fornendo input eccezionali o erronei al componente, ed è chiamata

robustness testing [8]. I fault introdotti con la tecnica di robustness testing rappresentano

possibili conseguenze di fault software reali nei componenti che interagiscono con il

componente target. La questione di stimare la rappresentatività dei fault così iniettati è

stata affrontata in uno studio di Madeira et al. [2], dove si dimostra che, sebbene questa

20

Page 25: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

tecnica possa ritenersi utile nel rivelare vulnerabilità nei componenti (intesa nei riguardi di

input eccezionali piuttosto che nell'accezione utilizzata nell'ambito della sicurezza), non è

utilizzabile per riprodurre fault che siano rappresentativi dei fault interni ai componenti, e

l'impatto causato dalle due classi di fault è sostanzialmente diverso.

In un altro importante lavoro [3], Madeira ha condotto uno studio sperimentale

sull'emulazione dei fault software mediante la fault injection. Uno dei problemi principali

della fault injection in generale, e della software fault injection in particolare, è la

rappresentatività dei fault iniettati, al fine di ottenere risultati significativi.

In letteratura sono presenti numerosi lavori che si occupano di studiare i fault hardware,

classificandoli ed ottenendo statistiche sulle tipologie e frequenze di occorrenza. Non si

può dire altrettanto sui fault software che superano le attività di testing. La scarsa presenza

in letteratura di lavori in merito a questa problematica è dovuta alla difficile comprensione

di questo tipo di fault, che sono spesso difficili da riprodurre e frequentemente, quando il

sistema è in fase operazionale, non vengono riportati, proprio a causa delle difficoltà

intrinseche che ciò comporta. Fra i pochi lavori in merito a questa problematica si

annoverano [15] e [17].

Sebbene altri lavori abbiano cercato di trovare una soluzione al problema di simulare fault

software attraverso la fault injection, il contributo di Madeira [3] consiste nel determinare

in che misura ci si può servire di tool di iniezione di guasti generici per l'emulazione dei

fault software e quanto questi fault siano accurati comparandoli con i fault software reali.

Il risultato a cui si perviene è solo parzialmente positivo: non tutti i software che si

riscontrano nella realtà possono essere simulati con questa tecnica. Da queste

considerazioni nasce l'esigenza di una tecnica differente, finalizzata alla simulazione dei

fault software. Proprio Madeira, in uno studio successivo [5] ha studiato l'utilizzo di una

tecnica pensata specificamente per l'iniezione di guasti software. Tale tecnica, denominata

G-SWFIT (Generic Software Fault Injection Technique), consiste nell'ispezionare il

codice binario dell'applicazione (è dunque una tecnica indipendente dal linguaggio di

21

Page 26: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

programmazione), al fine di trovare delle fault location in cui vengono iniettati errori,

piuttosto che fault, purchè questi siano rappresentativi di guasti software. Inoltre, questi

stessi guasti software sono tenuti, a loro volta, ad essere rappresentativi dei software fault

realmente presenti nei moderni sistemi, e con le stesse distribuzioni probabilistiche, sia in

termini di percentuali relative che in riferimento ai diversi moduli del sistema. Per gli

scopi di questo lavoro, l'aspetto più interessante del lavoro di Madeira consiste nella

metodologia di raccolta e classificazione dei dati (field data) utili per caratterizzare

statisticamente e quantitativamente i software fault che, come già discusso, sono una

tipologia di dati praticamente assente in letteratura.

Al fine di rispettare il requisito della rappresentatività dei software fault, vengono

collezionati numerosi fault presenti in sistemi reali, attraverso la raccolta di patch

applicate ad un discreto numero di programmi open source. Il codice di tali modifiche è

stato ispezionato manualmente per comprendere appieno e classificare correttamente il

relativo fault. In totale vengono raccolti 668 fault di applicazioni che appartengono a

disparate categorie di software: text editing, graphical editing, ambiente di shell, kernel di

sistema, multiplayer games ed altri. L'approccio utilizzato per classificare questi fault è

composto di diversi stadi. Il primo di questi consiste in una classificazione elementare

basata sull'ODC (cfr. paragrafo sull'ODC). Poiché, com'è stato discusso, questa

metodologia nasce con lo scopo di fornire un feedback per la fase di sviluppo, si rende

necessario un'ulteriore raffinamento nella classificazione che permetta di associare i fault

ad un determinato di tipo di costrutto del linguaggio di programmazione. Per costrutto si

intende un componente sintattico elementare del linguaggio di programmazione [5] e può

essere un'espressione, una valutazione, una chiamata a funzione etc. Madeira indica, nel

suo lavoro, tre di queste tipologie:

• costrutto mancante

• costrutto erroneo

• costrutto non necessario

22

Page 27: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Chiaramente quest'estensione all'ODC fornisce un ausilio per l'attività di emulazione dei

fault, poiché emulare un costrutto mancante è sostanzialmente diverso dall'emulare un

costrutto erroneo. L'ultimo stadio della classificazione introdotto, anch'esso, al fine di

facilitare l'attività di fault injection, serve per formulare un insieme di cosiddetti fault

emulation operators, ognuno dei quali emula uno specifico tipo di fault, basandosi non

solo sul tipo del fault ma anche sul contesto in cui si colloca la fault location.

Come si nota dalla seguente figura, l'attività di iniezione dei fault riceve come input i fault

operators ed il codice binario e produce, in uscita, una serie di versioni mutate

dell'eseguibile dell'applicazione, ognuna contenente uno specifico fault.

I fault operator ricordano i cosiddetti mutation operators utilizzati nella tecnica di

software mutation. Tuttavia si differenziano da questi in quanto sono basati su dati

osservati sperimentalmente, piuttosto che essere generati sulla base di considerazioni ed

analisi del codice. Inoltre, la software mutation ha lo scopo di generare il miglior insieme

di casi di test, mentre qui lo scopo è emulare i fault. I fault operators, infatti, modificano il

codice eseguibile introducendo le alterazioni che sarebbero prodotte da un compilatore se,

nel codice sorgente, fosse presente un determinato fault. Nella tabella seguente vengono

23

Illustrazione 6: La tecnica G-SWFIT

Page 28: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

esemplificati gli operatori che, in base allo studio di Maderia, sono relativi ai fault più

frequenti.

Operatore Fault emulato

OMFC Chiamata a funzione mancante

OMVIV Mancata inizializzazione di una variabile con un valore

OMVAV Mancata assegnazione di un valore ad una variabile

OMVAE Mancata assegnazione di una variabile mediante un'espressione

OMIA Costrutto if mancante in vicinanza di espressioni di valutazione

OMIFS Costrutto if ed espressioni di valutazione mancanti

OMIEB Costrutto if , espressioni di valutazione e parola chiave else mancanti

OMLAC Espressione in AND mancante in una condizione di valutazione

OMLOC Espressione in OR mancante in una condizione di valutazione

OMLPA Assenza di una parte ridotta e localizzata di un algoritmo

OWVAV Assegnazione di un valore erroneo ad una variabile

OWPFV Parametro errato in una chiamata a funzione

OWAEP Espressione aritmetica errata fornita come parametro in una chiamata a funzione

24

Page 29: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Capitolo 2: Coflight - un caso di studio di sistema Fault

Tolerant

Questo lavoro di tesi si è concentrato su un particolare sistema fault-tolerant che è, al

momento, in fase di prototipazione. Questo sistema, chiamato COFLIGHT, si colloca

nell'ambito dell'Air Traffic Management (ATM), recentemente diventato ragione di studio

e ricerca a causa della crescente domanda di utilizzo rivolta a questo tipo di sistemi. Le

previsioni, infatti, indicano che gli attuali sistemi ad ausilio dell'ATM non saranno in

grado di rispondere alle esigenze del prossimo futuro. Le stime di EUROCONTROL,

Organizzazione Europea per la Sicurezza del Traffico Aereo, dimostrano questo trend

[10].

IFR Movements (000s)

2006 2007 2014 2020 2025 2030

A: Global Growth 14,119 17,532 19,890 22,086

B: Business as Usual 12,930 15,553 17,763 19,549

C: Regualtion & Growth 9,439 9,916 12,930 14,955 16,724 18,170

D: Fragmenting World 11,773 13,460 15,062 16,507

Average Annual Growth

AAGR2030/2007

TrafficMultiple2030/20072006 2007 2014

2020/

2015

2025/

2021

2030/

2026

A: Global Growth 5.2% 3.8% 2.6% 2.1% 3.5% 2.2

B: Business as Usual 3.9% 3.1% 2.7% 1.9% 3.0% 2.0

C: Regualtion & Growth 3.9% 5.1% 3.9% 2.5% 2.3% 1.7% 2.7% 1.8

D: Fragmenting World 2.5% 2.2% 2.3% 1.8% 2.2% 1.7

Tuttavia, il problema della capacità di servizio dei sistemi ATM non è l'unico movente di

tali ricerche. I requisiti di tali sistemi, infatti, comprendono la necessità di interoperabilità

che è tipica dei sistemi complessi moderni, che devono essere in grado di interagire con

sistemi legacy o sviluppati da organizzazioni diverse, e di essere facilmente estendibili ed

integrabili.

25

Page 30: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Queste problematiche estendono ulteriormente la complessità di tali sistemi, già di per sé

complicati a causa della quantità di sottosistemi di cui sono composti, della loro

dislocazione, e della loro alta criticità.

I sistemi ATM, infatti, rientrano nella categoria dei sistemi Distributed Real-time

Embedded (DRE), una classe di particolare importanza in numerosi settori, fra cui quello

medico, finanziario, dei trasporti, tutti accomunati dal requisito che i diversi componenti

del sistema siano dislocati, eventualmente in aree notevolmente distanti, cooperando in

maniera affidabile per fornire uno o più servizi con tempistiche definite in maniera molto

rigida. Spesso, tuttavia, al requisito di real-time, si sostituisce quello meno stringente di

near real-time. Con tale requisito, si richiede che un sistema fornisca un servizio con una

tempistica che rientri in un intervallo ben definito di possibili valori.

Inoltre, i sistemi ATM, rientrano nell'ambito dei sistemi CCIS (Command, Control and

Information Systems), utilizzati in ambito militare. Questi sistemi stanno subendo,

recentemente, profonde modifiche strutturali, rese necessarie dalla rivoluzione

informativo-tecnologica a cui ha dato luogo l'avvento di Internet [11].

2.1 Introduzione a CARDAMOM

Cardamom è una piattaforma middleware di nuova generazione, nata con l'obbiettivo di

supportare lo sviluppo di sistemi dotati delle caratteristiche appena illustrate.

La caratteristiche tipiche di un middleware tradizionale consistono nel fornire trasparenza

a vari livelli di astrazione, fra cui:

• trasparenza del sistema operativo

• trasparenza del linguaggio di programmazione

• trasparenza della locazione

• trasparenza della migrazione

26

Page 31: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Per ulteriori approfondimenti in merito alle tecnologie middleware si rimanda a [23] e

[24].

Oltre alle caratteristiche tipiche di un middleware, vi è un insieme di caratteristiche

innovative, che rendono Cardamom una soluzione efficiente per le diverse problematiche

sopra esposte. Fra queste, le principali sono:

• conformità alla specifica CORBA dell'Object Management Group (OMG). L'OMG è

un consorzio internazionale non-profit per l'industria informatica, ad iscrizione aperta,

a cui fanno capo un notevole numero di aziende leader del settore. Questo è un

notevole sforzo in direzione della standardizzazione per l'interoperabilità, necessario

per sistemi complessi.

• supporto per il Modello a Componenti di Corba (CCM). I principali vantaggi che tale

modello comporta comprendono la facilità di deployment, l'alto grado di portabilità, la

separazione tra l'aspetto funzionale, ossia la logica applicativa, e gli altri aspetti non

funzionali, legati alla piattaforma d'esecuzione;

• conformità alla specifica CORBA Fault Tolerance. Come ampiamente evidenziato, i

sistemi in questione sono altamente critici e quindi necessitano di soluzioni che

forniscano la tolleranza ai guasti, garantendo il corretto funzionamento del sistema

anche in presenza di questi. La specifica CORBA Fault Tolerance è nata appunto con

lo scopo di standardizzare questi aspetti.

Al di là degli aspetti di Cardamom, strettamente legati alla tipologia di sistemi in

questione, vi sono una serie di caratteristiche che ne fanno un prodotto innovativo ed

appetibile in una serie di differenti contesti:

• è un prodotto open-source. I vantaggi che ciò comporta sono ben noti, ed è il caso di

menzionare il fatto che questo stesso lavoro si è avvalso di questa caratteristica.

• fornisce una piattaforma d'esecuzione a valore aggiunto. Tale valore aggiunto consiste

in una serie di servizi necessari ai sistemi in questione, come ad esempio la QoS.

27

Page 32: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Questo è uno degli aspetti che la specifica CORBA non copre e a cui Cardamom

sopperisce. Soluzioni di questo tipo vengono formalizzate e prototipizzate, quindi

sottoposte all'OMG.

• supporto alla Model Driven Architecture dell'OMG. Questo è un approccio al processo

di sviluppo che si concentra sul dominio applicativo prescindendo dall'ambiente

d'esecuzione finale, facilitando notevolmente quest'attività.

La figura 7 riassume la struttura ed i servizi forniti da Cardamom. Questi vengono detti

servizi pluggable ossia attivabili, a seconda della specifica applicazione. Di seguito

28

Illustrazione 7: I Pluggable Services di Cardamom

Page 33: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

vengono illustrati i principali fra questi servizi.

• System Management

E' uno dei servizi maggiormente importanti, in quanto si occupa di gestire e

monitorare tutti gli elementi del sistema. Per elementi del sistema, nella terminologia

di Cardamom, si intendono processi, componenti, applicazioni, nodi o interi

sottosistemi. Le attività principali del System Management sono:

◦ configurazione del sistema, in fase iniziale ed in fase operativa

◦ gestione dell'avvio (eventualmente ordinato) e della terminazione delle diverse

parti del sistema

◦ monitoraggio delle risorse dei nodi

◦ detection di elementi faulty

◦ riconfigurazione manuale o automatica del sistema, in seguito all'attivazione di

fault o all'occorrenza di failure

◦ notifica ad eventuali parti interessate di cambiamenti di stato o di configurazione

• Life Cycle service

Questo servizio si occupa di allocare e deallocare gli oggetti CORBA e gestire il ciclo

di vita dei servant attraverso strategie opportunamente definite, basate sulle policy dei

corrispondenti Portable Object Adapters (POA).

• Repository service

Fornisce un struttura di memorizzazione di per i riferimenti e gli attributi degli oggetti.

• Event service

Fornisce un supporto alla comunicazione asincrona mediante il modello push di

scambio dei messaggi

• Data distribution service

Supporta la creazione e la sincronizzazione di dati replicati sui diversi nodi, mediante

il modello publish-subscribe.

• Time management service

29

Page 34: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Permette l'esecuzione periodica di determinate operazioni ad istanti di tempo definiti

dall'utente o basati su time-out. Questo servizio è conforme alla specifica OMG

“Enhanced View of Time”

• Persistence service (non ancora implementato)

Fornisce un supporto alla persistenza dello stato degli oggetti CORBA mediante

tecniche di memorizzazione (file, database relazionali o object oriented)

• Transaction service (non ancora implementato)

Fornisce delle interfacce di supporto alle transazioni tra oggetti distribuiti

• Recording service (non ancora implementato)

Supporta la registrazione di eventi ed informazioni per l'analisi tecnica del sistema.

• Traces and performance service

Permette l'analisi a run-time delle prestazioni della piattaforma, così come

dell'applicazione.

Due servizi di Cardamom sono stati omessi in questa trattazione in quanto meritano un

maggiore approfondimento, presente nel seguito di questo capitolo:

• Fault-tolerant service

• Load-Balancing service

La figura 8 mostra che, oltre ai pluggable services, vi sono una serie di servizi di base

(core services) necessari a qualunque sistema, con i quali interagiscono i pluggable

services per fornire i loro servizi.

30

Page 35: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

I principali core services sono:

• Cardamom Foundation. E' un insieme di software ausiliari, che viene incluso in ogni

processo utente e fornisce pattern, protocolli e algoritmi comuni a tutti i servizi di

Cardamom. Inoltre, fornisce un'astrazione rispetto al sistema operativo e l'ORB

sottostanti in modo da rendere il sistema indipendente dalla specifica implementazione

di CORBA e dalla specifica piattaforma d'esecuzione.

• Configuration. La configurazione del sistema è demandata a due insiemi di file:

◦ Generation description – contengono, per ogni eseguibile dell'utente, i servizi e i

profili utilizzati, il compilatore, il sistema operativo e l'ORB utilizzati, etc.

◦ Deployment description – contengono informazioni circa il deployment del

sistema, come ad esempio la distribuzione dei processi sui diversi host.

E' utile, a questo punto, definire il concetto di oggetto Cardamom, poiché questo si

discosta dal concetto di oggetto CORBA comunemente conosciuto. Un oggetto

Cardamom incapsula un oggetto CORBA, che è in relazione biunivoca con esso, per cui

possiede tutte le proprietà di un tale oggetto, e ne estende le potenzialità fornendo dei

meccanismi utili all'interazione con i servizi Cardamom, come la persistenza, la fault

31

Illustrazione 8: Struttura di Cardamom

Page 36: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

tolerance, il load balancing etc.

2.2 Fault Tolerance Service

Il servizio Fault Tolerance di Cardamom è stato sviluppato in conformità alla specifica

CORBA Fault tolerance, presente in [24].

Tale specifica definisce un'architettura e un insieme di servizi e meccanismi per la fault

tolerance che siano di supporto ai sistemi distribuiti con caratteristiche di alta affidabilità e

availability (per una definizione si rimanda al paragrafo 1.1), e si basa sui concetti di

ridondanza, fault detection e fault recovery. La ridondanza viene attuata mediante la

replicazione degli oggetti CORBA, che vengono associati ad un object group, ed ognuno

di essi fa capo ad un'interfaccia comune. I membri di un object group possono essere

referenziati mediante un Interoperable Object Group Reference (IOGR) che è l'estensione

del concetto IOR utilizzato per referenziare i singoli oggetti al caso di un gruppo. Tutto ciò

è implementato, nell'ottica del middleware, in modo da essere completamente trasparente

ai client di tali oggetti che li referenziano come se fosse un unico oggetto. La specifica

CORBA Fault Tolerance definisce anche dei componenti che monitorino le diverse

repliche notificando eventi d'interesse come crash di applicazioni o di nodi.

Nella sua versione attuale, il servizio fault tolerance di Cardamom supporta la sola

modalità di replicazione warm passive, che consiste nel mantenere una replica di un'entità

costantemente aggiornata, ma in stato di inattività fino al momento in cui non viene

rilevato il failure della copia primaria.

Un processo Cardamom che ospita delle repliche di oggetti viene detto Fault Tolerance

Location (FT Location) ed è gestito da un oggetto di tipo LocationManager, che a sua

volta include un oggetto MembersAdmin responsabile di gestire le repliche.

La fault tolerance di Cardamom e attuata a livello di processo, nel senso che tutti gli

oggetti di un processo sono allo stesso tempo copie primarie o di backup, e inoltre tutti i

processi replicati devono contenere gli stessi oggetti. Le entità principali su cui si basa la

32

Page 37: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

fault tolerance sono il Fault Tolerance Manager e i Location Manager.

Come si nota dalla figura 9, il Fault Tolerance Manager è composto da tre elementi:

• Fault detector. Rileva la presenza di fault nel sistema e genera dei fault reports

• Fault notifier. Inoltra i fault reports alle entità interessate, preventivamente registrate al

servizio

• Replication Manager. Permette alle applicazioni di gestire i gruppi di oggetti e i

membri di questi. Inoltre, in quanto registrato al servizio di notifica dei fault report,

avvia il processo di recovery quando viene notificato un fault. In particolare, con la

33

Illustrazione 9: Fault Tolerance in Cardamom

Page 38: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

tecnica di replicazione warm passive, se la replica primaria di un gruppo viene

dichiarata faulty, il Replication Manager procede all'elezione di una nuova copia

primaria.

I Location Manager, invece, sono entità locali ai nodi che ospitano oggetti replicati e

possiedono un'interfaccia per permettere al Replication Manager di aggiornare le FT

Locations modificando il gruppo di repliche. Come accennato in precedenza, con la

replicazione warm passive, un oggetto viene attivato quanto è eletto primario, mentre la

precedente copia primaria viene disattivata dal rispettivo Location Manager.

2.3 Load Balancing Service

Il concetto di load balancing nasce dalla duplice necessità di suddividere il carico su più

server ed evitare la presenza di un single point of failure. In presenza di un unico server,

infatti, incaricato di svolgere una determinata funzione per un dato sistema, l'occorrenza di

un failure pregiudica completamente la disponibilità di quel servizio.

Quando invece il servizio è offerto da più di un server, la probabilità che ciò accada è

inversamente proporzionale al numero di server: in presenza di n server il sistema è in

grado di tollerare i fallimenti di n - 1 server, fornendo comunque il servizio desiderato,

seppure con performance ridotte, nel qual caso si parla di graceful degradation.

Il servizio di Load Balancing di Cardamom permette di smistare le richieste di

un'applicazione client ad un gruppo di server, in maniera da bilanciare il carico ad essi

demandato. A tal fine, il servizio fornisce un meccanismo per stabilire da quale server

deve essere servita ogni singola richiesta. E' basato sulla specifica CORBA, e prevede

diverse strategie di smistamento, fra cui la strategia round robin e la strategia random. In

particolare, la strategia round robin, utilizzata nell'implementazione di COFLIGHT,

discussa in seguito, consiste nello smistamento delle richieste secondo una modalità

circolare, nel senso che i server sono collegati logicamente a formare un cerchio, che viene

34

Page 39: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

percorso in un senso stabilito, e ogni richiesta viene servita dal nodo successivo nel

cerchio.

L'entità incaricata di mantenere l'elenco dei server disponibili è chiamata Load Balancing

Object Manager. La logica di load balancing può essere configurata staticamente oppure

può essere definita dall'applicazione che utilizza il servizio. In conformità con quanto

detto circa la trasparenza alla locazione, obbiettivo del middleware, lo smistamento

avviene senza che il client sia a conoscenza dei dettagli, sebbene, per questioni di

performance, il servizio viene collocato dal lato del client stesso. Infatti, il principio alla

base dell'implementazione di questo servizio è, come visto per il servizio di Fault

Tolerance, l'IOGR. Questo fa sì che il client ha un solo riferimento all'oggetto che

implementa l'interfaccia desiderata, ed è compito del servizio di load balancing tradurre

quest'indirizzo virtuale in un riferimento reale, relativo all'oggetto servente opportuno.

Questo servizio è implementato da quattro moduli fondamentali:

• LBCommon: fornisce dei servizi di ausilio alla gestione degli object group reference e

alla configurazione del servizio

• LBGroupManager: include, fra l'altro, la classe che implementa la vera e propria

attività di load balancing, che comprende la creazione di un gruppo, l'aggiunta o la

rimozione di membri e la scelta delle strategie35

Illustrazione 10: Load Balancing in modalità round robin

Page 40: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

• LBInit: classi di ausilio all'inizializzazione del servizio

• LBStrategies: interfacce per la definizione delle strategie di bilanciamento, ed alcune

implementazioni.

2.4 COFLIGHT

Come anticipato in precedenza, il sistema Coflight si colloca nell'ambito dei sistemi di

supporto all'Air Traffic Management. Più in dettaglio, tale sistema fa parte della categoria

dei Flight Data Processing System (FDPS), un componente basilare di un sistema ATM,

che si occupa della gestione dei piani di volo, chiamati, nella terminologia dell'ambiente,

Flight Data Plan (FDP). Un FDP è una struttura dati che contiene una serie di

informazioni in merito ad un volo aereo. Tra le principali rientrano gli identificativi degli

aeroporti di partenza e di arrivo, la tipologia del volo (IFR o VFR), il numero di

passeggeri, aeroporti di arrivo alternativi, ed alcune informazioni più dettagliate, di tipo

tecnico, che sono il prodotto dell'attività di flight planning, prevista per ogni volo, in cui si

effettua il calcolo della rotta per il volo, in modo da evitare collisioni e ottimizzare lo

spazio aereo che, come accennato, sarà sempre più intensamente trafficato con gli anni a

venire. Questa definizione di massima dell'FDP nasconde, in realtà una struttura dati molto

complessa e dalle dimensioni tutt'altro che trascurabili, a tal punto che si è reso necessario,

per essa così come per altre realtà di questo contesto, un processo di standardizzazione,

che è stato guidato dal progetto Avenue, con il quale sono state definite una serie di

interfacce ed un data dictionary con il consenso di tutti gli stakeholder [12].

36

Page 41: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

La complessità di questa struttura dati lascia intuire la corrispondente complessità del

sistema incaricato di gestirle, il FDPS, soprattutto se si tiene conto del fatto che questo

tipo di dati viene acceduto in scrittura con una frequenza che è stata stimata, nei sistemi

attualmente utilizzati, pari al 100 operazioni al secondo (in un campione di 8000 FPL),

che, considerata la dimensione dei dati acceduti è un carico notevole. Ciò non è dovuto

solo alla numerosità media dei voli attuali, ma anche al numero delle entità del sistema che

accedono a queste informazioni, fra cui i Processing Server, incaricati di processare i piani

di volo, le Controller Working Position (CWP), attraverso le quali si possono inserire,

aggiornare o cancellare piani di volo, ed altre.

Per rispondere ai requisiti di dependability precedentemente illustrati, non ultimi quello di

high availability e safety, Coflight è stato progettato prevedendo la presenza di più

Processing Server (tre nella versione attuale), gestiti secondo una politica di load

balancing. Per motivi prestazionali, inoltre, i tre Processing Server non vengono acceduti

in maniera diretta dai client, ma tramite l'intercessione di un componente che fa da

intermediario, chiamato Facade. Questo ha il compito di gestire le richieste che

provengono da tutti i client, inoltrandole ai processing server secondo la politica di load

balancing prevista (nel caso in esame la politica è round robin), facendo in modo che un

certo piano di volo sia processato, nello stesso momento, al più da un solo processing

server, per questioni di coerenza dei dati. Per questo motivo, il Facade ha anche il compito

37

Illustrazione 11: I tipi di dato di un FDP definiti dal progetto Avenue

Page 42: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

di accodare le richieste per piani di volo già in processamento, inoltrandole solo quando

possibile.

Questo aspetto del Facade fa intuire la necessità, da parte di quest'entità, di mantenere uno

stato dell'attività di processamento. Il concetto di stato di processamento verrà discusso

ampiamente nel paragrafo successivo, in quanto cruciale per l'attività di questo lavoro. In

questa trattazione introduttiva al sistema, è sufficiente tenere presente che il Facade tiene

costantemente traccia degli identificativi dei piani di volo correntemente in processamento

e i rispettivi identificativi dei client che ne hanno fatto richiesta. Questa seconda

informazione è necessaria a causa della politica di sincronizzazione con cui si gestiscono

le richieste, che prevede un disaccoppiamento tra client e facade al momento della

richiesta in modo che i client non rimangano bloccati in attesa della risposta: è il facade ad

inviare la notizia di processamento avvenuto al client che ne aveva fatto richiesta,

mediante il noto meccanismo delle callback.

L'importanza del facade, che già si va delineando, risulta ancora più chiara se si tiene

conto del fatto che rappresenta un single point of failure. Come già discusso, questo tipo di

problema va evitato nei sistemi safety-critical come questo, ed è per questo motivo che il

Facade è, in questo sistema, oggetto di replicazione: il servizio fault tolerance di

Cardamom permette di mantenere una copia di backup del facade primario costantemente

aggiornata con le informazioni circa i piani di volo, in maniera tale che se dovesse essere

rilevato un failure della copia primaria, da parte dell'infrastruttura di Cardamom preposta,

la copia di backup viene attivata e sostituisce l'unità faulty, garantendo la continuità del

servizo. Il punto appena esposto è di particolare importanza per questo lavoro, in quando

l'attività di testing del sistema, descritta nei capitoli successivi, riguarda appunto

quest'aspetto del sistema. Data la necessità di rendere possibile lo scambio di informazioni

sugli FDP tra un ampio numero di entità coinvolte, Coflight utilizza un paradigma di

comunicazione di tipo publish-subscribe in grado di disaccoppiare la comunicazione tra le

diverse entità. La tecnologia utilizzata per questo scopo è quella dei Data Distribution

38

Page 43: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Service (DDS), uno standard OMG che definisce un middleware per lo scambio di

informazioni, di tipo data-centric. Il disaccoppiamento tra le diverse entità interessate

consiste nella possibilità, da parte dei publishers di informazioni, di disinteressarsi

completamente delle entità che le riceveranno, così come i subscriber non hanno necessità

di sincronizzarsi direttamente con le entità che pubblicano le informazioni: un canale

d'informazione comune raccoglie le pubblicazioni e le sottoscrizioni garantendo che i

subscriber ricevano notifica delle pubblicazioni a cui sono interessati, nella versione più

aggiornata.

Nel caso particolare di Coflight il DDS viene utilizzato per lo scambio dei FDP, in

particolare, quando un client effettua una richiesta circa un certo FDP, questa viene

intercettata dal Facade, che come illustrato, la inoltra eventualmente ad un processing

server. Quest'ultimo, al fine di processare l'FDP in questione, ne preleva la versione più

aggiornata dal DDS. Una volta effettuato il processamento, il processing server restituisce

l'intero FDP aggiornato al facade, che provvederà a pubblicarlo sul DDS e a notificare il

client del completamento della richiesta.

L'architettura del sistema Coflight, quindi, prevede la separazione del sistema in più livelli

di astrazione: il livello applicativo, che risponde ai requisiti funzionali del sistema, si

poggia su un duplice livello middleware formato da Cardamom e dal DDS, che astraggono

i meccanismi di interazione tra le diverse entità. La figura che segue riassume questi

concetti.

39

Page 44: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Allo stato attuale, il prototipo prevede la possibilità di richiedere ai Processing Server,

attraverso la mediazione del Facade, le seguenti operazioni

1. Inserimento di un piano di volo

2. Cancellazione di un piano di volo

3. Aggiornamento di un piano di volo

4. Modifica dell'SSR (Secondary surveillance radar) di un piano di volo

Dato lo stadio prototipale del sistema le operazioni illustrate hanno un carattere fittizio, nel

senso che i dati realmente istanziati o modificati non hanno né gli attributi né i valori

collegati in qualche modo con i dati reali.

2.5 Modellazione a stati del sistema

L'approccio di studio della dependability utilizzato in questo lavoro si basa sulla

modellazione del sistema mediante un formalismo basato sugli stati. Ciò è stato dettato

dalla volontà di analizzare gli aspetti relativi alla dependability del sistema,

differenziandone le caratteristiche in base a diverse situazioni operative del sistema. Tali

40

Illustrazione 12: Architettura di Coflight

Page 45: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

situazioni, possono essere definite formalmente una volta introdotto un modello che tenga

in conto determinati aspetti. Poiché il processo di modellazione di un sistema difficilmente

comprendere tutti gli aspetti di questo, è sempre necessaria una cernita degli elementi da

considerare, che è comunque guidata dagli obbiettivi del modello stesso.

Nel caso in esame, l'obbiettivo è quello di guidare la validazione dei meccanismi di fault

tolerance del sistema, andando a testare un certo numero di specifiche condizioni di

funzionamento.

Il formalismo utilizzato è quello delle Finite State Machine (FSM), in base al quale si sono

analizzate diverse alternative per la definizione degli eventi e degli stati del sistema in

esame.In questa fase di definizione si sono affrontate una serie di problematiche, che

vengono qui riassunte ed in seguito analizzate:

• granularità nella definizione degli eventi d'interesse del sistema

• livello di dettaglio degli stati

• complessità del modello.

E' opportuno chiarire che, essendo il Facade e i Processing Server le entità critiche del

sistema, sia dal punto di vista della dependability che dal punto di vista della business

logic, si è deciso di definire stati e transizioni sulla base degli eventi di queste due entità.

Per quanto riguarda la definizione degli eventi è stata valutata l'opportunità di considerare

le system call effettuate dal Facade e dai Processing Server. Questo metodo fornisce la

possibilità di ottenere una consistente granularità nella modellazione del sistema, tale però

da risultare eccessiva per il caso in esame. Un'alternativa a questo metodo, che è quella

che è stata poi adottata, consiste nel considerare come simboli i messaggi di I/O del

Facade e dei Processing Server. Questo metodo, in confronto a quello precedente,

permette una minore granularità nella modellazione del sistema, non permettendo di

considerare particolari stati intermedi, tuttavia è sufficiente agli scopi di questo lavoro.

Con riferimento alla descrizione del funzionamento del sistema (par. 2.4), si riporta di

41

Page 46: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

seguito una tabella indicativa dei messaggi considerati.

Messaggi prodotti dal Facade

01 SSR Update invoked on Facade by some client 02 Facade sent an SSR update request to LB_Group 03 FDP Update invoked on Facade by some client 04 Facade sent an FDP update request to LB_Group 05 Request return invoked on Facade by some Processing Server 06 Request return invoked on some client by Facade 07 Insert operation requested to Facade 08 Insert operation requested to LB_Group by Facade 09 Delete operation requested to Facade 10 Delete operation requested to LB_Group by Facade 20 Delete confirmation sent to Facade by some Processing Server 11 Delete confirmation sent to some client by Facade

Messagi prodotti dai Processing Server12 SSR Update invoked on Processing Server by Facade 13 Processing Server sent an SSR update confirmation to Facade 14 FDP Update invoked on Processing Server by Facade 15 Processing Server sent an FDP update confirmation to Facade 16 FDP insert operation requested to Processing Server by

Facade 17 Processing Server sent a Insert FDP confirmation to Facade 18 Delete operation requested to Processing Server by Facade 19 Delete confirmation sent to Facade by Processing Server

Come risulta dalla tabella, ad ogni messaggio è stato associato un codice numerico

univoco, al quale va aggiunto l'identificativo del piano di volo a cui il messaggio si

riferisce. Di seguito si riporta, a titolo di esempio, un estratto di una sequenza di messaggi

scambiati dalle entità del sistema.

42

Page 47: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

0102: richiesta da parte del Client per il piano di volo 020202: richiesta da parte del Facade per il piano di volo 020101: richiesta da parte del Client per il piano di volo 010201: richiesta da parte del Facade per il piano di volo 011202: un Processing Server ha ricevuto una richiesta per il piano di volo 021201: un Processing Server ha ricevuto una richiesta per il piano di volo 011301: un Processing Server ha inviato una conferma di processamento per il piano di volo 010501: il Facade ha ricevuto una conferma per il piano di volo 011302: un Processing Server ha inviato una conferma di processamento per il piano di volo 020502: il Facade ha ricevuto una conferma per il piano di volo 020602: il Facade ha inviato una conferma al client per il piano di volo 020601: il Facade ha inviato una conferma al client per il piano di volo 01

Un'analisi altrettanto approfondita è stata fatta per la definizione degli stati del sistema. In

questa fase si sono presentate diverse possibilità, ognuna, come nel caso della definizione

dei messaggi, con differenti caratteristiche. Bisogna tenere in conto che l'obiettivo di

quest'attività è scegliere una soluzione che rappresenti un compromesso tra il livello di

dettaglio circa lo stato e la complessità ed il numero di stati che ne consegue.

Considerato il sistema in esame, e in particolare le tecniche di fault tolerance da esso

utilizzate, l'informazione minima che bisogna mantenere nel modellare lo stato è il numero

di richieste accodate ed il numero di richieste in processamento. Volendo aumentare il

dettaglio di informazione sullo stato si potrebbero aggiungere gli identificativi dei piani di

volo a cui queste richieste si riferiscono, tuttavia questa informazione aggiuntiva non è

realmente utile agli scopi di questo lavoro per cui è stata omessa.

Questa, inoltre, avrebbe comportato un consistente aumento del numero degli stati, infatti,

supponendo di limitare il numero di piani di volo ad un intero P, il numero massimo delle

richieste in coda a Q, si avrebbe un numero di stati pari a

A tale formula si perviene tenendo conto che, per la presenza di tre processing server,

ognuno di questi può processare uno qualunque dei P piani di volo, purchè questo non sia

43

P1!P1−3!

⋅∑i=0

Q

Pi =P1!

P1−3!⋅1−PQ1

1−P

Page 48: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

già in processamento presso un altro processing server. Da queste considerazioni deriva il

primo termine del prodotto. Il secondo termine, invece, è dovuto al fatto che, potendo il

Facade accodare Q richieste, ognuna relativa ad uno qualunque dei P piani, si può

rappresentare quest'informazione come la somma delle possibili combinazioni di P simboli

al variare del numero di richieste in coda tra 0 e Q.

Per P = 5 e Q = 3 il numero di stati diventa pari a 25 920. Escludendo questa

informazione, invece il numero di stati, nelle stesse ipotesi fatte nel caso precedente,

sarebbe pari a 44.

Per questo motivo, invece che tenere conto della situazione di accodamento e

processamento dei singoli piani di volo – quest'informazione viene quindi persa -, si è

deciso di mantenere un'informazione più sintetica che comprende il totale di questi valori

e si distinguono gli eventi a seconda che questi riguardino un piano di volo non ancora in

processamento, già in processamento, in coda etc.

Un'ulteriore informazione aggiuntiva sarebbe la tipologia delle richieste in coda ed in

processamento. Questa informazione potrebbe effettivamente fornire una visione più

approfondita del sistema e quindi una maggiore possibilità di scelta sul triggering della

fault injection, aiutando quindi a capire meglio quali sono le fasi che attraversa il sistema

che sono più vulnerabili alla presenza di fault. Tuttavia includere quest'informazione nella

modellazione dello stato del sistema comporta necessariamente un'esplosione del numero

di stati con una conseguente complicazione sia della fase di analisi del modello, sia di

quella di fault injection.

Infatti, anche volendo limitare superiormente il numero di richieste in coda e di

processamento, considerando tre tipologie di richieste, il numero di possibili stati rende

questo metodo impraticabile.

Volendo modellare formalmente questa situazione, si avrebbero le seguenti variabili:

• up (numero di richieste di update in processamento)

44

Page 49: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

• dp (numero di richieste di delete in processamento)

• ip (numero di richieste di insert in processamento)

• uq (numero di richieste di update in coda)

• dq (numero di richieste di delete in coda)

• iq (numero di richieste di insert in coda)

Queste variabili sono legate dalle seguenti relazioni:

up , dp , ip≥0

uq , dq , iq≥0

updpip≤3

updpip≤Q

Le ultime due relazioni esprimono rispettivamente il vincolo che non ci possono essere più

di tre richieste processate contemporaneamente ed il vincolo che non ci possono essere più

di Q richieste accodate. Ognuna di queste due relazioni comporta un numero di

combinazioni che è dato dal numero di punti a coordinate intere presenti all'interno di un

quarto di un cubo di lato rispettivamente 3 e Q.

45

Page 50: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Tali quantità valgono rispettivamente:

Una dimostrazione di queste relazioni è presente nell'Appendice A.

Infine, moltiplicando tra loro queste due quantità, si ottiene il numero di possibili stati di

questo modello. Anche con un numero massimo di richieste in coda relativamente piccolo,

si ha un numero di stati notevole (ad es. per Q = 4 si hanno 700 stati). Per questo motivo

quest'informazione è stata omessa.

Tenendo presente il funzionamento del sistema, ed in particolare la tecnica di load

balancing da esso utilizzata per fornire la funzionalità di processamento delle richieste,

emerge un'ulteriore informazione che risulta opportuno considerare ed è il numero di

richieste sospese. Poiché infatti, il sistema in esame prevede tre Processing Server distinti

che possono processare contemporaneamente altrettanti piani di volo distinti, esiste la

possibilità che al Facade giunga una richiesta per un ulteriore piano di volo, distinto dai tre

attualmente processati. Tale richiesta, ed altre analoghe richieste, vengono sospese, ossia

non vengono inoltrate dal Facade finchè un Processing Server non notifica ad esso il

completamento di un'operazione di processamento, rendendosi quindi disponibile per

processare ulteriori richieste. Per lo scopo di questo lavoro quest'informazione è utile e

non comporta, peraltro, significative complicazioni ed è stata dunque inclusa nella

modellazione dello stato del sistema, pervenendo dunque ad un modello, in forma di Finite

State Machine, in cui gli stati sono caratterizzati da:

1. numero di richieste in processamento

2. numero di richieste in coda

3. numero di richieste sospese

46

∑i=1

4

[4−i−1⋅i ]

∑i=1

Q1

[Q1−i−1⋅i ]

Page 51: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Un generico stato è rappresentato da una stringa suddivisa in tre parti, secondo questa

convenzione:

In questo modello le transizioni vengono attivate in corrispondenza dei relativi messaggi,

per cui è possibile identificare le une con gli altri.

Una versione semplificata del modello FSM presenta sei tipologie di transizione (ovvero

messaggi) che sono presentate nella seguente tabella:

47

Illustrazione 13: Modello a stati finiti del sistema

Page 52: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

CODICE MITTENTE DESTINATARIO DESCRIZIONEFR Facade Processing

ServerIl Facade inoltra al processing server una richiesta di un client

FRQ Facade Processing Server

Il Facade inoltra al processing server una richiesta che era stata precedentemente accodata

PSC Processing Server

Facade Un Processing Server conferma al Facade il processamento di un piano di volo

CR Client Facade Un client invia una richiesta al FacadeCRQ Client Facade Un client invia una richiesta al Facade per un piano di

volo già in processamentoPSC+ Processing

ServerFacade Un Processing Server conferma al Facade il

processamento di un piano di volo quando c'è più di una richiesta sospesa

Si noti che le diverse tipologie di richiesta e di conferma (update, insert, delete) sono state

sintetizzate in una sola tipologia. Ad esempio, le richieste del Facade al gruppo di

Processing Server sono identificate indistintamente dal messaggio FR.

La distinzione tra transizioni di tipo FR ed FRQ si rende necessaria poiché quando il

Facade riceve una notifica del completamento di una richiesta, inoltrando un'ulteriore

richiesta può transitare in uno stato diverso a seconda dei due casi. Ad esempio,

supponendo che il sistema si trovi nello stato 1:0:0, se il messaggio è di tipo FR significa

che il Facade sta inoltrando una richiesta che non era stata accodata, dunque il sistema

transita nello stato 1:1:0. Se invece il messaggio è di tipo FRQ il Facade sta inoltrando

una richiesta precedentemente accodata e dunque transita nello stato 0:1:0.

Un discorso analogo è valido per le richieste di tipo CR e CRQ. In particolare va

sottolineato che le richieste di tipo CR sono state incluse nel modello solo a scopo

esemplificativo, ma non hanno rilevanza pratica in quanto non determinano transizioni di

stato. Ad ogni modo, volendo seguire visivamente e concettualmente un percorso nel

modello degli stati, tali transizioni trovano un senso logico. Ad esempio, supponendo che

il sistema si trovi nello stato 0:0:0, quando un client sottopone una richiesta di

processamento, si hanno rispettivamente le transizioni CR, FR, PSC come risulta

dall'illustrazione 14.

48

Page 53: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

I messaggi di tipo CRQ fanno transitare il sistema in uno stato in cui il valore delle

richieste in coda è incrementato di un'unità. I messaggi di tipo PSC fanno transitare il

sistema in uno stato in cui il numero di richieste in processamento è decrementato di

un'unità. A questo fanno eccezione le transizioni di tipo PSC che partono dagli stati x:3:+.

In corrispondenza di tali eventi, infatti, il processing server che si è appena liberato,

notificando l'evento, avvia immediatamente il processamento della richiesta che era stata

sospesa. Per lo stesso motivo, i messaggi di tipo PSC+, non danno luogo a transizioni di

stato, poiché lo stato di partenza è caratterizzato dalla presenza di ulteriori richieste

sospese.

Di seguito si riporta un sequence diagram esemplificativo della logica di funzionamento

del sistema e delle interazioni tra le diverse entità, in cui sono inclusi gli stati attraversati

(figura 15).

49

Illustrazione 14: Un esempio di sequenza di messaggi applicata al modello

Page 54: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

50

Illustrazione 15: Sequence Diagram di un caso d'uso

Page 55: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Capitolo 3: Progettazione di campagne di testing basate su

Software Fault Injection

Nel Capitolo 1 è stato evidenziato che la software fault injection può essere utilizzata per

validare i meccanismi di fault tolerance di un sistema. Tale tematica viene ripresa e

approfondita in questo capitolo, che costituisce il fondamento di concetti e definizioni su

cui si basa il lavoro sperimentale effettuato, descritto nei capitoli successivi. E' importante

notare che le metodologie di validazione sono soggette esse stesse ad incorrettezze, di

conseguenza risulta di massima importanza organizzare le attività di testing evitandone

l'introduzione. In letteratura sono presenti diversi approcci al problema della progettazione

di attività di testing basate su software fault injection, fra cui il Dependability

Benchmarking Project [13], nato con l'obbiettivo di definire un framework per il

benchmarking di sistemi COTS-based, che possa essere usato, fra l'altro, per la

comparazione della dependability di diverse soluzioni tecnologiche. Ogni approccio,

comunque, si basa su un insieme di concetti, comuni a tutti, che sono descritti nel seguito.

3.1 Obiettivi, definizioni e metriche di valutazione

Gli obiettivi della fault injection riguardano sia la fase di sviluppo che quella operazionale,

in quanto, come già illustrato, questa è una tecnica che può essere applicata nelle diverse

fasi del ciclo di vita di un sistema.

Uno tra gli obiettivi principali, in generale e in particolare in questo caso di studio, è

quello di definire un insieme di fault da iniettare che siano rappresentativi dei fault reali.

Ciò è vero non solo per la software fault injection, ma anche nel caso dell'hardware.

Tuttavia, da un punto di vista logico, i fault hardware sono relativamente più facili da

trattare, perchè spesso si tratta di emulare l'inversione di un bit o la corruzione di un'area

di memoria, che, con le tecniche attuali, non presentano grosse difficoltà. Nel caso del

51

Page 56: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

software, invece, emulare un fault può comportare analisi più complesse, sia dal punto di

vista del triggering, sia dal punto di vista della natura stessa del fault, per cui il problema

della rappresentatività è molto sentito ed è tuttora oggetto di studio e ricerca. Chillarege et

al. hanno studiato dettagliatamente questo problema, in particolare in uno studio del 1996

[14], affrontandone i diversi aspetti e basandosi su dati raccolti sperimentalmente da

sistemi reali. Analizzare le statistiche sui fault trovati nei sistemi reali, infatti, è necessario

per definire il faultload, ossia l'insieme di fault da iniettare, anche chiamato fault library,

mediante tipologie di fault realistici, rispettando le distribuzioni probabilistiche che questi

presentano nella realtà. Il problema della rappresentatività non riguarda solo il faultload,

ma anche il profilo operazionale del sistema, ossia l'insieme di condizioni operative e di

utilizzo presentate dal sistema testato. Anche in questo caso si può fare riferimento a

statistiche ed analisi per riprodurre, in fase di testing, le opportune condizioni.

E' opportuno notare, tuttavia, che ci sono dei casi in cui la rappresentatività può non essere

un requisito fondamentale. E' possibile, ad esempio, ed è il caso della robustness testing,

che si voglia utilizzare la fault injection per testare semplicemente le reazioni del sistema

in presenza di un arbitrario tipo di fault, a prescindere dalla sua natura e, in questo caso,

non è necessario che i fault iniettati abbiano caratteristiche di rappresentatività.

Il lavoro di Chillarege affronta anche un altro problema che va tenuto in conto nella

progettazione delle campagne di fault injection e riguarda le locazioni in cui iniettare in

guasti. Nei sistemi software complessi, infatti, la modularità delle applicazioni implica la

necessità di contemplare l'iniezione differenziando i diversi moduli. Come constatato in

[15], ad esempio, i moderni sistemi software presentano una percentuale più alta di fault

nei moduli di interfacciamento con l'utente, rispetto ai sistemi più datati.

I risultati statistici di questo lavoro, confrontati con altri lavori che hanno analizzato la

stessa tipologia di sistema [16], hanno una caratteristica di generalità e dimostrano che

l'approccio della definizione del faultload basato su dati reali, quando questi sono presenti,

è una valida soluzione al problema della rappresentatività per la tipologia di sistema in

52

Page 57: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

esame, che è quella dei sistemi operativi di grosse dimensioni e con caratteristiche di

robustezza.

Un ulteriore problema da considerare nel progetto di attività di fault injection è la durata

degli esperimenti e, conseguentemente, dell'intera campagna sperimentale. Come è noto, i

fault possono richiedere tempi diversi per essere attivati, e degenerare in failure. Il

problema della rappresentatività introduce un ulteriore vincolo sull'attivazione dei fault,

poiché alterare la corretta tempificazione di iniezione può alterare la rappresentatività del

fault.

Il lavoro di Chillarege [14] propone una soluzione a questo problema, che consiste

nell'iniettare gli errori conseguenti ai fault, piuttosto che i fault stessi, in maniera da

accelerarne la catena di propagazione.

Come si è accennato in precedenza, l'attività di iniezione dei fault può essere intrusiva, per

cui un ulteriore obiettivo, in fase di progetto, è minimizzare le alterazioni al sistema da

parte delle tecniche utilizzate. Le diverse alternative, illustrate nel Capitolo 1, presentano

diversi vantaggi e svantaggi, e ognuna può essere preferibile a seconda degli scopi.

In termini formali, una campagna sperimentale di fault injection, intesa come una

sequenza di test, può essere descritta mediante quattro domini:

• F. sono i Fault da iniettare. Consiste nel dominio degli input dell'attività.

• A. è l'insieme delle Attivazioni, ossia delle condizioni che sollecitano il sistema,

favorendo l'attivazione dei fault.

• R. sono i cosiddetti Readout, ossia le osservazioni di determinati comportamenti del

sistema a fronte di una certa iniezione

• M. sono le Misure ricavate dai readout

In ogni esperimento, viene preso in considerazione un elemento dell'insieme F e,

contestualmente, viene definita l'attività che il sistema deve svolgere durante l'esperimento

(scelta di un elemento di A). Come illustrato, tali scelte possono essere fatte sulla base di

considerazioni statistiche. Infine, sulla base di precisi criteri, si raccolgono i risultati

53

Page 58: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

dell'esperimento, associandoli ad elementi dell'insieme R. Un esperimento, quindi, può

essere visto, in senso lato, come un punto all'interno dello spazio cartesiano FxAxR.

3.1.1 Il caso di studio COFLIGHT

In questo paragrafo viene esemplificato il modo in cui le problematiche generali esposte

nel paragrafo precedente sono state affrontate nello studio del sistema in esame.

Nel caso di studio COFLIGHT, il sistema testato si trova in fase di prototipazione e la

fault injection ha lo scopo di rivelare eventuali falle dei meccanismi di fault tolerance,

testando diversi stati del sistema.

Nel paragrafo 1.3 è stata illustrata la tecnica G-SWFIT introdotta da Madeira in [5] per la

definizione e l'iniezione di faultload rappresentativi per la fault injection in sistemi

software. La tecnica utilizzata nella prima campagna sperimentale di questo caso di studio

[25] non si discosta molto da quella proposta da Madeira: la definizione del faultload è

basata su quel lavoro, utilizzando gli stessi fault operators, peraltro già illustrati

precedentemente in questa trattazione (paragrafo 1.3). Tuttavia la tecnica di iniezione

propriamente detta si differenzia per il momento dell'iniezione: al fine di determinare le

possibili fault location, piuttosto che ispezionare il codice binario nella ricerca di pattern

relativi a sezioni di codice opportune, viene ispezionato direttamente il codice sorgente,

che, una volta determinati i fault, viene modificato mediante i fault operators.

Ovviamente, tale tecnica necessita del codice sorgente dell'applicazione, cosa che non

accade per la tecnica G-SWFIT, particolarmente adatta ai sistemi COTS-based. Entrambe

le tecniche necessitano di un adattamento allo specifico linguaggio di programmazione

con cui è implementato il sistema, tuttavia, la tecnica utilizzata in questo lavoro ha il

vantaggio di superare una serie di problemi di accuratezza e di corrispondenza tra le

modifiche agli eseguibili e i fault che rappresentano, che è un problema di cui soffre

l'approccio G-SWFIT (per approfondimenti si consulti [5]). Questo vantaggio ha il costo

di un aumento del tempo necessario alla generazione delle varianti faulty del sistema,

poiché si rende necessaria una separata ricompilazione del codice per ogni fault da

54

Page 59: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

iniettare. Il tool proposto in [25] produce a partire dall'input (il codice sorgente) un

insieme di patch relative, ognuna corrispondente ad un fault. In questo lavoro, il codice

che è stato sottoposto a quest'attività è quello del facade, che, come è stato ampiamente

discusso, rappresenta l'entità del sistema che più di tutte necessita di analisi e

approfondimenti. Il processo di compilazione è stato automatizzato mediante script,

prevedendo la raccolta dei diversi eseguibili per un successivo utilizzo. Nel caso in esame,

il tool ha generato 537 patch relative al codice sorgente del facade, rappresentative di

altrettanti fault.

Si noti che quest'approccio risponde, tra l'altro, alla problematica della rappresentatività

dei fault, che è stata illustrata nel paragrafo precedente.

Analogamente, il problema della rappresentatività del profilo operazionale e del necessario

contenimento dei tempi necessari agli esperimenti sono stati affrontati progettando un

opportuno workload che ha, inoltre, un requisito peculiare della tecnica proposta, che è

quello di testare i diversi stati del sistema (si veda, a tal proposito, il paragrafo 2.5).

A tale scopo è stato progettato ed implementato un client che effettuasse una successione

ben precisa e ripetibile di richieste in modo da sollecitare il sistema nella maniera

desiderata. Contestualmente si sono instrumentate le diverse entità del sistema in maniera

da permettere un maggiore controllo sulle transizioni degli stati. In particolare ai normali

parametri di scambio delle funzioni utilizzate nello scambio di messaggi (id del piano di

volo, callback del chiamante, etc.) si è aggiunto un parametro che permettesse al client di

gestire, indirettamente, il tempo di processamento dei processing server, che in questo

prototipo di sistema è un processamento fittizio.

E' il caso di chiarire che, nonostante questa tecnica, non tutte le transizioni sono

direttamente controllabili mediante il workload. In altre parole, con riferimento al modello

del sistema illustrato al paragrafo 2.5, tramite il client è possibile dare luogo ad un

messaggio di tipo CR o CRQ ma i conseguenti messaggi di tipo FR, FRQ, PSC seguono

spontaneamente dal comportamento del sistema. Tuttavia, tramite il parametro introdotto è

55

Page 60: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

possibile gestire con relativa precisione la tempistica dei messaggi PSC o PSC+ (a meno

di notevoli ritardi nello scambio di messaggi, dovuti – ad esempio – a problemi nella rete).

3.2 Misure e raccolta dati

I readout costituiscono un insieme di informazioni utili a caratterizzare lo stato del

sistema, mediante le quali vengono verificati una serie di predicati, finalizzati ad astrarre

le specifiche del sistema ed in particolare dei meccanismi di tolleranza ai guasti. Esempi di

predicati possono essere “fault attivato”, “fault attivato ed errore rilevato”, “errore rilevato

& servizio fornito correttamente”, etc. Tali predicati possono essere utilizzati per costruire

un modello del comportamento del sistema in presenza di fault, come è il caso

dell'esempio, in forma di grafo, riportato nella figura seguente.

La transizione 1 corrisponde all'evento di attivazione del fault, mentre la transizione 2

contempla il caso, plausibile, in cui un fault non venga attivato in un certo esperimento. La

transizione 3 comporta il rilevamento di un errore, che è, di norma, una transizione

necessaria per poter tollerare il guasto (transizione 6). Tuttavia può accadere (transizione

4) che l'errore non venga rilevato, ma viene tuttavia tollerato. Le transizioni 5 e 7, infine,

sono rappresentative rispettivamente di fallimenti da parte del meccanismo di detection

(così come per la transizione 4) e del meccanismo di fault tolerance. Un grafo di questo

56

Illustrazione 16: Predicati e modello di comportamento

Page 61: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

tipo può aiutare a modellare la misurazione di determinati parametri d'interesse, nel

momento in cui, sulla base dei dati sperimentali ottenuti, si associano alle transizioni

appena descritte, delle percentuali di occorrenza.

Le misure di dependability di un sistema possono essere classificate in base a diversi

criteri. Si possono infatti avere misure quantitative o qualitative, in quanto, ad esempio,

una campagna di test può essere finalizzata alla sola identificazione di determinate

caratteristiche del sistema, o di sue vulnerabilità, per cui non è necessario ottenere misure

a valori numerici.

Inoltre, le misure possono essere relative alla sola dependability oppure in congiunzione

alle performance del sistema. Un'altra distinzione può essere fatta tra misure comprensive

e misure specifiche: le prime riguardano il sistema nel suo complesso, al livello di servizio

fornito, prendendo in considerazione gli eventi che ne condizionano il comportamento; le

ultime dettagliano particolari aspetti di un sistema, come ad esempio le capacità dei

meccanismi di fault tolerance, la manutenibilità etc.

Ad ogni modo, le misure d'interesse per un certo sistema sono strettamente dipendenti dal

sistema stesso, e in particolare dall'implementazione di questo, incluse le caratteristiche di

controllabilità e osservabilità. Ad esempio, le misure d'interesse relative alla dependability

di un sistema operativo possono includere:

• misure relative alla robustness: un sistema operativo tipicamente interagisce col

sottostante livello hardware, e col soprastante livello middleware o applicativo, per cui

una misura d'interesse può essere il grado di resistenza ad input eccezionali

provenienti da questi livelli

• misure relative alla capacità di rilevamento e coverage, ad esempio di meccanismi per

preservare l'integrità del file system

• misure relative alla capacità di confinare gli errori

• misure temporali, ad esempio i tempi di riavvio, riconfigurazione o di esecuzione di

specifici task

57

Page 62: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Analogamente, i sistemi transazionali presentano misure di interesse proprie di questa

categoria, fra cui:

• numero di transazioni al minuto in presenza di fault

• numero di transazioni abortite in presenza di fault

• availabity in presenza di fault

• failure modes

Un discorso a parte è necessario per quanto riguarda i sistemi embedded, che esulano da

ciascuna categoria fra quelle affrontate e presentano caratteristiche diverse, e

conseguentemente misure d'interesse differenti, a seconda del sistema in esame. In questo

caso le specifiche del sistema costituiscono il riferimento rispetto al quale è possibile

definire quali siano i parametri da considerare. In ogni caso, infatti, la caratterizzazione di

un sistema deve tenere in conto gli obiettivi dello stesso, ossia, nei termini della

dependability, la conformità del servizio fornito alle specifiche relative. Ad ogni modo,

possono essere individuate delle misure di carattere generale:

• tempo di risposta in presenza di fault: è un parametro generalmente di grossa

rilevanza, in particolar modo per i sistemi real-time, fra i quali rientra il sistema

oggetto di questo lavoro. Assumendo che le caratteristiche temporali del servizio siano

note, si può misurare la degradazione delle performance del sistema in presenza di

fault

• throughput in presenza di fault: è un parametro di notevole importanza, soprattutto nel

caso dei sistemi DRE

• stabilità: rappresenta la misura in cui il failure di uno o più componenti del sistema ne

condizionano il comportamento complessivo

• Failure modes

Questi esempi di misure riguardano un sistema nella maniera in cui il suo comportamento

58

Page 63: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

può essere percepito dall'esterno. Tuttavia esistono una serie di misure che riguardano

aspetti che possono essere definiti interni al funzionamento del sistema, in particolare

quelle che caratterizzano i meccanismi di tolleranza ai guasti, e con riferimento alla

definizione formale delle campagne sperimentali di fault injection, si possono estrarre dai

readout degli esperimenti.

L'efficienza di un meccanismo di fault tolerance è legata alla relativa coverage e latency

(per le definizioni si veda il Capitolo 1). Si noti che entrambi i tipi di misure possono

richiedere l'instrumentazione del sistema sotto test, ed è appunto il caso del sistema in

esame in questo lavoro. Supposto che si abbiano a disposizione i mezzi necessari per

rilevare gli eventi di attivazione, di detection e di failure, le misurazioni possono essere

condotte con relativa facilità.

Le misure relative alla latency richiedono che, attraverso opportuni mezzi, si abbia la

possibilità di caratterizzare temporalmente gli eventi di iniezione, attivazione e detection.

In ogni caso, l'implementazione di tali misurazioni non può prescindere dallo specifico

sistema, e in particolare dall'implementazione dei meccanismi di detection.

Le misure relative alla coverage comprendono i seguenti fattori:

• fattore di attivazione dei fault: è il rapporto tra il numero di fault iniettati ed il numero

di fault attivati

• fattore di non isolamento degli errori: è la somma degli errori, rilevati e non,

degenerati in failure, divisa per il numero di fault attivati

• fattore di error detection – può essere calcolata in diversi modi, fra cui:

◦ numero di errori rilevati diviso il numero di errori attivati

◦ numero di errori rilevati diviso il numero di fault iniettati

• fattore di error recovery – anche questo può essere calcolato in diversi modi:

◦ numero di errori corretti diviso il numero di fault attivati

◦ numero di errori corretti diviso il numero di fault iniettati

59

Page 64: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Nella trattazione svolta finora si è supposta la presenza di mezzi per la raccolta dei dati

necessari ai diversi tipi di misurazioni, tuttavia questo punto merita un ulteriore

approfondimento.

Come è facile riconoscere, non solo le informazioni d'interesse variano a seconda del

sistema, ma varia anche il modo in cui queste possono essere raccolte. Generalmente, le

informazioni necessarie per ricavare misure di tipo prestazionale possono essere ottenute

mediante l'osservazione degli output ordinari del sistema. D'altro canto, le informazioni

che riguardano il funzionamento interno del sistema, come i meccanismi di fault tolerance,

o le informazioni relative ai fallimeni, generalmente vengono ottenute mediante una

preventiva instrumentazione del sistema, affinchè questo produca una serie di notifiche

utili, che vengono normalmente immagazzinate su opportuni supporti, o inviate ad entità

interessate.

Questo è un meccanismo noto col nome di logging ed è una pratica diffusa da tempo,

poiché fornisce un supporto notevole in numerose attività, come la diagnosi dei guasti,

l'analisi delle attività svolte e i rispettivi responsabili, analisi di mercato etc.

Tipicamente, una voce di log comprende le seguenti informazioni:

• data ed ora dell'evento

• descrizione dell'evento

• applicazione o modulo di sistema che ha notificato l'evento

• tipologia dell'evento

Ai fini della fault injection, i log sono fondamentali per la comprensione dei risultati degli

esperimenti, e generalmente costituiscono la gran parte dei readout di cui si è discusso

precedentemente.

3.3 Analisi dei dati

Poichè, di norma, i log sono utilizzati per ricavare un insieme di informazioni che è spesso

60

Page 65: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

notevolmente maggiore di quello necessario per gli scopi della fault injection, solitamente

si rende necessaria una fase di filtraggio dei dati, che produce, come risultato, un insieme

di informazioni essenziali, idoneo ad essere poi sottoposto ad una fase di analisi. Tale fase

di filtraggio è guidata da due criteri fondamentali: cosa va raccolto e come va raccolto.

Entrambi i criteri vanno definiti in dipendenza del sistema in esame e del tipo di analisi

che si intende effettuare sui dati, tuttavia in generale esistono delle problematiche comuni.

Ad esempio, il fatto che un evento comporti una serie di relative notifiche comporta spesso

una ridondanza di informazioni non necessaria per l'analisi dei dati.

Le tecniche di filtraggio principali si basano su due strategie principali:

• blacklist: consiste nel filtrare tutti gli eventi che contengono, nella voce di log, delle

parole chiave presenti nella lista

• whitelist: contrariamente alla strategia precedente gli unici eventi raccolti sono quelli

che contengono, nella voce di log, delle parole chiave presenti nella lista

Un'ulteriore fase di organizzazione dei dati, che precede la fase di analisi, e che spesso è

necessaria, è la fase di coalescenza delle informazioni. Letteralmente, il termine indica

un'attività di raggruppamento di parti divise e, nel caso in esame è appunto il lavoro di

individuare, fra le varie voci di log, quelle che sono accomunate da determinati criteri, in

base ai quali si hanno diversi tipi di coalescenza:

• temporale

• spaziale

• basata sui contenuti

La coalescenza temporale, anche detta tupling, si basa sulla vicinanza temporale degli

eventi: spesso, come anticipato, più voci di log possono indicare la notifica dello stesso

evento. Una tecnica frequentemente adottata consiste nel definire una finestra temporale

per il raggruppamento degli eventi. La coalescenza spaziale è, di norma, utilizzata per i

sistemi distribuiti, ed è utilizzata per raggruppare eventi ravvicinati nel tempo su nodi

61

Page 66: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

diversi del sistema. Tali eventi possono risultare dalla propagazione delle conseguenze di

altri eventi correlati. La tecnica utilizzata è simile a quella esposta per la coalescenza

temporale ma viene applicata sul concatenamento complessivo dei log di tutti i nodi.

Come illustrato in seguito, questo lavoro si è servito di una tecnica di questo tipo. La

coalescenza basata sui contenuti, invece, si basa sull'osservazione della descrizione degli

eventi ed è spesso usata in congiunzione alle altre due tipologie di coalescenza.

L'analisi dei dati che segue queste attività dipende dal contesto specifico per cui viene

effettuata, e generalmente consiste nello studio statistico dei dati al fine di estrarre

informazioni quantitative sui fault del sistema. Le tipologie di analisi che vengono

effettuate solitamente sono:

• Classificazione dei failure e delle relative operazioni di ripristino

• Distribuzione dei tempi di occorrenza dei failure e delle relative operazioni di

ripristino

• Correlazione tra i failure

• Derivazione e caratterizzazione di modelli di simulazione

La classificazione dei failure è finalizzata a definire i failure in base alla loro natura e/o

alla loro collocazione rispetto al sistema e a produrre statistiche in merito alla gravità dei

failure, il loro impatto sul comportamento del sistema, la coverage dei meccanismi di

recovery del sistema. L'analisi della distribuzione dei tempi di occorrenza dei failure e

delle relative operazioni di ripristino è finalizzata a modellare tali tempi mediante delle

variabili aleatorie continue, come quella esponenziale, lognormale, Weibull. L'analisi di

correlazione tra failure ha lo scopo di rilevare eventuali relazioni tra failure occorsi in

diversi componenti o in diversi nodi e permette di effettuare diagnosi on-line e derivare

tendenze statistiche dei failure correlati. L'analisi volta alla derivazione e popolazione dei

modelli, infine, permette di stimare i valori d'interesse per la modellazione che, come

evidenziato in precedenza, è una tecnica di notevole aiuto nello studio della dependability.

62

Page 67: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

3.3.1 Il caso di studio COFLIGHT

I readout ottenuti dalla campagna sperimentale in questione consistono in specifiche voci

dei log prodotti dalle diverse entità del sistema. E' opportuno chiarire una sfumatura nel

concetto di readout per questo particolare studio: un certo insieme di voci nei log è stato

analizzato per lo scopo, usuale, di verificare eventi anomali, mentre un altro insieme di

voci consente di risalire ai diversi stati del sistema così come sono stati modellati. La

notifica di tali voci è resa possibile da una preventiva instrumentazione del sistema,

secondo la convenzione esemplificata dall'esempio che segue:

1. Mittente del messaggio

2. Timestamp

3. Simbolo utilizzato per distinguere questo tipo di messaggi all'interno dei log

4. Codice del messaggio (si veda la tabella al paragrafo 2.5)

5. Identificativo del piano di volo a cui si riferisce il messaggio

Simili notifiche sono prodotte dalle seguenti entità:

• facade primario

• facade secondario

• processing server #1, #2, #3

I log che, invece, sono stati considerati per la rilevazione degli eventi d'interesse circa

l'andamento dell'esperimento sono quelli prodotti dalle seguenti entità:

• facade primario

• facade secondario

• client

• Cardamom Platform Supervision Daemon (CdmwDaemon) su ciascuno degli host

Quest'ultima è una facility dei core-services di Cardamom che è presente su ogni host del 63

Facade1 2009/05/06 12:48:18:615:865 [M] [02] [01]

1 2 3 4 5

Page 68: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

sistema ed ha il compito di monitorare le applicazioni in esecuzione sull'host, risultando

dunque utile per l'analisi dei risultati degli esperimenti.

Le voci dei log utili all'analisi dei risultati sono state estratte mediante operazioni di

filtraggio e sono quelle contenenti le seguenti stringhe (la notazione utilizzata è quella

delle espressioni regolari):

• "Facade1.*created" all'interno del log del CdmwDaemon

• "Facade2.*created"

• "exception.*facade1" all'interno del log CdmwDaemon.log

• "exception.*facade2"

• "switching" nel log facade_server.log del facade secondario

• “Num richieste eseguite con successo” nel log del client

Si noti che, nei file di log, a ciascuna delle voci illustrate sono associate data ed ora

dell'evento. Le misure estratte dalla campagna sperimentale sono il numero di esperimenti

andati a buon fine (o dualmente il numero di test falliti) e la distribuzione di tali dati

rispetto ai diversi stati del sistema. Per ogni test fallito, infatti, è stato determinato l'ultimo

stato in cui si trovava il sistema quando il test è terminato. Sebbene determinare lo stato in

cui si è attivato il guasto potrebbe sembrare un'alternativa migliore, comporterebbe una

complicazione eccessiva dell'attività di analisi, non necessaria agli scopi di questo lavoro.

Per esperimento andato a buon fine si intende, in questo lavoro, un esperimento in cui il

sistema ha servito tutte le richieste che sono state ad esso sottoposte. Analogamente, un

esperimento è definito fallito se il sistema ha servito un numero di richieste minore di

quelle sottoposte.

Inoltre, per ognuno dei test effettuati si è ricavata la sequenza degli stati attraversati, e tale

informazione è stata inserita all'interno di un file associato ad ognuno dei test. Di seguito

si riporta un estratto di un tale file:

01 01 → 00:00:00

64

Page 69: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

02 01 → 00:01:00

12 01 → 00:01:00

01 01 → 01:01:00

01 01 → 02:01:00

01 01 → 03:01:00

13 01 → 03:01:00

05 01 → 03:00:00

12 02 → 03:00:00

13 02 → 03:00:00

...

65

Page 70: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Secondo la convenzione utilizzata in questa tipologia di file, a sinistra della freccia sono

presenti i messaggi ricavati dai log, mediante la tecnica e la codifica esposta in

precedenza. A destra della freccia, invece, sono presenti gli stati attraversati. La freccia

indica una potenziale transizione di stato (il nuovo stato è appunto quello a destra della

freccia) dovuta al messaggio relativo.

Queste informazioni permettono di ricavare, per ogni test, quali sono gli stati attraversati e

dunque, anche l'ultimo stato del sistema prima che il fault, eventualmente, degenerasse in

un system failure.

E' stato sviluppato un tool al fine di derivare da questi log, in particolare dai messaggi

introdotti nei log appositamente per questo scopo (si veda il paragrafo 2.5), la sequenza

degli stati attraversati.

Tale tool riceve in ingresso i log dei facade e dei processing server, ne effettua una sorta di

coalescenza spaziale e temporale, ordina i messaggi temporalmente, conservando l'identità

del mittente e, da questa sequenza di messaggi ricava gli stati attraversati, coerentemente

con il modello del sistema illustrato nel Capitolo 2. Il funzionamento del tool è riassunto

nella figura 17.

66

Page 71: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

67

Illustrazione 17: Tool utilizzato per analizzare i log del sistema

Page 72: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Con riferimento al grafo in figura 16, che modella il comportamento del sistema in

presenza di fault, i predicati sono:

• Il facade primario è andato in crash (E)

• Il facade secondario è stato attivato (D)

• (1 OR 2) AND 3 AND il sistema ha servito tutte le richieste previste (T)

• 1 AND il facade secondario non è stato attivato (Failure)

• 1 AND 2 AND il sistema non ha servito tutte le richieste previste (Failure)

68

Page 73: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Capitolo 4: Valutazione sperimentale basata sullo stato

dell'arte

Questo capitolo si propone di descrivere i risultati ottenuti con le diverse campagne

sperimentali effettuate con riferimento alle metodologie e tecniche descritte nel capitolo

precedente. Al fine di comprendere con maggiore dettaglio le vulnerabilità del sistema,

infatti, sono state condotte più campagne, ognuna con una diversa configurazione, per

quanto riguarda le componenti soggette all'iniezione di guasti. Ciò è stato anche dettato

dalla necessità di esplorare il modello a stati del sistema con la maggiore accuratezza

possibile, poiché, come evidenziato in precedenza, la tipologia di fault utilizzata per queste

campagne, insieme con la tipologia di workload utilizzato e la logica di funzionamento

del sistema, spesso complica il controllo diretto delle transizioni fra i diversi stati del

sistema. Le campagne effettuate, descritte nei paragrafi successivi, prevedono le seguenti

configurazioni:

• Facade primario e secondario faulty

• Facade primario faulty con esplorazione del modello a stati in senso orizzontale

• Facade primario faulty con esplorazione del modello a stati in senso verticale

• Facade primario faulty con diversificazione delle richieste

• Un solo processing server faulty

• Tutti i processing server faulty

4.1 Entrambi i facade faulty

Questa campagna sperimentale è stata condotta iniettando i fault sia nel facade primario

che in quello secondario, utilizzando, di volta in volta, lo stesso fault per entrambi.

4.1.1 Copertura degli stati

La figura 18 mostra il comportamento del workload utilizzato in questa campagna in

69

Page 74: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

merito alla modalità di esplorazione del modello. Le frecce di colore blu corrispondono ad

eventi direttamente controllabili tramite il client, mentre quelle di colore giallo seguono

direttamente dal comportamento del sistema. Infine, le bande di colore verde evidenziano

l'ordine con cui vengono attraversati i diversi stati. Nel seguito, salvo dove diversamente

specificato, questo è il workload utilizzato per le altre campagne.

Ricordando che il sistema è composto da due repliche distinte del facade, si noti che i

fallimenti oggetto di questa discussione, e di quelle relative alle campagne sperimentali

seguenti, sono relativi ad un singolo facade e sono stati dedotti dai fallimenti complessivi,

ossia i casi in cui il sistema ha servito un numero di richieste minore del previsto. La

logica utilizzata per dedurre i fallimenti dei singoli facade consiste nel verificare, se il test

è complessivamente fallito, l'evento di switching della replica secondaria a replica

70

Illustrazione 18: Workload ad esplorazione orizzontale

Page 75: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

primaria. In caso affermativo, è possibile dedurre che entrambi i facade sono falliti,

perchè, pur essendo stata utilizzata la copia di backup, questa non ha assolto alla fornitura

del servizio in maniera corretta. In caso negativo evidentemente le modalità di fallimento

del facade primario sono tali da precludere l'attivazione del facade secondario che, non

essendo attivato non ha modo produrre un fallimento. Una terza alternativa è il caso in cui

il test è complessivamente riuscito, ossia il numero di richieste servite è pari a quello

previsto, tuttavia si riscontra l'occorrenza dell'evento di switching della replica secondaria

a replica primaria che suggerisce l'occorrenza di un fallimento da parte della copia

primaria. La figura 19 riassume quanto detto.

La figura 20 mostra il modello a stati finiti del sistema in cui sono riportate, per ogni stato

in cui è avvenuto almeno un fallimento, le percentuali di fallimento del facade primario.

71

Illustrazione 19: Classificazione dei test

Page 76: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

72

Illustrazione 20: Distribuzione dei fallimenti nello scenario con entrambi i Facade faulty

Page 77: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

In questa campagna sperimentale, costituita da 537 casi di test, sono stati riscontrati 145

fallimenti complessivi. Di questi, 68 casi presentano l'occorrenza di switching, per cui ad

essi corrispondono 136 fallimenti singoli, mentre in 77 casi lo switching non si è

verificato. Infine, in 5 casi, fra i test terminati con successo, si è verificato l'evento di

switching. Complessivamente, quindi, i fallimenti singoli che si sono verificati, del facade

primario e del secondario, sono 218.

Per questa particolare campagna è opportuno tenere presente che, nei casi in cui il test

complessivamente è fallito nonostante lo switching, quest'eventualità può verificarsi sia a

causa dei meccanismi di logging e recovery messi a disposizione della piattaforma, per cui

delle richieste, all'atto del failure del facade primario non vengono inoltrate al secondario,

sia a causa della natura stessa del fault iniettato, identico per entrambi i facade, che

determina la scorrettezza del servizio.

73

Illustrazione 21: Classificazione dei test per lo scenario con entrambi i Facade faulty

Page 78: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

4.2 Facade primario faulty (esplorazione del modello in senso orizzontale e

verticale)

In questa campagna sono stati utilizzati due scenari differenti dal punto di vista

dell'esplorazione del workload, ma entrambi hanno previsto l'iniezione dei guasti nel solo

facade primario. Nel primo scenario è stato utilizzato il workload di base illustrato in

figura 18, mentre nel secondo scenario è stato utilizzato un workload differente, in grado

di stimolare il sistema ad attraversare il modello in senso verticale, ossia colonna per

colonna, presentato più avanti.

4.2.1 Copertura degli stati (esplorazione in senso orizzontale)

I fallimenti del facade primario sono riportati nella seguente figura, che ne riporta la

distribuzione rispetto agli stati del modello.

74

Page 79: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

75

Illustrazione 22: Distribuzione dei fallimenti nello scenario con singolo Facade faulty ed esplorazione orizzontale

Page 80: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

In questa campagna si sono osservati 127 fallimenti complessivi del sistema, di cui 56 con

switching e 71 senza. Inoltre, in 21 casi il test è andato a buon fine grazie all'occorrenza di

switching, per cui, complessivamente si sono osservati 204 fallimenti singoli.

76

Illustrazione 23: Classificazione dei test per lo scenario con singolo Facade faulty ed esplorazione orizzontale

Page 81: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

4.2.2 Copertura degli stati (esplorazione in senso verticale)

La figura 24 mostra il comportamento del workload utilizzato in questa campagna in

merito alla modalità di esplorazione del modello. Le frecce di colore blu corrispondono ad

eventi direttamente controllabili tramite il client, mentre quelle di colore giallo seguono

direttamente dal comportamento del sistema. Infine, le bande di colore verde evidenziano

l'ordine con cui vengono attraversati i diversi stati.

77

Illustrazione 24: Workload ad esplorazione verticale

Page 82: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Segue il modello a stati (figura 25), in cui sono evidenziate le percentuali di fallimento del

facade primario per ogni stato.

78

Illustrazione 25: Distribuzione dei fallimenti nello scenario con singolo Facade faulty ed esplorazione verticale

Page 83: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

In questa campagna si sono osservati 136 fallimenti complessivi del sistema, di cui 74 con

switching e 62 senza. Inoltre, in 6 casi il test è andato a buon fine grazie all'occorrenza di

switching, per cui, complessivamente si sono osservati 216 fallimenti singoli.

79

Illustrazione 26: Classificazione dei test per lo scenario con singolo Facade faulty ed esplorazione verticale

Page 84: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

4.3 Facade primario faulty (workload con diversificazione delle richieste)

Il workload utilizzato in questa campagna è simile a quello utilizzato per la prima

campagna descritta, almeno per quanto riguarda l'attraversamento degli stati del modello.

Tuttavia si differenzia da quello in quanto presenta una diversificazione delle richieste,

utilizzando richieste di insert e delete oltre che di update. Di seguito si riporta, in dettaglio,

la sequenza di richieste effettuate mediante tale workload.

SSR UPDATE REQUEST , FDP:1 SSR UPDATE REQUEST , FDP:1 DELETE REQUEST , FDP:1 INSERT REQUEST , FDP:1 SSR UPDATE REQUEST , FDP:2 DELETE REQUEST , FDP:1 SSR UPDATE REQUEST , FDP:2 SSR UPDATE REQUEST , FDP:2 INSERT REQUEST , FDP:1 SSR UPDATE REQUEST , FDP:3 SSR UPDATE REQUEST , FDP:2 UPDATE REQUEST , FDP:1 SSR UPDATE REQUEST , FDP:2 SSR UPDATE REQUEST , FDP:2 UPDATE REQUEST , FDP:1 SSR UPDATE REQUEST , FDP:3 SSR UPDATE REQUEST , FDP:2 UPDATE REQUEST , FDP:1 SSR UPDATE REQUEST , FDP:4 SSR UPDATE REQUEST , FDP:3 SSR UPDATE REQUEST , FDP:2 UPDATE REQUEST , FDP:1

80

Page 85: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

4.3.1 Copertura degli stati

La figura riporta la distribuzione dei fallimenti del facade primario rispetto agli stati del

sistema.

81

Illustrazione 27: Distribuzione dei fallimenti nello scenario con singolo Facade faulty e diversificazione delle richieste

Page 86: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

In questa campagna di test ci sono stati in tutto 269 fallimenti dei facade. In 176 casi il test

è ritenuto complessivamente fallito (le richieste servite sono minori di quelle previste). In

89 di questi casi è fallito solo il facade primario (non dando la possibilità al meccanismo

di recovery di attivare il facade secondario). Nei restanti 87 casi il facade secondario è

stato attivato ma è fallito ugualmente. In 6 casi il test è andato a buon fine, con fallimento

del solo facade primario. Si fa presente che in alcuni casi il fallimento è avvenuto in uno

stato non previsto dal modello oppure in fase di inizializzazione del facade.

82

Illustrazione 28: Classificazione dei test per lo scenario con singolo Facade faulty e diversificazione delle richieste

Page 87: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

4.4 Processing server faulty

Sono state condotte due campagne sperimentali mirate a concentrare l'iniezione di fault sui

processing server. La prima ha avuto come target un solo processing server, mentre la

seconda ha previsto l'iniezione di fault in tutti i processing server del sistema. La

metodologia di iniezione è la stessa utilizzata nelle campagne concentrate sul facade e ha

dato luogo a 138 casi di test rappresentativi dell'iniezione di altrettanti fault del processing

server.

In queste campagne sperimentali si è osservato un basso numero di fallimenti del sistema,

identico in entrambi i casi. Di seguito si riportano gli stati finali del sistema nei due casi.

Un processing server faulty

5 03:01:00

2 03:02:00

4 11:03:00

Tutti i processing server faulty

7 00:00:00

4 18:04:00

Nella colonna a sinistra sono riportate le occorrenze di fallimento per gli stati a destra.

Come si nota un numero relativamente alto di fallimenti si è avuto in stati non previsti dal

modello.

Inoltre, nel caso di un solo processing server faulty (caso 1) in nessuno esperimento si è

osservata la mancata istanziazione del server, mentre nel caso di tutti i processing server

faulty (caso 2) ciò è avvenuto in alcuni test. In entrmbi i casi si sono osservati 11

fallimenti complessivi sui 138 casi di test effettuati.

Per quanto riguarda i test falliti del caso 1 è stato osservato che il numero di richieste

servite assume sempre un valore pari a 8 oppure a 18. Ricordando che le richieste

effettuate sono in tutto 22, si è dedotto, con l'ausilio dei log di sistema, che, quando le

richieste servite sono 18, il processing server accetta il processamento di una richiesta

83

Page 88: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

dopodiché va in crash. Il facade, non ricevendo alcuna conferma per tale richiesta,

conserva lo stato di blocco per l'id del piano di volo in questione causando l'accodamento

indefinito delle altre richieste relative a tali id (in tutto tre). Nei test con 8 richieste servite

si è riscontrato che il server faulty accetta i processamenti richiesti ma non li porta a

termine a causa di un errore nell'interazione con l'ORB. A seguito di quest'errore, tuttavia,

il server non va in crash e si rende disponibile per ulteriori richieste che, comunque,

falliscono similmente. A differenza di quanto detto per il caso 1, i test falliti del caso 2

presentano un numero di richieste servite sempre nullo.

In uno studio precedente sul sistema operativo Tandem GUARDIAN90 [16], è stato

dimostrato che, per quel particolare sistema, la replicazione dei processi è una tecnica

efficace per la software fault tolerance. Nel nostro caso, queste campagne dimostrano che

la replicazione dei processing server non è utile ai fini della software fault tolerance,

almeno per quanto riguarda la tipologia di fault emulati. Infatti, i test falliti nella

campagna con tutti i server faulty sono falliti, seppur con modalità diverse, anche quando

c'era un solo processing server faulty e gli altri fault free. Questo significa che un

fallimento di un solo processing server non è tollerato dal sistema ed è comparabile, dal

punto di vista della correttezza del servizio, al fallimento di tutte le copie.

Queste considerazioni di massima, però, prescindono alcune differenze sostanziali tra i

due sistemi:

per processi replicati in Tandem si intende l'insieme del processore e la copia del sistema

operativo in esecuzione su di esso, mentre nel nostro caso i processi sono istanze diverse

della stessa applicazione in esecuzione su host distribuiti. Inoltre la differenza

fondamentale dal punto della software fault tolerance è che in Tandem la replicazione è

progettata con lo scopo di tollerare i guasti mentre in Coflight, almeno per la versione

attuale, la replicazione è dovuta a motivi di load balancing e availability e non è prevista

una logica di funzionamento in grado di coordinare le copie per tollerare eventuali guasti.

84

Page 89: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

4.5 Vulnerabilità scoperte

Con il termine vulnerabilità in questo contesto si vuole intendere un difetto nei

meccanismi di fault tolerance che inficia la capacità di tollerare la presenza di guasti nel

resto del sistema. Le campagne sperimentali effettuate in questa fase del lavoro hanno

permesso di rivelare delle vulnerabilità del sistema e le circostanze che permettono di

manifestarle.

I fallimenti di tipo hang non vengono rilevati dal servizio di logging and recovery di

CARDAMOM

Quando un oggetto del sistema fallisce degenerando in uno stato di stallo, di fatto non

fornisce più il servizio previsto. L'infrastruttura di Cardamom preposta al monitoraggio dei

fallimenti delle entità del sistema non percepisce questo tipo di fallimento per cui, a sua

volta, fallisce nell'intento di prendere le opportune contromisure. Un esempio notevole di

ciò è il caso di hang del Facade in corrispondenza del quale il servizio di logging and

recovery non attiva la copia di backup decretando il fallimento della copia primaria. Un

ulteriore esempio di questa vulnerabilità è il caso di hang di un processing server: quando

è in stato di processamento per una certa richiesta e degenera in uno stato di stallo, il

Facade, non essendo notificata tale occorrenza, continua a ritenere che la richiesta sia in

stato di processamento, accodando indefinitamente le richieste relative al piano di volo in

questione.

In caso di crash del Facade primario, le richieste in coda vengono perse

Come illustrato in precedenza, poiché il Facade fa da tramite tra i client e i processing

server, si occupa di accodare le richieste relative ad un piano di volo già in processamento.

Le informazioni circa le richieste inoltrate vengono conservate un'apposita struttura dati di

cui è presente una copia nella replica di backup che viene aggiornata quando modificata.

Tuttavia le richieste accodate non ricevono lo stesso trattamento e, in caso di crash del

85

Page 90: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

facade primario, quando viene attivata la replica di backup questa non è aggiornata circa la

presenza delle richieste accodate che, di conseguenza, vengono perse, senza alcuna

notifica al client.

86

Page 91: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Capitolo 5: Iniezione di guasti di concorrenza

Nel capitolo precedente è stato evidenziato che, mediante le metodologie proposte, non si

è in grado di stabilire con precisione la capacità del sistema di tollerare l'occorrenza di un

guasto in dipendenza dello stato in cui si trova. Inoltre, una notevole percentuale di stati

del modello (35%) non è stata testata, come evidenzia la figura 30, in cui gli stati in rosso

sono quelli non testati.

La figura mostra, peraltro, una versione modificata del modello del sistema presentato nel

Capitolo 2. Tale modello, infatti, prevede una semplificazione riguardo alle transizioni fra

gli stati di tipo *:3:+ e quelli di tipo *:3:0. Questa semplificazione consiste nel collassare

nell'unica transizione CR dagli stati *:3:0 a quelli *:3:+ le transizioni CR e FR. Lo stesso

discorso vale per la transizione CR dagli stati *:3:+ agli stessi stati.

La figura 29 esemplifica quanto detto.

87Illustrazione 29: Le semplificazioni rimosse dal modello

Page 92: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Tali semplificazioni sono state rimosse dal modello in modo tale da renderlo

maggiormente idoneo a supportare la determinazione dei percorsi per l'attivazione dei

conflitti. Di seguito (figura 30) si riporta la versione modificata del modello.

In questo capitolo e nel successivo viene illustrata una metodologia innovativa, nata con lo

scopo di superare questi limiti. A tal fine sono stati valutati diversi lavori presenti i

letteratura, che riguardano i software fault transienti riscontrati in sistemi reali. Da tali

lavori si desume che le cause più frequenti per questo tipo di bug sono:

• errori nella sincronizzazione fra thread

• influenza di eventi esterni nella tempificazione

• gestione errata della memoria

• presenza di fault all'interno di codice utilizzato a sua volta per la gestione

dell'occorrenza di un altro fault

• input anomali

88

Illustrazione 30: Nuova versione del modello a stati finiti

Page 93: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

• software aging

In questo lavoro sono stati presi in considerazione i guasti riguardanti la concorrenza tra

flussi di esecuzione. La programmazione concorrente, negli ultimi anni, ha subito una

notevole diffusione sia in ambienti ad alte prestazioni, sia nei comuni ambienti desktop.

Questo è dovuto, in particolar modo, alla diffusione altrettanto rapida dell'hardware multi-

core, le cui potenzialità sono sfruttate a pieno solo grazie all'implementazione di flussi di

esecuzione concorrenti. Tuttavia questo tipo di programmazione presenta delle

caratteristiche che la rendono piuttosto complicata rispetto alla programmazione

sequenziale e, per questo motivo, insieme con la sua diffusione, sono aumentate le

occorrenze di bug legati a questa tecnica. Si tratta dei bug di concorrenza, che rientrano

nella categoria dei software fault introdotti in fase di sviluppo (si consulti il Capitolo 1 per

una classificazione dei software fault), e per quanto concerne la tipologia di

manifestazione rientrano frequentemente, per la loro natura, nella classe degli heisenbug.

Le problematiche più frequenti legate alla programmazione concorrente dipendono

dall'uso scorretto di dei lock (è il caso dei deadlock, che si verifica quando, in un gruppo

flussi d'esecuzione, ognuno attende che un altro rilasci una risorsa per proseguire) oppure

dalla mancata sincronizzazione (è il caso dei data race).

Per quello che concerne questo lavoro, un'interessante trattazione sull'argomento è stata

effettuata in [17]. Tale articolo, peraltro di recente pubblicazione (2008), affronta diversi

aspetti legati ai bug di concorrenza trovati nei sistemi reali, e in particolare, si occupa di

definire quali sono le tipologie più frequenti di questi fault sulla base di dati sperimentali.

Più in dettaglio, vengono esaminati i pattern, le manifestazioni e le strategie di risoluzione

dei bug (circa cento) trovati in un vasto spettro di applicazioni open-source, con lo scopo

di fornire delle linee guida per l'attività di bug detection, di testing del software e di

progetto dei linguaggi di programmazione con supporto alla concorrenza.

Di seguito vengono illustrati i risultati di maggiore interesse dal punto di vista di questo

lavoro, in particolar modo per la definizione del modello dei guasti illustrata nel paragrafo

seguente.

89

Page 94: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

1. di tutti i guasti esaminati, la quasi totalità appartiene alle 3 classi: atomicity-violation

(48.57%), deadlock (29.52%) e order-violation (22.86%) bugs

2. la quasi totalità (96%) dei bug esaminati si manifestano sicuramente se viene viene

imposto un certo ordine parziale tra due soli thread

3. una notevole parte (66%) dei bug non correlati a deadlock riguarda l'accesso

concorrente ad una sola variabile

4. la quasi totalità (92%) dei bug esaminati si manifesta certamente se viene imposto un

certo ordinamento parziale tra non più di quattro accessi in memoria

Il pattern atomicity-violation si riscontra quando, in fase di programmazione, si assume

erroneamente che piccole porzioni di codice vengano eseguite atomicamente, come

nell'esempio seguente, in cui l'interleaving errato, che può verificarsi, è S1 – S3 – S2:

Thread 1 Thread 2S1: if (data_struct->field) ...{ S3: data_struct->field=NULLS2:fputs(data_struct->field,...) ...}

Un ulteriore errore, tipicamente commesso in fase di programmazione è quello di

assumere un ordinamento tra operazioni di thread diversi che, di fatto non viene imposto.

Quest'errore conduce ad un bug pattern di tipo order-violation ed è esemplificato nella

figura che segue.

Thread 1 Thread 2void init(...){ void mMain(...)... {mThread=CreateThread(mMain,...) mState=mThread->State... ...} }

90

Page 95: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Lo scheduling indesiderato, che si può presentare in questo caso, consiste nell'eseguire

l'accesso in lettura della variabile condivisa mThread da parte del thread 2 prima che

questa sia effettivamente inizializzata dal thread 1 col valore restituito dal metodo

CreateThread.

Si noti che i bug che presentano questo pattern sono diversi da quelli di tipo data-race o di

tipo atomicity-violation: anche se due accessi alla stessa variabile vengono protetti dallo

stesso lock, oppure due porzioni di codice sono atomiche l'una rispetto all'altra, l'ordine di

esecuzione fra queste può essere comunque non garantito.

5.1 Definizione del modello dei guasti

La definizione del modello dei guasti utilizzato in questa fase del lavoro tiene conto dei

risultati 1, 3, 4 del lavoro [17], si per quanto riguarda l'ispezione delle fault location idonee

all'iniezione, sia per quanto riguarda la tipologia di guasto da iniettare. Poiché i bug di tipo

atomicity-violation sono riscontrati con maggiore frequenza, questo lavoro si è concentrato

su questa particolare tipologia di bug, tralasciando quelli di tipo order-violation.

Questo tipo di bug sono legati, il più delle volte, ad un uso scorretto dei lock, e sebbene

questa non sia l'unica causa che induce a tali problemi, è stata identificata come la più

rappresentativa, per cui il fault model proposto in questa campagna prevede la rimozione

di primitive di locking in opportune location al fine di rendere non atomico l'accesso ad

una variabile condivisa da parte di due thread, di cui almeno uno acceda in scrittura.

Emulare una simile tipologia di bug in un sistema reale richiede un'ispezione del codice,

statica o dinamica, che per i sistemi complessi può essere impraticabile poiché bisogna

identificare non solo i possibili accessi a variabili condivise effettuare dalle varie

componenti del sistema, ma anche il tipo di accesso ed i lock acquisiti durante un certo

accesso. Nell'ambito di questa campagna sperimentale sono stati osservati gli accessi

effettuati dall'applicazione, in particolare il facade, sottoposta, in sede operazionale, ad un

workload opportunamente progettato al fine di stimolare il sistema a svolgere determinate

91

Page 96: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

attività, comunque rappresentative del reale funzionamento, che permettessero di ricoprire,

entro certi limiti, tutto l'insieme dei possibili accessi.

In tali condizioni, una volta instrumentato opportunamente il sistema, è possibile ricavare

le informazioni necessarie all'emulazione del fault model. Più in dettaglio, fissato l'insieme

I degli input considerati, per ogni input i∈ I sono necessarie le seguenti informazioni:

• l'insieme delle variabili sv j accedute in corrispondenza degli input in I: sv j∈SV

• l'insieme degli accessi alla variabile condivisa sv j per ciascun input i: a∈Ai , j

• il tipo di accesso (lettura o scrittura) per ogni accesso a sv j : type(a)=r oppure

type(a)=w

• l'insieme dei lock acquisiti durante l'accesso a: La

E' opportuno notare che alcuni accessi in memoria possono non essere effettuati in tutti i

casi anche a parità di input i (a causa di sorgenti di non determinismo come l'I/O). Per tale

ragione in questa trattazione sono stati considerati unicamente gli accessi effettuati

deterministicamente in corrispondenza di un certo input i∈I . Tali accessi possono

essere determinati reiterando l'esecuzione dell'esperimento.

Di fatto, le fault location sono state individuate mediante un'attenta ispezione manuale del

codice in cerca di elementi sintattici del linguaggio di programmazione relativi alla

sincronizzazione dei thread, in particolare le primitive di locking. Il sistema in esame è

implementato in linguaggio C++, e fa uso delle primitive di supporto al multithreading

offerte da Cardamom (per un approfondimento si consulti [19]). Tali primitive sono basate

sui lock e sulle condition variables, per cui l'ispezione delle fault location, di fatto sezioni

di codice critiche, si è basata sulla ricerca di tali primitive, ed ha riscontrato 13 possibili

locazioni, illustrate di seguito. Le print presenti all'interno delle sezioni riassumono le

variabili accedute dalla sezione ed il tipo di accesso (w – scrittura, r – lettura, rw – lettura

92

Page 97: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

e scrittura) e sono state utilizzate in fase di osservazione delle sezioni critiche accedute dal

sistema in presenza di un workload generico.

Sezione critica 0

void Facade_impl::sblocca(long fdpid){

...

lockz[index].mutex->lock();

std::cout << "[CS][0][lockz(r), lockz.id(r), lockz.flag(r,w), lockz.mutex(r), lockz.cond(r),

stato(r)]" << std::endl;

lockz[index].flag=false;

recover_stato(index);

lockz[index].cond->broadcast();

lockz[index].mutex->unlock();

Sezione critica 1

void Facade_impl::save_stato(const int index,const char* client_back_id){

...

mutex_stato->lock();

std::cout << "[CS][1][lockz(r), stato(w)]" << std::endl;

stato[index*DIM]=lockz[index].flag;

stato[(index*DIM)+1]=client_back_id[0];

stato[(index*DIM)+2]=client_back_id[1];

stato[(index*DIM)+3]=client_back_id[2];

mutex_stato->unlock();

...

Il metodo save_stato serve ad aggiornare la struttura dati che contiene le informazioni

sulle callback dei client in attesa di conferma di un processamento. Questa struttura dati

93

Page 98: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

viene trasferita alla copia di backup del Facade quando modificata.

Sezione critica 2

void Facade_impl::save_stato(const int index,const char* client_back_id){

...

mutex_flag->lock();

std::cout << "[CS][2][m_state_changed(w)]" << std::endl;

m_state_changed = true;

mutex_flag->unlock();

Sezione critica 3

void Facade_impl::recover_stato(const int index){

...

mutex_stato->lock();

std::cout << "[CS][3][stato(w)]" << std::endl;

stato[index*DIM]=lockz[index].flag;

stato[(index*DIM)+1]=c;

stato[(index*DIM)+2]=c;

stato[(index*DIM)+3]=c;

mutex_stato->unlock();

Il metodo recover_stato viene utilizzato dalla copia di backup quando viene promossa a

replica primaria e server per ricostruire lo stato del facade primario prima del failure, al

fine di proseguirne la fornitura del servizio in maniera corretta.

94

Page 99: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Sezione critica 3b

void Facade_impl::recover_stato(const int index){

...

mutex_flag->lock();

std::cout << "[CS][2][m_state_changed(w)]" << std::endl;

m_state_changed = true;

mutex_flag->unlock();

Sezione critica 4

int Facade_impl::blocca(long fdpid){

...

lockz[index].mutex->lock();

std::cout << "[CS][4][lockz(r), lockz.flag(r,w), lockz.mutex(r), lockz.cond(r)]" << ...

while(lockz[index].flag==true){

rw_lock->readUnlock();

lockz[index].cond->wait();

rw_lock->readLock();

}

lockz[index].flag=true;

lockz[index].mutex->unlock();

Il metodo blocca serve per la sincronizzazione tra thread che accedono allo stesso piano di

volo, identificato dal parametro d'ingresso fdpid.

95

Page 100: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Sezione critica 5

bool Facade_impl::has_state_changed() {

bool flag_state;

mutex_flag->lock();

std::cout << "[CS][5][m_state_changed(r)]" << std::endl;

flag_state=m_state_changed;

mutex_flag->unlock();

return flag_state;

}

Il metodo has_state_changed viene utilizzato dal servizio di logging e recovery di

Cardamom per valutare l'eventualità in cui la copia di backup del Facade vada aggiornata

con le nuove informazioni circa lo stato.

Sezione critica 6

FT::State* Facade_impl::get_state()

throw (FT::NoStateAvailable)

{

FT::State_var s = new FT::State();

mutex_stato->lock();

std::cout << "[CS][6][stato(r)]" << std::endl;

s->length(stato->length());

for(CORBA::ULong i=0;i<stato->length();i++)

s[i]=stato[i];

mutex_stato->unlock();

96

Page 101: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Il metodo get_state viene utilizzato dal servizio di logging e recovery di Cardamom

insieme con has_state_changed nell'eventualità in cui la copia di backup del Facade vada

aggiornata per recuperare le nuove informazioni circa lo stato.

Sezione critica 7

FT::State* Facade_impl::get_state() throw (FT::NoStateAvailable)

{

...

mutex_flag->lock();

std::cout << "[CS][7][m_state_changed(w)]" << std::endl;

m_state_changed = false;

mutex_flag->unlock();

Sezione critica 8

void Facade_impl::delete_return(const Mockup::FullFDP & fdp) throw(CORBA::SystemException) {

...

rw_lock->writeLock();

std::cout << "[CS][8][lockz(r), lockz.id(r), lockz.flag(w), lockz.callback(w),

lockz.mutex(w), lockz.cond(w)]" << std::endl;

int del_pos = search(fdp.key);

lockz[del_pos].id = 0;

lockz[del_pos].flag = false;

lockz[del_pos].client_back_id = CORBA::string_dup("");

delete lockz[del_pos].mutex;

lockz[del_pos].mutex = 0;

delete lockz[del_pos].cond;

97

Page 102: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

lockz[del_pos].cond = 0;

rw_lock->writeUnlock();

Questa fa parte delle sezioni critiche più delicate in quanto effettua delle operazioni per la

cancellazione di un piano di volo. Per tale motivo è stata utilizzata intensivamente per

produrre i conflitti oggetto di questa campagna sperimentale.

Sezione critica 9

int Facade_impl::blocca(long fdpid){

rw_lock->readLock();

std::cout << "[CS][9][lockz(r), lockz.id(r), lockz.flag(r,w), lockz.mutex(r), ...

int index=search(fdpid);

lockz[index].mutex->lock();

std::cout << "[CS][4][lockz(r), lockz.flag(r,w), lockz.mutex(r), lockz.cond(r)]" << ...

while(lockz[index].flag==true){

rw_lock->readUnlock();

lockz[index].cond->wait();

rw_lock->readLock();

}

lockz[index].flag=true;

lockz[index].mutex->unlock();

rw_lock->readUnlock();

return index;

}

Questa sezione critica include la sezione critica 4 per cui l'insieme delle variabili accedute

da questa include quelle della quarta.

98

Page 103: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Sezione critica 10

void Facade_impl::sblocca(long fdpid){

rw_lock->writeLock();

std::cout << "[CS][10][index(w), lockz(r), lockz.id(r), lockz.flag(r,w), lockz.mutex(r),

lockz.cond(r), stato(r)]" << std::endl;

int index=search(fdpid);

lockz[index].mutex->lock();

std::cout << "[CS][0][lockz(r), lockz.id(r), lockz.flag(r,w), lockz.mutex(r), lockz.cond(r),

stato(r)]" << std::endl;

lockz[index].flag=false;

recover_stato(index);

lockz[index].cond->broadcast();

lockz[index].mutex->unlock();

rw_lock->writeUnlock();

}

Il metodo sblocca è il duale del metodo blocca ed è utilizzato per coordinare l'accesso

concorrente alla struttura dati contenente le informazioni di lock sui piani di volo. Questa

sezione critica include la sezione critica 0 per cui l'insieme delle variabili accedute da

questa include quelle della quarta.

Sezione critica 11

CdmwFDPSDemo::ClientCB_ptr Facade_impl::get_client_cback(long fdpid) throw(CORBA::SystemException{

...

CdmwFDPSDemo::ClientCB_var client_back_ref;

rw_lock->writeLock();

std::cout << "[CS][11][lockz(r), lockz.callback(r)]" << std::endl;

int index = search(fdpid);

99

Page 104: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

...

try

{

obj = ni.resolve ((char*)lockz[index].client_back_id);

client_back_ref = CdmwFDPSDemo::ClientCB::_narrow( obj.in() );

}

...

rw_lock->writeUnlock();

Questa sezione critica include un accesso in lettura alla varibile condivisa lockz che

permette di recuperare l'id della callback del client per poter notificare ad esso l'avvenuto

processamento

Sezione critica 12

void Facade_impl::insertFDP(CORBA::Long fdpid,const char* client_back, CORBA::Long sleeptime)

throw(CORBA::SystemException){

...

rw_lock->writeLock();

std::cout << "[CS][12][lockz(r,w), lockz.id(w), lockz.flag(w), lockz.callback(r),

lockz.mutex(w), lockz.cond(w)]" << std::endl;

if(fdpid>(long)lockz.size()){

Lock p;

p.id=fdpid;

p.flag=false;

p.client_back_id=CORBA::string_dup(client_back);

p.mutex = new Cdmw::OsSupport::Mutex::Mutex();

100

Page 105: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

p.cond = new Cdmw::OsSupport::Condition::Condition(*(p.mutex));

Lock vl;

vl.id=0;

p.flag=false;

int x=0;

else

{

lockz[fdpid-1]=p;

}

...

x=lockz.size()+1;

for(int i=x; i<=fdpid; i++)

lockz.push_back(vl);

lockz[lockz.size()-1]=p;

}

else

{

cout << " MIDDLE\n";

lockz[fdpid-1]=p;

}

rw_lock->writeUnlock();

Questa sezione critica è particolamente delicata perchè include operazioni di allocazione

ed inserimento nella struttura dati per la gestione dei lock dei piani di volo. Per tale motivo

è stata utilizzata intensivamente per produrre i conflitti oggetto di questa campagna

sperimentale.

101

Page 106: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Sezione critica 13

void Facade_impl::save_stato(const int index,const char* client_back_id){

rw_lock->writeLock();

std::cout << "[CS][13][lockz(r), lockz.callback(w), stato(w)]" << std::endl;

lockz[index].client_back_id=CORBA::string_dup(client_back_id);

rw_lock->writeUnlock();

Rispetto al formalismo introdotto in precedenza, l'insieme delle fault location coincide con

l'insieme La mentre gli accessi a coincidono con le operazioni di lettura e scrittura

effettuati all'interno della sezione critica in questione.

Di seguito viene illustrata la corrispondenza tra l'insieme degli input I e l'esecuzione delle

sezioni critiche a cui danno luogo, causando, di conseguenza i relativi accessi a alle

varibili condivise sv j .

Insert 12 9 4 13 1 2 5 6 7 11 10 0 3 3b 5 6 7 CR FR PSC

SSR Update 9 4 13 1 2 5 6 7 11 10 0 3 3b 5 6 7 CR FR PSC

Update 9 4 13 1 2 5 6 7 11 10 0 3 3b 5 6 7 CR FR PSC

Delete 9 4 13 1 2 5 6 7 11 10 0 3 3b 8 5 6 7 CR FR PSC

102

Page 107: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

A meno dell'operazione di insert, queste operazioni, effettuate su piani di volo già in

processamento, comportano le stesse sequenze di sezioni critiche viste sopra, in cui però,

ai messaggi CR vanno sostituiti messaggi di tipo CRQ.

Tali sequenze vengono eventualmente interrotte a favore di altre sequenze, relative a

operazioni distinte. Ad es. un'operazione di update accodata comporta che, fra le sezioni

critiche dovute ai messaggi CRQ e FR siano presenti quelle relative al messaggio PSC

dell'operazione in processamento e che ha causato l'accodamento.

La tabella che segue mostra per ogni variabile condivisa sv j , le sezioni critiche da cui è

acceduta e il tipo di accesso. Per semplicità, i singoli accessi presenti in una determinata

sezione critica sono stati raggruppati dando priorità agli accessi in scrittura per definire la

tipologia di accesso risultante.

Sezione critica - tipo di accessostato 0-R 1-W 3-W 6-R 10-Rm_state_changed 2-W 3b-W 5-R 7-W 0-W lockz 0-R 1-R 3-R 4-R 8-R 9-R 10-R 11-R 12-RW 13-Rlockz-id 8-R 9-R 10-R 12-Wlockz-flag 0-W 4-RW 8-W 9-RW 10-RW 12-W lockz-callback 8-W 11-R 12-W 13-W lockz-mutex 0-R 4-R 8-W 9-R 10-R 12-W lockz-cond 0-R 4-R 8-W 9-R 10-R 12-W

Tali informazioni sono state sottoposte all'elaborazione di un tool appositamente

implementato per determinare tutti i possibili conflitti tra due sezioni critiche (o,

equivalentemente, tra due thread) su una variabile o su variabili multiple, membri di una

stessa struttura dati. Di seguito viene riportato l'output di tale tool, che evidenzia la

variabile oggetto del conflitto, le sezioni critiche in conflitto e la modalità di accesso alla

variabile (R: lettura, W: scrittura, RW: lettura e scrittura).

103

Page 108: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

lockz (1-R) <-- (12-RW) lockz (3-R) <-- (12-RW) lockz (6-R) <-- (12-RW) lockz (8-R) <-- (12-RW) lockz (9-R) <-- (12-RW) lockz (10-R) <-- (12-RW) lockz (11-R) <-- (12-RW) lockz (12-RW) <-- (12-RW) lockz (13-R) <-- (12-RW) lockz-callback (8-W) <-- (8-W) lockz-callback (8-W) <-- (12-W) lockz-callback (8-W) <-- (13-W) lockz-callback (11-R) <-- (8-W) lockz-callback (11-R) <-- (12-W) lockz-callback (11-R) <-- (13-W) lockz-callback (12-W) <-- (8-W) lockz-callback (12-W) <-- (12-W) lockz-callback (12-W) <-- (13-W) lockz-callback (13-W) <-- (8-W) lockz-callback (13-W) <-- (12-W) lockz-callback (13-W) <-- (13-W) lockz-cond (8-W) <-- (8-W) lockz-cond (8-W) <-- (12-W) lockz-cond (9-R) <-- (8-W) lockz-cond (9-R) <-- (12-W) lockz-cond (10-R) <-- (8-W) lockz-cond (10-R) <-- (12-W) lockz-cond (12-W) <-- (8-W) lockz-cond (12-W) <-- (12-W) lockz-flag (8-W) <-- (8-W) lockz-flag (8-W) <-- (9-RW) lockz-flag (8-W) <-- (10-RW) lockz-flag (8-W) <-- (12-W) lockz-flag (9-RW) <-- (4-RW) lockz-flag (9-RW) <-- (8-W) lockz-flag (9-RW) <-- (9-RW) lockz-flag (9-RW) <-- (10-RW) lockz-flag (9-RW) <-- (12-W) lockz-flag (10-RW) <-- (0-W) lockz-flag (10-RW) <-- (8-W) lockz-flag (10-RW) <-- (9-RW) lockz-flag (10-RW) <-- (10-RW) lockz-flag (10-RW) <-- (12-W) lockz-flag (12-W) <-- (8-W)

lockz-flag (12-W) <-- (9-RW) lockz-flag (12-W) <-- (10-RW) lockz-flag (12-W) <-- (12-W) lockz-id (8-R) <-- (12-W) lockz-id (9-R) <-- (12-W) lockz-id (10-R) <-- (12-W) lockz-id (12-W) <-- (12-W) lockz-mutex (8-W) <-- (8-W) lockz-mutex (8-W) <-- (12-W) lockz-mutex (9-R) <-- (8-W) lockz-mutex (9-R) <-- (12-W) lockz-mutex (10-R) <-- (8-W) lockz-mutex (10-R) <-- (12-W) lockz-mutex (12-W) <-- (8-W) lockz-mutex (12-W) <-- (12-W) m_state_changed (2-W) <-- (2-W) m_state_changed (2-W) <-- (3b-W) m_state_changed (2-W) <-- (7-W) m_state_changed (2-W) <-- (0-W) m_state_changed (3b-W) <-- (2-W) m_state_changed (3b-W) <-- (3b-W) m_state_changed (3b-W) <-- (7-W) m_state_changed (3b-W) <-- (0-W) m_state_changed (5-R) <-- (2-W) m_state_changed (5-R) <-- (3b-W) m_state_changed (5-R) <-- (7-W) m_state_changed (5-R) <-- (0-W) m_state_changed (7-W) <-- (2-W) m_state_changed (7-W) <-- (3b-W) m_state_changed (7-W) <-- (7-W) m_state_changed (7-W) <-- (0-W) m_state_changed (0-W) <-- (2-W) m_state_changed (0-W) <-- (3b-W) m_state_changed (0-W) <-- (7-W) m_state_changed (0-W) <-- (0-W) stato (1-W) <-- (1-W) stato (1-W) <-- (3-W) stato (3-W) <-- (1-W) stato (3-W) <-- (3-W) stato (6-R) <-- (1-W) stato (6-R) <-- (3-W) stato (10-R) <-- (1-W) stato (10-R) <-- (3-W)

L'occorrenza di un conflitto di accessi ad una variabile può avere conseguenze diverse a

seconda della specifica funzione della variabile stessa:

• lockz: un conflitto su tale variabile è un esempio di conflitto a variabili multiple

poiché è una struttura dati incaricata di conservare lo stato di processamento delle

104

Page 109: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

richieste sui piani di volo inoltrate ai processing server ed formata dai seguenti campi

◦ id: costituisce l'identificativo del piano di volo a cui si riferisce la richiesta – un

conflitto su questa variabile può produrre un errore di incoerenza dei dati o un

accesso in memoria non valido.

◦ callback: costituisce un identificativo del client che ha effettuato la richiesta,

necessaria per notificarne ad esso il completamento – anche in questo caso, un

conflitto su questa variabile può produrre un errore di incoerenza dei dati o un

accesso in memoria non valido.

◦ mutex: come indicato dal nome, serve per disciplinare l'accesso alla variabile lockz

- un conflitto su questa variabile può produrre un accesso in memoria non valido.

◦ cond: si tratta di una variabile condition, anch'essa usata per gestire la concorrenza

degli accessi alla variabile lockz – un conflitto su questa variabile può produrre un

accesso in memoria non valido.

◦ flag: è utilizzata da un meccanismo di controllo della concorrenza specifico del

sistema in esame – un conflitto su tale variabile può produrre un errore di

incoerenza dei dati o un accesso in memoria non valido.

Si noti che la struttura dati che contiene lo stato di processamento è in realtà un

array di elementi di tipo lockz, ognuno relativo ad uno specifico piano di volo.

• m_state_changed: si tratta di una variabile utilizzata per segnalare al meccanismo di

recovery di Cardamom il cambiamento dello stato di una copia primaria replicata, in

questo caso il facade – un conflitto su tale variabile può produrre un errore di

incoerenza dei dati, in particolare il mancato aggiornamento dello stato da parte della

copia di backup

• stato: contiene le informazioni circa lo stato del facade - un conflitto su tale variabile

può produrre un errore di incoerenza dei dati, in particolare l'aggiornamento di uno

stato errato da parte della copia di backup

105

Page 110: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Fra i conflitti trovati, sono stati analizzati in maggior dettaglio quelli relativi alle sezioni

critiche 12 ed 8, in quanto i conflitti a cui sono suscettibili hanno conseguenze più gravi

dal punto di vista dei requisiti del sistema e sono più facilmente osservabili. Di questi,

sono stati utilizzati solo 4 conflitti, che hanno, fra l'altro, la caratteristica di dare luogo a

crash del facade, per cui dal punto di vista dell'osservabilità dei risultati degli esperimenti

sono particolarmente utili e sono descritti di seguito.

CONFLICT_1

Variabile condivisa: lockz-cond

Sezioni critiche in conflitto: (9-R) <-- (12-W)

Operazioni in conflitto:

12: lockz.push_back(...)

12: lockz[lockz.size()-1] = p OR lockz[fdpid-1] = p

9: lockz[index].cond->wait()

Questo conflitto è stato attivato rimuovendo le primitive di lock per l'accesso alla sezione

critica 12. Il workload utilizzato effettua una richiesta di update sul piano di volo 1 e, a

breve distanza di tempo, un'ulteriore richiesta di update per lo stesso piano di volo seguita

da una operazione di insert ancora per lo stesso piano di volo.

L'interleaving che ha portato al system failure riscontrato (crash del Facade) è stato

riprodotto con gbd mediante un breakpoint appena prima dell'istruzione

lockz[index].cond->wait();

Interrompendo l'esecuzione della sezione critica 9 in quel punto e facendo schedulare la

s.c. 12 che esegue

lockz[fdpid-1] = p

si attiva un errore in seguito all'esecuzione della sezione critica 9 precedentemente

interrotta. Tale errore comporta un crash del facade nel momento in cui, all'interno della

chiamata wait() si di chiamare il metodo set_unlock() su un lock non attivato.

106

Page 111: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

CONFLICT_2

Variabile condivisa: lockz-cond

Sezioni critiche in conflitto: (10-R) <-- (8-W)

Operazioni in conflitto:

10:lockz[index].cond->broadcast();

8:delete lockz[del_pos].cond;

8:lockz[del_pos].cond = 0;

Questo conflitto è stato attuato rimuovendo le primitive di lock() e unlock() dalla sezione

critica 8. Il workload utilizzato effettua una richiesta di delete sul piano di volo 1 e, a

breve distanza di tempo, una richiesta di update per lo stesso piano di volo. L'interleaving

che ha portato al system failure (crash del facade) riscontrato è stato riprodotto con gbd

mediante un breakpoint appena prima dell'istruzione

lockz[index].cond->broadcast();

Interrompendo l'esecuzione della sezione critica 10 in quel punto e facendo schedulare la

s.c. 8 che esegue

delete lockz[del_pos].cond;

lockz[del_pos].cond = 0;

si attiva un errore in seguito all'esecuzione della sezione critica 10 precedentemente

interrotta, che porta ad un accesso in memoria non valido, causando il crash del facade.

CONFLICT_3

Variabile condivisa: lockz-mutex

Sezioni critiche in conflitto: (9-R) <-- (8-W)

Operazioni in conflitto:

9:lockz[index].mutex->lock();

8:delete lockz[del_pos].mutex;

8:lockz[del_pos].mutex = 0;

107

Page 112: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Questo conflitto è stato attuato rimuovendo le primitive di lock() e unlock() dalla sezione

critica 9. Il workload utilizzato effettua una richiesta di update sul piano di volo 1 e, a

breve distanza di tempo, una richiesta di delete per lo stesso piano di volo. L'interleaving

che ha portato al system failure (crash del facade) riscontrato è stato riprodotto con gbd

mediante un breakpoint appena prima dell'istruzione

lockz[index].mutex->lock();

Interrompendo l'esecuzione della sezione critica 9 in quel punto e facendo schedulare la

s.c. 8 che esegue

delete lockz[del_pos].mutex;

lockz[del_pos].mutex = 0;

si attiva un errore in seguito all'esecuzione della sezione critica 9 precedentemente

interrotta, che porta ad un accesso in memoria non valido, causando il crash del facade.

Non è possibile attuare lo stesso conflitto rimuovendo le primitive di lock() e unlock()

dalla sezione critica 8 in quanto, al momento del breakpoint all'istruzione

lockz[index].mutex->lock();

il relativo thread ha acquisito il lock in lettura di rw_lock, per cui, nella delete_return() la

chiamata a sblocca, che richiede l'acquisizione dello stesso lock in scrittura, resta in attesa

indefinita.

CONFLICT_4

Variabile condivisa: lockz-mutex

Sezioni critiche in conflitto: (10-R) <-- (8-W)

Operazioni in conflitto:

10:lockz[index].mutex->lock();

8:delete lockz[del_pos].mutex;

8:lockz[del_pos].mutex = 0;

108

Page 113: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Questo conflitto è stato attuato rimuovendo le primitive di lock() e unlock() dalla sezione

critica 8. Il workload utilizzato effettua una richiesta di delete sul piano di volo 1 e, a

breve distanza di tempo, una richiesta di update per lo stesso piano di volo. L'interleaving

che ha portato al system failure (crash del facade) riscontrato è stato riprodotto con gbd

mediante un breakpoint appena prima dell'istruzione

lockz[index].mutex->lock();

Interrompendo l'esecuzione della sezione critica 10 in quel punto e facendo schedulare la

s.c. 8 che esegue

delete lockz[del_pos].mutex;

lockz[del_pos].mutex = 0;

si attiva un errore in seguito all'esecuzione della sezione critica 10 precedentemente

interrotta, che porta ad un accesso in memoria non valido, causando il crash del facade.

Oltre a questi quattro conflitti che sono stati scelti per la campagna sperimentale sono stati

rilevati numerosi altri conflitti, alcuni dei quali non attivabili a causa di subordinazione ad

altri lock, altri attivabili e rivelatisi benigni, ossia l'errore a cui danno luogo viene

immediatamente corretto o non ha modo di propagarsi, altri ancora causano dei cosiddetti

content failure, ossia alterano il valore corretto delle informazioni. Di seguito si riportano,

a titolo di esempio, alcuni di tali conflitti.

CONFLICT

Variabile condivisa: lockz-callback

Sezioni critiche in conflitto: (11-R) <-- (8-W)

Questo conflitto non è stato attuato perchè, anche rimuovendo le primitive di lock() e

unlock() dalla sezione critica 8, questa non viene acceduta in quanto è protetta dalle

chiamate a blocca() e sblocca() , che sono primitive di sincronizzazione definite dagli

sviluppatori di questo particolare sistema.

109

Page 114: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

CONFLICT

Variabile condivisa: lockz-callback

Sezioni critiche in conflitto: (12-W) <-- (8-W)

Questo conflitto è stato attuato rimuovendo le primitive di lock() e unlock() dalla sezione

critica 12. Il workload utilizzato effettua una richiesta di delete per il piano di volo 1 e, a

breve distanza di tempo, una richiesta di insert per lo stesso piano di volo. L'interleaving

proposto consiste nell'eseguire prima le eventuali operazioni di preparazione

all'inserimento della sezione critica 12:

lockz.push_back(vl);

poi le operazioni di cancellazione e deallocazione della sezione critica 8:

lockz[del_pos].id = 0;

lockz[del_pos].flag = false;

lockz[del_pos].client_back_id = CORBA::string_dup("");

delete lockz[del_pos].mutex;

lockz[del_pos].mutex = 0;

delete lockz[del_pos].cond;

lockz[del_pos].cond = 0;

ed infine l'inserimento effettivo del piano di volo all'interno della struttura dati prevista:

lockz[lockz.size()-1]=p; oppure lockz[fdpid-1]=p;

Questo conflitto si è rivelato benigno, ossia, sebbene la cancellazione nella sezione critica

8 sia in conflitto con la sezione critica 12, gli effetti di questa vengono sovrascritti con i

valori finali corretti.

CONFLICT

Variabile condivisa: lockz-cond

Sezioni critiche in conflitto: (8-W) <-- (8-W)

110

Page 115: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Questo conflitto è stato attuato rimuovendo le primitive di lock() e unlock() per l'accesso

alla sezione critica 8. Il workload utilizzato effettua due richieste di delete per lo stesso

piano di volo in un breve intervallo di tempo. L'interleaving che ha comportato il conflitto

è stato riprodotto con gdb mediante un breakpoint prima delle istruzioni

lockz[del_pos].id = 0;

lockz[del_pos].flag = false;

lockz[del_pos].client_back_id = CORBA::string_dup("");

delete lockz[del_pos].mutex;

lockz[del_pos].mutex = 0;

delete lockz[del_pos].cond;

lockz[del_pos].cond = 0;

Facadendo eseguire questo blocco di istruzioni prima ad un thread e poi all'altro, dopo che

entrambi hanno impostato lo stesso valore per del_pos, il conflitto si è rivelato di tipo

benigno, nel senso che, alla fine dell'esecuzione, lo stato rimane corretto.

CONFLICT

Variabile condivisa: lockz

Sezioni critiche in conflitto: (1-R) <-- (12-RW)

12: lockz.push_back(...)

12: lockz[lockz.size()-1] = p OR lockz[fdpid-1] = p

1:stato[...] = lockz[index].flag

Questo conflitto è stato attivato rimuovendo le primitive di lock per l'accesso alla sezione

critica 12. Il workload utilizzato effettua una richiesta di update sul piano di volo 1 e, a

breve distanza di tempo, una richiesta di insert per lo stesso piano di volo. L'interleaving

che ha portato al content failure riscontrato è stato riprodotto con gbd mediante un

breakpoint appena prima dell'istruzione

111

Page 116: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

stato[...] = lockz[index].flag

Interrompendo l'esecuzione della sezione critica 1 in quel punto e facendo schedulare la

s.c. 12 che esegue

lockz[fdpid-1] = p

si attiva un errore in seguito all'esecuzione della sezione critica 1 precedentemente

interrotta. Quest'errore degenera in un failure quando lo stato erroneo viene passato al

meccanismo di recovery per aggiornare la copia di backup del Facade .

CONFLICT

Variabile condivisa: lockz-cond

Sezioni critiche in conflitto: (10-R) <-- (12-W)

12: lockz.push_back(...)

12: lockz[lockz.size()-1] = p OR lockz[fdpid-1] = p

10: lockz[index].cond->broadcast();

Questo conflitto è stato attivato rimuovendo le primitive di lock per l'accesso alla sezione

critica 12. Il workload utilizzato effettua una richiesta di update sul piano di volo 1 e, a

breve distanza di tempo, un'ulteriore richiesta di update per lo stesso piano di volo seguita

da una operazione di insert ancora per lo stesso piano di volo. L'interleaving che ha portato

al failure riscontrato è stato riprodotto con gbd mediante un breakpoint appena prima

dell'istruzione

lockz[index].cond->broadcast();

Interrompendo l'esecuzione della sezione critica 10 in quel punto e facendo schedulare la

s.c. 12 che esegue

lockz[fdpid-1] = p

si attiva un errore in seguito all'esecuzione della sezione critica 10 precedentemente

interrotta. La chiamata broadcast() viene eseguita su una variabile 'cond' diversa da quella

prevista, per cui i thread in attesa sulla variabile 'cond' corretta non ricevono la

112

Page 117: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

segnalazione di broadcast.

Per concludere, la figura seguente 31 il processo di definizione del fault model.

5.2 Iniezione dei guasti

Con riferimento al formalismo introdotto nel paragrafo precedente, la fault injection

consiste nei seguenti passi:

1. Considerare ogni coppia di sezioni critiche s' ed s'' , contenenti rispettivamente i due

accessi a' e a'' con type(a') = w e type(a'') = r

2. ossia i conflitti illustrati nel paragrafo precedente

3. Considerare l’insieme di lock L da cui le sezioni s' ed s'' sono protette, ossia

L=Ls '∩L s ' '

4. Rimuovere l’acquisizione dei lock L (e il relativo rilascio)

In merito al terzo punto, la rimozione delle operazioni di acquisizione e rilascio dei lock

può essere effettuata o staticamente, ricompilando il codice privato di tali operazioni,

oppure dinamicamente, ad esempio mediante un debugger. Dati gli scopi di questo lavoro,

è stata adottata la prima alternativa. Sempre in merito allo stesso punto, si è già accennato

in precedenza che, per far collidere due sezioni critiche, è sufficiente rimuovere le

primitive di lock ad una sola delle due. Tuttavia, la rimozione in una sezione può avere

effetti diversi se applicata all'altra sezione.113

Illustrazione 31: Processo di definizione del fault model

Page 118: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Quale tra le due sezioni deve essere soggetta alla rimozione non è un dato generale e va

determinato in dipendenza del caso specifico, come è stato fatto in questo lavoro.

A scopo esemplificativo si riportano, di seguito, alcuni estratti di codice contenenti sezioni

critiche, in cui è evidenziata la rimozione delle primitive di sincronizzazione.

Quest'esempio mostra la rimozione delle primitive di sincronizzazione da una sezione di

codice che, per inserire un piano di volo all'interno dell'apposita struttura dati lockz,

variabile condivisa, necessita di essere protetta.

114

Page 119: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Questo, invece, è un estratto di codice responsabile della cancellazione di un piano di volo,

operazione particolarmente delicata dal punto di vista della sincronizzazione, in cui sono

state rimosse le primitive di lock e unlock.

5.3 Attivazione dei guasti

Il risultato 2 del lavoro [17], illustrato precedentemente, dimostra che, sebbene in molti

casi, specialmente nei sistemi complessi, il numero di thread sia molto elevato, la

manifestazione di un bug di concorrenza, nella maggior parte dei casi, coinvolge solo due

thread. Ciò è dovuto al fatto che la maggior parte dei thread non interagisce strettamente

con molti altri e la maggior parte della comunicazione e collaborazione viene condotta tra

due thread, o comunque tra un piccolo gruppo di thread. Quanto detto non contraddice

l'osservazione, comunemente accettata, secondo cui i bug sulla concorrenza si manifestano

più facilmente in condizioni di workload notevolmente impegnativi. Anzi, un tale

workload aumenta appunto la probabilità che si verifichino determinati ordinamenti tra

due thread che possono determinare la manifestazione dei bug.

La fase di attivazione dei guasti effettuata nella campagna sperimentale oggetto di questo

115

Page 120: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

capitolo e del seguente si basa fortemente su questo risultato, oltre che sul risultato 5. La

metodologia utilizzata, infatti, per raccogliere un insieme di possibili fault sulla

concorrenza prevede che, una volta individuata una fault location, ed iniettato un fault, il

sistema viene esercitato in modo che si verifichi l'esecuzione concorrente di due soli

thread, o più in dettaglio di due sezioni critiche, che opportunamente schedulate

conducono all'attivazione del fault. In questo modo il processo di attivazione è

notevolmente semplificato in quanto, con soli due thread, ci si può concentrare sulla

corretta schedulazione senza interessarsi di ciò che avviene per gli altri thread.

In questa campagna sperimentale vi sono determinati requisiti per ciò che riguarda

l'attivazione dei fault, e sono i seguenti:

1. la manifestazione deve essere transiente: lo scheduling dei thread deve causare

l'interferenza tra gli accessi in memoria, preventivamente privati delle primitive di

sincronizzazione, solo in particolari occasioni, in maniera controllabile

2. deve essere possibile decidere lo stato in cui attivare il guasto

3. deve essere possibile fornire al sistema gli input necessari ad indurre l'esecuzione di

thread

◦ responsabili della collisione

◦ responsabili di far transitare il sistema in un determinato stato

In merito al primo punto, si noti che, una volta rimosse le primitive di sincronizzazione,

non è possibile garantire che si abbiano interferenze solo quando si interviene

appositamente sullo scheduling. Tuttavia, date le dinamiche del sistema e la rapidità con

cui le operazioni vengono effettuate la probabilità che ciò accada è molto bassa e questa

eventualità è stata comunque monitorata durante gli esperimenti, essendo stati, questi,

condotti manualmente, come descritto più avanti in questo capitolo.

Per quanto riguarda i restanti requisiti, si è mostrato nei capitoli precedenti che mediante

116

Page 121: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

un opportuno workload è possibile far transitare il sistema negli stati desiderati a meno di

pochi stati che fanno eccezione, comunque controllabili indirettamente. In questo modo è

possibile, almeno in linea di principio, imporre lo scheduling per l'attivazione del guasto in

qualsivoglia stato. Il requisito 3 impone un ulteriore vincolo a questo discorso, richiedendo

che sia possibile attivare i thread che poi, in un preciso stato e opportunamente schedulati,

vadano in conflitto.

Il rispetto di tale vincolo dipende dal particolare stato in questione e di ciò si è tenuto

conto nella formulazione della tecnica di input selection descritta in seguito.

Per determinare gli input da fornire al sistema al fine di poter controllare gli stati

attraversati, in particolare quello in cui attivare il guasto, e indurre l'esecuzione di sezioni

critiche in conflitto è stata ideata una tecnica basata sulla formalizzazione del modello che,

mediante un opportuno algoritmo, fornisce le informazioni per determinare, per ogni stato,

quali conflitti possono essere attuati, gli input da fornire per attuarli e i percorsi nel

modello che, a partire dagli input, pervengono allo stato target, ossia quello in cui si vuole

attivare il guasto.

Ai suddetti percorsi si richiedono le seguenti proprietà:

• il percorso deve terminare nello stato in cui si vuole attivare il fault

• deve includere le transizioni che comportano l'esecuzione delle due sezioni critiche

desiderate per la collisione

• deve poter essere attraversato completamente anche sospendendo una delle sezioni

critiche

• deve essere percorribile deterministicamente attraverso gli input che è possibile fornire

Formalmente, l'algoritmo proposto riceve in input le seguenti informazioni:

• stato target

• messaggio finale: è il messaggio che fa transitare il sistema nello stato target e, inoltre,

attiva l'esecuzione, fra le altre, di una della due sezioni critiche desiderate

117

Page 122: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

• messaggio intermedio: è il messaggio che attiva l'esecuzione dell'altra sezione critica

desiderata

Fissato un certo stato, l'algoritmo verifica l'esistenza di percorsi per ognuno dei quattro

conflitti scelti e, in caso positivo, fornisce gli input da fornire e lo stato di partenza del

percorso (i parametri di I/O sono spiegati in dettaglio nel paragrafo seguente).

Tramite il workload si induce il sistema a transitare in tale stato di partenza e si producono

gli input richiesti mentre attraverso un debugger (in questo caso Gdb, illustrato in seguito),

una volta che il sistema è giunto nello stato target, si forza l'interleaving delle operazioni

che portano al conflitto.

Fissato un certo concurrency fault, a cui corrispondono due sezioni critiche ben definite,

con un preciso interleaving, è dunque possibile verificare una delle tre seguenti

eventualità, per ogni stato:

• non esiste un percorso valido (che rispetta i requisiti esposti)

• esiste un percorso valido, ma non si riesce a forzarlo entro un timeout (ad es. a causa

di vincoli di ordinamento "opponenti")

• esiste un percorso valido e l'iniezione va a buon fine

Nell'ultima eventualità, può accadere che il failure avvenga in uno stato diverso dallo stato

target.

5.4 Implementazione

In questo paragrafo vengono illustrati alcuni dettagli implementativi riguardo alla

campagna sperimentale in questione. In particolare, viene discusso l'algoritmo per la

determinazione dei percorsi utili all'attivazione dei conflitti e la tecnica utilizzata per

imporre lo scheduling desiderato alle operazioni dei thread in conflitto.

118

Page 123: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

5.4.1 Algoritmo per la determinazione dei percorsi

Per verificare se in un determinato stato è possibile attivare un certo conflitto è stato ideato

un algoritmo che, procedendo a ritroso dallo stato target, determina due percorsi parziali.

Il primo percorso parziale termina nello stato target x tramite il messaggio finale y (che

comporta l'esecuzione dell'accesso a' - per una definizione si veda il paragrafo precedente)

partendo da uno stato z in cui sia possibile fornire, tramite un client, un certo messaggio di

input (CR o CRQ).

Sia w il messaggio intermedio (che comporta l'accesso a''), le cui operazioni relative, in

fase di scheduling, si devono “sospendere”. Il secondo percorso parziale termina in z

attraverso w partendo da uno stato s in cui sia possibile fornire, tramite un client, un certo

messaggio di input.

Determinati questi percorsi parziali, attraverso il workload

• si induce il sistema a transitare nello stato s

• si controllano gli input e lo scheduling in modo da far transitare il sistema in z tramite

w

• si sospende l'esecuzione delle operazioni relative a w

• si controllano gli input e lo scheduling in modo da far transitare il sistema in x tramite

y

Un esempio di tale percorso e fornito in Figura 32, la quale include un estratto dalla FSM

di Figura 30. Supponiamo di voler iniettare un guasto nello stato 2:1:0 tra l’accesso X,w,1

(variabile condivisa X, accesso in scrittura, n° 1) a seguito del messaggio PSC e l’accesso

X,r,2 (variabile condivisa X, accesso in lettura, n° 2) a seguito del messaggio CRQ.

L’algoritmo, partendo dallo stato 2:1:0, trova prima un percorso (first backward path) che

termini in quello stato con l’arco PSC, e che come primo arco contenga un messaggio di

tipo CR o CRQ (i quali corrispondono agli input che il tester può inviare). Nell’esempio,

tale percorso e dato dalla sequenza 2:1:0 → CR → 2:1:0 → FR → 2:2:0 → PSC → 2:1:0.

A partire dal primo stato del percorso appena trovato (nell’esempio, coincide con 2:1:0),

119

Page 124: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

trova un percorso all’indietro che termini con l’arco CRQ, e che inizi con un arco CR o

CRQ. In questo caso, tale percorso (second o backward path) è costituito da 1:1:0 → CRQ

→ 2:1:0.

Per attivare il guasto utilizzando il percorso in Figura 32, occorre inviare al sistema delle

richieste CR e CRQ secondo la tempificazione mostrata in Figura 33. Inizialmente il

sistema è nello stato 1:1:0 (tale stato può essere raggiunto tramite lo stesso workload

discusso nel paragrafo 3.1.1). Viene dapprima inviata una richiesta di update per un piano

di volo già accodato, per servire la quale viene istanziato il thread 1. Il sistema transita

nello stato 1:1:0 tramite il second backward path. Quando il thread 1 accede alla sezione

critica relativa all'accesso a'' = X,w,1, esso viene bloccato tramite breakpoint.

Successivamente viene inviata una richiesta di tipo insert, a seguito della quale verrà

istanziato il thread 2, ed il sistema transita nello stato 2:1:0 tramite il first backward path.

Infine, dopo che il thread 1 avrà effettuato l'accesso a' = X,r,2, il thread 1 viene sbloccato

per effettuare l'accesso a''. In tal modo, si attiva l'interferenza tra i due thread (in questo

esempio, il valore viene sovrascritto prima della lettura).

120

Illustrazione 32: Esempio di percorso per l'attivazione di un conflitto

Page 125: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

In generale, possono esistere molteplici percorsi che soddisfano i requisiti previsti.

Tuttavia, è preferibile identificare il percorso più breve possibile. Nella pratica, anche se,

ai fini dell'iniezione di un guasto alcune operazioni di locking vengono rese inefficaci, è

possibile che altri lock (o altre risorse) siano stati acquisiti in precedenza dai thread

coinvolti. Per tale ragione, se si blocca un thread in attesa che interferisca con un secondo

thread, quest'ultimo potrebbe essere impossibilitato a continuare l'esecuzione a causa del

blocco del primo thread. Riducendo la lunghezza del percorso si riduce anche la

probabilità che si verifichi questa situazione. Non essendo possibile evitare tale situazione,

né sapere a priori se essa si verificherà, è possibile stabilire un tempo massimo di blocco di

un thread. Nel caso in cui tale tempo massimo venga superato, si ritiene che la situazione

patologica si sia verificata e l'esperimento viene interrotto. Nel caso in esame, il tempo

massimo è stato determinato in base al tempo massimo di processamento (simulato)

richiesto dal workload sommato ad un margine di sicurezza.

5.4.2 Tecnica di controllo dello scheduling

Per determinare lo scheduling in grado di attivare i 4 conflitti previsti, la seconda

campagna di fault injection è stata preceduta da una fase sperimentale in cui ogni conflitto

è stato studiato, dal punto di vista dell'interleaving delle operazioni, a prescindere dallo

stato del sistema. Una volta determinato, per ogni conflitto, lo scheduling da imporre,

questo è stato riprodotto senza la necessità di modifiche, in ogni stato previsto dalla

campagna (ove possibile – si veda il capitolo 6).

Lo scheduling è stato dunque controllato in fase di runtime del sistema, attraverso Gdb

121

Illustrazione 33: Esmpio di scheduling per l'attivazione di un conflitto

Page 126: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

(GNU Debugger) [18]. Gdb è uno strumento utile per la comprensione di ciò che accade

durante l'esecuzione di un'applicazione o in seguito ad un crash di questa, permettendo di

leggere i valori delle variabili utilizzate, aree di memoria, etc. ma la caratteristica più utile

ai fini di questo lavoro è la possibilità di introdurre dei breakpoint corrispondenti a precise

locazioni (istruzioni) del codice sorgente, affinchè, durante l'esecuzione del sistema, il

flusso di esecuzione possa essere interrotto in determinati punti. I breakpoint possono

essere definiti sulla base di opportune istruzioni, possono essere condizionate a particolari

eventi, e soprattutto possono essere attivati per singoli thread o gruppi di essi.

In tal modo, Gdb fornisce un supporto essenziale per controllare l'esecuzione concorrente

di più thread poiché rende possibile gestire l'avanzamento delle operazioni controllando i

singoli thread pemettendo, di conseguenza, di controllare lo scheduling di determinate

operazioni.

Nella pratica, Gdb è stato usato per controllare il processo Facade (primario), e la tecnica

utilizzata prevede che, all'avvio di questo, venga lanciato automaticamente anche Gdb,

forzando la sospensione iniziale dell'esecuzione (in realtà la sospensione avviene in

seguito alle operazioni di inizializzazione).

Dopo aver configurato i breakpoint necessari, in dipendenza del conflitto in questione, si

riprende l'esecuzione del processo, che eventualmente istanzia i diversi thread in

dipendenza del workload, fra cui quelli che si vuole far collidere. I breakpoint possono

essere ignorati fino al punto in cui si arriva allo stato target, momento in cui,

manualmente, si interviene sullo scheduling interrompendo e riprendendo i diversi thread,

come descritto nei precedenti paragrafi.

Qualora sia possibile attivare il conflitto, a meno dei casi silenti di content failure, Gdb

fornisce un output dettagliato, esplicativo del failure riscontrato (segmentation fault, abort,

etc.). Segue un esempio della tecnica appena descritta.

Stato target 1:0:0Conflitto 2

122

Page 127: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Variabile condivisa lockz-condSezioni critiche in conflitto (10-R) <-- (8-W)Messaggio finale e intermedio

PSC, PSC

Breakpoint 591: void Facade_impl::updateCB(...){...}

608: ps_group_Interface->requestCB(...);

776: void Facade_impl::deleteFDP(...){...}

916: lockz[del_pos].id = 0; lockz[del_pos].flag = false; lockz[del_pos].client_back_id = ... delete lockz[del_pos].mutex; lockz[del_pos].mutex = 0; delete lockz[del_pos].cond; lockz[del_pos].cond = 0;

1012: lockz[index].cond->broadcast();

Per motivi pratici, i breakpoint sono stati attivati per tutti i thread e, fino al

raggiungimento dello stato target, sono stati ingorati manualmente. Tuttavia, una possibile

estensione può prevedere la possibilità di automatizzare questo processo.

Tutti i thread relativi ad operazioni di update, dunque, vengono interrotti al breakpoint

591. Viene dapprima schedulato un thread che fa un'update sul piano di volo 1 (thread 1),

poi un ulteriore thread che fa la stessa operazione (thread 2 - lo stato attuale è 1:1:0).

Quando il thread 1 si ferma al breakpoint 1012 viene fatto continuare (lo stato attuale è

1:0:0). Si schedula il thread che effettua la delete del piano di volo 1 (thread 3 - anch'esso

precedentemente interrotto al breakpoint 776) (stato 1:1:0) e viene fatto proseguire fino al

breakpoint 916 (stato 1:0:0), dopodichè viene schedulato un ulteriore thread di update sul

piano di volo 1 (thread 4) (stato 1:1:0), che prosegue l'esecuzione fino al breakpoint 1012

(stato 1:0:0). In questo punto si attiva la scrittura non protetta effettuata dal thread 3 dopo

il breakpoint 916 e, quando si riprende l'esecuzione del thread 4, che accede in lettura a

quella variabile (ormai deallocata), si verifica il crash del Facade per Segmentation Fault.

123

Page 128: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Capitolo 6: Valutazione sperimentale basata sull'iniezione di

guasti di concorrenza

6.1 Copertura degli stati

Le tecniche discusse nel capitolo precedente, di supporto alla metodologia illustrata,

consentono, in linea di principio, di testare il sistema in qualunque stato di funzionamento,

attivando un arbitrario conflitto fra quelli a disposizione. Tuttavia, come anticipato, ciò

nella pratica non è sempre vero.

In alcuni stati, ad esempio, può non esistere il percorso per l'attivazione del conflitto, ossia

non esiste, nel modello degli stati, un modo di percorrerlo tale che si pervenga allo stato

target avendo attraversato gli archi opportuni.

In altri casi, può capitare che, pur esistendo il percorso, non è possibile percorrerlo a causa

del tipo di conflitto che, richiedendo la sospensione di un flusso di esecuzione in un

particolare punto del percorso, preclude la continuazione dell'attraversamento.

E' possibile, ad esempio, che ci siano meccanismi di protezione, al di fuori di quelli

oggetto della fault injection, tali da far bloccare reciprocamente i thread coinvolti nel

conflitto.

In altri casi, esemplificati più avanti, sebbene esista il percorso e sebbene non vi siano i

problemi di sincronizzazione appena esposti, può capitare che non si riesca ad attivare il

conflitto. Tale circostanza è dovuta alla tipologia di conflitto che, per poter essere attivato,

può necessitare di particolari tipi di richieste, con un preciso ordine di arrivo, e relative ad

un particolare piano di volo. Tali condizioni possono essere rispettate solo in dipendenza

dello stato del sistema.

Premesso quanto detto, in questa campagna si è adottato un approccio sperimentale a tali

problemi, ricercando dapprima il percorso per ogni conflitto e per ogni stato, poiché 124

Page 129: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

l'esistenza del percorso è una condizione necessaria all'attivazione del conflitto. In seguito,

si è applicata la tecnica di iniezione per tutti gli stati previsti e per tutti i conflitti per i quali

è stato trovato un percorso. Quando è sorto uno dei problemi sopra esposti, l'esperimento è

stato scartato e il conflitto è stato definito come non attivabile.

Di seguito si riporta, per ogni stato considerato in questa campagna, i possibili conflitti che

è stato possibile attuare (in linea di principio), le relative sezioni critiche, i percorsi nel

modello degli stati che consentono l'attuazione del conflitto, gli stati di partenza di tali

percorsi, così come prodotti dall'algoritmo descritto nel paragrafo 5.4.1. Sono presenti

anche stati già testati dalla campagna precedente poiché sono stati effettuati dei test a

campione anche per questo insieme di stati.

Stato target 1:0:0

Conflitti lockz-cond (10-R) <-- (8-W) (PSC, PSC)

lockz-mutex (10-R) <-- (8-W) (PSC, PSC)

First subpath

1:0:0 --(CR)--> 1:0:0 --(FR)--> 1:1:0 --(PSC)--> 1:0:0

z: 1:0:0

Second subpath

1:0:0 --(CR)--> 1:0:0 --(FR)--> 1:1:0 --(PSC)--> 1:0:0

s: 1:0:0

lockz-mutex (9-R) <-- (8-W) (CR, PSC)

First subpath

1:0:0 --(CR)--> 1:0:0 --(FR)--> 1:1:0 --(PSC)--> 1:0:0

s: 1:0:0

125

Page 130: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Second subpath

1:0:0 --(CR)--> 1:0:0

z: 1:0:0

Stato target 2:0:0

Conflitti lockz-cond (10-R) <-- (8-W) (PSC, PSC)

lockz-mutex (10-R) <-- (8-W) (PSC, PSC)

First subpath

2:0:0 --(CR)--> 2:0:0 --(FR)--> 2:1:0 --(PSC)--> 2:0:0

z: 2:0:0

Second subpath

2:0:0 --(CR)--> 2:0:0 --(FR)--> 2:1:0 --(PSC)--> 2:0:0

s: 2:0:0

lockz-mutex (9-R) <-- (8-W) (CR, PSC)

First subpath

2:0:0 --(CR)--> 2:0:0 --(FR)--> 2:1:0 --(PSC)--> 2:0:0

s: 2:0:0

Second subpath

2:0:0 --(CR)--> 2:0:0

z: 2:0:0

Stato target 0:1:0

Conflitti lockz-cond (10-R) <-- (8-W) (PSC, PSC)

lockz-mutex (10-R) <-- (8-W) (PSC, PSC)

First subpath

0:1:0 --(CR)--> 0:1:0 --(FR)--> 0:2:0 --(PSC)--> 0:1:0

z: 0:1:0

126

Page 131: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Second subpath

0:1:0 --(CR)--> 0:1:0 --(FR)--> 0:2:0 --(PSC)--> 0:1:0

s: 0:1:0

lockz-mutex (9-R) <-- (8-W) (CR, PSC)

First subpath

0:1:0 --(CR)--> 0:1:0 --(FR)--> 0:2:0 --(PSC)--> 0:1:0

s: 0:1:0

Second subpath

0:1:0 --(CR)--> 0:1:0

z: 0:1:0

Stato target 2:1:0

Conflitti lockz-cond (10-R) <-- (8-W) (PSC, PSC)

lockz-mutex (10-R) <-- (8-W) (PSC, PSC)

First subpath

2:1:0 --(CR)--> 2:1:0 --(FR)--> 2:2:0 --(PSC)--> 2:1:0

z: 2:1:0

Second subpath

2:1:0 --(CR)--> 2:1:0 --(FR)--> 2:2:0 --(PSC)--> 2:1:0

s: 2:1:0

lockz-mutex (9-R) <-- (8-W) (CR, PSC)

2:1:0 --(CR)--> 2:1:0 --(FR)--> 2:2:0 --(PSC)--> 2:1:0

z: 2:1:0

Second subpath

2:1:0 --(CR)--> 2:1:0

s: 2:1:0

lockz-cond (9-R) <-- (12-W) (CRQ, CR)

127

Page 132: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

First subpath

2:1:0 --(CR)--> 2:1:0

z: 2:1:0

Second subpath

1:1:0 --(CRQ)--> 2:1:0

s: 1:1:0

Stato target 0:2:0

Conflitti lockz-cond (10-R) <-- (8-W) (PSC, PSC)

lockz-mutex (10-R) <-- (8-W) (PSC, PSC)

First subpath

0:2:0 --(CR)--> 0:2:0 --(FR)--> 0:3:0 --(PSC)--> 0:2:0

z: 0:2:0

Second subpath

0:2:0 --(CR)--> 0:2:0 --(FR)--> 0:3:0 --(PSC)--> 0:2:0

s: 0:2:0

lockz-mutex (9-R) <-- (8-W) (CR, PSC)

First subpath

0:2:0 --(CR)--> 0:2:0 --(FR)--> 0:3:0 --(PSC)--> 0:2:0

s: 0:2:0

Second subpath

0:2:0 --(CR)--> 0:2:0

z: 0:2:0

Stato target 2:2:0

Conflitti lockz-cond (10-R) <-- (8-W) (PSC, PSC)

128

Page 133: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

lockz-mutex (10-R) <-- (8-W) (PSC, PSC)

2:2:0 --(CR)--> 2:2:0 --(FR)--> 2:3:0 --(PSC)--> 2:2:0

z: 2:2:0

Second subpath

2:2:0 --(CR)--> 2:2:0 --(FR)--> 2:3:0 --(PSC)--> 2:2:0

s: 2:2:0

lockz-mutex (9-R) <-- (8-W) (CR, PSC)

First subpath

2:2:0 --(CR)--> 2:2:0 --(FR)--> 2:3:0 --(PSC)--> 2:2:0

s: 2:2:0

Second subpath

2:2:0 --(CR)--> 2:2:0

z: 2:2:0

lockz-cond (9-R) <-- (12-W) (CRQ, CR)

First subpath

2:2:0 --(CR)--> 2:2:0

z: 2:2:0

Second subpath

1:2:0 --(CRQ)--> 2:2:0

s: 1:2:0

129

Page 134: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Stato target 3:2:0

Conflitti lockz-cond (10-R) <-- (8-W) (PSC, PSC)

lockz-mutex (10-R) <-- (8-W) (PSC, PSC)

First subpath

3:2:0 --(CR)--> 3:2:0 --(FR)--> 3:3:0 --(PSC)--> 3:2:0

z: 3:2:0

Second subpath

3:2:0 --(CR)--> 3:2:0 --(FR)--> 3:3:0 --(PSC)--> 3:2:0

s: 3:2:0

lockz-mutex (9-R) <-- (8-W) (CR, PSC)

First subpath

3:2:0 --(CR)--> 3:2:0 --(FR)--> 3:3:0 --(PSC)--> 3:2:0

s: 3:2:0

Second subpath

3:2:0 --(CR)--> 3:2:0

z: 3:2:0

lockz-cond (9-R) <-- (12-W) (CRQ, CR)

First subpath

3:2:0 --(CR)--> 3:2:0

z: 3:2:0

Second subpath

2:2:0 --(CRQ)--> 3:2:0

s: 2:2:0

130

Page 135: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Stato target 1:3:+

lockz-cond (9-R) <-- (12-W) (CRQ, CR)

First subpath

0:3:+ --(CRQ)--> 1:3:+

s: 0:3:+

Second subpath

1:3:+ --(CR)--> 1:3:+

z: 1:3:+

Stato target 2:3:+

lockz-cond (9-R) <-- (12-W) (CRQ, CR)

First subpath

1:3:+ --(CRQ)--> 2:3:+

s: 1:3:+

Second subpath

2:3:+ --(CR)--> 2:3:+

z: 2:3:+

Stato target 3:3:+

lockz-cond (9-R) <-- (12-W) (CRQ, CR)

First subpath

2:3:+ --(CRQ)--> 2:3:+

s: 2:3:+

Second subpath

2:3:+ --(CR)--> 2:3:+

z: 2:3:+

131

Page 136: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

L'algoritmo finora considerato, applicato all'insieme di stati seguente, non ha prodotto

percorsi utili per nessuno dei conflitti considerati:

2:3:0, 0:3:+

Al fine di ottenere una maggiore copertura e testare anche questi stati, oltre che per cercare

di attivare altri conflitti in alcuni stati già coperti, è stato rilassato il vincolo che impone i

thread relativi alle richieste iniettate come unici thread confliggenti. Con riferimento alla

descrizione formale dell'algoritmo, finora si è imposto che i messaggi relativi alle sezioni

critiche in conflitto fossero w ed y.

Per gli stati in questione, invece, si è prevista la possibilità che i thread in conflitto

potessero essere quelli i cui messaggi relativi facessero parte dei messaggi utilizzati per far

transitare il sistema nello stato s. Per questi stati i percorsi, illustrati di seguito, sono stati

trovati manualmente, adoperando l'algoritmo descritto con il rilassamento proposto.

Stato target 0:3:+

Conflitti lockz-mutex (9-R) <-- (8-W) (CR, PSC)

Second subpath

0:2:0 --(CR)--> 0:2:0 --(FR)--> 0:3:0 [altre richieste] --(PSC)--> 0:3:+

s: 0:2:0

First subpath

0:3:+ --(CR)--> 0:3:+

z: 0:3:+

Se la richiesta di delete del primo percorso parziale non fosse fatta prima di arrivare allo

stato 0:3:0 sarebbe sospesa, e quindi servita dopo qualche altra richiesta (PSC), che

farebbe cambiare lo stato.

132

Page 137: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Stato target 1:3:+

Conflitti lockz-mutex (9-R) <-- (8-W) (CR, PSC)

First subpath

1:2:0 --(CR)--> 1:2:0 --(FR)--> 1:3:0 [altre richieste]--(PSC)--> 1:3:+

s: 1:3:+

Second subpath

1:3:+ --(CR)--> 1:3:+

z: 1:3:+

Stato target 2:3:+

Conflitti lockz-mutex (9-R) <-- (8-W) (CR, PSC)

First subpath

2:2:0 --(CR)--> 2:2:0 --(FR)--> 2:3:0 [altre richieste]--(PSC)--> 2:3:+

s: 2:2:0

Second subpath

2:3:+ --(CR)--> 2:3:+

z: 2:3:+

Stato target 3:3:+

Conflitti lockz-mutex (9-R) <-- (8-W) (CR, PSC)

First subpath

3:3:0 --(CR)--> 3:3:0 --(FR)--> 3:3:+ [altre richieste sospese]--(PSC)--> 3:3:+

s: 3:3:0

Second subpath

3:3:+ --(CR)--> 3:3:+

z: 3:3:+

133

Page 138: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Stato target 0:3:0 Non è stato possbile attuare nessun conflitto

Stato target 1:3:0

Conflitti lockz-mutex (9-R) <-- (8-W) (CR, PSC)

First subpath

1:2:0 --(CR)--> 1:2:0 --(FR)--> 1:3:0 [altre richieste]--(PSC)--> 1:3:0

s: 1:2:0

Second subpath

1:3:0 --(CR)--> 1:3:0

z: 1:3:0

Stato target 2:3:0

Conflitti lockz-mutex (9-R) <-- (8-W) (CR, PSC)

First subpath

2:2:0 --(CR)--> 2:2:0 --(FR)--> 2:3:0 [altre richieste]--(PSC)--> 2:3:0

s: 2:2:0

Second subpath

2:3:0 --(CR)--> 2:3:0

z: 2:3:0

Stato target 3:3:0

Conflitti lockz-mutex (9-R) <-- (8-W) (CR, PSC)

First subpath

3:2:0 --(CR)--> 3:2:0 --(FR)--> 3:3:0 [altre richieste]--(PSC)--> 3:3:0

s: 3:2:0

Second subpath

3:3:0 --(CR)--> 3:3:0

z: 3:3:0

La figura che segue evidenzia i conflitti che, di fatto, è stato possibile attuare, per ogni

134

Page 139: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

stato del modello considerato.

La figura 34 riassume i seguenti risultati:

• tutti gli stati non coperti dalla campagna precedente sono stati testati mediante la

tecnica proposta (copertura del 100%)

• la tecnica proposta, unitamente a quella della campagna precedente, permette di testare

il 100% degli stati del modello (risultato valido solo per questo caso particolare)

• non è possibile attivare ogni conflitto in ogni stato

Un caso particolare dell'ultimo punto è lo stato 0:3:0. Per questo stato, infatti, così come

135

Illustrazione 34: Risultati della campanga di concurrency fault injection

Page 140: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

per altri stati già coperti dalla campagna precedente, sono stati effettuati dei test a

campione, ma non è stato possibile attivare alcun conflitto. Di seguito vengono esaminati i

quattro conflitti per lo stato 0:3:0 e vengono discusse le cause della mancata attivazione.

Conflitto 1

Variabile condivisa: lockz-cond

Sezioni critiche in conflitto: (9-R) <-- (12-W)

Messaggio intermedio e messaggio finale: (CRQ, CR)

Non esiste un percorso utile per attivare questo conflitto

Conflitto 2

Variabile condivisa: lockz-cond

Sezioni critiche in conflitto: (10-R) <-- (8-W)

Messaggio intermedio e messaggio finale: (PSC, PSC)

Si veda il Conflitto 4

Conflitto 3

Variabile condivisa: lockz-mutex

Sezioni critiche in conflitto: (9-R) <-- (8-W)

Messaggio intermedio e messaggio finale: (CR, PSC)

Per poter attivare questo conflitto è necessario bloccare una richiesta di update un certo

piano di volo x all'istruzione

lockz[index].mutex->lock();

A questo punto è necessario schedulare una richiesta di delete di x affinchè esegua le

operazioni

delete lockz[del_pos].mutex;

lockz[del_pos].mutex = 0;

136

Page 141: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Tuttavia, in questo stato non si può interrompere la richiesta di update ed effettuare una

richiesta di delete in quanto verrebbe sospesa e l'unico modo di ritornare nello stato 0:3:0

sarebbe mediante una PSC di una richiesta già in processamento, non relativa al piano di

volo x. Per questo è necessario avviare la delete su x prima dell'update su x. Tuttavia ciò

comporta, necessariamente, che poi l'update venga accodata, pervenendo allo stato 1:3:0,

dal quale non è possibile ritornare in 0:3:0 sospendendo sia la richiesta di delete che quella

di update. Per questi motivi non è possibile attivare questo conflitto in questo stato.

Conflitto 4

Variabile condivisa: lockz-mutex

Sezioni critiche in conflitto: (10-R) <-- (8-W)

Messaggio intermedio e messaggio finale: (PSC, PSC)

Per ottenere questo conflitto è necessario schedulare prima una PSC, interrompendola

all'istruzione

lockz[index].mutex->lock();

e poi schedulare un'altra PSC che esegue

delete lockz[del_pos].mutex;

lockz[del_pos].mutex = 0;

Partendo dallo stato 0:3:0 è possibile schedulare la prima PSC arrivando in 0:3:0 con una

sequenza CR, FR che possa poi indurre tale PSC. Tuttavia non è possibile fare la stessa

cosa per la seconda PSC a partire dallo stato 0:3:0 perchè la richiesta verrebbe sospesa. Né

è possibile arrivare in 0:3:0 con due sequenze CR, FR perchè necessariamente una delle

due CR verrebbe accodata.

Per tali motivi non è possibile attivare questo conflitto in questo stato. Un analogo

discorso vale per il conflitto 2.

137

Page 142: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

6.2 Vulnerabilità scoperte

Questa campagna sperimentale ha dimostrato che mediante la tecnica esposta è possibile

esplorare stati del sistema che la tecnica precedente non era riuscita a coprire. Nel caso

particolare di questo sistema, fra tali stati rientra una classe di stati particolarmente

sensibili a vulnerabilità, ossia gli stati *:*:+ con richieste sospese. Sebbene non sia stata

dimostrata concretamente una vulnerabilità del sistema legata ad eventi di crash del

Facade in questi stati, i risultati di questa campagna suggeriscono la necessità di un

maggior approfondimento della valutazione delle tecniche di fault tolerance in questi stati

del sistema, poiché la gestione delle richieste sospese, dal punto di vista dei meccanismi di

logging e recovery, necessita di essere testata dettagliatamente.

138

Page 143: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Conclusioni e sviluppi futuri

In questo lavoro sono state valutate due tecniche per la Sofware Fault Injection

utilizzando, come caso di studio un sistema per la gestione dei piani di volo, chiamato

Coflight.

Entrambe le tecniche sono state supportate da un modello a stati finiti del sistema,

appositamente definito, che ha permesso di valutarne l'efficacia in dipendenza delle

diverse condizioni di funzionamento, o stati del sistema. L'utilità di un tale modello è

risultata evidente in entrambi i casi, poiché è stato mostrato che, guidando gli esperimenti

di fault injection attraverso i diversi stati è possibile ottenere una maggiore comprensione

delle problematiche legate ai fault iniettati e le conseguenze che portano.

Il sistema in esame è stato dunque instrumentato opportunamente per fare in modo che le

entità di interesse (Facade e Processing Server) producessero un insieme di messaggi, in

corrispondenza degli eventi relativi a determinate transizioni del modello proposto.

Attraverso tali messaggi è stato possibile mettere in relazione il funzionamento del sistema

con le transizioni nel modello e, dunque, comprendere gli stati attraversati, e in particolar

modo quelli relativi all'attivazione dei fault o all'occorrenza di failure. E' stato

implementato un tool apposito per ricavare queste informazioni in maniera automatica a

partire dai log delle diverse entità del sistema.

Una volta approntato il sistema nella maniera descritta si è proceduto alla valutazione della

prima tecnica: G-SWFIT. Oggetto dell'iniezione sono stati il Facade (537 fault iniettati) e i

Processing Server (138 fault iniettati), con particolare enfasi sul Facade, single point of

failure del sistema ed entità maggiormente critica a causa delle funzioni che svolge.

Sono stati implementati, inoltre, quattro workload differenti al fine di stimolare il sistema

ad attraversare gli stati in maniera differente e tale scelta si è rivelata utile a coprire il

maggior numero di stati possibile. Tuttavia, dai risultati di questa prima campagna

sperimentale è emerso che mediante questa tecnica non è possibile coprire tutti gli stati del

sistema (il 35% degli stati è rimasto non testato).

139

Page 144: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Un'ulteriore limitazione di questa tecnica, peraltro non banale, consiste nella tipologia dei

fault, di fatto, emulati. Uno degli scenari proposti per testare l'iniezione sul Facade, che ha

previsto l'iniezione sia sulla copia primaria che su quella secondaria, ha rivelato che nel

94% dei casi, un fault attivato e degenerato in un failure nella copia primaria ha avuto lo

stesso comportamento anche nella copia di backup. Questo suggerisce che la tipologia di

fault in questione è rappresentativa dei bohrbugs piuttosto che degli heisenbug. Ma la fault

tolerance non nasce come contromisura per i bohrbugs, già sufficientemente testati e

rimossi durante la fase di testing di un sistema, quanto per contrastare gli heisenbugs che

difficilmente hanno il comportamento ripetitivo e facilmente riproducibile dei bohrbugs.

Proprio da queste limitazioni è nato lo studio che ha permesso di definire la tecnica

proposta in questo lavoro: la tecnica di iniezione dei bug di concorrenza. Questa tipologia

di bug, infatti, sulla base di studi pregressi, è stata identificata come quella più frequente

tra gli heisenbug, per cui è stato definito un fault model in grado di emularla al meglio.

Il fault model è stato definito con riferimento ai risultati di uno studio precedente,

mediante una serie di errori di programmazione concorrente legati alla sincronizzazione

fra thread e raccogliendo una serie di conflitti fra diverse sezioni critiche del codice del

Facade.

Contestualmente sono state definite le relative condizioni di attivazione, consistenti in

precisi interleaving fra le operazioni dei differenti flussi di esecuzione.

In seguito si è proceduto a verificare l'attivabilità dei conflitti raccolti in ognuno degli stati

non coperti dalla campagna precedente. Nel caso particolare di questo sistema, tale tecnica

ha prodotto risultati estremamente positivi: il 100% degli stati precedentemente non

coperti sono stati coperti con la tecnica proposta. Tuttavia si è sottolineato il fatto che

questo non è un risultato generale, ma dipende dal sistema in esame. Si è mostrato, infatti,

mediante test effettuati a campione su altri stati, che vi sono casi in cui, mediante questa

tecnica, non si riesce ad attivare alcun conflitto.

Ad ogni modo, il risultato complessivo dell'integrazione delle due tecniche è positivo: tutti

140

Page 145: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

gli stati del modello sono stati testati e entrambe le tecniche hanno permesso di rivelare

vulnerabilità nei meccanismi di fault tolerance del sistema, o quantomeno, evidenziarne di

potenziali.

Proprio le potenziali vulnerabilità rivelabili mediante queste tecniche e mediante il

supporto di un modello del sistema sono uno dei possibili sviluppi di questo lavoro, che

comprendono anche:

• la possibilità di testare modelli del sistema differenti (ad es. le catene di Markov

nascoste)

• valutare i differenti livelli di granularità dello stato (accennati in questo lavoro)

• adattare ed applicare la metodologia proposta a COTS

141

Page 146: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Appendice A: Modellazioni alternative del sistema

Nel Capitolo 2 si sono discusse diverse alternative per la modellazione del sistema, fra cui

una che prevede di tenere in conto la tipologia delle richieste in coda ed in processamento.

In quest'appendice si dimostrano le relazioni esposte nel paragrafo 2.5 circa il numero di

stati che si ottiene volendo tenere in conto tali informazioni. Come anticipato, le variabili

utili per questo tipo di modellazione sono:

• up (numero di richieste di update in processamento)

• dp (numero di richieste di delete in processamento)

• ip (numero di richieste di insert in processamento)

• uq (numero di richieste di update in coda)

• dq (numero di richieste di delete in coda)

• iq (numero di richieste di insert in coda)

Queste variabili sono legate dalle seguenti relazioni:

up ,dp , ip≥0

uq ,dq , iq≥0variabili non negative

updpip≤3 non ci possono essere più di tre richieste processate

contemporaneamente

uqdqiq≤Q non ci possono essere più di Q richieste accodate

Ognuna di queste due relazioni comporta un numero di combinazioni che è dato dal

numero di punti a coordinate intere presenti all'interno di un quarto di un cubo di lato

rispettivamente 3 e Q.

Tali quantità valgono rispettivamente:

142

Page 147: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

∑i=1

4

[4−i−1⋅i ]

∑i=1

Q1

[Q1−i−1⋅i ]

Dimostrazione

Consideriamo l'espressione poiché l'altra è un caso particolare

di questa.

Vogliamo dimostrare che quest'espressione fornisce il numero dei possibili modi di

scrivere T con 0≤T≤Q come la somma di 3 variabili.

Si consideri la relazione ricorsiva

comb(n) = comb(n-1) + n + 1

comb(0)= 1

Supponiamo vero che comb(n) sia il numero di combinazioni per ottenere esattamente n

come somma di tre variabili, allora, per ottenere T, con 0≤T≤Q , bisogna calcolare

Un modo di dimostrare che comb(n) è il numero di combinazioni per ottenere esattamente

n come somma di tre variabili è il principio di induzione.

Il passo base è banalmente verificato:

comb(0) = 1 (c'è un solo modo ed è 0 + 0 + 0)

comb(1) = 3 (1 + 0 + 0 oppure 0 + 1 + 0 oppure 0 + 0 +1)

Supponendo vera l'ipotesi induttiva per per n-1 dimostriamo che è vera per n.

Supponiamo che il numero di combinazioni per ottenere T=n-1 sia pari a comb(n-1).

A partire da tali combinazioni si possono ottenere 3 gruppi di combinazioni sommando 1 a

ciascuna combinazione (o terna) in una precisa posizione della terna.

143

∑i=1

Q1

[Q1−i−1⋅i ]

combi≤Q=∑i=0

Q

[combi ]

Page 148: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Valgono le seguenti proprietà:

• I 3 gruppi hanno la stessa dimensione perchè sono generati a partire dallo stesso

insieme di combinazioni iniziale, sommando 1 ad una posizione.

• I 3 gruppi includono tutte le combinazioni per ottenere T=n ma includono alcune

combinazioni ripetute

• Per ogni combinazione del gruppo 1 (ma vale in generale) esiste almeno una

combinazione equivalente nel gruppo 2 ed una equivalente nel gruppo 3:

◦ Detta (x+1,y,z) la combinazione considerata per il gruppo 1, la combinazione

equivalente per il gruppo 2 si ottiene sommando 1 alla seconda posizione della

combinazione (x+1,y-1,z) del gruppo di partenza.

◦ Va fatta eccezione per le combinazioni (n-k, 0, k) che non sono sicuramente

presenti nel gruppo 2 (ma sono presenti nel gruppo 3 per k≠0 ) e le

combinazioni (n-k, k, 0) che non sono sicuramente ripetute nel gruppo 3.

• Per ogni combinazione nel gruppo 1 esiste al più una combinazione equivalente nel

gruppo 2 ed una equivalente nel gruppo 3: se così non fosse ci sarebbero 2

combinazioni uguali nel gruppo 2 o nel gruppo 3, ma ciò è assurdo.

144

Page 149: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Un approccio per la Software Fault Injection in Sistemi Software Complessi e Distribuiti

Date queste proprietà:

• Il gruppo 1 ha comb(n-1) combinazioni univoche per ottenere T=n

• Il gruppo 2 ha n combinazioni aggiuntive per ottenere T=n che non esistono nel

gruppo 1 ma esistono nel gruppo 3 (ossia quelle del tipo (0, n-k, k)).

• Il gruppo 3 ha una combinazione aggiuntiva per ottenere T=n che non esiste né nel

gruppo 1 né nel gruppo 2 (ossia del tipo (0, 0, n)).

Complessivamente l'intersezione dei tre gruppi fornisce comb(n-1) + n + 1 combinazioni

e tale valore è pari a comb(n).

Infine, si dimostra, ma qui è omesso per brevità, che

145

comb0≤i≤Q=∑i=0

Q

[combi]=∑i=1

Q1

[Q1−i−1⋅i ]

Page 150: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

Bibliografia[1] Avresky, D.; Arlat, J.; Laprie, J.-C.; Crouzet, Y., “Fault injection for the formal testing

of fault tolerance”, Twenty-Second International Symposium on Fault Tolerant Computing,

Page(s):345 – 354, 8-10 July 1992

[2] Moraes, R.; Barbosa, R.; Duraes, J.; Mendes, N.; Martins, E.; Madeira, H., “Injection of

faults at component interfaces and inside the component code: are they equivalent?”,

Dependable Computing Conference. EDCC '06. Sixth European, pp.53-64, 18-20 Oct.

2006

[3] Madeira, H.; Costa, D.; Vieira, M., “On the emulation of software faults by software

fault injection”, DSN 2000. Proceedings International Conference on Dependable Systems

and Networks, pp.417-426, 2000

[4] J. Gray, “A Census of Tandem Systems Availability between 1985 and 1990”, IEEE

Tranactions on Reliability, vol. 39, no. 4, pp. 409-418, Oct. 1990

[5] Joao A. Duraes, Henrique S. Madeira, “Emulation of Software Faults: A Field Data

Study and a Practical Approach”, IEEE Transactions on Software Engineering, vol. 32, no.

11, pp. 849-867, November, 2006.

[6] J. C. Laprie, A. Avizienis, and H. Kopetz, “Dependability: Basic Concepts and

Terminology.”, 1992, Springer-Verlag New York, Inc.

[7] Avizienis, A.; Laprie, J.-C.; Randell, B.; Landwehr, C., “Basic concepts and taxonomy

of dependable and secure computing,” IEEE Transactions on Dependable and Secure

Computing, vol.1, no.1, pp. 11-33, Jan.-March 2004

[8] Koopman, P.; Sung, J.; Dingman, C.; Siewiorek, D.; Marz, T., “Comparing operating

systems using robustness benchmarks”, Proceedings of The Sixteenth Symposium on

Reliable Distributed Systems, pp.72-79, 22-24 Oct 1997

[9] Ram Chillarege, Inderpal S. Bhandari, Jarir K. Chaar, Michael J. Halliday, Diane S.

Moebus, Bonnie K. Ray, and Man-Yuen Wong. “Orthogonal defect classification - a

concept for in-process measurements” IEEE Transactions on Software Engineering,

18(11):943–956, 1992.

[10] http://www.eurocontrol.int/statfor/public/subsite_homepage/homepage.html

Page 151: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

[11] Cheah, Mervyn ; Lock Pin, Chew ; Chee Ping, Tan. “Command Control and

Information Systems in the Age of Knowledge-Centricity” Defence Science and

Technology Agency (Singapore), June 2004

[12] http://www.eurocontrol.int/eec/public/standard_page/ERS_avenue.html

[13] http://www.laas.fr/DBench/

[14] Christmansson, J. and Chillarege, “Generation of an error set that emulates software

faults based on field data”, Proceedings of the the Twenty-Sixth Annual international

Symposium on Fault-Tolerant Computing , June 25 - 27, 1996, IEEE Computer Society,

Washington, DC, 304.

[15] Li, Z., Tan, L., Wang, X., Lu, S., Zhou, Y., and Zhai, C. “Have things changed now?:

an empirical study of bug characteristics in modern open source software”,Proceedings of

the 1st Workshop on Architectural and System Support For Improving Software

Dependability, October 21 - 21, 2006, ACM, New York, NY, 25-33

[16] I. Lee and R.K. Iyer, “Faults, Symptoms, and Software Fault Tolerance in Tandem

GUARDIAN90 Operating System” Proceedings of the 23rd IEEE International

Symposium on Fault-Tolerant Computing, pp. 20-29, 1993

[17] S. Lu, S. Park, E. Seo, and Y. Zhou, “Learning from mistakes: a comprehensive study

on real world concurrency bug characteristics” Proceedings of the 13th international

conference on Architectural support for programming languages and operating systems,

pp. 329-339, 2008, ACM

[18] http://www.gnu.org/software/gdb/

[19] http://cardamom.ow2.org/doc.html

[20] Michael Grottke; Kishor S. Trivedi, “Fighting Bugs: Remove, Retry, Replicate, and

Rejuvenate” Computer , vol.40, no.2, pp.107-109, Feb. 2007

[21] Inhwan Lee; Iyer, R.K., “Software dependability in the Tandem GUARDIAN

system”, IEEE Transactions on Software Engineering, vol.21, no.5, pp.455-467, May 1995

[22] M. Sullivan and R. Chillarege, “Software defects and their impact on systems

availability – A study of field failures on operating systems”, Proceedings of the 21st Fault

Tolerant Computing Symposium, pp. 2-9, Jun. 1991.

[23] S. Russo, C. Savy, D. Cotroneo, A. Sergio, “Introduzione a Corba”, McGraw-Hill,

Oct. 2002

[24] http://www.omg.org/technology/documents/corba_spec_catalog.htm

Page 152: Un approccio per la Software Fault Injection in Sistemi ...E' necessario comprendere che produrre software privo di errori è molto difficile. L'attività di sviluppo del software,

[25] D. Cotroneo, R. Natella, A. Pecchia, S. Russo “An Approach for Assessing Logs by

Software Fault Injection ”, Workshop on Proactive Failure Avoidance, Recovery and

Maintenance (PFARM) Estoril, Lisbon, Portugal, June 29th, 2009