json: make sure parse always sets *end

Funnel all of the return paths in the main parsing routine through the
code that sets the *end pointer so that all error cases set it.

Change-Id: I0565913f7b9488470ede79dc1af84eb4b9a03225
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
Daniel Verkamp 2017-01-03 16:52:06 -07:00
parent 222bac51e8
commit d6fd64cdab

View File

@ -202,10 +202,12 @@ json_decode_string(uint8_t *str_start, uint8_t *buf_end, uint8_t **str_end, uint
* Shortest valid string (the empty string) is two bytes (""), * Shortest valid string (the empty string) is two bytes (""),
* so this can't possibly be valid * so this can't possibly be valid
*/ */
*str_end = str;
return SPDK_JSON_PARSE_INCOMPLETE; return SPDK_JSON_PARSE_INCOMPLETE;
} }
if (*str++ != '"') { if (*str++ != '"') {
*str_end = str;
return SPDK_JSON_PARSE_INVALID; return SPDK_JSON_PARSE_INVALID;
} }
@ -222,17 +224,21 @@ json_decode_string(uint8_t *str_start, uint8_t *buf_end, uint8_t **str_end, uint
flags & SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE ? out : NULL); flags & SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE ? out : NULL);
assert(rc != 0); assert(rc != 0);
if (rc < 0) { if (rc < 0) {
*str_end = str;
return rc; return rc;
} }
out += rc; out += rc;
} else if (str[0] <= 0x1f) { } else if (str[0] <= 0x1f) {
/* control characters must be escaped */ /* control characters must be escaped */
*str_end = str;
return SPDK_JSON_PARSE_INVALID; return SPDK_JSON_PARSE_INVALID;
} else { } else {
rc = utf8_valid(str, buf_end); rc = utf8_valid(str, buf_end);
if (rc == 0) { if (rc == 0) {
*str_end = str;
return SPDK_JSON_PARSE_INCOMPLETE; return SPDK_JSON_PARSE_INCOMPLETE;
} else if (rc < 0) { } else if (rc < 0) {
*str_end = str;
return SPDK_JSON_PARSE_INVALID; return SPDK_JSON_PARSE_INVALID;
} }
@ -245,6 +251,7 @@ json_decode_string(uint8_t *str_start, uint8_t *buf_end, uint8_t **str_end, uint
} }
/* If execution gets here, we ran out of buffer. */ /* If execution gets here, we ran out of buffer. */
*str_end = str;
return SPDK_JSON_PARSE_INCOMPLETE; return SPDK_JSON_PARSE_INCOMPLETE;
} }
@ -442,7 +449,7 @@ spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t nu
size_t con_start_value; size_t con_start_value;
uint8_t *data = json; uint8_t *data = json;
uint8_t *new_data; uint8_t *new_data;
int rc; int rc = 0;
const struct json_literal *lit; const struct json_literal *lit;
enum { enum {
STATE_VALUE, /* initial state */ STATE_VALUE, /* initial state */
@ -476,11 +483,11 @@ spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t nu
case 'f': case 'f':
case 'n': case 'n':
/* true, false, or null */ /* true, false, or null */
if (state != STATE_VALUE) return SPDK_JSON_PARSE_INVALID; if (state != STATE_VALUE) goto done_invalid;
lit = &g_json_literals[(c >> 3) & 3]; /* See comment above g_json_literals[] */ lit = &g_json_literals[(c >> 3) & 3]; /* See comment above g_json_literals[] */
assert(lit->str[0] == c); assert(lit->str[0] == c);
rc = match_literal(data, json_end, lit->str, lit->len); rc = match_literal(data, json_end, lit->str, lit->len);
if (rc < 0) return rc; if (rc < 0) goto done_rc;
ADD_VALUE(lit->type, data, data + rc); ADD_VALUE(lit->type, data, data + rc);
data += rc; data += rc;
state = depth ? STATE_VALUE_SEPARATOR : STATE_END; state = depth ? STATE_VALUE_SEPARATOR : STATE_END;
@ -488,9 +495,12 @@ spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t nu
break; break;
case '"': case '"':
if (state != STATE_VALUE && state != STATE_NAME) return SPDK_JSON_PARSE_INVALID; if (state != STATE_VALUE && state != STATE_NAME) goto done_invalid;
rc = json_decode_string(data, json_end, &new_data, flags); rc = json_decode_string(data, json_end, &new_data, flags);
if (rc < 0) return rc; if (rc < 0) {
data = new_data;
goto done_rc;
}
/* /*
* Start is data + 1 to skip initial quote. * Start is data + 1 to skip initial quote.
* Length is data + rc - 1 to skip both quotes. * Length is data + rc - 1 to skip both quotes.
@ -517,9 +527,9 @@ spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t nu
case '7': case '7':
case '8': case '8':
case '9': case '9':
if (state != STATE_VALUE) return SPDK_JSON_PARSE_INVALID; if (state != STATE_VALUE) goto done_invalid;
rc = json_valid_number(data, json_end); rc = json_valid_number(data, json_end);
if (rc < 0) return rc; if (rc < 0) goto done_rc;
ADD_VALUE(SPDK_JSON_VAL_NUMBER, data, data + rc); ADD_VALUE(SPDK_JSON_VAL_NUMBER, data, data + rc);
data += rc; data += rc;
state = depth ? STATE_VALUE_SEPARATOR : STATE_END; state = depth ? STATE_VALUE_SEPARATOR : STATE_END;
@ -528,9 +538,10 @@ spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t nu
case '{': case '{':
case '[': case '[':
if (state != STATE_VALUE) return SPDK_JSON_PARSE_INVALID; if (state != STATE_VALUE) goto done_invalid;
if (depth == SPDK_JSON_MAX_NESTING_DEPTH) { if (depth == SPDK_JSON_MAX_NESTING_DEPTH) {
return SPDK_JSON_PARSE_MAX_DEPTH_EXCEEDED; rc = SPDK_JSON_PARSE_MAX_DEPTH_EXCEEDED;
goto done_rc;
} }
if (c == '{') { if (c == '{') {
con_type = SPDK_JSON_VAL_OBJECT_BEGIN; con_type = SPDK_JSON_VAL_OBJECT_BEGIN;
@ -548,8 +559,8 @@ spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t nu
case '}': case '}':
case ']': case ']':
if (trailing_comma) return SPDK_JSON_PARSE_INVALID; if (trailing_comma) goto done_invalid;
if (depth == 0) return SPDK_JSON_PARSE_INVALID; if (depth == 0) goto done_invalid;
con_type = containers[--depth]; con_type = containers[--depth];
con_start_value = con_value[depth]; con_start_value = con_value[depth];
if (values && con_start_value < num_values) { if (values && con_start_value < num_values) {
@ -557,18 +568,18 @@ spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t nu
} }
if (c == '}') { if (c == '}') {
if (state != STATE_NAME && state != STATE_VALUE_SEPARATOR) { if (state != STATE_NAME && state != STATE_VALUE_SEPARATOR) {
return SPDK_JSON_PARSE_INVALID; goto done_invalid;
} }
if (con_type != SPDK_JSON_VAL_OBJECT_BEGIN) { if (con_type != SPDK_JSON_VAL_OBJECT_BEGIN) {
return SPDK_JSON_PARSE_INVALID; goto done_invalid;
} }
ADD_VALUE(SPDK_JSON_VAL_OBJECT_END, data, data + 1); ADD_VALUE(SPDK_JSON_VAL_OBJECT_END, data, data + 1);
} else { } else {
if (state != STATE_VALUE && state != STATE_VALUE_SEPARATOR) { if (state != STATE_VALUE && state != STATE_VALUE_SEPARATOR) {
return SPDK_JSON_PARSE_INVALID; goto done_invalid;
} }
if (con_type != SPDK_JSON_VAL_ARRAY_BEGIN) { if (con_type != SPDK_JSON_VAL_ARRAY_BEGIN) {
return SPDK_JSON_PARSE_INVALID; goto done_invalid;
} }
ADD_VALUE(SPDK_JSON_VAL_ARRAY_END, data, data + 1); ADD_VALUE(SPDK_JSON_VAL_ARRAY_END, data, data + 1);
} }
@ -579,7 +590,7 @@ spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t nu
break; break;
case ',': case ',':
if (state != STATE_VALUE_SEPARATOR) return SPDK_JSON_PARSE_INVALID; if (state != STATE_VALUE_SEPARATOR) goto done_invalid;
data++; data++;
assert(con_type == SPDK_JSON_VAL_ARRAY_BEGIN || assert(con_type == SPDK_JSON_VAL_ARRAY_BEGIN ||
con_type == SPDK_JSON_VAL_OBJECT_BEGIN); con_type == SPDK_JSON_VAL_OBJECT_BEGIN);
@ -588,23 +599,23 @@ spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t nu
break; break;
case ':': case ':':
if (state != STATE_NAME_SEPARATOR) return SPDK_JSON_PARSE_INVALID; if (state != STATE_NAME_SEPARATOR) goto done_invalid;
data++; data++;
state = STATE_VALUE; state = STATE_VALUE;
break; break;
case '/': case '/':
if (!(flags & SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS)) { if (!(flags & SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS)) {
return SPDK_JSON_PARSE_INVALID; goto done_invalid;
} }
rc = json_valid_comment(data, json_end); rc = json_valid_comment(data, json_end);
if (rc < 0) return rc; if (rc < 0) goto done_rc;
/* Skip over comment */ /* Skip over comment */
data += rc; data += rc;
break; break;
default: default:
return SPDK_JSON_PARSE_INVALID; goto done_invalid;
} }
if (state == STATE_END) { if (state == STATE_END) {
@ -638,8 +649,16 @@ spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t nu
} }
/* Invalid end state - ran out of data */ /* Invalid end state - ran out of data */
rc = SPDK_JSON_PARSE_INCOMPLETE;
done_rc:
assert(rc < 0);
if (end) { if (end) {
*end = data; *end = data;
} }
return SPDK_JSON_PARSE_INCOMPLETE; return rc;
done_invalid:
rc = SPDK_JSON_PARSE_INVALID;
goto done_rc;
} }