Docsity
Docsity

Prepara i tuoi esami
Prepara i tuoi esami

Studia grazie alle numerose risorse presenti su Docsity


Ottieni i punti per scaricare
Ottieni i punti per scaricare

Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium


Guide e consigli
Guide e consigli

Fondamenti di Analisi e Verifica del Software, Dispense di Ingegneria del Software

Appunti completi per il corso di Fondamenti di Analisi e Verifica del Software tenuto nel corso di Ingegneria e Scienze Informatiche dell'Università degli Studi di Verona.

Tipologia: Dispense

2022/2023

In vendita dal 30/05/2023

simoneferrari
simoneferrari 🇮🇹

5

(1)

15 documenti

1 / 90

Toggle sidebar

Documenti correlati


Anteprima parziale del testo

Scarica Fondamenti di Analisi e Verifica del Software e più Dispense in PDF di Ingegneria del Software solo su Docsity! FONDAMENTI DI ANALISI E VERIFICA DEL SOFTWARE APPUNTI DI FERRARI SIMONE UNIVERSITÀ DEGLI STUDI DI VERONA A.A 2022/2023 - 2° ANNO Pag. 2 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche SOMMARIO INTRODUZIONE CORSO 7 CONCETTI BASE DI ANALISI 7 Programma 7 Capire i comportamenti del software 7 Conoscenza=semantica=significato 8 Perché e quando si fa analisi 8 Quali programmi e quali proprietà 8 Quali programmi 8 Quali proprietà 9 Quando si esegue l’analisi: Statica e Dinamica 9 Il limite: incalcolabilità 10 Superare la non terminazione 10 Automazione 10 Approssimazione 10 Soundness (Solidità) 11 Completeness (Completezza) 11 Famiglie di analisi 11 Proprietà dell'analisi 11 Model Checking 12 Analisi conservativa 12 Individuazione dei bug 13 Testing 13 Ottenere ciò di cui hai bisogno 13 Esempi 13 Buffer overflow 14 Web app security 14 Ingredienti per parlare di analisi 15 Astrazione matematica 15 La semantica come astrazioni 16 Control Flow graph (Diagrammi di flusso di controllo) 17 MODELLAZIONE DEI PROGRAMMI 18 Modello del programma 18 Il linguaggio 18 Semantica 18 Stato della memoria 19 Semantica delle espressioni 19 Semantica dei comandi 19 Semantica del while 19 Semantica transazionale (operativa) 20 La semantica come punto fisso 20 L'idea: tracce finite 21 Control Flow Graph 21 Basic Block 22 Generazione di CFG 23 Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 5 di 90 Funzioni di astrazione e concretizzazione 65 Connessioni di Galois (pronunciato “Galuà”) 66 Ordinamento e operazioni nel mondo astratto 66 La costruzione formale 66 Connessioni di Galois 66 Esempio 66 Inserzioni di Galois 67 Operatori di chiusura superiore (uco) 67 Esempio 67 Famiglie di Moore 68 Riassunto 68 Esempio grafico 69 Reticolo delle astrazioni 70 Computazioni astratte e concrete 70 Correttezza (soundness) 70 Soundness sulla chiusura 71 Completezza (precision) 71 Completeness sulla chiusura 72 Forward vs Backward 72 Esempio su intervalli di interi 72 Esempio intervalli 73 Estrapolazione del punto fisso 74 ANALISI NON DISTRIBUTIVE 74 Problemi non distributivi 74 Propagazione delle costanti 74 Costruzione dell’analisi 75 Dominio astratto 76 Abstract edge effect (Semantica astratta) 76 Esempio 77 MOP vs MFP 78 Rafforzare l’analisi 78 Analisi degli Intervalli 79 Analisi dell'intervallo 79 Astrarre gli stati concreti 80 Soluzione MOP 80 Abstract edge effect 81 Computazione MFP 81 Rafforzare l’analisi 81 Esempio 82 Widening 83 Narrowing 83 Sintesi dell’approccio 83 ESERCITAZIONE 1 84 ANALISI DINAMICA 84 Introduzione 84 Testing 84 Anno Accademico 2022/2023 Pag. 6 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Obiettivi del testing 84 Tipologie di errori 84 Progressione di un fallimento 85 Aspetti teorici 85 Teoremi 86 Processo di testing 86 Generazione dei casi di test 86 Approccio code-based 87 Coverage testing 87 Structural coverage testing 88 Statement coverage 88 Branch coverage 88 Statement vs Branch 89 "Tutti i rami" possono ancora mancare alcune condizioni 89 Condition coverage 89 Path coverage 90 Combinazione di analisi e test 90 Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 7 di 90 FONDAMENTI DI INGEGNERIA DEL SOFTWARE 4S008901 | 2° ANNO - I SEMESTRE INTRODUZIONE CORSO ● CFU : 6 ● Esame : ○ Scritto : domande ed esercizi. Valutazione in 30esimi o come bonus 0-4. ■ Se 30esimi: ● Registrare voto <= 26 ● Orale : per avere voto superiore a 26. ■ Se bonus 0-4: ● Bonus valido se >=1 ● Progetto : approfondimento singolo/gruppo da 2 persone. Relazione scritta+orale. ● Risultato : 26pt progetto + bonus 0-4 APPUNTI LEZIONE 1 | 03/10/22 CONCETTI BASE DI ANALISI Programma Analisi statica (Analisi sul codice, proprietà semantiche sono indecidibili, per teorema di Rice) ● Analisi statica: Data Flow ● Analisi statica mediante interpretazione astratta Analisi dinamica (Valuta le proprietà su un sottoinsieme di possibilità, si parla anche di Testing) ● Aspetti formali del testing ● Monitoring Slicing (tecniche di manipolazione e trasformazione di programmi) Verifica (Model checking, approssimando… difficile dare risposte certe) Capire i comportamenti del software Lo scopo dell’Analisi e della Verifica è rispondere alla domanda: Il nostro software funzionerà nella realtà come previsto? La risposta viene dall'analisi dei nostri progetti utilizzando la nostra conoscenza della natura che realizzerà i progetti ● Vogliamo assicurarci che il nostro software funzioni come previsto ● Per un' affidabilità generale , vogliamo assicurarci che il software non si arresti in modo anomalo in caso di interruzione improvvisa ● Se il software interagisce con il mondo esterno, vogliamo assicurarci che non venga ingannato per violare la sicurezza del computer host ● Se il software deve controllare le auto, vogliamo assicurarci che non le porti a un incidente Anno Accademico 2022/2023 Pag. 10 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Il limite: incalcolabilità Dato un linguaggio di programmazione da analizzare e una proprietà di interesse , un' analisi di programma ideale calcolerebbe sempre in modo completamente automatizzato il risultato esatto in un tempo finito . Linguaggio Turing-completo la non terminazione è indecidibile. ⇒ Insieme di tutti i programmi in questo linguaggio L Non esiste un halt per il programma tale che Non esiste un algoritmo tale che per qualsiasi programma decida automaticamente una proprietà semantica non banale (Teorema di Rice) Una proprietà semantica è una proprietà che può essere completamente definita rispetto all'insieme delle esecuzioni di un programma Una proprietà semantica non è banale quando ci sono programmi che la soddisfano e programmi che non la soddisfano . Significa che dobbiamo arrenderci? Superare la non terminazione L e analisi che andremo a prendere in considerazione dovranno tutte subire qualche tipo di imitazione : ● Rinunciando all'automazione ● Mirando solo a una classe ristretta di programmi (cioè rinunciando a per ogni programma nel teorema di Rice), ● Indebolendo la richiesta di precisione , non essendo sempre in grado di fornire una risposta esatta (cioè rinunciando alla decisione nel teorema di Rice) Automazione Rinunciare all'automazione significa lasciare che le analisi del programma richiedano una certa quantità di input da parte dell'utente . Ciò significa che l'analisi è in parte manuale poiché gli utenti devono calcolare parte dei risultati da soli. Questo processo potrebbe essere soggetto a errori , in modo tale che l'errore umano possa in definitiva portare a risultati errati. Per evitare tali errori , gli strumenti di analisi del programma possono verificare in modo indipendente le informazioni fornite dall'utente. Approssimazione Invece di rinunciare all'automazione , possiamo allentare le condizioni sull'analisi del programma lasciando che a volte restituisca risultati imprecisi. Non significa sbagliare, ma accettare risultati non accurati. Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 11 di 90 Soundness (Solidità) Quando la proprietà è vera, sono certo della risposta. Se invece è falso, non posso essere sicuro che la proprietà non sia realmente soddisfatta. Completeness (Completezza) Vale il contrario della Soundness : se la proprietà è falsa, ne sono certo. Ma se è vera, non posso esserne sicuro. Famiglie di analisi Verifica : come assicurarsi che il programma funzioni correttamente ● Model Checking : esplorazione esauriente di sistemi finiti Analisi statica conservativa : cosa si può dire sul programma senza eseguirlo ● Automatico, approccio Sound e incompleto Individuazione dei bug : tentativo di individuare la causa dell'errore ● Ricerca errori , automatico, non sound, incompleto, basato su euristica Testing : prova a dimostrare che il programma non è corretto selezionando un insieme di esecuzioni finite Proprietà dell'analisi Confronto delle famiglie in termini di caratteristiche delle analisi: Automatica? Per ogni programma? Soundness? Completeness? Dinamica o Statica? Anno Accademico 2022/2023 Pag. 12 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Ricordare che: ● Statico : lavora su codice ● Dinamico : lavora sull’output Model Checking Verifica un modello di programma utilizzando una sorta di enumerazione esaustiva ✅ Automatica ❌ Per ogni programma : solo sistemi finiti ✅ Soundness : Rispetto al modello (se il modello non è in grado di catturare esattamente i comportamenti del programma, la verifica del modello sintetizzato può essere incompleta o non funzionante, rispetto al programma di input) ✅ Complete : come soundness ➡ Statica Analisi conservativa Calcola descrizioni conservative dei programmi utilizzando risorse limitate. ✅ Automatica ✅ Per ogni programma : completamente approssimativo l'insieme di tutti i programmi comportamenti utilizzando un insieme specifico di proprietà ✅ Soundness : descrizione conservativa dei comportamenti del programma ❌ Complete : impossibile rappresentare tutte le proprietà statiche del programma e imporre la terminazione ➡ Statica Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 15 di 90 ● Sembra innocuo... query = “ SELECT Username, UserID, Password FROM Users WHERE Username = ‘bob’ -- AND Password = ‘ ’ ” Propagazione della contaminazione Possono esistere catene di variabili che a partire dall’input possono contaminare e produrre falle di sicurezza. Analisi del puntatore ● Due variabili in diversi punti del programma possono fare riferimento allo stesso oggetto? ● Risposta: analisi del puntatore! Staticamente lo stesso oggetto può spostarsi tra i parametri di un programma: ● Parametro di una funzione ● Valore di ritorno di una funzione ● Ritirato o inserito in una struttura dati ● Può essere riferito con nomi diversi L'analisi del puntatore raccoglie e osserva queste operazioni ● Possiamo seguire gli oggetti durante l'esecuzione del programma Ingredienti per parlare di analisi Astrazione matematica Generalità, Potenza, Semplicità ed Efficienza Anno Accademico 2022/2023 Pag. 16 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche La semantica come astrazioni I puntini rappresentano gli stati , una fotografia del programma . Fotografa la situazione della macchina. Il livello di astrazione è in relazione con ciò che voglio osservare. Weakest precondition semantics Hoare assiomatic semantics Il processo di astrazione deve garantire dei vincoli per poter risalire all’esecuzione del programma, a partire dal risultato. Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 17 di 90 Astrazione per guardare solo il segno : Problema : dal dominio dei numeri negativi non posso risalire a quale dominio originale in C appartenga. Approssimo quindi all’oggetto concreto. E lo 0? Come approssimo 0? Non so cosa scegliere. Questa astrazione non rispetta i vincoli. Aggiungo quindi lo 0, e ho la migliore approssimazione possibile, compreso lo 0. Control Flow graph (Diagrammi di flusso di controllo) Rappresentazione finita del flusso di controllo dei programmi A mano è meglio separare le singole istruzioni… e non andare per gruppi di righe. Non abbiamo IF e WHILE: agiscono sul controllo, e generano quindi archi. Anno Accademico 2022/2023 Pag. 20 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Semantica transazionale (operativa) Quando la semantica compositiva (denotazionale) non è ovvia possiamo definire una semantica di stile transizionale (operativa) . Questa semantica è definita come l'insieme di tutte le (possibile infinite) sequenze di transizioni di stato dagli stati iniziali , ovvero di esecuzioni di istruzioni di programma, denotate da sequenze di stati nel sistema di transizione ● Fornisce il significato dei programmi “eseguendo” le sue affermazioni su un interprete (cioè componendo gli effetti delle affermazioni). ● Il modello matematico consiste nell'utilizzare tracce in un sistema di transizione La raccolta di tutte queste tracce, a partire dagli stati iniziali, è anche chiamata semantica della traccia del programma. La semantica come punto fisso La semantica di un programma può essere vista come l' invariante del calcolo del programma La semantica del programma può essere espressa come punto fisso della funzione che modella il comportamento del programma Una semantica a punto fisso è specificata come una coppia ⟨D,F⟩ dove: ● il poset (insieme con ordine parziale) ⟨D,≤⟩ è il dominio semantico ● F : D → D è una mappa totale, monotona e iterabile ed è il trasformatore semantico Semantica operativa a piccoli passi che descrive formalmente i singoli passi di calcolo Un sistema di transizione è una coppia ⟨𝛴,𝜏⟩ dove: ● 𝛴 è un insieme non vuoto di stati ● 𝜏 ⊆ 𝛴× 𝛴 è la relazione di transizione La semantica operativa di un linguaggio di programmazione associa ad ogni programma (scritto in quel linguaggio) un sistema di transizione. Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 21 di 90 L'idea: tracce finite Punto rosso : stato bloccante Punto Blu : stato non bloccante Computazione : La semantica transizionale dei comandi cambia principalmente nella semantica del ciclo, poiché non calcola il punto fisso ma descrive la singola transizione e nella composizione è una semantica a passaggio singolo LEZIONE 3 | 11/10/22 Control Flow Graph È un grafico generato dalla sintassi del programma Permette di comprendere facilmente la struttura del codice ● Codice morto ● Debug ● Test CFG modella i flussi di controllo nel programma (procedura) Il CFG è definito come un grafo orientato G = (N, E) ● Un nodo è un blocco di base 𝑛 ∈ 𝑁 ○ Un Basic Block è una sequenza massima di stmts con un unico punto di ingresso, un unico punto di uscita e nessun ramo interno Anno Accademico 2022/2023 Pag. 22 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche ○ Per semplicità, assumiamo un nodo di ingresso univoco e un nodo di uscita univoco 𝑛 0 nelle discussioni successive 𝑛 𝑓 ● Un arco è possibile il trasferimento del controllo dal blocco al blocco 𝑒 = ( 𝑛 𝑖 , 𝑛 𝑓 ) ∈ 𝐸 𝑛 𝑖 𝑛 𝑗 Basic Block Definizione ● Un basic block è una sequenza massima di istruzioni consecutive con un unico punto di ingresso, un unico punto di uscita e nessun ramo interno Unità di base nell'analisi del flusso di controllo Ottimizzazioni del codice a livello locale ● Eliminazione della ridondanza ● Allocazione dei registri Input : una sequenza di istruzioni di codice intermedie 1. Determinare i leader , le prime affermazioni dei basic blocks ● Il primo statement nella sequenza (punto di ingresso) è un leader ● Qualsiasi statement s che è target di un ramo (condizionale o incondizionato) è un leader (esiste goto s) ● Qualsiasi dichiarazione immediatamente successiva a un branch (condizionale o incondizionata) o a un ritorno è un leader 2. Per ogni leader , il suo basic block è il leader e tutte le istruzioni fino al leader successivo o alla fine del programma, ma escluso Come identifichiamo i basic bloc? ● Inizio di un basic block ● Fine di un basic block Leader: la prima tupla del block Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 25 di 90 LEZIONE 4 | 11/10/2022 APPROSSIMAZIONE Idea Sia Q una proprietà tale che non sia decidibile! ⟦ 𝑃 ⟧ ⊆ 𝑄 Calcolare un'approssimazione di tale che: ⟦ 𝑃 ⟧ # ⟦ 𝑃 ⟧ ● Correttezza / integrità (soundness) : ⟦ 𝑃 ⟧ ⊆ ⟦ 𝑃 ⟧ # ● Decidibilità : ⟦ 𝑃 ⟧ # ⊆ 𝑄 La soundness permette di sfruttare la decidibilità dell'approssimazione: ● ⟦P⟧# ⊆ Q ⇒ ⟦P⟧ ⊆ Q ● Altrimenti, non lo sappiamo! Astrazione della semantica Vedremo come costruire da ⟦ 𝑃 ⟧ # ⟦ 𝑃 ⟧ Specifichiamo la semantica come una coppia : una funzione f (con punto fisso) e un dominio (ordinato) di calcolo D Avremo bisogno di studiare: ● Astrazione del dominio della computazione e delle relazioni tra oggetti concreti e astratti ○ Le osservazioni "astratte" dei dati e come sono associate a quelle osservate ● Astrazione del calcolo con particolare attenzione all'astrazione dei calcoli a punto fisso ○ Come la semantica manipola queste osservazioni astratte L'astrazione è il processo di sostituzione di qualcosa di concreto con una descrizione che si occupa di alcune (in generale non tutte) proprietà , conosciute anche come modello astratto! ● Può descrivere con precisione alcune proprietà! ● Impossibile descrivere tutte le proprietà. Insieme di oggetti in , allora è l’insieme delle proprietà su Σ 𝑃 (Σ) Σ ● Gli elementi in A sono quelli esattamente descritti dall'astrazione (senza perdita di precisione). ● Gli elementi non in A devono essere rappresentati da altri elementi di A (senza perdita di precisione) Oggetti Nell'analizzare/dimostrare programmi dobbiamo considerare oggetti che rappresentano parti dello stato di calcolo: ● Valori: booleani, interi,... ● nomi di variabili ● ambienti ● Stacks Proprietà Le proprietà sono insiemi di oggetti (con quella proprietà) ● Numeri dispari ● Numeri pari ● Numeri interi ● Numeri in un range di valori Anno Accademico 2022/2023 Pag. 26 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Il reticolo delle proprietà L’insieme delle proprietà sugli oggetti di è un reticolo completo distributivo. Σ Dove: Direzione di astrazione Quando si approssima una proprietà concreta P con una P astratta , la relazione stabilita è ● P è un'astrazione/approssimazione di P Consideriamo essenzialmente due casi ● Approssimazione dal basso : P ⊆ P ● Approssimazione dall'alto : P ⊇ P ● Si potrebbero considerare altre relazioni Le due nozioni sono duali, solo una deve essere studiata ● Di solito dall'alto (eccesso), è più difficile trovare utili approssimazioni dal basso Esempio: approssimazione per difetto (dal basso) Se il punto non è in P# allora non so se sia in P. Esempio: approssimazione per eccesso (dall’alto) La proprietà concreta è un insieme di oggetti ● Gli oggetti sono complessi ● L'insieme è potenzialmente infinito ● In generale non rappresentabile a macchina Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 27 di 90 La proprietà astratta è un insieme più ampio di oggetti ● A volte più grande significa più estensibile da rappresentare ● MA, strutture più grandi ben scelte possono avere codifiche più semplici che possono essere sfruttate per la memorizzazione e il calcolo Astrazione minima Assumiamo che le proprietà concrete devono essere approssimate per difetto tale che: 𝑃 ⊆ 𝑃 # P# lo vogliamo il più piccolo possibile, ma migliore approssimazione possibile. Solitamente si ha un insieme composto da: proprietà astratta + grande Dove il + grande è più semplice da rappresentare, perché individua l’invariante che vogliamo osservare tra gli oggetti concreti. Ovviamente voglio l’approssimazione minima, ovvero la migliore. Una buona scelta per l'astrazione è quella in cui esiste la migliore approssimazione per qualsiasi proprietà concreta Esempio: il dominio dei segni Ci interessa studiare le proprietà della moltiplicazione e dell'addizione di interi ● Programmi = moltiplicazione/addizione di interi ● Proprietà = il segno di argomenti e risultati ● Semantica concreta = le operazioni standard ben note che manipolano gli interi ● Semantica astratta = operazioni astratte date dalla regola del segno per la moltiplicazione e l'addizione Il primo passo è approssimare il dominio degli oggetti La proprietà che vogliamo studiare suggerisce gli oggetti del dominio astratto ● + rappresenta numeri interi positivi con 0 ● - rappresenta numeri interi negativi con 0 ● 0 rappresenta il singleton {0} Dominio concreto: 𝑃 ( 𝑍 ) Dominio astratto: {>, 0 +, 0 −, 0 , ⊘} Anno Accademico 2022/2023 Pag. 30 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Esiste la traccia qui sotto? Non sappiamo…. Di cosa abbiamo ancora bisogno ● Tracciare insiemi di stati anziché singoli stati: abbiamo un'esecuzione spuria a causa della raccolta, ma solo tra gli stati raggiungibili . ● Dobbiamo raccogliere ulteriormente i calcoli , calcolando sui punti del programma invece che sulla fase di calcolo Collecting sui punti del programma Ci stiamo effettivamente muovendo verso la decidibilità? NO. Supponiamo che in orizzontale ci siano delle tracce. E in verticale siano discretamente separati gli step. Quando faccio la Collective Semantics, eseguo un’istruzione in un punto di programma. Posso quindi guardare invece che il tempo di esecuzione (che cresce), il punto di programma osservato. Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 31 di 90 Andando avanti nel tempo, noi visitiamo più volte punti all’interno del ciclo. (2-34) Vengono quindi collezionati i punti sulla base dello step. Anche questo non garantisce terminazione, ma in alcuni casi gli insiemi si stabilizzano anche se non si termina mai l’esecuzione. Esempio: x=0; while x >= 0 { x = x } Anno Accademico 2022/2023 Pag. 32 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Di cosa abbiamo ancora bisogno ● Tracciare insiemi di stati anziché singoli stati: abbiamo un'esecuzione spuria a causa della raccolta, ma solo tra gli stati raggiungibili. ● Collective Semantics: raccogliamo i calcoli, calcolando sui punti del programma invece che sulla fase di calcolo. ● Dobbiamo astrarre ulteriormente il calcolo, calcolando le proprietà degli stati raggiungibili in ogni punto del programma Collecting on Properties Invece che ad elencare gli elementi che abbiamo raggiunto, descriviamo la proprietà invariante Supponiamo di guardare gli intervalli (invece che elementi singoli) Introduciamo computazioni spurie non solo a causa di tracce non esistenti, ma anche a causa che introduciamo stati che non vengono mai raggiunti nel concreto. Si aumenta quindi grado di rumore. Secondo passo computare il punto fisso su proprietà degli stati raggiunti Che rumore aggiungiamo? ● Collecting Semantics : abbiamo un'esecuzione spuria a causa dell’insieme, ma solo tra stati raggiungibili ● Collecting on Properties : aggiungiamo stati spuri dovuti all'approssimazione dei dati, e quindi la raccolta di calcoli aggiunge calcoli spuri anche tra questi stati. Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 35 di 90 Analisi basate su CFG: Approccio algoritmico Algoritmo ricorsivo di calcolo delle proprietà su CFG Abbiamo un CFG per ogni funzione/procedura Analisi del codice: ● Locale (all'interno di un block ): considera i basic block in isolamento; ● Intra-procedurale : esamina il flusso di informazioni all'interno di un unico CFG ; ● Interprocedurale (all'interno di un programma ): considera il flusso di informazioni tra le funzioni. In genere utilizza il grafico delle chiamate : un grafico con un nodo per ciascuna funzione e significa che la funzione f potrebbe chiamare la funzione g. Un ciclo rappresenta la 𝑓 ⟶ 𝑔 ricorsione; Il modello di data flow analysis consiste nel caratterizzare come le informazioni di interesse vengono trasformate all'interno di un blocco ● L'informazione è caratterizzata come la soluzione di un'equazione di punto fisso definita per ogni blocco del CFG In alcuni casi questa equazione si ottiene in tre passaggi : ● Caratterizzare le informazioni che entrano in un blocco , che è l' unione delle informazioni di uscita dei blocchi precedenti; ● Caratterizzare l'informazione all'uscita del blocco , che è l'informazione all'ingresso trasformata dalle operazioni eseguite nel blocco (prendiamo ciò che entra, lo si modifica, e si mette in uscita). ● Queste definizioni vengono quindi combinate in un'equazione punto fisso. Il calcolo avviene per punto fisso (ho una info iniziale vuota, insignificante, e visitiamo via via i nodi del CFG). Available Expression Nel punto B, y+z è valutato una seconda volta? Ho due possibilità: ● Se la y+z al punto di programma B viene sempre valutata dopo quella al punto di programma A. ○ Arrivo a B sempre dopo A? ■ Generalizzazione : E’ vero che la valutazione di una espressione è sempre eseguita prima di un’altra espressione ● Le variabili y e z hanno gli stessi valori prima di B che avevano prima di A ○ Le variabile coinvolte vengono mai modificate tra A e B? ■ Generalizzazione : Una variabile in un punto di programma ha sempre lo stesso valore che aveva prima di un altro punto di programma? Anno Accademico 2022/2023 Pag. 36 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Esempio : bubble sort Codice generato dal compilatore Per un trattamento sistematico di questa ottimizzazione dobbiamo rispondere alle seguenti domande : ● Una valutazione di un'espressione verrà sempre eseguita prima di un'altra? ● Una variabile ha sempre lo stesso valore in un determinato punto del programma che aveva in un altro punto del programma? Per rispondere a queste domande abbiamo bisogno di : ● Una semantica operazionale ● Un metodo che identifichi i calcoli ridondanti, e quindi comporta che: ○ Non tutti i calcoli ridondanti sono catturabili (E’ ridondante? SI FALSI NEGATIVI) ○ Non classificare mai come ridondante un calcolo che non lo è. (E’ ridondante? NO FALSI POSITIVI) [DEF] Available Un'espressione è available (disponibile) nella variabile in un punto del programma se 𝑒 𝑥 𝑝 ● deve essere stata valutata in un punto precedente a 𝑒 𝑝 ● Sia che tutte le variabili in non devono essere modificate tra la valutazione di in e 𝑥 𝑒 𝑒 𝑥 𝑝 ○ né né nessuna delle variabili in sono state modificate nel mezzo 𝑥 𝑒 Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 37 di 90 1) Caratterizzare l’informazione in ingresso ad un blocco In input , si prende al passo iniziale nulla, al passo N l’intersezione dei predecessori di N tra le espressioni disponibili dai predecessori di N) 2) Caratterizzare l’informazione in uscita ad un blocco In output , si computa la semantica e si capisce cosa si rende disponibile in uscita. ● Espressioni generate nel blocco (esempio: w+5) ● Ciò che era disponibile in input (x+y) e che non è stato modificato ( uccisa (z+2) dalla semantica) Il punto fisso è necessario in quanto input è definito mediante output e output mediante input. Ogni nodo n è annotato con un insieme AvailIn(n) contenente l' espressione disponibile all'ingresso nel blocco Inizializzazione : Equazione da risolvere: Anno Accademico 2022/2023 Pag. 40 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Schema di data flow analysis Forward (parte dallo stato iniziale e visita in avanti il CFG costruendo informazioni) FAin è definito come combinazione di FAout (e si usano i predecessori) Backward (parte dallo stato finale e visita in indietro il CFG costruendo informazioni) BAout è definito come combinazione di BAin (e si usano i successori) Il cerchietto con il più può essere : ● Analisi Possibile: unione ● Analidi Definita: intersezione LEZIONE 7 | 24/10/22 Framework formale per l’approccio semantico Definizione del framework formale : riscrivere stesso approccio in modo semantico, ovvero dare un trasformatore semantico che trasforma la semantica (ciò che osserviamo ad ogni step) e poi in funzione di questa semantica forniamo algoritmo di risoluzione. 1. Definiamo e formalizziamo le informazioni astratte di cui abbiamo bisogno per eseguire l'analisi ; 2. Definiamo l'abstract edge effect ( funzione di trasferimento ) su questo nuovo dominio di informazioni astratte (monotoniche) ● Costruiamo un sistema di disuguaglianze (una diseq. per ogni punto di programma) in cui le incognite sono le informazioni astratte in ogni punto del programma e cerchiamo la soluzione migliore, ovvero MENO ○ Iterazione ingenua del punto fisso ○ Iterazione round-robin ● Cerchiamo la soluzione MOP ( merge over all path ) che permetta di eseguire una trasformazione del programma sound. Nella realtà, possiamo calcolare la MFP (soluzione del sistema di disequazioni), che approssima la soluzione MOP. Le due soluzioni coincidono quando l'abstract edge effect è distributivo. La semantica astratta (chiamata edge effect) determina l'insieme di assegnazioni disponibili in un punto del programma sulla base dell’etichetta del punto di programma e dell’istruzione precedentemente available . Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 41 di 90 Step da svolgere 1) Caratterizzare l’informazione astratta. 2) Caratterizzare la funzione di trasferimento (per induzione sul linguaggio del CFG) [DEF] Definitively Available DEF : essere sempre disponibile per qualunque cammino possibile. Definitivamente disponibile in V se è disponibile in ogni cammino che va dall’entry point del CFG a v. Termination and soundness La terminazione è assicurata da : ● Monotonia delle funzioni di trasferimento (preserva l’ordine) ● Un reticolo completo ACC (no catene ascendenti infinite) La solidità segue la costruzione del punto fisso Dimostrazione di Soundness Può essere suddiviso in due parti: 1. La prova della correttezza degli effetti di bordo astratti rispetto alla definizione di disponibilità; 2. La dimostrazione della correttezza della sostituzione di espressioni definitivamente disponibili con accessi a variabili; La dimostrazione deve collegare la sintassi con la semantica! Precisione dell'analisi - Dove si perde precisione? Questa analisi perde qualche opportunità per rimuovere i calcoli ridondanti : ● Si considerano percorsi irrealizzabili (non percorribili) : sono considerati negli abstract edge effects. Perdiamo precisione perché in un determinato punto potrei ritenere una espressione come “non disponibile” a causa di un percorso in input non percorribile. Anno Accademico 2022/2023 Pag. 42 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche ● Non si guardano i valori delle variabili. Esempio: X = 2X-X rende l’espressione non disponibile anche se X effettivamente non cambia di valore. Si supponga che l'assegnazione sia disponibile in , e che esista un arco 𝑥 ← 𝑦 + 𝑧 𝑢 . Supponiamo che il valore di sia sempre quello che ha in . In questo caso la 𝑘 = ( 𝑢 , 𝑦 ← 𝑒 , 𝑣 ) 𝑒 𝑦 𝑢 trasformazione che sostituisce con sarebbe comunque corretta anche se non 𝑦 + 𝑧 𝑥 𝑥 ← 𝑦 + 𝑧 sarebbe più riconosciuta come disponibile in . 𝑣 Computazione della soluzione L’idea principale consiste nel creare un sistema di disequazioni . La prima esprime il presupposto che all'ingresso del programma non siano disponibili input; Ogni arco generico k che va da u a v genera la seconda disuguaglianza, la quale prende l'assegnamento propagato come disponibile nell’arco K, ovvero: disponibile già per u e sopravvissuto, o reso disponibile. Esempio Step successivo di risoluzione… Soluzione : Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 45 di 90 La soluzione MOP è più precisa della soluzione che noi calcoliamo mediante la soluzione del sistema di transizione MFP (soluzione punto fisso). Calcolo MOP e differenze con MFP Per quanto riguarda l'MFP, il MOP cambia quando viene applicato l'operatore di unione : 1. L'algoritmo (calcolo MFP) visita i blocchi di base , non necessariamente nell'ordine di esecuzione 2. In ogni punto di confluenza , l'algoritmo (calcolo MFP) applica l'operatore di unione ai valori ottenuti fino a quel punto . Alcuni valori potrebbero non essere ottenuti da alcuna esecuzione . MOP vs MFP In generale non sono la stessa cosa Ci sono alcuni casi pratici le due soluzioni concordano ● Quando tutte le funzioni di trasferimento (effetto bordo astratto) sono distributive Esempio : l'aumento sui naturali è distributivo ma non rigoroso. Add è rigoroso ma non distributivo Anno Accademico 2022/2023 Pag. 46 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Quello che segue è un risultato importante La condizione di raggiungibilità è necessaria I punti di programma irraggiungibili possono essere facilmente identificati e quindi rimossi senza modificare la semantica del programma Funzione distributiva su operatore Merge 𝑓 ( 𝑥 1 ∪ 𝑥 2 ) = 𝑓 ( 𝑥 1 ) ∪ 𝑓 ( 𝑥 2 ) Se f è distributiva (e se tutti i nodi del programma sono raggiungibili), allora per ogni . Ovvero 𝑀𝑂𝑃 [ 𝑉 ] = 𝑀𝑃𝐹 [ 𝑉 ] 𝑉 𝑦 [ 𝑣 ] = 𝑦 *[ 𝑣 ] Se è distributiva, abbiamo un algoritmo MFP per calcolare la mappa. Analisi distributivi I problemi distributivi sono “facili” . ● I DFA riguardanti la struttura del codice sono tipicamente distributivi! ● Esempio : variabili in tempo reale, espressioni disponibili, raggiungimento di definizioni, espressioni molto occupate sono tutti problemi distributivi. ● Si tratta di proprietà relative a COME viene eseguito il programma (il calcolo) e quindi più vicino alla struttura (sintassi) del codice. ● L’unica perdita di informazione è dovuto all’uso del CFG A questo gruppo appartengono le Available Expression. Analisi non distributivi ● I tipici problemi non distributivi riguardano COSA calcolano i programmi . Si entra nel merito della memoria, ci si allontana dalla sintassi. ● Esempio : l'uscita è una costante, un valore positivo, appartiene a un intervallo, è delimitata ecc. ● Esempio : analisi di propagazione costante ● L’errore è aggiunto a causa del calcolo della soluzione (per punto fisso su un sistema di disequazioni) Per ogni punto di programma p determina se una variabile ha sempre lo stesso valore costante ogni volta che l'esecuzione raggiunge p. Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 47 di 90 Riassunto Approccio algoritmico La funzione di trasferimento è la funzione che trasforma la proprietà analizzata ad ogni passaggio o iterazione. Descrive come avviene il calcolo. La famiglia di funzioni di trasferimento (una per ogni blocco) in un framework di flussi di dati 𝐹 : 𝑉 → 𝑉 ha le seguenti proprietà: ● Include la funzione identità I(x)=x, per ogni x∈V; ● È chiuso rispetto alla composizione Descrive ciò che avviene in ogni blocco. Ad esempio, per l'espressione disponibile la famiglia è composta da funzioni della forma Semantica : f monotona definita induttivamente sulla struttura sintattica del linguaggio del CFG. General Framework Algorithm Soluzione iterativa per il framework del flusso di dati ● INPUT : Framework del flusso di dati composto come segue 1. Un CFG con nodi Entry e Exit 2. Un insieme di valori V 3. Un'operazione merge ⊔ 4. Un insieme di funzioni di trasferimento F tali che fB in F sia la funzione del blocco base B 5. Un valore costante vEntry o vExit che rappresenta rispettivamente le condizioni iniziali in un'analisi in avanti o all'indietro ● OUTPUT : Valori in V degli insiemi IN[B] e OUT[B] per ogni blocco B del CFG Forward data-flow algorithm 1. Input inizializzato al valore iniziale 2. Si inizilizza ogni blocco diverso dalla entry inserendo un qualcosa neutro rispetto operatore MERGE (x U false = x) 3. Affinchè abbiamo che qualche elemento di IN cambia a. Allora per ogni blocco che non è la Entry i. Ricalcolo ciò che è vero in ingresso al blocco (uso ciò che era in uscita dai predecessori facendone merge) ii. Emetto in output il risultato di fB applicata a ciò che valeva in input Anno Accademico 2022/2023 Pag. 50 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche LEZIONE 9 | 07/11/22 Liveness Analisi che cerca di individuare quali variabili sono “vive” nella porzione di codice che si sta analizzando. Che cos'è la data flow analisys Wiki : l'analisi del flusso di dati è una tecnica per raccogliere informazioni sul possibile insieme di valori calcolati in vari punti in un programma per computer. Una definizione migliore? L'analisi del flusso di dati è una tecnica per raccogliere informazioni su come i dati fluiscono in fase di esecuzione in vari punti di un programma per computer. Analisi delle variabili in tempo reale Indispensabile per l'allocazione dei registri : due variabili vive contemporanee non possono essere memorizzate nello stesso registro! X e Y non possono essere memorizzati nella stessa posizione n se sono entrambi in uso! Utile per la SW watermarking (l'algoritmo QP) Variabili non inizializzate Una volta che l'analizzatore ha calcolato gli insiemi di variabili attive per ciascun nodo nel CFG, è semplice trovare l'uso di variabili che potrebbero non essere inizializzate Considera una variabile x ● Se x è nella voce, allora per costruzione esiste un percorso per un uso di x lungo il quale x non è definito ● Quindi, x nella voce implica la presenza di un uso di x che può ricevere un valore non inizializzato. ● Il compilatore riconosce la situazione e la segnala al programmatore. Esempio Codice del programma e relativo CFG: Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 51 di 90 Una variabile è viva se è utilizzata nei cammini che raggiungono quel nodo (backward) Variabili Usate e Definite L'insieme di variabili utilizzate e definite su un arco nel CFG può essere derivato dall'istruzione che etichetta il bordo: Variabili Live e Dead x è live all'uscita di C se x contiene un valore che verrà utilizzato dopo (si leggerà: right-hand side) x non è live dopo C se prima del suo utilizzo futuro verrà riassegnato (x := exp e x ∉ exp) Se x non è live , è dead ! Eliminazione codice dead : se x è dead dopo x:=exp allora possiamo cancellare x:=exp Il codice morto è indecidibile!! Dipendenza dalla continuazione Se una variabile è eventualmente live o (definitivamente) dead dipende dalla possibile continuazione dell'esecuzione del programma ● Tutte le variabili sono morte alla fine del programma ● C'è un solo percorso da ogni punto del programma all'uscita Al punto 1, y non è live perché ridefinita. Anno Accademico 2022/2023 Pag. 52 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Esempio di prima Variabile B Una variabile è attiva se verrà utilizzata prima di essere ridefinita L'ultimo utilizzo della variabile b come r-value è Istruzione 4 La variabile b è usata in istruzione 4: è live nell’arco 3 -> 4 Istruzione 3 non assegna nulla a b, quindi b è vivo anche nell'arco 2 ->3 Istruzione 2 assegna un valore a b. Ciò significa che il valore di b prima di stm 2 non viene utilizzato Quindi il b "live range" è: {2 -> 3, 3 -> 4} Variabile A a è live negli archi 4 -> 5 e 5 -> 2 La variabile a è live nell’arco 1 -> 2 a è morto nei archi 2 -> 3 e 3 -> 4 Anche se il nodo 3 a ha un valore, questo valore non verrà utilizzato poiché nel nodo 4 viene assegnato un nuovo valore ad a. Variabile C c è vivo in tutti gli archi Liveness può essere utilizzato per rilevare se c è una variabile locale, quindi c viene utilizzato senza inizializzazione (questo può essere utilizzato per generare un avviso) Conclusione : ● Sono sufficienti 2 registri : le variabili a e b non sono mai vive contemporaneamente sullo stesso fronte ● Quindi, invece di due variabili a e b possiamo usare solo una variabile ab Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 55 di 90 LEZIONE 10 | 08/11/22 Approccio semantico Il dominio è 2 VARS ● Si fornisce un insieme di variabili live all’uscita ● Si definisce l’abstract edge effect. È un'analisi backward : l’edge effect determina l'insieme di variabili eventualmente presenti in u dato l'insieme di variabili eventualmente presenti in v, a condizione che l'arco k=(u,lab,v) Soluzione MOP L'insieme di variabili di programma eventualmente presenti in un punto di programma v si ottiene come unione di insiemi sui percorsi X set di variabili live finali Ordine : inclusione di set: un insieme più piccolo di variabili attive significa insiemi più grandi di variabili morte (maggiore ottimizzazione Computazione Analogamente alle espressioni available , ma fissiamo l'insieme X che è l'insieme di tutte le variabili che sono live all'uscita poiché è un' analisi backward : da v a u. È una analisi possible. Il sistema delle disuguaglianze risultante è: Il reticolo completo per le soluzioni è finito L'abstract edge effect è monotono ● Possiamo usare l'iterazione round-robin per la soluzione minima L’abstract edge effect è distributivo ● La soluzione minima è la soluzione MOP Anno Accademico 2022/2023 Pag. 56 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Esempio Step by step L'iterazione round-robin fornisce la soluzione dopo un solo round , dato il giusto ordine delle incognite, a partire dalla soluzione a set vuoto: Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 57 di 90 Falsi positivi dell’analisi di liveness non dovuti all’approssimazione Quando si utilizza l'analisi per trasformare i programmi, la rimozione dell'assegnazione a variabili morte può generare altre variabili morte , supponiamo che y sia live nell'output del programma Può classificare la variabile come live a causa di usi successivi nelle assegnazioni a variabili morte Applicare iterativamente l’analisi non è una soluzione efficiente Possiamo sfruttare in modo ricorsivo quanto sta già calcolando il programma? Si raffina l’analisi decidendo se inserire una variabile tra le variabili live. True Use Funziona con una condizione più restrittiva per la live ● Vero uso e vero live: ○ Un uso in un assegnamento a una variabile morta non è considerato true use Ricordiamo che il true use dipende dalle informazioni che arrivano da un arco. Teniamo in considerazione l’informazione k=(u, lab, v) Ci si chiede se y è truely use nell’arco La condizione aggiuntiva che il lato sinistro dell'assegnazione deve essere veramente vivo costituisce l'unica differenza rispetto alla normale vivacità. Anno Accademico 2022/2023 Pag. 60 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Analisi di copy propagation L’analizzatore tiene traccia , ad ogni punto di programma e per una certa variabile x , dell’insieme di variabili che contengono il valore di x (copie) , per poterle rimpiazzarle tutte con un uso di x . Più grande è questo insieme, maggiori sono le chance di ottimizzare il codice. Questa ottimizzazione passa per la liveness. Propagazione di tutte le copie : determinare per ogni punto di programma quali variabili sono copie Costruire le equazioni Le equazioni da costruire sono: CopyIn(n) sarà quindi l’insieme delle copie che valgono in entrata ad un nodo , mentre CopyOut(n) sarà l’insieme delle copie che valgono in uscita da un nodo . Entrambi sono sottoinsiemi dell’insieme delle copie definito come: Inoltre, il fatto che una copia è disponibile prima di un blocco p se è disponibile dopo ogni predecessore di p ci dice che l’ analisi è forward (predecessori) e definite (intersezione) (l’informazione si propaga per intersezione). Logicamente, ogni variabile è copia di se stessa , quindi togliamo x e y dove x != y. Esempio - Approccio algoritmico Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 61 di 90 Abstract edge effect Definiamo la semantica astratta nel caso dell’analisi di copy propagation per ogni etichetta del CFG: Ricordando che Computazione Analogamente alle espressioni available, fissiamo l'insieme X che è l'insieme di tutte le copie in entrata poiché è un'analisi in avanti: da u a v. È definito. Il sistema di disequazioni risultante è: Esempio - Approccio semantico Imprecisione dell'analisi Tutti i percorsi CFG sono considerati percorsi di esecuzione effettivi. L'insieme di copie cancellate da VarKill[n] è un'approssimazione . Ad esempio, considera l'assegnazione come x:=x o che non modifica il valore della variabile. Anno Accademico 2022/2023 Pag. 62 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Reaching Definitions Dato un program point n vogliamo identificare le definizioni di variabili (assegnamenti) che raggiungono n senza ridefinizioni intermedie . Tale proprietà può essere formalizzata come: dove (x, p) significa che x è definita al punto di programma p . Inoltre, useremo il simbolo speciale ? per dire che una variabile non è stata definita. Ottimizzazione code motion L’analisi di reaching definitions viene usata in code motion . In particolare so che se faccio un assegnamento dentro un ciclo senza però modificare le sue variabili all’interno del ciclo , allora posso spostarlo direttamente all’entrata del ciclo (invariante). Approccio Algoritmico - Equazioni L’analisi è Forward Possible ed è specificata dalle seguenti equazioni: Manipolandole possiamo ottenere la seguente equazione di punto fisso : Si può notare come l’informazione iniziale sia che all’entry nessuna variabile è stata definita . L’analisi è quindi forward e possible (l’informazione si propaga per unione). Approccio Semantico - Abstract Edge Effect Definiamo la semantica astratta nel caso dell’analisi di reaching definitions per ogni etichetta del CFG : Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 65 di 90 INTERPRETAZIONE ASTRATTA Analisi statica tramite AI Verifica : definire e dimostrare automaticamente una proprietà dei possibili comportamenti di un programma informatico complesso Astrazione : il ragionamento/calcolo può essere fatto su un'astrazione di questi comportamenti trattando quegli elementi dei comportamenti relativi alla proprietà considerata Teoria : Interpretazione astratta L’idea (esempio del fiore) Un oggetto può essere rappresentato come una coppia formata da un’origine e un insieme finito di pixel neri (su sfondo bianco). Sovra-approssimazione La sovra-approssimazione di un oggetto è un oggetto avente la stessa origine ma un insieme di pixel più ampio. Ad esempio, un fiore lo posso descrivere come un poligono (aggiungo del rumore). Possiamo però notare che c'è una relazione d’ordine tra il fiore e il poligono, ovvero che il mondo astratto (poligono) ha meno dettagli ma contiene l’oggetto concreto (fiore). Oggetti e domini astratti Un oggetto astratto è una rappresentazione matematica dell’approssimazione di un oggetto concreto (il concreto è contenuto nell’astratto). Un dominio astratto, invece, è l'insieme degli oggetti astratti e delle funzioni astratte che rappresentano le operazioni concrete. Elementi di astrazione Dominio astratto Un dominio astratto è un insieme di oggetti astratti più operazioni astratte (approssimando quelle concrete) Astrazione Una funzione di astrazione α associa ogni oggetto concreto o a un'approssimazione rappresentata da un oggetto astratto α (o). Confronto tra astrazioni Perdere più informazioni : più astratto (diametro della penna più grande). Diverse forme di astrazione: non confrontabili (diverse forme di penna) Funzioni di astrazione e concretizzazione L’astrazione avviene per mezzo di una funzione α che mappa ogni oggetto concreto o nella sua rappresentazione astratta α(o). La concretizzazione , invece, avviene per mezzo di una funzione γ che mappa ogni oggetto astratto o ̄ nell’oggetto concreto γ(o ̄) che rappresenta. Anno Accademico 2022/2023 Pag. 66 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Connessioni di Galois (pronunciato “Galuà”) Le funzioni α e γ sono monotone (preservano l’ordine) , ovvero se due oggetti concreti (o astratti) sono in relazione tra loro allora lo devono essere anche nella rispettiva rappresentazione astratta (o concreta). Ordinamento e operazioni nel mondo astratto Un oggetto astratto è più piccolo (⊑) di un altro oggetto astratto se ha meno errore . La rappresentazione astratta sar`a quindi più precisa e contenuta (⊆) in quella meno precisa. Con l’aggiunta di questo ordinamento posso trasferire le operazioni nel mondo astratto. LEZIONE 13 | 28/11/22 La costruzione formale Connessioni di Galois Per garantire l’esistenza della migliore approssimazione , occorre descrivere matematicamente la relazione tra il mondo concreto e quello astratto . Abbiamo già visto che esistono due funzioni α e γ , dette funzioni di astrazione e concretizzazione, che garantiscono l’esistenza della migliore approssimazione (sugli insiemi ordinati A e C). Possiamo dire che esse formano una connessione di Galois se : ● α e γ stesse sono monotone . ● ∀ 𝑎 ∈ 𝐴 , 𝑐 ∈ 𝐶 . α ( 𝑐 ) ≤ 𝐴 𝑎 ⟺ 𝑐 ≤ 𝐶 γ ( 𝑎 ) Una connessione di Galois (GC) si scrive come: dove la funzione α è detta aggiunta sinistra , mentre la funzione γ è detta aggiunta destra . Inoltre, la connessione di Galois tra due domini è univoca (se due oggetti hanno la stessa α allora hanno anche la stessa γ e viceversa) e quindi le funzioni α e γ sono identificabili attraverso: Ogni elemento astratto ha uno specifico significato concreto da osservare Esempio Supponiamo di avere due insiemi A e B in relazione tra loro mediante . Indichiamo con A′ 𝑅 ⊆ 𝐴 × 𝐵 l’approssimazione di A, cioè l’astrazione che contiene tutti gli elementi di B che sono in relazione con tutti gli elementi di A′. Analogamente, indichiamo con B′ l’approssimazione di B, cioè l’astrazione che contiene tutti gli elementi di A che sono in relazione con tutti gli elementi di B′. Nella figura sottostante viene mostrata una rappresentazione grafica in cui si utilizzano gli insiemi A = {1, 3, 5} e B = {2, 4, 6} e come relazione l’essere minore di. Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 67 di 90 Inserzioni di Galois Una connessione di Galois in cui vale che (identità) si dice inserzione di Galois . In questo αγ ( 𝑎 ) = 𝑎 caso l’astrazione è suriettiva per cui ho che più elementi vanno nello stesso valore concreto; e inoltre, la concretizzazione è iniettiva perchè un valore concreto è anche la sua concretizzazione. Una inserzione di Galois (GI) si scrive come: Se nella concretizzazione di un valore astratto ho un solo valore concreto rappresentato, posso rimuovere i valori astratti ridondanti (per la suriettività) e unirli insieme in gruppi creando le inserzioni di Galois . Operatori di chiusura superiore (uco) Rappresentano un’ulteriore modalità di rappresentazione astratta. Una funzione è un upper ρ : 𝐶 → 𝐶 closure operator (uco) se soddisfa le seguenti proprietà: ● Estensività , (rho va sempre verso qualcosa di meno preciso) ∀ 𝑥 ∈ 𝐶 . ρ ( 𝑥 ) ≥ 𝑥 ● Monotonia , ∀ 𝑥 , 𝑦 ∈ 𝐶 . 𝑥 ≤ 𝑦 ⇒ ρ ( 𝑥 ) ≤ ρ ( 𝑦 ) ● Idempotenza , (rho può perdere informazione, ma sempre in botta unica) ∀ 𝑥 ∈ 𝐶 . ρρ ( 𝑥 ) = ρ ( 𝑥 ) Nelle connessioni di Galois (o nelle inserzioni di Galois) γα è un uco. Esempio Le GI associano ad ogni elemento concreto la proprietà astratta rappresentata fuori dal concreto, mentre gli uco associano ad ogni elemento concreto la proprietà astratta come suo significato dentro il concreto . Nella figura sottostante viene mostrato un esempio di uco (a sinistra) ottenuto partendo da una GI (a destra). Anno Accademico 2022/2023 Pag. 70 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Reticolo delle astrazioni Se è un reticolo completo , allora < 𝐶 , ≤ , ∧ , ∨ , ⊥ , ⊤ > < 𝑢𝑐𝑜 ( 𝐶 ), ⊑ , ⊓ , ⊔ , λ 𝑥 . ⊤ , λ 𝑥 . 𝑥 > è un reticolo completo in cui vengono soddisfatte le seguenti proprietà: LEZIONE 14 | 29/11/22 Computazioni astratte e concrete Finora abbiamo visto come costruire i domini astratti, ma il nostro obiettivo è quello di spostare la computazione da un mondo concreto non decidibile ad un mondo astratto decidibile. Correttezza (soundness) Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 71 di 90 In modo equivalente possiamo concretizzare la correttezza confrontando i risultati nel mondo concreto. E’ la Best Correct Approximation (BCA) Soundness sulla chiusura Vedere i due insiemi come Input e Output. Completezza (precision) La completezza codifica una situazione ideale in cui non si verifica alcuna perdita di precisione nel calcolo astratto La backward completeness considera le astrazioni sull'output delle operazioni La forward completeness considera le astrazioni sull'input alle operazioni Anno Accademico 2022/2023 Pag. 72 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Completeness sulla chiusura Osservare la proprietà del calcolo astratto non genera imprecisione . Forward vs Backward I due tipi di completezza rappresentano una situazione ideale in cui non si verifica alcuna perdita di precisione durante l’astrazione. In particolare: ● La Backward-completezza considera l’astrazione sull’output delle operazioni (non si accumula alcuna perdita di precisione astraendo in ρ gli argomenti di f). ● La Forward-completezza considera l’astrazione sull’input delle operazioni (non si accumula alcuna perdita di precisione approssimando il risultato della funzione f calcolata in ρ). Esempio su intervalli di interi Consideriamo un dominio composto da certi intervalli di interi (con distinzione tra positivi e negativi). I pallini rossi sono gli intervalli che formano la rappresentazione astratta degli intervalli concreti. La funzione f che dovremo calcolare è il quadrato. La proprietà astratta sarà quindi rappresentata da tutti i valori positivi, poiché i valori negativi al quadrato confluiscono in quelli positivi. Il primo insieme di pallini rossi considerato {Z, [0, +∞], [0, 10]} è Forward ma non Backward completo, in particolare: ● forward-complete perché per ogni elemento vale che f ◦ ρ = ρ ◦ f ◦ ρ, ovvero se seguo f in avanti cado sempre dentro l’insieme. Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 75 di 90 Questa analisi può quindi essere utile per l’ottimizzazione del codice. ● Ad esempio, nella figura sottostante, il fatto che la variabile x sia costante a 7 rende sempre vero il test al punto 2, per cui si potrebbe eliminare direttamente tale test. Inoltre, questa analisi è un caso speciale di valutazione parziale dei programmi . Infatti, per ogni punto di programma v si calcolano le seguenti informazioni: ● Quale valore ha una variabile quando il controllo raggiunge V? ● Il punto V è potenzialmente raggiungibile? Esempio Siccome siamo nell’analisi delle costanti, dobbiamo verificare che i valori delle variabili rimangano sempre gli stessi. Quindi, se una variabile non è costante, metteremo un ? in quanto a priori non possiamo sapere se nel futuro essa sarà costante o meno. Dopo aver raggiunto il punto fisso alla terza iterazione, facciamo alcune considerazioni. Le uniche variabili che mutano il loro valore sono d (continua a crescere) ed e (continua a decrescere). Ad esempio, dall'iterazione 2 passa da valore 4 a valore 5 e quindi le abbiamo messo valore ?. Abbiamo poi una perdita di precisione sulla variabile c perch ́e e+d =?+? non so cosa fa, anche se in realtà so che c è costante perchè d cresce sempre di 1 ed e decresce sempre di 1. Costruzione dell’analisi Dobbiamo innanzitutto costruire un reticolo fatto da tutti i singoletti uniti a ⊤. Il dominio astratto sarà quindi fatto dall’insieme di tutti i numeri interi unito ⊤. Dobbiamo poi astrarre il dominio delle memorie (da cui si estraggono i valori delle variabili). Aggiungiamo quindi il ⊥ per modellare le espressioni non raggiungibili. D(x) sarà un singoletto se il valore di x è costante nel punto di programma considerato, oppure sarà ⊤ nel caso in cui non si sa se è costante. Anno Accademico 2022/2023 Pag. 76 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Dominio astratto Il dominio astratto deve essere una famiglia di Moore , ovvero devono esistere ⊥, ⊤ e i singoletti dei valori che mi identificano un valore costante (non confrontabili gli uni con gli altri). Nel dominio astratto rappresentato nella figura sottostante, α(0, 1) = ⊤ perchè abbiamo una variabile non costante, mentre α(5) = 5 perché la variabile è costante. L'ordine su questo insieme di stati astratti D è LBU (Least Upper Bound) : Abstract edge effect (Semantica astratta) Andiamo ora a definire la semantica astratta per ogni arco k = (u, lab, v), dove lab sono i comandi del CFG che simula il programma. Un arco è ⊥ se l'espressione non è raggiungibile. Mentre se una variabile definita nel dominio D è raggiungibile, c'è bisogno di una funzione di valutazione astratta per calcolare il suo valore. Tale funzione dovrà gestire il caso in cui il valore di un’espressione non può essere determinato in D e quindi viene valutato a ⊤. Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 77 di 90 Per garantire questo dobbiamo rimpiazzare gli operatori concreti op con una loro versione astratta op# così definita: La semantica astratta delle espressioni sarà quindi la seguente: La semantica astratta dei comandi, invece, è la seguente: Esempio Anno Accademico 2022/2023 Pag. 80 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche L'unione non riempie i buchi. L’intersezione invece non ha buchi. Astrarre gli stati concreti Un insieme di interi è approssimato dal più piccolo intervallo [l, u] che lo contiene . La corrispondente concretizzazione, però, sarà per cui viene persa l’informazione precisa di quali erano gli { 𝑛 | 𝑙 ≤ 𝑛 ≤ 𝑢 } interi dell’insieme originale. Dove MIN e MAX sono: Infine, nelle figure sottostanti si mostra in che modo le operazioni aritmetiche e booleane possono essere fatte sugli intervalli . Soluzione MOP La soluzione MOP per l'analisi dell'intervallo in un punto v del programma è il limite minimo superiore di tutte le informazioni fornite da tutti i percorsi dal punto di ingresso a v per l'associazione iniziale D⊤ , tale che D⊤(x)=⊤: Risolvere il sistema di disuguaglianze associato porta a un approssimazione della soluzione MOP. Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 81 di 90 Abstract edge effect La semantica astratta per l’analisi degli intervalli è simile a quella già definita per l’ analisi di constant propagation : Computazione MFP Analogamente alla propagazione costante, fissiamo la memoria astratta D che è lo stato che associa a ciascuna variabile il suo valore astratto. Il sistema di disequazioni risultante è Il reticolo completo per le soluzioni è infinito e non ACC L'abstract edge effect è monotono ● Possiamo usare l'iterazione round-robin per la soluzione minima L'abstract edge effect non è distributivo ● La soluzione minima approssima la soluzione MOP Rafforzare l’analisi Anche nel caso degli intervalli possiamo migliorare la semantica, e quindi l’analisi propagando l'informazione data dalle guardie . Infatti, se seguiamo il ramo falso sappiamo che la guardia è falsa mentre se seguiamo il ramo vero sappiamo che la guardia è vera e quindi possiamo intersecare questa informazione con quella collezionata fino al punto di branch. Per rendere effettivo questo rafforzamento, la semantica astratta va aggiornata con: Anno Accademico 2022/2023 Pag. 82 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Dove Esempio Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 85 di 90 Progressione di un fallimento Un mistake del programmatore causa un difetto nel codice (fault) che potrebbe causare un fallimento . Il testing vuole quindi cercare i difetti nel codice con l’obiettivo di metterli in evidenza per fare in modo che possano essere corretti dagli sviluppatori. L’obiettivo ultimo del testing è comunque quello di migliorare la qualità generale del codice. Infatti, tramite l’errore, il testing misura quanto l’esecuzione del codice si allontana dal suo comportamento atteso. I test possono rivelare fallimenti, ma sono i difetti che devono essere trovati e rimossi; trovare un guasto (la causa di un guasto) può richiedere molto tempo ed essere imprevedibile. L'errore è la misura di quanto siano errati i risultati. Quindi, gli scopi del test sono ● Causare guasti al fine di rendere visibili i guasti in modo che i guasti possano essere riparati e non essere consegnati nel codice che va ai clienti ● Valutare il livello qualitativo complessivo del codice. Aspetti teorici In generale possiamo dire che un programma P è una funzione che va da un insieme di dati in input D ad un insieme di dati in output R. ● Se P(d) rispetta le specifiche (nessun fallimento) allora è sound (ok(P, d)) , altrimenti non lo è. ● Un programma è sound (ok(P )) se per ogni input non va in errore , ovvero: . ∀ 𝑑 ∈ 𝐷 . 𝑜𝑘 ( 𝑃 , 𝑑 ) Un test T per P è un sottoinsieme di 𝐷 , 𝑇 ⊆ 𝐷 Diciamo poi che un programma è sound sul test se supera la correttezza per ogni dato 𝑇 ⊆ 𝐷 ( 𝑜𝑘 ( 𝑃 , 𝑇 )) di test t: . ∀ 𝑡 ∈ 𝑇 . 𝑜𝑘 ( 𝑃 , 𝑡 ) L’obiettivo del testing è quindi quello di trovare un T tale per cui . ¬ 𝑜𝑘 ( 𝑃 , 𝑇 ) ● Un test T è di successo (success(T,P)) se trova uno o più fallimenti su P . ( ¬ 𝑜𝑘 ( 𝑃 , 𝑇 )) ● Un test T è detto ideale (ideal) se il suo fallimento implica la correttezza del programma P: . 𝑜𝑘 ( 𝑃 , 𝑇 ) ⇒ 𝑜𝑘 ( 𝑃 ) Infine, il testing deve poter selezionare i predicati su cui procedere con il test stesso. Quindi, un criterio di selezione di test C per P sarà un insieme di predicati su D. Un test T è selezionato da C (selected(C,T)) se . tale per cui c(t) è vero e . ∀ 𝑡 ∈ 𝑇 . ∃ 𝑐 ∈ 𝐶 ∀ 𝑐 ∈ 𝐶 . ∃ 𝑡 ∈ 𝑇 tale per cui c(t) è vero. Un criterio di selezione C è affidabile per P (reliable(P,C)) se tutti i test selezionati da C producono o tutti successi o tutti fallimenti, ovvero: . 𝑠𝑢𝑐𝑐𝑒𝑠𝑠 ( 𝑇 1 , 𝑃 ) ⇔ 𝑠𝑢𝑐𝑐𝑒𝑠𝑠 ( 𝑇 2 , 𝑃 ) ● Non è necessario che tutti i test rilevino lo stesso guasto Un criterio di selezione C è valido per P (valid(C, P )) se trova almeno un test T in cui il programma P fallisce, ovvero: se allora tale per cui . ∃ 𝑑 ∈ 𝑑 . ¬ 𝑜𝑘 ( 𝑃 , 𝑑 ) ∃ 𝑇 . 𝑠𝑒𝑙𝑒𝑐𝑡𝑒𝑑 ( 𝐶 , 𝑇 ) ¬ 𝑜𝑘 ( 𝑃 , 𝑇 ) Anno Accademico 2022/2023 Pag. 86 di 90 | Corso di Laurea Magistrale in Ingegneria e Scienze Informatiche Esempio Teoremi Teorema di Goodenough & Gerhart : se si intersecano i test affidabili con quelli validi, si ottengono quelli di fallimento per P; se poi si interseca il tutto con i test selezionati per quei casi in cui P non fallisce, allora si ottiene che il programma P è sempre corretto. In altre parole, ogni test selezionato da un criterio affidabile e valido è ideale. 𝑟𝑒𝑙𝑖𝑎𝑏𝑙𝑒 ( 𝐶 , 𝑃 ) ∧ 𝑣𝑎𝑙𝑖𝑑 ( 𝐶 , 𝑃 ) ∧ 𝑠𝑒𝑙𝑒𝑐𝑡𝑒𝑑 ( 𝐶 , 𝑇 ) ∧¬ 𝑠𝑢𝑐𝑐𝑒𝑠𝑠 ( 𝑇 , 𝑃 ) ⇒ 𝑜𝑘 ( 𝑃 ) L' affidabilità garantisce gli stessi risultati per tutti i test selezionato da C La validità garantisce che, se il programma non è corretto, almeno un test selezionato rileverà l'errore Il fallimento di un test selezionato da C permette quindi di dedurre il fallimento di qualsiasi test su P+ Teorema di Howden : non esiste un algoritmo che dato P genera un test finito ideale , ovvero un test selezionato da C, affidabile e valido. Se P è corretto solo su d ∈ D, un criterio C affidabile e ideale deve generare esattamente d. Questo teorema non dice quindi che C non esiste, bensì che C può esistere ma non esiste un modo per calcolarlo . Tesi di Dijkstra : il testing può provare la presenza di difetti nel programma ma non la loro assenza. In altre parole, il testing può dimostrare che un programma non è corretto, ma non può dimostrare che lo è. Teorema di Weyuker : dato un programma P, i problemi seguenti sono indecidibili. ● Esiste un input che fa eseguire un certo comando? ● Esiste un input che fa eseguire un certo branch? ● Esiste un input che fa eseguire un certo cammino? Processo di testing L’esecuzione dei casi di test è solo una piccola parte del processo di testing . La parte difficile è la generazione dei casi di test, i quali devono essere pensati a seconda di quello che fa il programma . Occorre quindi pianificare il processo di testing per trovare forme di misura che aiutino a capire quando fermare il test. Generazione dei casi di test Problema di generazione del caso di test : come generare i dati di test Test delle partizioni: dividere i programmi in classi di (quasi)equivalenza Ferrari Simone Fondamenti di Analisi e Verifica del Software | Pag. 87 di 90 Per generare dati di test esistono diversi approcci , tra cui : ˆ ● Random . ● Analisi funzionale (black box), basata sulle specifiche. ˆ ● Analisi strutturale (white box), basata sul codice. ● Grey box , basato su informazioni parziali. ● Fault - based , basato sulle classi dei difetti. Approccio code-based Nell’analisi statica abbiamo guardato alla semantica analizzando la sintassi. Nel testing possiamo decidere il grado di esaustività del test guardando al codice. Per generare i casi di test basandosi sul codice si può ricorrere alla coverage del codice su CFG , ovvero ad una metrica che misura la completezza del testing . Per misurare la coverage , si parte sempre dalla seguente domanda: quali parti devono essere ancora testate nel codice? Infatti, se una parte del CFG non viene mai testata, non si scopriranno mai gli errori. Con parte del CFG si intendono : comandi (blocchi), branch (archi), condizioni e cammini. Coverage testing Il coverage testing viene effettuato sulle varie componenti del CFG . Si avranno quindi i seguenti criteri di coverage: 1. Statement coverage . 2. Branch coverage . 3. Condition coverage . 4. Path coverage . L'esecuzione di tutti gli elementi del flusso di controllo non garantisce l'individuazione di tutti i guasti (ma integra i test funzionali) ● L'esecuzione di un'istruzione errata potrebbe non sempre risultare in un errore ○ Lo stato potrebbe non essere danneggiato quando l'istruzione viene eseguita con alcuni valori di dati ○ Lo stato corrotto potrebbe non propagarsi attraverso l'esecuzione per portare infine al fallimento Qual è il valore della coverage strutturale? ● Aumenta la fiducia nella completezza dei test ○ Rimuove alcune evidenti inadeguatezze Codice d’esempio Anno Accademico 2022/2023
Docsity logo


Copyright © 2024 Ladybird Srl - Via Leonardo da Vinci 16, 10126, Torino, Italy - VAT 10816460017 - All rights reserved