Investigating the application of differential fuzzing to support the identification and suppression of equivalent mutants: An experimental study
Questo studio sperimentale dimostra che il fuzzing differenziale è un approccio pratico e indipendente dal linguaggio per identificare ed eliminare efficientemente i mutanti equivalenti in diversi progetti software reali, ottenendo punteggi di mutazione quasi perfetti e generando input azionabili per rafforzare le suite di test tradizionali.
Articolo originale sotto licenza CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/). Questa è una spiegazione generata dall'IA dell'articolo qui sotto. Non è stata scritta né approvata dagli autori. Per precisione tecnica, consulta l'articolo originale. Leggi il disclaimer completo
Il testing del software è il processo di verifica se un programma per computer funziona correttamente, ma trovare ogni possibile errore è quasi impossibile perché i programmi sono complessi e gli input sono infiniti. Per affrontare questo problema, i ricercatori utilizzano una tecnica chiamata mutation testing, che consiste nell'introdurre intenzionalmente piccoli errori realistici nel codice per vedere se i test esistenti riescono a rilevarli. Se un test non riesce a individuare l'errore, significa che la suite di test non è abbastanza robusta. Tuttavia, questo metodo deve affrontare un ostacolo ostinato: alcuni di questi errori finti sono così sottili da non cambiare affatto il comportamento del programma, rendendoli impossibili da rilevare. Questi sono noti come mutanti equivalenti, e identificarli richiede solitamente un esperto umano che debba passare un tempo significativo a leggere il codice riga per riga, un processo lento e costoso che ha a lungo frenato l'uso diffuso di questo metodo di testing.
Allo stesso tempo, un altro metodo di testing chiamato fuzzing è diventato uno strumento standard per trovare falle di sicurezza. Il fuzzing funziona alimentando un programma con enormi quantità di dati casuali o malformati per vedere se causa un crash. Sebbene sia efficace nel trovare bug che causano l'arresto di un programma, il fuzzing tradizionale spesso perde il tipo di errori sottili che cambiano il modo in cui un programma calcola o si comporta senza causare un crash. Uno studio recente condotto da ricercatori dell'Università di San Paolo esplora un modo per combinare questi due mondi. Hanno investigato una tecnica chiamata differential fuzzing, che esegue il programma originale e una versione con un piccolo errore fianco a fianco, fornendo loro esattamente gli stessi dati e confrontando i risultati. Se le due versioni producono output differenti, l'errore viene rilevato. I ricercatori volevano vedere se questo approccio potesse identificare automaticamente quei mutanti equivalenti così elusivi e farlo molto più velocemente di quanto possa fare un essere umano.
Per testare questa idea, il team ha selezionato sei funzioni specifiche da quattro diversi e bennoti progetti di software open-source scritti in quattro diversi linguaggi di programmazione: C++, C, Go e Python. Questi progetti includevano Bitcoin Core, un protocollo per criptovalute; OpenSSL, una libreria crittografica; LND, una rete di canali di pagamento; e Arrow, una libreria per date e orari. Utilizzando uno strumento in grado di generare errori per qualsiasi linguaggio di programmazione, hanno creato 1.090 variazioni valide di queste funzioni. Prima che il testing automatizzato iniziasse, i ricercatori hanno ispezionato manualmente gli errori per rimuovere quelli che erano ovviamente equivalenti, lasciando un insieme di casi impegnativi per vedere se il sistema automatizzato potesse distinguere il resto. Hanno poi eseguito cinque diversi scenari di test su questi errori, che spaziavano dai classici unit test a sessioni di fuzzing con limite temporale di cinque minuti per errore.
I risultati hanno mostrato che il fuzzing tradizionale, che cerca solo crash, era il metodo meno efficace, rilevando pochissimi errori. Al contrario, l'approccio del differential fuzzing si è dimostrato straordinariamente potente. Quando gli è stato dato un limite di tempo di cinque minuti per testare ogni errore, questo metodo ha identificato e confermato il comportamento degli errori in cinque delle sei funzioni, raggiungendo un tasso di successo compreso tra il 98 e il 100 percento. Per l'unica funzione in cui inizialmente ha avuto difficoltà, i ricercatori hanno scoperto che l'aggiunta di una semplice lista di parole chiave attese ha aiutato il sistema a comprendere meglio l'input, permettendogli infine di raggiungere un punteggio perfetto. Lo studio ha anche rivelato che il tempo necessario per trovare questi errori era sorprendentemente breve; in media, il sistema trovava le differenze in circa 30 secondi, molto più velocemente dei 15 minuti che un essere umano impiega tipicamente per analizzare manualmente un singolo caso.
Oltre a trovare gli errori, i ricercatori hanno scoperto che i dati utilizzati durante il processo di fuzzing contenevano un valore nascosto. La collezione di input generati dallo strumento di fuzzing, nota come seed corpus, conteneva casi di test specifici che gli standard unit test avevano mancato. Questi input sono stati in grado di eliminare mutanti che le suite di test tradizionali non riuscivano a rilevare. Ciò suggerisce che i dati già generati dai team di sicurezza possono essere riutilizzati per rafforzare le suite di test regolari, trasformando un sottoprodotto del testing di sicurezza in una risorsa per la qualità del software in generale. Lo studio ha anche analizzato quanto tempo fosse necessario per trovare gli errori più difficili da rilevare, scoprendo che, sebbene la maggior parte venisse trovata rapidamente, alcuni richiedevano significativamente più tempo e mostravano un pattern in cui la difficoltà variava enormemente, proprio come accade quando alcuni compiti richiedono un po' più di tempo mentre altri ne richiedono moltissimo.
I ricercatori hanno concluso che il differential fuzzing offre un modo pratico e indipendente dal linguaggio per supportare la classificazione di questi errori difficili. Non richiede nuovi strumenti complessi o configurazioni specifiche per il linguaggio, poiché confronta semplicemente il codice originale con la versione modificata. Trattando gli errori sopravvissuti come candidati per la revisione manuale invece di cercare di classificare ogni singolo errore, il metodo riduce drasticamente lo sforzo umano necessario. Lo studio suggerisce che questo approccio può essere integrato nei flussi di lavoro esistenti per filtrare efficientemente gli errori che sono realmente equivalenti, lasciando agli esperti umani solo il piccolo numero di casi che rimangono incerti. Questa scoperta indica che un semplice confronto automatizzato dei comportamenti del programma può risolvere un problema che è stato a lungo considerato troppo costoso e dispendioso in termini di tempo per un'adozione industriale diffusa.
Sommerso dagli articoli nel tuo campo?
Ricevi digest giornalieri degli articoli più recenti corrispondenti alle tue parole chiave di ricerca — con riassunti tecnici, nella tua lingua.