From 23dafa47391d02d00cfe41e1526a9091ba99ddea Mon Sep 17 00:00:00 2001 From: Kyle Chisholm Date: Fri, 25 Nov 2016 04:53:22 -0500 Subject: [PATCH 1/8] added Print function call for pre-allocated buffer --- cJSON.c | 10 ++++++++++ cJSON.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/cJSON.c b/cJSON.c index 766e558..3dc6491 100644 --- a/cJSON.c +++ b/cJSON.c @@ -886,6 +886,16 @@ char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) return print_value(item, 0, fmt, &p); } +int cJSON_PrintMallocedBuffer(cJSON *item,char *buf,const int len, cjbool fmt) +{ + char *out; + printbuffer p; + p.buffer = buf; + p.length = len; + p.offset = 0; + out = print_value(item,0,fmt,&p); + return (out != buf ? -1 : 0); +} /* Parser core - when encountering text, process appropriately. */ static const char *parse_value(cJSON *item, const char *value, const char **ep) diff --git a/cJSON.h b/cJSON.h index dbbb739..1f1ed7b 100644 --- a/cJSON.h +++ b/cJSON.h @@ -83,6 +83,8 @@ extern char *cJSON_Print(const cJSON *item); extern char *cJSON_PrintUnformatted(const cJSON *item); /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ extern char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with length buf_len */ +extern int cJSON_PrintMallocedBuffer(cJSON *item, char *buf, const int len, int fmt); /* Delete a cJSON entity and all subentities. */ extern void cJSON_Delete(cJSON *c); From 602c241a0ba237e8c65e7db5757702c0d3a2cb2f Mon Sep 17 00:00:00 2001 From: Kyle Chisholm Date: Fri, 25 Nov 2016 04:55:38 -0500 Subject: [PATCH 2/8] fixed "make test" on Mac (clang) --- Makefile | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index b633c80..614b7c1 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,9 @@ UTILS_LIBNAME = libcjson_utils CJSON_TEST = cJSON_test UTILS_TEST = cJSON_test_utils +CJSON_TEST_SRC = cJSON.c test.c +UTILS_TEST_SRC = cJSON.c cJSON_Utils.c test_utils.c + LDLIBS = -lm LIBVERSION = 1.0.2 @@ -66,11 +69,11 @@ test: tests #tests #cJSON -$(CJSON_TEST): cJSON.c cJSON.h test.c - $(CC) $^ -o $@ $(LDLIBS) -I. +$(CJSON_TEST): $(CJSON_TEST_SRC) cJSON.h + $(CC) $(CJSON_TEST_SRC) -o $@ $(LDLIBS) -I. #cJSON_Utils -$(UTILS_TEST): cJSON.c cJSON.h test.c - $(CC) $^ -o $@ $(LDLIBS) -I. +$(UTILS_TEST): $(UTILS_TEST_SRC) cJSON.h cJSON_Utils.h + $(CC) $(UTILS_TEST_SRC) -o $@ $(LDLIBS) -I. #static libraries #cJSON From de93d76d0b9408a5720968656d90d553b254b5ae Mon Sep 17 00:00:00 2001 From: Kyle Chisholm Date: Fri, 25 Nov 2016 13:33:10 -0500 Subject: [PATCH 3/8] changed to cJSON_PrintPreallocated, added flag in printbuffer --- cJSON.c | 15 +++++++++++++-- cJSON.h | 2 +- test.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/cJSON.c b/cJSON.c index 3dc6491..4263c9b 100644 --- a/cJSON.c +++ b/cJSON.c @@ -244,6 +244,7 @@ typedef struct char *buffer; int length; int offset; + cjbool noalloc; } printbuffer; /* realloc printbuffer if necessary to have at least "needed" bytes more */ @@ -261,6 +262,10 @@ static char* ensure(printbuffer *p, int needed) return p->buffer + p->offset; } + if (p->noalloc) { + return NULL; + } + newsize = pow2gt(needed); newbuffer = (char*)cJSON_malloc(newsize); if (!newbuffer) @@ -882,17 +887,19 @@ char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) } p.length = prebuffer; p.offset = 0; + p.noalloc = false; return print_value(item, 0, fmt, &p); } -int cJSON_PrintMallocedBuffer(cJSON *item,char *buf,const int len, cjbool fmt) +int cJSON_PrintPreallocated(cJSON *item,char *buf, const int len, const cjbool fmt) { char *out; printbuffer p; p.buffer = buf; p.length = len; p.offset = 0; + p.noalloc = true; out = print_value(item,0,fmt,&p); return (out != buf ? -1 : 0); } @@ -1147,7 +1154,11 @@ static char *print_array(const cJSON *item, int depth, cjbool fmt, printbuffer * child = item->child; while (child && !fail) { - print_value(child, depth + 1, fmt, p); + ptr = print_value(child, depth + 1, fmt, p); + if (!ptr) + { + return NULL; + } p->offset = update(p); if (child->next) { diff --git a/cJSON.h b/cJSON.h index 1f1ed7b..4d015c3 100644 --- a/cJSON.h +++ b/cJSON.h @@ -84,7 +84,7 @@ extern char *cJSON_PrintUnformatted(const cJSON *item); /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ extern char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt); /* Render a cJSON entity to text using a buffer already allocated in memory with length buf_len */ -extern int cJSON_PrintMallocedBuffer(cJSON *item, char *buf, const int len, int fmt); +extern int cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const int fmt); /* Delete a cJSON entity and all subentities. */ extern void cJSON_Delete(cJSON *c); diff --git a/test.c b/test.c index 7706d97..1952858 100644 --- a/test.c +++ b/test.c @@ -22,6 +22,7 @@ #include #include +#include #include "cJSON.h" /* Parse text to JSON, then render back to text, and print! */ @@ -219,16 +220,60 @@ void create_objects(void) /* cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root, 1), "City", cJSON_CreateIntArray(ids, 4)); */ out = cJSON_Print(root); - cJSON_Delete(root); printf("%s\n", out); + + printf("Test cJSON_PrintPreallocated:\n"); + /* create buffer */ + size_t len = strlen(out) + 1; + char *buf = malloc(len); + + /* create buffer to fail */ + size_t len_fail = strlen(out); + char *buf_fail = malloc(len_fail); + free(out); + /* Print to buffer */ + if (cJSON_PrintPreallocated(root, buf, len, 1) != 0) { + printf("cJSON_PrintPreallocated failed (but it should not have!)\n"); + free(buf_fail); + free(buf); + exit(EXIT_FAILURE); + } else { + printf("cJSON_PrintPreallocated:\n%s\n", buf); + } + + /* unformatted output */ + if (cJSON_PrintPreallocated(root, buf, len, 0) != 0) { + printf("cJSON_PrintPreallocated failed (but it should not have!)\n"); + free(buf_fail); + free(buf); + exit(EXIT_FAILURE); + } else { + printf("cJSON_PrintPreallocated (unformatted):\n%s\n", buf); + } + + free(buf); + + /* force it to fail */ + if (cJSON_PrintPreallocated(root, buf_fail, len_fail, 1) != 0) { + printf("cJSON_PrintPreallocated failed (as expected)\n"); + } else { + printf("cJSON_PrintPreallocated worked (but it should have failed!)\n"); + printf("cJSON_PrintPreallocated:\n%s\n", buf_fail); + } + + free(buf_fail); + cJSON_Delete(root); + root = cJSON_CreateObject(); cJSON_AddNumberToObject(root, "number", 1.0 / zero); out = cJSON_Print(root); - cJSON_Delete(root); printf("%s\n", out); + cJSON_Delete(root); + free(out); + } int main(void) From 4d1dcaa160980bbe6f09a67fac63027f46c3f2c2 Mon Sep 17 00:00:00 2001 From: Kyle Chisholm Date: Mon, 28 Nov 2016 03:20:34 -0500 Subject: [PATCH 4/8] check print_value return --- cJSON.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cJSON.c b/cJSON.c index 4263c9b..707fe44 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1154,8 +1154,7 @@ static char *print_array(const cJSON *item, int depth, cjbool fmt, printbuffer * child = item->child; while (child && !fail) { - ptr = print_value(child, depth + 1, fmt, p); - if (!ptr) + if (!print_value(child, depth + 1, fmt, p)) { return NULL; } @@ -1472,7 +1471,10 @@ static char *print_object(const cJSON *item, int depth, cjbool fmt, printbuffer p->offset+=len; /* print value */ - print_value(child, depth, fmt, p); + if (!print_value(child, depth, fmt, p)) + { + return NULL; + }; p->offset = update(p); /* print comma if not last */ From 99896d879c151fbd97c02e40608ceb4e113efbfc Mon Sep 17 00:00:00 2001 From: Kyle Chisholm Date: Mon, 28 Nov 2016 03:21:15 -0500 Subject: [PATCH 5/8] function to print and compare to preallocated buffer --- test.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/test.c b/test.c index 1952858..7e17dff 100644 --- a/test.c +++ b/test.c @@ -82,6 +82,63 @@ struct record const char *country; }; + +/* Create a bunch of objects as demonstration. */ +int print_preallocated(cJSON *root) +{ + /* declarations */ + char *out = NULL; + char *buf = NULL; + char *buf_fail = NULL; + int len = 0; + int len_fail = 0; + + /* formatted print */ + out = cJSON_Print(root); + + /* create buffer to succeed */ + /* the extra 64 bytes are in case a floating point value is printed */ + len = strlen(out) + 64; + buf = malloc(len); + + /* create buffer to fail */ + len_fail = strlen(out); + buf_fail = malloc(len_fail); + + /* Print to buffer */ + if (cJSON_PrintPreallocated(root, buf, len, 1) != 0) { + printf("cJSON_PrintPreallocated failed!\n"); + if (strcmp(out, buf) != 0) { + printf("cJSON_PrintPreallocated not the same as cJSON_Print!\n"); + printf("cJSON_Print result:\n%s\n", out); + printf("cJSON_PrintPreallocated result:\n%s\n", buf); + } + free(out); + free(buf_fail); + free(buf); + return -1; + } + + /* success */ + printf("%s\n", buf); + + /* force it to fail */ + if (cJSON_PrintPreallocated(root, buf_fail, len_fail, 1) == 0) { + printf("cJSON_PrintPreallocated failed to show error with insufficient memory!\n"); + printf("cJSON_Print result:\n%s\n", out); + printf("cJSON_PrintPreallocated result:\n%s\n", buf_fail); + free(out); + free(buf_fail); + free(buf); + return -1; + } + + free(out); + free(buf_fail); + free(buf); + return 0; +} + /* Create a bunch of objects as demonstration. */ void create_objects(void) { From 3917fb5255ddcdb7860e7f0d539ab1cf95fcab80 Mon Sep 17 00:00:00 2001 From: Kyle Chisholm Date: Mon, 28 Nov 2016 03:24:02 -0500 Subject: [PATCH 6/8] use print_preallocated function to test printout of JSON --- test.c | 89 +++++++++++++++------------------------------------------- 1 file changed, 23 insertions(+), 66 deletions(-) diff --git a/test.c b/test.c index 7e17dff..7a45c34 100644 --- a/test.c +++ b/test.c @@ -148,7 +148,6 @@ void create_objects(void) cJSON *img = NULL; cJSON *thm = NULL; cJSON *fld = NULL; - char *out = NULL; int i = 0; /* Our "days of the week" array: */ @@ -210,21 +209,20 @@ void create_objects(void) cJSON_AddNumberToObject(fmt, "frame rate", 24); /* Print to text */ - out = cJSON_Print(root); - /* Delete the cJSON */ + if (print_preallocated(root) != 0) { + cJSON_Delete(root); + exit(EXIT_FAILURE); + } cJSON_Delete(root); - /* print it */ - printf("%s\n",out); - /* release the string */ - free(out); /* Our "days of the week" array: */ root = cJSON_CreateStringArray(strings, 7); - out = cJSON_Print(root); + if (print_preallocated(root) != 0) { + cJSON_Delete(root); + exit(EXIT_FAILURE); + } cJSON_Delete(root); - printf("%s\n", out); - free(out); /* Our matrix: */ root = cJSON_CreateArray(); @@ -235,11 +233,11 @@ void create_objects(void) /* cJSON_ReplaceItemInArray(root, 1, cJSON_CreateString("Replacement")); */ - out = cJSON_Print(root); + if (print_preallocated(root) != 0) { + cJSON_Delete(root); + exit(EXIT_FAILURE); + } cJSON_Delete(root); - printf("%s\n", out); - free(out); - /* Our "gallery" item: */ root = cJSON_CreateObject(); @@ -253,13 +251,13 @@ void create_objects(void) cJSON_AddStringToObject(thm, "Width", "100"); cJSON_AddItemToObject(img, "IDs", cJSON_CreateIntArray(ids, 4)); - out = cJSON_Print(root); + if (print_preallocated(root) != 0) { + cJSON_Delete(root); + exit(EXIT_FAILURE); + } cJSON_Delete(root); - printf("%s\n", out); - free(out); /* Our array of "records": */ - root = cJSON_CreateArray(); for (i = 0; i < 2; i++) { @@ -276,61 +274,20 @@ void create_objects(void) /* cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root, 1), "City", cJSON_CreateIntArray(ids, 4)); */ - out = cJSON_Print(root); - printf("%s\n", out); - - printf("Test cJSON_PrintPreallocated:\n"); - /* create buffer */ - size_t len = strlen(out) + 1; - char *buf = malloc(len); - - /* create buffer to fail */ - size_t len_fail = strlen(out); - char *buf_fail = malloc(len_fail); - - free(out); - - /* Print to buffer */ - if (cJSON_PrintPreallocated(root, buf, len, 1) != 0) { - printf("cJSON_PrintPreallocated failed (but it should not have!)\n"); - free(buf_fail); - free(buf); + if (print_preallocated(root) != 0) { + cJSON_Delete(root); exit(EXIT_FAILURE); - } else { - printf("cJSON_PrintPreallocated:\n%s\n", buf); } - - /* unformatted output */ - if (cJSON_PrintPreallocated(root, buf, len, 0) != 0) { - printf("cJSON_PrintPreallocated failed (but it should not have!)\n"); - free(buf_fail); - free(buf); - exit(EXIT_FAILURE); - } else { - printf("cJSON_PrintPreallocated (unformatted):\n%s\n", buf); - } - - free(buf); - - /* force it to fail */ - if (cJSON_PrintPreallocated(root, buf_fail, len_fail, 1) != 0) { - printf("cJSON_PrintPreallocated failed (as expected)\n"); - } else { - printf("cJSON_PrintPreallocated worked (but it should have failed!)\n"); - printf("cJSON_PrintPreallocated:\n%s\n", buf_fail); - } - - free(buf_fail); cJSON_Delete(root); root = cJSON_CreateObject(); cJSON_AddNumberToObject(root, "number", 1.0 / zero); - out = cJSON_Print(root); - printf("%s\n", out); + + if (print_preallocated(root) != 0) { + cJSON_Delete(root); + exit(EXIT_FAILURE); + } cJSON_Delete(root); - - free(out); - } int main(void) From 8df4cd46eb321332f2e5e6e580c1b4f230dc2959 Mon Sep 17 00:00:00 2001 From: Kyle Chisholm Date: Mon, 28 Nov 2016 03:34:53 -0500 Subject: [PATCH 7/8] more concise return --- cJSON.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cJSON.c b/cJSON.c index 707fe44..58a1ffd 100644 --- a/cJSON.c +++ b/cJSON.c @@ -894,14 +894,12 @@ char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) int cJSON_PrintPreallocated(cJSON *item,char *buf, const int len, const cjbool fmt) { - char *out; printbuffer p; p.buffer = buf; p.length = len; p.offset = 0; p.noalloc = true; - out = print_value(item,0,fmt,&p); - return (out != buf ? -1 : 0); + return print_value(item,0,fmt,&p) != NULL; } /* Parser core - when encountering text, process appropriately. */ From 6622c54f18a4ad3cd621f4228013fbf6dba1fa88 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 28 Nov 2016 23:06:22 +0700 Subject: [PATCH 8/8] Handle out of memory when printing string --- cJSON.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 58a1ffd..3b61798 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1452,7 +1452,10 @@ static char *print_object(const cJSON *item, int depth, cjbool fmt, printbuffer } /* print key */ - print_string_ptr(child->string, p); + if (!print_string_ptr(child->string, p)) + { + return NULL; + } p->offset = update(p); len = fmt ? 2 : 1;