diff --git a/fuzzing/cjson_array_fuzzer.cc b/fuzzing/cjson_array_fuzzer.cc new file mode 100644 index 00000000..da82a5bf --- /dev/null +++ b/fuzzing/cjson_array_fuzzer.cc @@ -0,0 +1,104 @@ +// Copyright 2025 Google LLC +// Fuzz target for cJSON array operations +// Targets: cJSON_CreateStringArray, cJSON_Duplicate, cJSON_Compare + +#include +#include +#include +#include + +// Helper to safely create string array from fuzz input +cJSON* create_string_array_from_input(const char* data, size_t size) { + // Parse input as newline-separated strings + const char* strings[32]; + int count = 0; + char* temp = (char*)malloc(size + 1); + if (!temp) return NULL; + + memcpy(temp, data, size); + temp[size] = '\0'; + + char* token = strtok(temp, "\n"); + while (token && count < 32) { + strings[count++] = token; + token = strtok(NULL, "\n"); + } + + cJSON* arr = NULL; + if (count > 0) { + arr = cJSON_CreateStringArray(strings, count); + } + + free(temp); + return arr; +} + +// Fuzz target for cJSON array and comparison operations +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < 2) return 0; + + // Split input into two parts for comparison testing + size_t split = size / 2; + + // Create first JSON object + char* input1 = (char*)malloc(split + 1); + if (!input1) return 0; + memcpy(input1, data, split); + input1[split] = '\0'; + + cJSON* obj1 = cJSON_Parse(input1); + free(input1); + + // Create second JSON object + char* input2 = (char*)malloc(size - split + 1); + if (!input2) { + if (obj1) cJSON_Delete(obj1); + return 0; + } + memcpy(input2, data + split, size - split); + input2[size - split] = '\0'; + + cJSON* obj2 = cJSON_Parse(input2); + free(input2); + + // Test cJSON_Compare - 0% coverage target + if (obj1 && obj2) { + cJSON_Compare(obj1, obj2, cJSON_False); + cJSON_Compare(obj1, obj2, cJSON_True); // case-sensitive + } + + // Test cJSON_Duplicate - 0% coverage target + if (obj1) { + cJSON* dup1 = cJSON_Duplicate(obj1, cJSON_False); // shallow + if (dup1) cJSON_Delete(dup1); + + cJSON* dup2 = cJSON_Duplicate(obj1, cJSON_True); // deep + if (dup2) cJSON_Delete(dup2); + } + + // Test cJSON_CreateStringArray - 0% coverage target + cJSON* str_array = create_string_array_from_input((const char*)data, size); + if (str_array) { + // Test detaching and deleting items + cJSON* detached = cJSON_DetachItemFromArray(str_array, 0); + if (detached) cJSON_Delete(detached); + + cJSON_DeleteItemFromArray(str_array, 0); + cJSON_Delete(str_array); + } + + // Test object detachment functions + if (obj1) { + cJSON* detached = cJSON_DetachItemFromObject(obj1, "key"); + if (detached) cJSON_Delete(detached); + + cJSON_DeleteItemFromObject(obj1, "key"); + cJSON_DeleteItemFromObjectCaseSensitive(obj1, "Key"); + } + + // Cleanup + if (obj1) cJSON_Delete(obj1); + if (obj2) cJSON_Delete(obj2); + + return 0; +} diff --git a/fuzzing/cjson_manipulation_fuzzer.cc b/fuzzing/cjson_manipulation_fuzzer.cc new file mode 100644 index 00000000..e986d600 --- /dev/null +++ b/fuzzing/cjson_manipulation_fuzzer.cc @@ -0,0 +1,59 @@ +// Copyright 2025 Google LLC +// Fuzz target for cJSON object manipulation functions +// Targets: cJSON_Parse, cJSON_ReplaceItemInObject, cJSON_AddItemToObject + +#include +#include +#include +#include + +// Fuzz target for cJSON object manipulation +// This targets functions that currently have 0% coverage according to Fuzz Introspector +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // Ensure null-terminated string for JSON parsing + char* input = (char*)malloc(size + 1); + if (!input) return 0; + + memcpy(input, data, size); + input[size] = '\0'; + + // Parse the input as JSON + cJSON* root = cJSON_Parse(input); + if (!root) { + free(input); + return 0; + } + + // Test cJSON_ReplaceItemInObject - 0% coverage target + cJSON* replacement = cJSON_CreateString("fuzz_value"); + if (replacement) { + cJSON_ReplaceItemInObject(root, "key", replacement); + // Also test case-sensitive version + cJSON_ReplaceItemInObjectCaseSensitive(root, "Key", replacement); + } + + // Test cJSON_AddItemToObject - another 0% coverage target + cJSON* new_item = cJSON_CreateNumber(42); + if (new_item) { + cJSON_AddItemToObject(root, "fuzz_key", new_item); + } + + // Test cJSON_AddItemToObjectCS (constant string key) + cJSON* cs_item = cJSON_CreateBool(1); + if (cs_item) { + cJSON_AddItemToObjectCS(root, "const_key", cs_item); + } + + // Test array manipulation + cJSON* array = cJSON_GetObjectItem(root, "array"); + if (array && cJSON_IsArray(array)) { + cJSON* arr_item = cJSON_CreateNumber(123); + cJSON_ReplaceItemInArray(array, 0, arr_item); + } + + // Cleanup + cJSON_Delete(root); + free(input); + + return 0; +} diff --git a/fuzzing/cjson_serialization_fuzzer.cc b/fuzzing/cjson_serialization_fuzzer.cc new file mode 100644 index 00000000..f7a67008 --- /dev/null +++ b/fuzzing/cjson_serialization_fuzzer.cc @@ -0,0 +1,77 @@ +// Copyright 2025 Google LLC +// Fuzz target for cJSON serialization functions +// Targets: cJSON_PrintPreallocated, cJSON_PrintBuffered + +#include +#include +#include +#include + +// Fuzz target for cJSON serialization with preallocated buffers +// Targets 0% coverage functions identified by Fuzz Introspector +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // Ensure null-terminated string + char* input = (char*)malloc(size + 1); + if (!input) return 0; + + memcpy(input, data, size); + input[size] = '\0'; + + // Parse JSON first + cJSON* root = cJSON_Parse(input); + if (!root) { + free(input); + return 0; + } + + // Test cJSON_PrintPreallocated - 0% coverage target + // This function prints to a user-provided buffer + size_t buffer_size = 65536; // 64KB initial buffer + char* buffer = (char*)malloc(buffer_size); + if (buffer) { + cJSON_bool prealloc_result = cJSON_PrintPreallocated( + root, buffer, (int)buffer_size, cJSON_False + ); + // Try with formatted output as well + if (!prealloc_result) { + cJSON_PrintPreallocated(root, buffer, (int)buffer_size, cJSON_True); + } + free(buffer); + } + + // Test various cJSON structures for better coverage + cJSON* test_obj = cJSON_CreateObject(); + if (test_obj) { + // Add various data types + cJSON_AddNullToObject(test_obj, "null_val"); + cJSON_AddTrueToObject(test_obj, "true_val"); + cJSON_AddFalseToObject(test_obj, "false_val"); + cJSON_AddBoolToObject(test_obj, "bool_val", cJSON_True); + cJSON_AddNumberToObject(test_obj, "num_val", 3.14159); + cJSON_AddStringToObject(test_obj, "str_val", "test"); + cJSON_AddRawToObject(test_obj, "raw_val", "{\"nested\":true}"); + + // Create and add array + cJSON* arr = cJSON_CreateIntArray((const int[]){1, 2, 3}, 3); + cJSON_AddItemToObject(test_obj, "int_array", arr); + + cJSON* double_arr = cJSON_CreateDoubleArray( + (const double[]){1.1, 2.2, 3.3}, 3 + ); + cJSON_AddItemToObject(test_obj, "double_array", double_arr); + + cJSON* float_arr = cJSON_CreateFloatArray( + (const float[]){1.1f, 2.2f, 3.3f}, 3 + ); + cJSON_AddItemToObject(test_obj, "float_array", float_arr); + + // Cleanup + cJSON_Delete(test_obj); + } + + // Cleanup + cJSON_Delete(root); + free(input); + + return 0; +}