From 6b740e78bd36959c8e0bc0310dd0707fead41ff4 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 17 Jan 2018 06:14:14 +1030 Subject: [PATCH] json: more sanity checks on JSON output. We should never have an unnamed element, nor an named array field. Signed-off-by: Rusty Russell --- common/json.c | 78 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/common/json.c b/common/json.c index df51c732e..0934b2951 100644 --- a/common/json.c +++ b/common/json.c @@ -12,7 +12,9 @@ #include struct json_result { - unsigned int indent; + /* tal_arr of types we're enclosed in. */ + jsmntype_t *wrapping; + /* tal_count() of this is strlen() + 1 */ char *s; }; @@ -365,6 +367,21 @@ static bool result_ends_with(struct json_result *res, const char *str) return streq(res->s + len - strlen(str), str); } +static void check_fieldname(const struct json_result *result, + const char *fieldname) +{ + size_t n = tal_count(result->wrapping); + if (n == 0) + /* Can't have a fieldname if not in anything! */ + assert(!fieldname); + else if (result->wrapping[n-1] == JSMN_ARRAY) + /* No fieldnames in arrays. */ + assert(!fieldname); + else + /* Must have fieldnames in objects. */ + assert(fieldname); +} + static void json_start_member(struct json_result *result, const char *fieldname) { /* Prepend comma if required. */ @@ -372,48 +389,67 @@ static void json_start_member(struct json_result *result, const char *fieldname) && !result_ends_with(result, "{ ") && !result_ends_with(result, "[ ")) result_append(result, ", "); + + check_fieldname(result, fieldname); if (fieldname) result_append_fmt(result, "\"%s\" : ", fieldname); } +static void result_add_indent(struct json_result *result) +{ + size_t i, indent = tal_count(result->wrapping); + + if (!indent) + return; + + result_append(result, "\n"); + for (i = 0; i < indent; i++) + result_append(result, "\t"); +} + +static void result_add_wrap(struct json_result *result, jsmntype_t type) +{ + size_t indent = tal_count(result->wrapping); + + tal_resize(&result->wrapping, indent+1); + result->wrapping[indent] = type; +} + +static void result_pop_wrap(struct json_result *result, jsmntype_t type) +{ + size_t indent = tal_count(result->wrapping); + + assert(indent); + assert(result->wrapping[indent-1] == type); + tal_resize(&result->wrapping, indent-1); +} + void json_array_start(struct json_result *result, const char *fieldname) { json_start_member(result, fieldname); - if (result->indent) { - unsigned int i; - result_append(result, "\n"); - for (i = 0; i < result->indent; i++) - result_append(result, "\t"); - } + result_add_indent(result); result_append(result, "[ "); - result->indent++; + result_add_wrap(result, JSMN_ARRAY); } void json_array_end(struct json_result *result) { - assert(result->indent); - result->indent--; result_append(result, " ]"); + result_pop_wrap(result, JSMN_ARRAY); } void json_object_start(struct json_result *result, const char *fieldname) { json_start_member(result, fieldname); - if (result->indent) { - unsigned int i; - result_append(result, "\n"); - for (i = 0; i < result->indent; i++) - result_append(result, "\t"); - } + result_add_indent(result); result_append(result, "{ "); - result->indent++; + result_add_wrap(result, JSMN_OBJECT); } void json_object_end(struct json_result *result) { - assert(result->indent); - result->indent--; result_append(result, " }"); + result_pop_wrap(result, JSMN_OBJECT); } void json_add_num(struct json_result *result, const char *fieldname, unsigned int value) @@ -498,13 +534,13 @@ struct json_result *new_json_result(const tal_t *ctx) /* Using tal_arr means that it has a valid count. */ r->s = tal_arrz(r, char, 1); - r->indent = 0; + r->wrapping = tal_arr(r, jsmntype_t, 0); return r; } const char *json_result_string(const struct json_result *result) { - assert(!result->indent); + assert(tal_count(result->wrapping) == 0); assert(tal_count(result->s) == strlen(result->s) + 1); return result->s; }