I compilatori effettuano una analisi statica del codice per verificare che un programma soddisfi particolari caratteristiche di correttezza statica, per poter generare il codice oggetto.
Tipiche anomalie identificabili:
Si esegue una attenta lettura individuale del codice per individuare errori e/o discrepanze con il progetto.
Il lettore effettua mentalmente una pseudo-esecuzione del codice e processi di astrazione che lo conducono a verificare la correttezza del codice rispetto alle specifiche e il rispetto di standard adottati.
Tipici difetti identificabili:
nomi di identificatori errati, errato innesto di strutture di controllo, loop infiniti, inversione di predicati, commenti non consistenti con il codice, incorretto accesso ad array o altre strutture dati, incoerenza tra tipi di dati coinvolti in una istruzione, incoerenza tra parametri formali ed effettivi in chiamate a subroutine, inefficienza dell’algoritmo, non strutturazione del codice, codice morto, etc.
L’efficacia di tale tecnica è limitata se chi la esegue è la stessa persona che ha scritto il codice.
Riunioni formali cui partecipa un gruppo di persone tra cui almeno una del gruppo di sviluppo, un moderatore ed altri esperti.
Lo sviluppatore legge il codice ad alta voce, linea per linea, e i partecipanti fanno commenti e/o annotazioni.
Tipicamente queste riunioni sono preannunciate ai partecipanti cui viene fornita la documentazione necessaria (codice e relativi documenti) per la revisione.
È una tecnica che riesce ad individuare fra il 30 e il 70% degli errori nella logica del programma.
L’obiettivo della riunione è scoprire difetti, non correggerli. Comunque, spesso l’analisi dei difetti effettuata viene discussa e vengono decise le eventuali azioni da intraprendere:
Il codice è analizzato usando checklist dei tipici errori di programmazione, quali:
Analisi informale del codice svolta da vari partecipanti i quali ‘operano come il computer’: in pratica, si scelgono alcuni casi di test e si simula l’esecuzione del codice a mano (si attraversa- walkthrough- il codice).
L’organizzazione della riunione è simile a quella della tecnica delle Ispezioni:
Il flusso di controllo è esaminato per verificarne la correttezza.
Il codice è rappresentato tramite un grafo, il grafo del flusso di controllo (Control flow Graph – CfG), i cui nodi rappresentano statement (istruzioni eo predicati) del programma e gli archi il passaggio del flusso di controllo.
Il grafo è esaminato per identificare ramificazioni del flusso di controllo e verificare l’esistenza di eventuali anomalie quali codice irraggiungibile e non strutturazione.
Analisi dell’evoluzione del valore delle variabili durante l’esecuzione di un programma, permettendo di rilevare anomalie.
Intrinsecamente è dinamica, ma alcuni aspetti possono essere analizzati staticamente. L’analisi statica è legata alle operazioni eseguite su una variabile:
Es. Nell’espressione
a:=b+c;
la variabile a è definita mentre b e c sono usate
La definizione (d) di una variabile, così come un annullamento (a), cancella l’effetto di una precedente definizione della stessa variabile, ovvero ad essa è associato il nuovo valore derivante dalla nuova definizione (o il valore nullo).
Una corretta sequenza di operazioni prevede che:
Sequenze di istruzioni sono riconducibili a sequenze di definizioni (d), usi (u) e annullamenti (a) delle variabili referenziate nei comandi.
Il programma non è eseguito con i valori effettivi ma con valori simbolici dei dati di input.
L’esecuzione procede come una esecuzione normale ma non sono elaborati valori, bensì formule formate dai valori simbolici degli input.
Gli output sono formule dei valori simbolici degli input.
L’esecuzione simbolica anche di programmi di modeste dimensioni può risultare molto difficile.
Ciò è dovuto all’esecuzione delle istruzioni condizionali: deve essere valutato ciascun caso (vero e falso); in programmi con cicli ciò può portare a situazioni difficilmente gestibili.
Nel caso di esecuzioni simboliche con condizioni, alcuni statement sono eseguiti solo se gli input soddisfano determinate condizioni.
Una Path Condition (pc), per un determinato statement, indica le condizioni che gli input devono soddisfare affinchè una esecuzione percorra un cammino lungo cui lo statement viene eseguito.
Una pc è un’espressione Booleana sugli input simbolici di un programma.
All’inizio dell’esecuzione simbolica essa assume il valore vero (pc := true).
Per ogni condizione che si incontrerà lungo l’esecuzione, pc assumerà differenti valori a seconda dei differenti casi relativi ai diversi cammini dell’esecuzione.
Quali sono le Path Condition per eseguire gli statement
4
6
8 ?
Ciascun nodo foglia dell'execution tree sarà percorso per una certa pc. In foto iI CFG ed il corrispondente Execution Tree.
Ogni foglia dello execution tree rappresenta un cammino che sarà percorso per certi valori di input.
Le Pc associate a due differenti foglie sono distinte; ciascuna foglia dello execution tree rappresenta un cammino che sarà percorso per la Pc ad essa associata.
Non esistono esecuzioni per cui sono vere contemporaneamente più Pc (vero solo per programmi sequenziali).
Feasible Path: un cammino per il quale esiste un insieme di dati di ingresso che soddisfa la path condition.
Unfeasible Path: un cammino per il quale non esiste un insieme di dati di ingresso che soddisfa la path condition.
Se l’output ad ogni foglia è corretto allora il programma è corretto.
Ma, quanti rami può avere un execution tree?
Davis (1973)
Il problema di stabilire se esiste una soluzione per un sistema di diseguaglianze é indecidibile.
Un cammino é eseguibile se esiste un punto del dominio di ingresso che rende soddisfatta la sua path condition (… un sistema di diseguaglianze).
La determinazione della feasibility o della infeasibility di un cammino è indecidibile.
NB. se si riesce a dimostrare che ciascun predicato nella path condition è dipendente linearmente dalle variabili di ingresso, allora il problema è risolvibile con algoritmi di programmazione lineare.
Attività di ricerca e correzione dei difetti che sono causa di malfunzionamenti.
É l’attività conseguenziale all’esecuzione di un test che ha avuto successo.
Il debugging è ben lungi dall’essere stato formalizzato
Ridurre la distanza tra difetto e malfunzionamento.
Mantenendo un’immagine dello stato del processo in esecuzione in corrispondenza dell’esecuzione di specifiche istruzioni.
Il modo più inefficace per fare debugging. Diversi approcci possibili:
Ricorrervi solo quando altre tecniche hanno fallito!
Processo di ragionamento Induttivo: dal particolare al generale. Basato sulla raccolta di dati ed indizi sul fallimento, formulazione e verifica di ipotesi sulle possibili cause, in modo iterativo.
Si procede dal generale al particolare: Si formulano varie ipotesi sulla causa dell'errore e si raccolgono dati per validarle o scartarle.
Si cerca di ripercorrere il codice “all’indietro” a partire dal punto dove si è verificato il malfunzionamento (istruzione di output oppure eccezione).
Analogamente alla tecnica delle Path Condition, diventa via via più difficile procedere all’indietro all’allargarsi del campo di possibilità.
Il debugging è un’attività estremamente intuitiva, che però deve essere operata nell’ambito dell’ambiente di sviluppo e di esecuzione del codice.
Strumenti a supporto del debugging sono quindi convenientemente integrati nelle piattaforme di sviluppo (IDE), in modo da poter accedere ai dati del programma, anche durante la sua esecuzione, senza essere invasivi rispetto al codice;
In assenza di ambienti di sviluppo, l’inserimento di codice di debugging invasivo rimane l’unica alternativa.
2. Ciclo di Vita e Processi Software
3. Processi per lo sviluppo rapido del software
4. Sviluppo Agile del Software
5. Test Driven Development (TDD)
7. Component Based Software Engineering (CBSE): Generalità
8. Component Based Software Engineering (CBSE): Il processo di svi...
9. Ingegneria del Software orientato ai Servizi
10. Ingegnerizzazione dei Servizi
11. I Processi di Manutenzione del Software
12. Reengineering, Refactoring e Reverse Engineering del Software
13. Verifica e Convalida del Software. Richiami e concetti di base ...
14. Tecniche di Testing Dinamico
15. Testing di Sistemi Object Oriented
16. Automazione del testing e Analisi Mutazionale
17. Tecniche di Analisi Statica del codice e il Debugging
18. Stima dei costi nei progetti Software
19. Il Modello COCOMO per la stima dei costi Software – La gestio...
20. Gestione e Miglioramento dei Processi di Produzione del Softwar...
21. La Valutazione della Qualità dei Processi Software – Il Capa...