Skip to content

Memory allocation/deallocation mismatch in fuzz_array.c causes immediate crash with AddressSanitizer #43

@OwenSanzas

Description

@OwenSanzas

Description

Summary

The fuzz_array.c fuzzer has a critical memory management bug that causes it to crash immediately when built with AddressSanitizer. The fuzzer uses C's free() function to deallocate memory allocated with C++'s new[] operator,
violating C++ memory management rules.

Impact

  • Status: Blocks all fuzzing of CUPS array functionality
  • Scope: Affects anyone running fuzz_array with AddressSanitizer (including OSS-Fuzz)

The fuzzer crashes on the very first test case, achieving zero code coverage and preventing discovery of real bugs in CUPS.

Root Cause

Allocation (C++ new[]) in fuzz_helpers.cpp:21,24:

void generate_fuzz_array_data(const uint8_t *data, size_t size, FuzzArray *outData) {
    // ...
    outData->str1 = new char[fuzz_str1.length() + 1];  // C++ new[]
    outData->str2 = new char[fuzz_str2.length() + 1];  // C++ new[]
}

Deallocation (C free()) in fuzz_array.c:161-162:
free(first_string);   // ❌ Wrong: should use delete[]
free(second_string);  // ❌ Wrong: should use delete[]

AddressSanitizer Error

==1==ERROR: AddressSanitizer: alloc-dealloc-mismatch (operator new [] vs free)
    #0 in free
    #1 in LLVMFuzzerTestOneInput fuzz_array.c:161:3

0x7be2be1e08d0 is located 0 bytes inside of 2-byte region
allocated by thread T0 here:
    #0 in operator new[](unsigned long)
    #1 in generate_fuzz_array_data fuzz_helpers.cpp:21:21
    #2 in LLVMFuzzerTestOneInput fuzz_array.c:51:3

SUMMARY: AddressSanitizer: alloc-dealloc-mismatch fuzz_array.c:161:3

Reproduction Steps

1. Build fuzzers with AddressSanitizer:
# Using OSS-Fuzz infrastructure
python3 infra/helper.py build_fuzzers --sanitizer address cups
2. Run the fuzzer with any input:
./fuzz_array test_input
3. Expected: Fuzzer crashes immediately with alloc-dealloc-mismatch

Solution

The codebase already provides the correct deallocation function in fuzz_helpers.cpp:29-32:

void free_fuzz_array_data(FuzzArray *data) {
    delete[] data->str1;  // ✓ Correct
    delete[] data->str2;  // ✓ Correct
}

Fix: Replace the incorrect free() calls with the proper helper function.

Proposed Patch

--- a/projects/cups/fuzzer/fuzz_array.c
+++ b/projects/cups/fuzzer/fuzz_array.c
@@ -158,8 +158,8 @@
   cupsArrayDelete(array);
   cupsArrayDelete(dup_array);

-  free(first_string);
-  free(second_string);
+  // Free fuzz input data using the correct C++ delete[]
+  free_fuzz_array_data(&fuzzInput);

   if (status != 0) {
     abort();

Testing

After applying the patch:

1. Rebuild the fuzzer with AddressSanitizer
2. Run with test inputs - no crash should occur
3. Fuzzer should successfully test CUPS array operations

Additional Context

- C++ standard requires matching allocation/deallocation pairs:
  - newdelete
  - new[] → delete[]
  - malloc() → free()
- Mixing these causes undefined behavior
- AddressSanitizer correctly detects this violation

The irony is that the correct solution (free_fuzz_array_data()) was already implemented in the codebase, but fuzz_array.c doesn't use it.

Environment

- Compiler: Clang with AddressSanitizer
- Platform: Any (bug is platform-independent C++ standard violation)
- OSS-Fuzz: Affected

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions