fix memory leak in the json parser and add more tests for cxJsonFromString - relates to #777 default tip

Wed, 10 Dec 2025 14:05:20 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 10 Dec 2025 14:05:20 +0100
changeset 1563
6e2f83ef6f5a
parent 1562
f2b63cad2142

fix memory leak in the json parser and add more tests for cxJsonFromString - relates to #777

src/json.c file | annotate | diff | comparison | revisions
tests/test_json.c file | annotate | diff | comparison | revisions
--- a/src/json.c	Wed Dec 10 13:12:27 2025 +0100
+++ b/src/json.c	Wed Dec 10 14:05:20 2025 +0100
@@ -557,6 +557,7 @@
     }
     cxJsonValueFree(json->parsed);
     json->parsed = NULL;
+    token_destroy(&json->uncompleted);
     cx_strfree_a(json->allocator, &json->uncompleted_member_name);
 }
 
--- a/tests/test_json.c	Wed Dec 10 13:12:27 2025 +0100
+++ b/tests/test_json.c	Wed Dec 10 14:05:20 2025 +0100
@@ -199,6 +199,43 @@
     }
 }
 
+CX_TEST(test_json_from_string_errors) {
+    CX_TEST_DO {
+        CxJsonValue *obj = NULL;
+        CX_TEST_ASSERT(cxJsonFromString(NULL, "", &obj) == CX_JSON_NO_DATA);
+        CX_TEST_ASSERT(cxJsonFromString(NULL, cx_str(NULL), &obj) == CX_JSON_NO_DATA);
+        CX_TEST_ASSERT(cxJsonFromString(NULL, "\"incomplete", &obj) == CX_JSON_INCOMPLETE_DATA);
+        CX_TEST_ASSERT(cxJsonFromString(NULL, "{ \"incomplete\": ", &obj) == CX_JSON_INCOMPLETE_DATA);
+        CX_TEST_ASSERT(cxJsonFromString(NULL, "{\"number\": 47110815!}", &obj) == CX_JSON_FORMAT_ERROR_NUMBER);
+        CX_TEST_ASSERT(cxJsonFromString(NULL, "[ \"unexpected token\" : true ]", &obj) == CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
+        CX_TEST_ASSERT(cxJsonFromString(NULL, "} [", &obj) == CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
+        CX_TEST_ASSERT(obj && obj->type == CX_JSON_NOTHING);
+    }
+}
+
+CX_TEST(test_json_from_string_multiple_values) {
+    CxJsonStatus status;
+    CxJsonValue *obj = NULL;
+    CX_TEST_DO {
+        status = cxJsonFromString(NULL, "{ \"obj1\": \"hello\" }\n\"value2\"\n", &obj);
+        
+        // TODO: what is the expected behavior here? Is this an error or do we ignore the second value?
+        CX_TEST_ASSERT(status == CX_JSON_NO_ERROR);
+        CX_TEST_ASSERT(cxJsonIsObject(obj));
+        // CX_TEST_ASSERT(status == CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
+        
+        cxJsonValueFree(obj);
+        
+        // TODO: this really should be an error in theory
+        status = cxJsonFromString(NULL, "\"value\" \n ] syntax error [", &obj);
+        CX_TEST_ASSERT(status == CX_JSON_NO_ERROR);
+        CX_TEST_ASSERT(cxJsonIsString(obj));
+        // CX_TEST_ASSERT(status == CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
+        
+        cxJsonValueFree(obj);
+    }
+}
+
 CX_TEST(test_json_escaped_strings) {
     cxstring text = cx_str(
             "{\n"
@@ -449,6 +486,13 @@
         // now there is everything read
         result = cxJsonNext(&json, &obj);
         CX_TEST_ASSERT(result == CX_JSON_NO_DATA);
+        
+        // Test 2: abort after incomplete token
+        cxJsonReset(&json);
+        
+        cxJsonFill(&json, "\"incomplete token");
+        result = cxJsonNext(&json, &obj);
+        CX_TEST_ASSERT(result == CX_JSON_INCOMPLETE_DATA);
 
         cxJsonDestroy(&json);
     }
@@ -1519,6 +1563,8 @@
     cx_test_register(suite, test_json_simple_object);
     cx_test_register(suite, test_json_large_object);
     cx_test_register(suite, test_json_from_string);
+    cx_test_register(suite, test_json_from_string_errors);
+    cx_test_register(suite, test_json_from_string_multiple_values);
     cx_test_register(suite, test_json_escaped_strings);
     cx_test_register(suite, test_json_escaped_unicode_strings);
     cx_test_register(suite, test_json_escaped_unicode_malformed);

mercurial