Benchmarks for ERTS 2026: Fuzz Testing in Memory-Safe Verification Environments
This directory contains a suite of benchmark tests designed to evaluate the effectiveness of fuzz testing in detecting memory safety vulnerabilities when starting from Ada entry points. These benchmarks are part of a study presented at the 2026 Embedded Real Time Systems Conference.
Overview
Each benchmark consists of an Ada subprogram that serves as a fuzzing entry point, which then calls into C code containing deliberate memory safety vulnerabilities. The goal is to determine whether a fuzzer can discover the specific input values that trigger these vulnerabilities by fuzzing the Ada interface.
Test Classification
The benchmarks are organized according to the following vulnerability categories:
| Bug Type | Number of Test Variants | Description |
|---|---|---|
| Stack buffer overflow | 3 | A stack buffer overflow occurs when a program writes more data than a stack-allocated buffer can hold. |
| Heap buffer overflow | 2 | A heap buffer overflow happens when writes extend past the bounds of a dynamically allocated buffer. |
| Double free | 2 | Occurs when a program calls free() (or equivalent) more than once on the same memory pointer. |
| Use after free | 2 | Occurs when a program continues to use or reference memory after it has been freed/deallocated. |
| Array in struct | 2 | Occurs when doing an out of bounds access in an array declared within a struct. |
| Out of bounds pointer arithmetics | 1 | Vulnerability where out-of-bounds pointer arithmetic causes a pointer to jump from one buffer into an adjacent buffer illegally. |
| ASan overflow evading | 1 | A specific heap buffer overflow that exploits AddressSanitizer's fundamental architectural limitation by overflowing a buffer such that ASan poisoned redzone memory is avoided. |
Benchmark Test Details
Stack Buffer Overflow (3 variants)
1. simple_bugs.c::simple_stack_overflow()
- Entry Point: Called from Ada via FFI binding
- Goal: Detect stack buffer overflow by fuzzing the
valueparameter - Vulnerability: The function creates three stack-allocated buffers and writes beyond the bounds of the middle buffer both before (negative indexing) and after (positive indexing) its allocated space
- Trigger Condition: When
valueis large enough to cause the loop indices to access memory outside themiddle[STACK_SIZE]array bounds
2. bugs.c::process_user_config()
- Entry Point: Called from Ada via FFI binding
- Goal: Detect complex stack buffer overflow requiring multiple conditions
- Vulnerability: Stack buffer of size 16 can be overflowed via
memcpy()with attacker-controlled length - Trigger Condition: Requires
length > 16ANDlength < 100ANDconfig_idin range [800001, 800999]
3. ada_bugs.adb::Buffer_Overflow_Fuzz()
- Entry Point: Pure Ada subprogram
Ada_Bugs.Buffer_Overflow_Fuzz(Index: Integer) - Goal: Detect buffer overflow using unchecked type conversion
- Vulnerability: A 10-element buffer is unsafely cast to a 50-element buffer pointer using
Ada.Unchecked_Conversion, allowing writes beyond the original buffer bounds - Trigger Condition: When
Index > 10(the original buffer size)
Heap Buffer Overflow (2 variants)
1. simple_bugs.c::simple_heap_buffer_overflow()
- Entry Point: Called from Ada via FFI binding
- Goal: Detect heap buffer overflow (off-by-one error)
- Vulnerability: A heap buffer of size
valueis allocated, but the read loop iterates toi <= valueinstead ofi < value, causing a one-byte read overflow - Trigger Condition: Any non-zero
valuewill trigger the off-by-one read
2. bugs.c::write_cache_entry()
- Entry Point: Called from Ada via FFI binding
- Goal: Detect heap out-of-bounds write with incorrect bounds checking
- Vulnerability: A heap array of 10 elements is allocated, but a second conditional branch allows writes at extremely large offsets without proper bounds checking
- Trigger Condition: Requires
offsetin range [500000, 599999] to reach the vulnerable code path
Double Free (2 variants)
1. bugs.c::cleanup_resource_handle()
- Entry Point: Called from Ada via FFI binding
- Goal: Detect double free caused by overlapping cleanup logic
- Vulnerability: Memory is freed by "Module A" if
cleanup_idis in [100001, 199999], then freed again by "Module B" ifcleanup_idis in [150001, 249999] - Trigger Condition: Requires
cleanup_idin the overlapping range [150001, 199999]
2. ada_bugs.adb::Double_Free_Fuzz()
- Entry Point: Pure Ada subprogram
Ada_Bugs.Double_Free_Fuzz(Free_Count: Integer) - Goal: Detect double free using unchecked deallocation
- Vulnerability: Memory is freed when
Free_Count >= 1, then the same pointer is reconstituted from a saved address and freed again whenFree_Count >= 2 - Trigger Condition: When
Free_Count >= 2
Use After Free (2 variants)
1. bugs.c::handle_session_data()
- Entry Point: Called from Ada via FFI binding
- Goal: Detect use-after-free requiring specific input range
- Vulnerability: Memory is freed when
action_codeis in [1000000, 1001000], but subsequently accessed regardless of whether it was freed - Trigger Condition: Requires
action_codein range [1000000, 1001000]
2. ada_bugs.adb::Use_After_Free_Fuzz()
- Entry Point: Pure Ada subprogram
Ada_Bugs.Use_After_Free_Fuzz(Control: Integer) - Goal: Detect use-after-free using unchecked pointer manipulation
- Vulnerability: A pointer is freed when
Control < 0, but its address is saved and the pointer is reconstituted and dereferenced regardless - Trigger Condition: When
Control < 0
Array in Struct (2 variants)
1. simple_bugs.c::simple_struct_array_access()
- Entry Point: Called from Ada via FFI binding
- Goal: Detect out-of-bounds access to an array within a struct
- Vulnerability: A struct contains a 4-byte array followed by an unsigned int. The array is accessed with
index % sizeof(super_struct), which can access beyond the array into theother_valuefield or beyond - Trigger Condition: When
indexmodulo the struct size results in an index >= 4 (the array size)
2. ada_bugs.adb::Record_Array_Access()
- Entry Point: Pure Ada subprogram
Ada_Bugs.Record_Array_Access(Index: Interfaces.Unsigned_8) - Goal: Detect out-of-bounds access to an array field within an Ada record
- Vulnerability: A record contains a 128-element array followed by an unsigned 32-bit integer. Array access uses the full range of an unsigned 8-bit index (0-255), allowing writes beyond the array bounds
- Trigger Condition: When
Index > 128
Out of Bounds Pointer Arithmetics (1 variant)
out_of_bounds_arithmetic.c::test_out_of_bounds_arithmetic()
- Entry Point: Called from Ada via
Bounds_Test.Execute_Test(Offset_Multiplier: Integer) - Goal: Demonstrate vulnerability where out-of-bounds pointer arithmetic causes a pointer to illegally jump from one buffer to an adjacent buffer
- Vulnerability: Two adjacent buffers are allocated on the stack. A pointer to the first buffer is advanced by the distance between the buffers, causing it to point into the second buffer. This is a capability violation that ASAN cannot detect (it only checks dereferences, not arithmetic)
- Trigger Condition: Any input value that doesn't crash the program will trigger the vulnerability
- Note: This is primarily designed to demonstrate the difference between ASAN and CHERI-style capability-based protection
ASan Overflow Evading (1 variant)
asan_evasion.c::test_asan_evade()
- Entry Point: Called from Ada via FFI binding
- Goal: Demonstrate a heap buffer overflow that can evade AddressSanitizer's detection
- Vulnerability: Two small (1-byte) heap buffers are allocated adjacently. An overflow of 31 bytes from the first buffer attempts to corrupt the second buffer. Due to ASAN's redzone architecture (typically 16-32 bytes between allocations), this specific overflow distance can potentially avoid the poisoned redzone and reach the second buffer undetected
- Trigger Condition: Requires heap layout where buffers are positioned such that a 32-byte overflow from
buf1[0]reachesbuf2[0]without hitting ASAN redzones - Note: This is an architectural limitation of ASAN's redzone-based approach
Source Files
Ada Entry Points
ada_bugs.ads/ada_bugs.adb: Pure Ada implementations of buffer overflow, use-after-free, double-free, and record array access vulnerabilitiesbounds_test.ads/bounds_test.adb: Ada wrapper for the out-of-bounds pointer arithmetic testtest_bounds_ada.adb: Standalone Ada program demonstrating the bounds testbugs_c.ads: Ada FFI bindings for complex C vulnerabilities inbugs.csimple_bugs_c.ads: Ada FFI bindings for simpler C vulnerabilities insimple_bugs.c
C Implementations
bugs.c: Complex vulnerabilities requiring specific input ranges (stack overflow, heap overflow, double free, use-after-free, uninitialized memory, null pointer dereference)simple_bugs.c: Simpler vulnerabilities with fewer preconditions (stack overflow, heap overflow, struct array access)out_of_bounds_arithmetic.c: Pointer arithmetic vulnerability demonstrating ASAN limitationsasan_evasion.c: Heap overflow specifically designed to evade ASAN detection
Usage
These benchmarks are designed to be compiled with instrumentation (ASAN, MSAN, UBSan, etc.) and fuzzed from their Ada entry points. The fuzzer must discover the specific input values that satisfy the conditional branches leading to each vulnerability.
Research Context
This benchmark suite supports research into:
- The effectiveness of fuzz testing when starting from memory-safe languages (Ada)
- The ability of fuzzers to discover complex, condition-guarded vulnerabilities
- The detection capabilities and limitations of different sanitizers (ASAN, MSAN, CHERI)
- Cross-language vulnerability propagation in mixed Ada/C codebases
License
Part of the ERTS 2026 conference submission materials.