From 7f3850e6bcfef275d0e60eda5440d7fbeb14e971 Mon Sep 17 00:00:00 2001 From: Mehmet Akif TASOVA Date: Thu, 21 Feb 2019 16:58:57 +0300 Subject: [PATCH] introduce json_object_new_string_noalloc() On some low memory systems, calling malloc (by the use of strdup) causes memory fragmentation which eventually results in out of memory situation. using json_object_new_string_noalloc helps to solve this issue. also add basic test for json_object_new_string_noalloc --- json_object.c | 17 +++++++++++ json_object.h | 13 ++++++++ tests/Makefile.am | 1 + tests/test_string_noalloc.c | 48 ++++++++++++++++++++++++++++++ tests/test_string_noalloc.expected | 1 + tests/test_string_noalloc.test | 1 + 6 files changed, 81 insertions(+) create mode 100644 tests/test_string_noalloc.c create mode 100644 tests/test_string_noalloc.expected create mode 120000 tests/test_string_noalloc.test diff --git a/json_object.c b/json_object.c index 344af51..711a352 100644 --- a/json_object.c +++ b/json_object.c @@ -1015,6 +1015,23 @@ static void json_object_string_delete(struct json_object* jso) json_object_generic_delete(jso); } +struct json_object* json_object_new_string_noalloc(char *s) +{ + struct json_object *jso = json_object_new(json_type_string); + if (!jso) + return NULL; + jso->_delete = &json_object_string_delete; + jso->_to_json_string = &json_object_string_to_json_string; + jso->o.c_string.len = strlen(s); + if(jso->o.c_string.len < LEN_DIRECT_STRING_DATA) { + memcpy(jso->o.c_string.str.data, s, jso->o.c_string.len); + free(s); + } else { + jso->o.c_string.str.ptr = s; + } + return jso; +} + struct json_object* json_object_new_string(const char *s) { struct json_object *jso = json_object_new(json_type_string); diff --git a/json_object.h b/json_object.h index c4a9cb2..d73dcce 100644 --- a/json_object.h +++ b/json_object.h @@ -893,6 +893,19 @@ JSON_EXPORT int json_object_set_double(struct json_object *obj,double new_value) /* string type methods */ +/** Create a new empty json_object of type json_type_string + * + * Use given string as is, do not call malloc if given string is longer + * than internal buffer size. Ownership of s will be transferred to + * json_object and s will be freed when json_object_put decided to free + * memory of json_object. + * + * @param s the string, must be heap alloacted and must not be freed. + * @returns a json_object of type json_type_string + * @see json_object_new_string_len() + */ +JSON_EXPORT struct json_object* json_object_new_string_noalloc(char *s); + /** Create a new empty json_object of type json_type_string * * A copy of the string is made and the memory is managed by the json_object diff --git a/tests/Makefile.am b/tests/Makefile.am index ea57bda..434c98c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -27,6 +27,7 @@ TESTS+= test_set_value.test TESTS+= test_visit.test TESTS+= test_json_pointer.test TESTS+= test_int_add.test +TESTS+= test_string_noalloc.test check_PROGRAMS= check_PROGRAMS += $(TESTS:.test=) diff --git a/tests/test_string_noalloc.c b/tests/test_string_noalloc.c new file mode 100644 index 0000000..6be7458 --- /dev/null +++ b/tests/test_string_noalloc.c @@ -0,0 +1,48 @@ +/* + * Tests if binary strings are supported. + */ + +#include +#include +#include +#include "config.h" + +#include "json_inttypes.h" +#include "json_object.h" +#include "json_tokener.h" + +int main(void) +{ + /* this test has a space after the null character. check that it's still included */ + char *str1 = strdup("This string should be longer than 32 characters"); + char *str2 = strdup("this string is short"); + struct json_object *jso_str = NULL; + + if (!str1 || !str2) + { + puts("FAIL: strdup() returned NULL"); + return 1; + } + + jso_str = json_object_new_string_noalloc(str1); + if (!jso_str) + { + puts("FAIL: json_object_new_string_noalloc(str1) returned NULL"); + return 2; + } + + json_object_put(jso_str); + jso_str = NULL; + + jso_str = json_object_new_string_noalloc(str2); + if (!jso_str) + { + puts("FAIL: json_object_new_string_noalloc(str2) returned NULL"); + return 3; + } + + json_object_put(jso_str); + + puts("PASS"); + return 0; +} diff --git a/tests/test_string_noalloc.expected b/tests/test_string_noalloc.expected new file mode 100644 index 0000000..7ef22e9 --- /dev/null +++ b/tests/test_string_noalloc.expected @@ -0,0 +1 @@ +PASS diff --git a/tests/test_string_noalloc.test b/tests/test_string_noalloc.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_string_noalloc.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file