Fuzzing automatically generates and runs large numbers of inputs to trigger errors in programs under test. Testing a software library this way requires a harness: a small program that encodes a library usage pattern and feeds the fuzzer's inputs into the library. Because different harnesses exercise different functionalities and reach different library states, effective testing depends on generating many of them, and state-of-the-art tools do so automatically. This continuous production of harnesses comes at a cost: each one must be compiled. Compilation diverts computational resources away from input generation, and the generated code can reach hundreds of gigabytes on disk. In this thesis we remove compilation from this loop. We present CIRO (C++ IR for Objects), an intermediate representation paired with a virtual machine, designed specifically to execute automatically generated C and C++ harnesses without recompiling them. Instead of compiling each new harness to native code, CIRO interprets it directly, turning a recurring per-harness compilation cost into a one-time investment. CIRO supports a subset of C and C++, can be easily integrated with existing harness generation tools, and has been evaluated on well-known libraries including LibTIFF, OpenCV, c-ares, and cJSON. In our experiments, we find that CIRO achieves execution speeds comparable to those of native harnesses: on targets that spend most of each execution inside the library, interpreted harnesses match or even exceed native throughput, and even in the worst case observed, they retain more than 40% of it. At the same time, CIRO reduces per-harness disk usage by five to six orders of magnitude: each native harness used for testing occupied between roughly 320 and 390 MB of disk space, while the corresponding CIRO harness occupied between a few hundred bytes and a couple of kilobytes. Note that CIRO harnesses also require an interpreter executable, comparable in size to a single native harness, but this is built once per library and its cost is amortized over many harnesses.

Il fuzzing genera ed esegue automaticamente grandi quantità di input con l'obiettivo di provocare errori nei programmi in fase di test. Testare una libreria software in questo modo richiede un harness: un piccolo programma che codifica un pattern di utilizzo della libreria e le inoltra gli input prodotti dal fuzzer. Poiché harness diversi esercitano funzionalità diverse e raggiungono stati diversi della libreria, un testing efficace dipende dalla generazione di molti harness, e gli strumenti allo stato dell'arte li producono automaticamente. Questa produzione continua di harness ha però un costo: ognuno di essi deve essere compilato. La compilazione sottrae risorse computazionali alla generazione degli input, e il codice generato può raggiungere centinaia di gigabyte su disco. In questa tesi eliminiamo la compilazione da questo ciclo. Presentiamo CIRO (C++ IR for Objects), una rappresentazione intermedia affiancata da una macchina virtuale, progettata specificamente per eseguire harness C e C++ generati automaticamente senza doverli ricompilare. Invece di compilare ogni nuovo harness in codice nativo, CIRO lo interpreta direttamente, trasformando un costo di compilazione ricorrente per ogni harness in un investimento una tantum. CIRO supporta un sottoinsieme del C e del C++, può essere integrato facilmente con gli strumenti esistenti per la generazione di harness ed è stato valutato su librerie note quali LibTIFF, OpenCV, c-ares e cJSON. Nei nostri esperimenti osserviamo che CIRO raggiunge velocità di esecuzione paragonabili a quelle degli harness nativi: sui target che trascorrono la maggior parte di ogni esecuzione all'interno della libreria, gli harness interpretati eguagliano o addirittura superano il throughput nativo e, anche nel caso peggiore osservato, ne conservano oltre il 40%. Allo stesso tempo, CIRO riduce l'occupazione su disco per harness di cinque o sei ordini di grandezza: ogni harness nativo usato per i test occupava tra circa 320 e 390 MB di spazio su disco, mentre il corrispondente harness CIRO occupava tra poche centinaia di byte e un paio di kilobyte. Si noti che gli harness CIRO richiedono anche un eseguibile interprete, di dimensioni paragonabili a quelle di un singolo harness nativo, ma questo viene compilato una sola volta per libreria e il suo costo si ammortizza su molti harness.

CIRO: Sviluppo di un'interprete a supporto del fuzzing di librerie C++

ZANELLATO, AUGUSTO CESARE
2025/2026

Abstract

Fuzzing automatically generates and runs large numbers of inputs to trigger errors in programs under test. Testing a software library this way requires a harness: a small program that encodes a library usage pattern and feeds the fuzzer's inputs into the library. Because different harnesses exercise different functionalities and reach different library states, effective testing depends on generating many of them, and state-of-the-art tools do so automatically. This continuous production of harnesses comes at a cost: each one must be compiled. Compilation diverts computational resources away from input generation, and the generated code can reach hundreds of gigabytes on disk. In this thesis we remove compilation from this loop. We present CIRO (C++ IR for Objects), an intermediate representation paired with a virtual machine, designed specifically to execute automatically generated C and C++ harnesses without recompiling them. Instead of compiling each new harness to native code, CIRO interprets it directly, turning a recurring per-harness compilation cost into a one-time investment. CIRO supports a subset of C and C++, can be easily integrated with existing harness generation tools, and has been evaluated on well-known libraries including LibTIFF, OpenCV, c-ares, and cJSON. In our experiments, we find that CIRO achieves execution speeds comparable to those of native harnesses: on targets that spend most of each execution inside the library, interpreted harnesses match or even exceed native throughput, and even in the worst case observed, they retain more than 40% of it. At the same time, CIRO reduces per-harness disk usage by five to six orders of magnitude: each native harness used for testing occupied between roughly 320 and 390 MB of disk space, while the corresponding CIRO harness occupied between a few hundred bytes and a couple of kilobytes. Note that CIRO harnesses also require an interpreter executable, comparable in size to a single native harness, but this is built once per library and its cost is amortized over many harnesses.
2025
CIRO: Development of an interpreter aiding C++ libraries fuzzing
Il fuzzing genera ed esegue automaticamente grandi quantità di input con l'obiettivo di provocare errori nei programmi in fase di test. Testare una libreria software in questo modo richiede un harness: un piccolo programma che codifica un pattern di utilizzo della libreria e le inoltra gli input prodotti dal fuzzer. Poiché harness diversi esercitano funzionalità diverse e raggiungono stati diversi della libreria, un testing efficace dipende dalla generazione di molti harness, e gli strumenti allo stato dell'arte li producono automaticamente. Questa produzione continua di harness ha però un costo: ognuno di essi deve essere compilato. La compilazione sottrae risorse computazionali alla generazione degli input, e il codice generato può raggiungere centinaia di gigabyte su disco. In questa tesi eliminiamo la compilazione da questo ciclo. Presentiamo CIRO (C++ IR for Objects), una rappresentazione intermedia affiancata da una macchina virtuale, progettata specificamente per eseguire harness C e C++ generati automaticamente senza doverli ricompilare. Invece di compilare ogni nuovo harness in codice nativo, CIRO lo interpreta direttamente, trasformando un costo di compilazione ricorrente per ogni harness in un investimento una tantum. CIRO supporta un sottoinsieme del C e del C++, può essere integrato facilmente con gli strumenti esistenti per la generazione di harness ed è stato valutato su librerie note quali LibTIFF, OpenCV, c-ares e cJSON. Nei nostri esperimenti osserviamo che CIRO raggiunge velocità di esecuzione paragonabili a quelle degli harness nativi: sui target che trascorrono la maggior parte di ogni esecuzione all'interno della libreria, gli harness interpretati eguagliano o addirittura superano il throughput nativo e, anche nel caso peggiore osservato, ne conservano oltre il 40%. Allo stesso tempo, CIRO riduce l'occupazione su disco per harness di cinque o sei ordini di grandezza: ogni harness nativo usato per i test occupava tra circa 320 e 390 MB di spazio su disco, mentre il corrispondente harness CIRO occupava tra poche centinaia di byte e un paio di kilobyte. Si noti che gli harness CIRO richiedono anche un eseguibile interprete, di dimensioni paragonabili a quelle di un singolo harness nativo, ma questo viene compilato una sola volta per libreria e il suo costo si ammortizza su molti harness.
fuzzing
c++
interpreter
File in questo prodotto:
File Dimensione Formato  
thesis.pdf

accesso aperto

Dimensione 639.36 kB
Formato Adobe PDF
639.36 kB Adobe PDF Visualizza/Apri

The text of this website © Università degli studi di Padova. Full Text are published under a non-exclusive license. Metadata are under a CC0 License

Utilizza questo identificativo per citare o creare un link a questo documento: https://hdl.handle.net/20.500.12608/110970