From 1c38dea651447fcaf4ec5930d622a7d0e6384e43 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 23 Apr 2021 21:19:49 +0300 Subject: [PATCH] json_pointer: move array out-of-bounds check outside of is_valid_index() The out-of-bounds check is useful when trying to index/obtain a value from an array. However, when we set a value to a specific JSON pointer, we can allow values that are outside the length of the current array. The RFC6901 doc isn't clear on that aspect, and doing so is a bit more in-line with how json_object_array_{put,insert}_idx() functions behave. This changes the behavior of json_pointer_set{f}() because now a value can be set anywhere in the array. Also, added a test-case for this behavior change. Signed-off-by: Alexandru Ardelean --- json_pointer.c | 21 ++++++++++----------- tests/test_json_pointer.c | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/json_pointer.c b/json_pointer.c index f04b487..e834c3b 100644 --- a/json_pointer.c +++ b/json_pointer.c @@ -42,7 +42,7 @@ static void string_replace_all_occurrences_with_char(char *s, const char *occur, } } -static int is_valid_index(struct json_object *jo, const char *path, size_t *idx) +static int is_valid_index(const char *path, size_t *idx) { size_t i, len = strlen(path); /* this code-path optimizes a bit, for when we reference the 0-9 index range @@ -53,7 +53,7 @@ static int is_valid_index(struct json_object *jo, const char *path, size_t *idx) if (is_plain_digit(path[0])) { *idx = (path[0] - '0'); - goto check_oob; + return 1; } errno = EINVAL; return 0; @@ -77,13 +77,6 @@ static int is_valid_index(struct json_object *jo, const char *path, size_t *idx) // We know it's all digits, so the only error case here is overflow, // but ULLONG_MAX will be longer than any array length so that's ok. *idx = strtoull(path, NULL, 10); -check_oob: - len = json_object_array_length(jo); - if (*idx >= len) - { - errno = ENOENT; - return 0; - } return 1; } @@ -93,8 +86,14 @@ static int json_pointer_get_single_path(struct json_object *obj, char *path, { if (json_object_is_type(obj, json_type_array)) { - if (!is_valid_index(obj, path, idx)) + if (!is_valid_index(path, idx)) return -1; + if (*idx >= json_object_array_length(obj)) + { + errno = ENOENT; + return -1; + } + obj = json_object_array_get_idx(obj, *idx); if (obj) { @@ -129,7 +128,7 @@ static int json_pointer_set_single_path(struct json_object *parent, const char * /* RFC (Chapter 4) states that '-' may be used to add new elements to an array */ if (path[0] == '-' && path[1] == '\0') return json_object_array_add(parent, value); - if (!is_valid_index(parent, path, &idx)) + if (!is_valid_index(path, &idx)) return -1; return json_object_array_put_idx(parent, idx, value); } diff --git a/tests/test_json_pointer.c b/tests/test_json_pointer.c index 4ac78cb..09c195a 100644 --- a/tests/test_json_pointer.c +++ b/tests/test_json_pointer.c @@ -269,6 +269,22 @@ static void test_example_set(void) printf("%s\n", json_object_get_string(jo1)); json_object_put(jo1); + + jo1 = json_tokener_parse("[0, 1, 2, 3]"); + jo2 = json_tokener_parse("[0, 1, 2, 3, null, null, null, 7]"); + + assert(0 == json_pointer_set(&jo1, "/7", json_object_new_int(7))); + assert(1 == json_object_equal(jo1, jo2)); + + json_object_put(jo1); + + jo1 = json_tokener_parse("[0, 1, 2, 3]"); + + assert(0 == json_pointer_setf(&jo1, json_object_new_int(7), "/%u", 7)); + assert(1 == json_object_equal(jo1, jo2)); + + json_object_put(jo1); + json_object_put(jo2); } static void test_wrong_inputs_set(void)