aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorey Farrell <git@cfware.com>2018-01-22 15:39:58 -0500
committerCorey Farrell <git@cfware.com>2018-02-01 15:54:25 -0500
commit37e0ee4d485f8d0821ea357d8bf97d3904145b73 (patch)
tree09a8210b1ff29b36443b04d5d0d1134da8c9f8af
parentdc3b313e91b573f393d8717c1c9e8c11a51f7ab1 (diff)
downloadjansson-37e0ee4d485f8d0821ea357d8bf97d3904145b73.zip
jansson-37e0ee4d485f8d0821ea357d8bf97d3904145b73.tar.gz
jansson-37e0ee4d485f8d0821ea357d8bf97d3904145b73.tar.bz2
json_dump: Fix thread safety issue.
Circular reference detection in json_dump was not thread safe. Replace visited flag with a hashtable_t. Issue #387
-rw-r--r--src/dump.c90
-rw-r--r--src/jansson_private.h2
-rw-r--r--src/value.c4
3 files changed, 48 insertions, 48 deletions
diff --git a/src/dump.c b/src/dump.c
index 63a9c15..8e725c9 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -196,8 +196,17 @@ static int compare_keys(const void *key1, const void *key2)
return strcmp(*(const char **)key1, *(const char **)key2);
}
+static int loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size)
+{
+ snprintf(key, key_size, "%p", json);
+ if (hashtable_get(parents, key))
+ return -1;
+
+ return hashtable_set(parents, key, json_null());
+}
+
static int do_dump(const json_t *json, size_t flags, int depth,
- json_dump_callback_t dump, void *data)
+ hashtable_t *parents, json_dump_callback_t dump, void *data)
{
int embed = flags & JSON_EMBED;
@@ -251,58 +260,53 @@ static int do_dump(const json_t *json, size_t flags, int depth,
{
size_t n;
size_t i;
-
- json_array_t *array;
+ /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
+ char key[2 + (sizeof(json) * 2) + 1];
/* detect circular references */
- array = json_to_array(json);
- if(array->visited)
- goto array_error;
- array->visited = 1;
+ if (loop_check(parents, json, key, sizeof(key)))
+ return -1;
n = json_array_size(json);
if(!embed && dump("[", 1, data))
- goto array_error;
+ return -1;
if(n == 0) {
- array->visited = 0;
+ hashtable_del(parents, key);
return embed ? 0 : dump("]", 1, data);
}
if(dump_indent(flags, depth + 1, 0, dump, data))
- goto array_error;
+ return -1;
for(i = 0; i < n; ++i) {
if(do_dump(json_array_get(json, i), flags, depth + 1,
- dump, data))
- goto array_error;
+ parents, dump, data))
+ return -1;
if(i < n - 1)
{
if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
- goto array_error;
+ return -1;
}
else
{
if(dump_indent(flags, depth, 0, dump, data))
- goto array_error;
+ return -1;
}
}
- array->visited = 0;
+ hashtable_del(parents, key);
return embed ? 0 : dump("]", 1, data);
-
- array_error:
- array->visited = 0;
- return -1;
}
case JSON_OBJECT:
{
- json_object_t *object;
void *iter;
const char *separator;
int separator_length;
+ /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
+ char key[2 + (sizeof(json) * 2) + 1];
if(flags & JSON_COMPACT) {
separator = ":";
@@ -314,21 +318,19 @@ static int do_dump(const json_t *json, size_t flags, int depth,
}
/* detect circular references */
- object = json_to_object(json);
- if(object->visited)
- goto object_error;
- object->visited = 1;
+ if (loop_check(parents, json, key, sizeof(key)))
+ return -1;
iter = json_object_iter((json_t *)json);
if(!embed && dump("{", 1, data))
- goto object_error;
+ return -1;
if(!iter) {
- object->visited = 0;
+ hashtable_del(parents, key);
return embed ? 0 : dump("}", 1, data);
}
if(dump_indent(flags, depth + 1, 0, dump, data))
- goto object_error;
+ return -1;
if(flags & JSON_SORT_KEYS)
{
@@ -338,7 +340,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
size = json_object_size(json);
keys = jsonp_malloc(size * sizeof(const char *));
if(!keys)
- goto object_error;
+ return -1;
i = 0;
while(iter)
@@ -362,10 +364,10 @@ static int do_dump(const json_t *json, size_t flags, int depth,
dump_string(key, strlen(key), dump, data, flags);
if(dump(separator, separator_length, data) ||
- do_dump(value, flags, depth + 1, dump, data))
+ do_dump(value, flags, depth + 1, parents, dump, data))
{
jsonp_free(keys);
- goto object_error;
+ return -1;
}
if(i < size - 1)
@@ -374,7 +376,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
dump_indent(flags, depth + 1, 1, dump, data))
{
jsonp_free(keys);
- goto object_error;
+ return -1;
}
}
else
@@ -382,7 +384,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
if(dump_indent(flags, depth, 0, dump, data))
{
jsonp_free(keys);
- goto object_error;
+ return -1;
}
}
}
@@ -401,31 +403,27 @@ static int do_dump(const json_t *json, size_t flags, int depth,
dump_string(key, strlen(key), dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1,
- dump, data))
- goto object_error;
+ parents, dump, data))
+ return -1;
if(next)
{
if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
- goto object_error;
+ return -1;
}
else
{
if(dump_indent(flags, depth, 0, dump, data))
- goto object_error;
+ return -1;
}
iter = next;
}
}
- object->visited = 0;
+ hashtable_del(parents, key);
return embed ? 0 : dump("}", 1, data);
-
- object_error:
- object->visited = 0;
- return -1;
}
default:
@@ -489,10 +487,18 @@ int json_dump_file(const json_t *json, const char *path, size_t flags)
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
{
+ int res;
+ hashtable_t parents_set;
+
if(!(flags & JSON_ENCODE_ANY)) {
if(!json_is_array(json) && !json_is_object(json))
return -1;
}
- return do_dump(json, flags, 0, callback, data);
+ if (hashtable_init(&parents_set))
+ return -1;
+ res = do_dump(json, flags, 0, &parents_set, callback, data);
+ hashtable_close(&parents_set);
+
+ return res;
}
diff --git a/src/jansson_private.h b/src/jansson_private.h
index 1e1cb3c..d19cf9c 100644
--- a/src/jansson_private.h
+++ b/src/jansson_private.h
@@ -35,7 +35,6 @@
typedef struct {
json_t json;
hashtable_t hashtable;
- int visited;
} json_object_t;
typedef struct {
@@ -43,7 +42,6 @@ typedef struct {
size_t size;
size_t entries;
json_t **table;
- int visited;
} json_array_t;
typedef struct {
diff --git a/src/value.c b/src/value.c
index 94869f4..d27bb12 100644
--- a/src/value.c
+++ b/src/value.c
@@ -67,8 +67,6 @@ json_t *json_object(void)
return NULL;
}
- object->visited = 0;
-
return &object->json;
}
@@ -354,8 +352,6 @@ json_t *json_array(void)
return NULL;
}
- array->visited = 0;
-
return &array->json;
}