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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions