From 5edab75bdc559707b3abb9ef526e411e7f583b40 Mon Sep 17 00:00:00 2001 From: Krzysztof Gabis Date: Fri, 19 Oct 2012 16:24:24 +0200 Subject: [PATCH] Checking malloc errors, added limits on nesting and object/array size. Also small refractoring and one new test regarding nesting. --- parson.c | 109 +++++++++++++++++++++++++++++++++++-------------------- tests.c | 36 +++++++++--------- 2 files changed, 86 insertions(+), 59 deletions(-) diff --git a/parson.c b/parson.c index 0650dfc..99a6ae4 100644 --- a/parson.c +++ b/parson.c @@ -27,6 +27,8 @@ #include "parson.h" #define STARTING_CAPACITY 10 +#define MAX_CAPACITY 10000 +#define MAX_NESTING 19 #define sizeof_token(a) (sizeof(a) - 1) /* Type definitions */ @@ -58,22 +60,22 @@ struct json_array_t { }; /* JSON Object */ -static JSON_Object * json_object_init(); +static JSON_Object * json_object_init(void); static int json_object_add(JSON_Object *object, const char *name, JSON_Value *value); static void json_object_free(JSON_Object *object); /* JSON Array */ -static JSON_Array * json_array_init(); -static void json_array_add(JSON_Array *array, JSON_Value *value); +static JSON_Array * json_array_init(void); +static int json_array_add(JSON_Array *array, JSON_Value *value); static void json_array_free(JSON_Array *array); /* JSON Value */ -static JSON_Value * json_value_init_object(); -static JSON_Value * json_value_init_array(); +static JSON_Value * json_value_init_object(void); +static JSON_Value * json_value_init_array(void); static JSON_Value * json_value_init_string(const char *string); static JSON_Value * json_value_init_number(double number); static JSON_Value * json_value_init_boolean(int boolean); -static JSON_Value * json_value_init_null(); +static JSON_Value * json_value_init_null(void); /* Parser */ char * parson_strndup(const char *string, size_t n); @@ -83,28 +85,32 @@ static char * copy_and_remove_whitespaces(const char *string); static int is_utf_string(const char *string); static const char * parse_escaped_characters(const char *string); static const char * get_string(const char **string); -static JSON_Value * parse_object_value(const char **string); -static JSON_Value * parse_array_value(const char **string); +static JSON_Value * parse_object_value(const char **string, size_t depth); +static JSON_Value * parse_array_value(const char **string, size_t depth); static JSON_Value * parse_string_value(const char **string); static JSON_Value * parse_boolean_value(const char **string); static JSON_Value * parse_number_value(const char **string); static JSON_Value * parse_null_value(const char **string); -static JSON_Value * parse_value(const char **string); +static JSON_Value * parse_value(const char **string, size_t depth); /* JSON Object */ -static JSON_Object * json_object_init() { - JSON_Object *new_object = (JSON_Object*)malloc(sizeof(JSON_Object)); - new_object->names = (const char**)malloc(sizeof(char*) * STARTING_CAPACITY); - new_object->values = (JSON_Value**)malloc(sizeof(JSON_Value*) * STARTING_CAPACITY); - new_object->capacity = STARTING_CAPACITY; - new_object->count = 0; - return new_object; +static JSON_Object * json_object_init(void) { + JSON_Object *new_obj = (JSON_Object*)malloc(sizeof(JSON_Object)); + if (!new_obj) { return NULL; } + new_obj->names = (const char**)malloc(sizeof(char*) * STARTING_CAPACITY); + if (!new_obj->names) { free(new_obj); return NULL; } + new_obj->values = (JSON_Value**)malloc(sizeof(JSON_Value*) * STARTING_CAPACITY); + if (!new_obj->names) { free(new_obj->names); free(new_obj); return NULL; } + new_obj->capacity = STARTING_CAPACITY; + new_obj->count = 0; + return new_obj; } static int json_object_add(JSON_Object *object, const char *name, JSON_Value *value) { size_t index; if (object->count >= object->capacity) { size_t new_capacity = object->capacity * 2; + if (new_capacity > MAX_CAPACITY) { return 0; } object->names = (const char**)realloc((void*)object->names, new_capacity * sizeof(char*)); object->values = (JSON_Value**)realloc(object->values, new_capacity * sizeof(JSON_Value*)); object->capacity = new_capacity; @@ -129,22 +135,26 @@ static void json_object_free(JSON_Object *object) { } /* JSON Array */ -static JSON_Array * json_array_init() { +static JSON_Array * json_array_init(void) { JSON_Array *new_array = (JSON_Array*)malloc(sizeof(JSON_Array)); + if (!new_array) { return NULL; } new_array->items = (JSON_Value**)malloc(STARTING_CAPACITY * sizeof(JSON_Value*)); + if (!new_array->items) { free(new_array); return NULL; } new_array->capacity = STARTING_CAPACITY; new_array->count = 0; return new_array; } -static void json_array_add(JSON_Array *array, JSON_Value *value) { +static int json_array_add(JSON_Array *array, JSON_Value *value) { if (array->count >= array->capacity) { size_t new_capacity = array->capacity * 2; + if (new_capacity > MAX_CAPACITY) { return 0; } array->items = (JSON_Value**)realloc(array->items, new_capacity * sizeof(JSON_Value*)); array->capacity = new_capacity; } array->items[array->count] = value; array->count++; + return 1; } static void json_array_free(JSON_Array *array) { @@ -157,22 +167,27 @@ static void json_array_free(JSON_Array *array) { } /* JSON Value */ -static JSON_Value * json_value_init_object() { +static JSON_Value * json_value_init_object(void) { JSON_Value *new_value = (JSON_Value*)malloc(sizeof(JSON_Value)); + if (!new_value) { return NULL; } new_value->type = JSONObject; new_value->value.object = json_object_init(); + if (!new_value->value.object) { free(new_value); return NULL; } return new_value; } -static JSON_Value * json_value_init_array() { +static JSON_Value * json_value_init_array(void) { JSON_Value *new_value = (JSON_Value*)malloc(sizeof(JSON_Value)); + if (!new_value) { return NULL; } new_value->type = JSONArray; new_value->value.array = json_array_init(); + if (!new_value->value.array) { free(new_value); return NULL; } return new_value; } static JSON_Value * json_value_init_string(const char *string) { JSON_Value *new_value = (JSON_Value*)malloc(sizeof(JSON_Value)); + if (!new_value) { return NULL; } new_value->type = JSONString; new_value->value.string = string; return new_value; @@ -180,6 +195,7 @@ static JSON_Value * json_value_init_string(const char *string) { static JSON_Value * json_value_init_number(double number) { JSON_Value *new_value = (JSON_Value*)malloc(sizeof(JSON_Value)); + if (!new_value) { return NULL; } new_value->type = JSONNumber; new_value->value.number = number; return new_value; @@ -187,20 +203,24 @@ static JSON_Value * json_value_init_number(double number) { static JSON_Value * json_value_init_boolean(int boolean) { JSON_Value *new_value = (JSON_Value*)malloc(sizeof(JSON_Value)); + if (!new_value) { return NULL; } new_value->type = JSONBoolean; new_value->value.boolean = boolean; return new_value; } -static JSON_Value * json_value_init_null() { +static JSON_Value * json_value_init_null(void) { JSON_Value *new_value = (JSON_Value*)malloc(sizeof(JSON_Value)); + if (!new_value) { return NULL; } new_value->type = JSONNull; return new_value; } /* Parser */ char * parson_strndup(const char *string, size_t n) { - char *output_string = (char*)calloc(n + 1, 1); + char *output_string = (char*)malloc(n + 1); + if (!output_string) { return NULL; } + output_string[n] = '\0'; strncpy(output_string, string, n); return output_string; } @@ -224,7 +244,8 @@ static char *copy_and_remove_whitespaces(const char *string) { char *output_string_ptr = output_string; const char *string_ptr = string; const char *skipped_string = NULL; - char current_char; + char current_char; + if (!output_string) { return NULL; } while (*string_ptr) { current_char = *string_ptr; switch (current_char) { @@ -262,7 +283,8 @@ static const char * parse_escaped_characters(const char *string) { char *output_string_ptr = output_string; const char *string_ptr = string; char current_char; - unsigned int utf_val; + unsigned int utf_val; + if (!output_string) { return NULL; } while (*string_ptr) { current_char = *string_ptr; if (current_char == '\\') { @@ -326,15 +348,15 @@ static const char * get_string(const char **string) { return (const char*)parsed_string; } -static JSON_Value * parse_value(const char **string) { +static JSON_Value * parse_value(const char **string, size_t depth) { JSON_Value *output_value = NULL; - if (*string == NULL) { return NULL; } + if (*string == NULL || depth > MAX_NESTING) { return NULL; } switch ((*string)[0]) { case '{': - output_value = parse_object_value(string); + output_value = parse_object_value(string, depth + 1); break; case '[': - output_value = parse_array_value(string); + output_value = parse_array_value(string, depth + 1); break; case '\"': output_value = parse_string_value(string); @@ -357,21 +379,22 @@ static JSON_Value * parse_value(const char **string) { return output_value; } -static JSON_Value * parse_object_value(const char **string) { +static JSON_Value * parse_object_value(const char **string, size_t depth) { JSON_Value *output_value = json_value_init_object(); const char *new_key = NULL; - JSON_Value *new_value = NULL; + JSON_Value *new_value = NULL; + if (!output_value) { return NULL; } (*string)++; if (**string == '}') { (*string)++; return output_value; } /* empty object */ while (**string != '\0') { new_key = get_string(string); - if (new_key == NULL || **string != ':') { + if (!new_key || **string != ':') { json_value_free(output_value); return NULL; } (*string)++; - new_value = parse_value(string); - if (new_value == NULL) { + new_value = parse_value(string, depth); + if (!new_value) { free((void*)new_key); json_value_free(output_value); return NULL; @@ -391,21 +414,26 @@ static JSON_Value * parse_object_value(const char **string) { return output_value; } -static JSON_Value * parse_array_value(const char **string) { +static JSON_Value * parse_array_value(const char **string, size_t depth) { JSON_Value *output_value = json_value_init_array(); - JSON_Value *new_array_value = NULL; + JSON_Value *new_array_value = NULL; + if (!output_value) { return NULL; } (*string)++; if (**string == ']') { /* empty array */ (*string)++; return output_value; } while (**string != '\0') { - new_array_value = parse_value(string); + new_array_value = parse_value(string, depth); if (new_array_value == NULL) { json_value_free(output_value); return NULL; } - json_array_add(json_value_get_array(output_value), new_array_value); + if(!json_array_add(json_value_get_array(output_value), new_array_value)) { + free(new_array_value); + json_value_free(output_value); + return NULL; + } if (**string != ',') { break; } (*string)++; } @@ -455,11 +483,12 @@ JSON_Value * json_parse_file(const char *filename) { size_t file_size; char *file_contents; JSON_Value *output_value; - if (fp == NULL) { return NULL; } + if (!fp) { return NULL; } fseek(fp, 0L, SEEK_END); file_size = ftell(fp); rewind(fp); file_contents = (char*)malloc(sizeof(char) * (file_size + 1)); + if (!file_contents) { fclose(fp); return NULL; } fread(file_contents, file_size, 1, fp); fclose(fp); file_contents[file_size] = '\0'; @@ -472,9 +501,9 @@ JSON_Value * json_parse_string(const char *string) { JSON_Value *output_value = NULL; const char *json_string = string ? copy_and_remove_whitespaces(string) : NULL; const char *json_string_ptr = json_string; - if (json_string == NULL) { return NULL; } + if (!json_string) { return NULL; } if (*json_string == '{' || *json_string == '[') { - output_value = parse_value((const char**)&json_string_ptr); + output_value = parse_value((const char**)&json_string_ptr, 0); } free((void*)json_string); return output_value; diff --git a/tests.c b/tests.c index 0c80191..ef5c05f 100644 --- a/tests.c +++ b/tests.c @@ -29,11 +29,11 @@ else{puts(" FAIL");tests_failed++;} #define STREQ(A, B) (A && B ? strcmp(A, B) == 0 : 0) -void test_suite_1(); -void test_suite_2(); -void test_suite_3(); +void test_suite_1(void); +void test_suite_2(void); +void test_suite_3(void); -void print_commit_info(const char *username, const char * repo); +void print_commit_info(const char *username, const char *repo); static int tests_passed; static int tests_failed; @@ -50,22 +50,18 @@ int main(int argc, const char * argv[]) { } /* 3 test files from json.org */ -void test_suite_1() { - int i; - JSON_Value *root_value; - char filename[128]; - for (i = 1; i <= 3; i++) { - filename[0] = '\0'; - sprintf(filename, "tests/test_1_%d.txt", i); - printf("Testing %s:\n", filename); - root_value = json_parse_file(filename); - TEST(root_value != NULL); - if (root_value != NULL) { json_value_free(root_value); } - } +void test_suite_1(void) { + JSON_Value *val; + TEST((val = json_parse_file("tests/test_1_1.txt")) != NULL); + if (val) { json_value_free(val); } + TEST((val = json_parse_file("tests/test_1_2.txt")) != NULL); + if (val) { json_value_free(val); } + TEST((val = json_parse_file("tests/test_1_3.txt")) != NULL); + if (val) { json_value_free(val); } } /* Testing correctness of parsed values */ -void test_suite_2() { +void test_suite_2(void) { JSON_Value *root_value; JSON_Object *object; JSON_Array *array; @@ -138,7 +134,8 @@ void test_suite_2() { } /* Testing values, on which parsing should fail */ -void test_suite_3() { +void test_suite_3(void) { + const char nested_20x[] = "[[[[[[[[[[[[[[[[[[[[\"hi\"]]]]]]]]]]]]]]]]]]]]"; TEST(json_parse_string(NULL) == NULL); TEST(json_parse_string("") == NULL); /* empty string */ TEST(json_parse_string("[\"lorem\",]") == NULL); @@ -167,9 +164,10 @@ void test_suite_3() { TEST(json_parse_string("[\"\n\"]") == NULL); /* control character */ TEST(json_parse_string("[\"\f\"]") == NULL); /* control character */ TEST(json_parse_string("[\"\r\"]") == NULL); /* control character */ + TEST(json_parse_string(nested_20x) == NULL); /* too deep */ } -void print_commit_info(const char *username, const char * repo) { +void print_commit_info(const char *username, const char *repo) { JSON_Value *root_value; JSON_Array *commits; JSON_Object *commit;