aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorallen <leloucharcher@163.com>2019-10-12 15:36:05 +0800
committerallen <leloucharcher@163.com>2019-10-12 15:36:05 +0800
commit00d2d274bc4260d9197d5003cfb4531f7eca494b (patch)
treeda59c8ff9048da225330ba5a316af619d89a00fe
parentcb4727c4a931a471f7d2f1594b162a71349b4dfe (diff)
downloadjansson-00d2d274bc4260d9197d5003cfb4531f7eca494b.zip
jansson-00d2d274bc4260d9197d5003cfb4531f7eca494b.tar.gz
jansson-00d2d274bc4260d9197d5003cfb4531f7eca494b.tar.bz2
add loop check for json_object_update_recursive function
-rw-r--r--src/value.c50
-rw-r--r--test/suites/api/test_object.c33
2 files changed, 75 insertions, 8 deletions
diff --git a/src/value.c b/src/value.c
index 1996232..e09a485 100644
--- a/src/value.c
+++ b/src/value.c
@@ -37,7 +37,7 @@ static JSON_INLINE int isnan(double x) { return x != x; }
static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); }
#endif
-json_t *do_deep_copy(const json_t *, hashtable_t *);
+json_t *do_deep_copy(const json_t *json, hashtable_t *parents);
static JSON_INLINE void json_init(json_t *json, json_type type)
{
@@ -214,24 +214,56 @@ int json_object_update_missing(json_t *object, json_t *other)
return 0;
}
-int json_object_update_recursive(json_t *object, json_t *other)
+int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *parents)
{
const char *key;
json_t *value;
+ char loop_key[LOOP_KEY_LEN];
+ int res = 0;
if(!json_is_object(object) || !json_is_object(other))
return -1;
+ if(jsonp_loop_check(parents, other, loop_key, sizeof(loop_key)))
+ return -1;
+
json_object_foreach(other, key, value) {
json_t *v = json_object_get(object, key);
if(json_is_object(v) && json_is_object(value))
- json_object_update_recursive(v, value);
+ {
+ if(do_object_update_recursive(v, value, parents))
+ {
+ res = -1;
+ break;
+ }
+ }
else
- json_object_set_nocheck(object, key, value);
+ {
+ if(json_object_set_nocheck(object, key, value))
+ {
+ res = -1;
+ break;
+ }
+ }
}
- return 0;
+ hashtable_del(parents, loop_key);
+
+ return res;
+}
+
+int json_object_update_recursive(json_t *object, json_t *other)
+{
+ int res;
+ hashtable_t parents_set;
+
+ if (hashtable_init(&parents_set))
+ return -1;
+ res = do_object_update_recursive(object, other, &parents_set);
+ hashtable_close(&parents_set);
+
+ return res;
}
void *json_object_iter(json_t *json)
@@ -349,7 +381,7 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
result = json_object();
if(!result)
- return NULL;
+ goto out;
/* Cannot use json_object_foreach because object has to be cast
non-const */
@@ -368,6 +400,8 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
}
iter = json_object_iter_next((json_t *)object, iter);
}
+
+out:
hashtable_del(parents, loop_key);
return result;
@@ -668,7 +702,7 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents)
result = json_array();
if(!result)
- return NULL;
+ goto out;
for(i = 0; i < json_array_size(array); i++)
{
@@ -679,6 +713,8 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents)
break;
}
}
+
+out:
hashtable_del(parents, loop_key);
return result;
diff --git a/test/suites/api/test_object.c b/test/suites/api/test_object.c
index ac10936..0493e98 100644
--- a/test/suites/api/test_object.c
+++ b/test/suites/api/test_object.c
@@ -209,7 +209,7 @@ static void test_conditional_updates()
static void test_recursive_updates()
{
- json_t *invalid, *object, *other;
+ json_t *invalid, *object, *other, *barBefore, *barAfter;
invalid = json_integer(42);
@@ -241,6 +241,10 @@ static void test_recursive_updates()
object = json_pack("{sis{si}}", "foo", 1, "bar", "baz", 2);
other = json_pack("{s{si}}", "bar", "baz", 3);
+ barBefore = json_object_get(object, "bar");
+
+ if(!barBefore)
+ fail("can't get bar object before json_object_update_recursive");
if(json_object_update_recursive(object, other))
fail("json_object_update_recursive failed");
@@ -254,6 +258,33 @@ static void test_recursive_updates()
if(json_integer_value(json_object_get(json_object_get(object, "bar"), "baz")) != 3)
fail("json_object_update_recursive failed to update nested value");
+ barAfter = json_object_get(object, "bar");
+ if(!barAfter)
+ fail("can't get bar object after json_object_update_recursive");
+
+ if(barBefore != barAfter)
+ fail("bar object reference changed after json_object_update_recursive");
+
+ json_decref(object);
+ json_decref(other);
+
+ /* check circular reference */
+ object = json_pack("{s{s{si}}}", "foo", "bar", "baz", 2);
+ other = json_pack("{s{s{si}}}", "foo", "bar", "baz", 2);
+ json_object_set(json_object_get(json_object_get(object, "foo"), "bar"), "baz",
+ json_object_get(other, "foo"));
+ json_object_set(json_object_get(json_object_get(other, "foo"), "bar"), "baz",
+ json_object_get(other, "foo"));
+
+ if(!json_object_update_recursive(object, other))
+ fail("json_object_update_recursive update a circular reference!");
+
+ json_object_set_new(json_object_get(json_object_get(other, "foo"), "bar"), "baz",
+ json_integer(1));
+
+ if(json_object_update_recursive(object, other))
+ fail("json_object_update_recursive failed!");
+
json_decref(object);
json_decref(other);
}