Skip to content

Commit

Permalink
Fix heap buffer overflow with C style comments.
Browse files Browse the repository at this point in the history
The problem was caused by C style comments not correctly parsing a single '/' in the source.

Fixes #90.
  • Loading branch information
sheredom committed Oct 11, 2022
1 parent 39e57be commit bdcf2e1
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 20 deletions.
44 changes: 24 additions & 20 deletions json.h
Expand Up @@ -356,8 +356,7 @@ enum json_parse_error_e {
json_parse_error_allocator_failed,

/* the JSON input had unexpected trailing characters that weren't part of the.
*/
/* JSON value. */
JSON value. */
json_parse_error_unexpected_trailing_characters,

/* catch-all error for everything else that exploded (real bad chi!). */
Expand Down Expand Up @@ -543,31 +542,33 @@ int json_skip_whitespace(struct json_parse_state_s *state) {

json_weak int json_skip_c_style_comments(struct json_parse_state_s *state);
int json_skip_c_style_comments(struct json_parse_state_s *state) {
if (state->offset >= state->size) {
/* to have a C-style comment we need at least 2 characters of space */
if ((state->offset + 2) > state->size) {
return 0;
}
/* do we have a comment?. */

/* do we have a comment? */
if ('/' == state->src[state->offset]) {
/* skip '/'. */
state->offset++;
if ('/' == state->src[state->offset + 1]) {
/* we had a comment of the form // */

if ('/' == state->src[state->offset]) {
/* we had a comment of the form //. */
/* skip first '/' */
state->offset++;

/* skip second '/'. */
/* skip second '/' */
state->offset++;

while (state->offset < state->size) {
switch (state->src[state->offset]) {
default:
/* skip the character in the comment. */
/* skip the character in the comment */
state->offset++;
break;
case '\n':
/* if we have a newline, our comment has ended! Skip the newline. */
/* if we have a newline, our comment has ended! Skip the newline */
state->offset++;

/* we entered a newline, so move our line info forward. */
/* we entered a newline, so move our line info forward */
state->line_no++;
state->line_offset = state->offset;
return 1;
Expand All @@ -576,10 +577,13 @@ int json_skip_c_style_comments(struct json_parse_state_s *state) {

/* we reached the end of the JSON file! */
return 1;
} else if ('*' == state->src[state->offset]) {
/* we had a comment in the C-style long form. */
} else if ('*' == state->src[state->offset + 1]) {
/* we had a comment in the C-style long form */

/* skip '*'. */
/* skip '/' */
state->offset++;

/* skip '*' */
state->offset++;

while (state->offset + 1 < state->size) {
Expand All @@ -589,16 +593,16 @@ int json_skip_c_style_comments(struct json_parse_state_s *state) {
state->offset += 2;
return 1;
} else if ('\n' == state->src[state->offset]) {
/* we entered a newline, so move our line info forward. */
/* we entered a newline, so move our line info forward */
state->line_no++;
state->line_offset = state->offset;
}

/* skip character within comment. */
/* skip character within comment */
state->offset++;
}

/* Comment wasn't ended correctly which is a failure. */
/* comment wasn't ended correctly which is a failure */
return 1;
}
}
Expand Down Expand Up @@ -628,7 +632,7 @@ int json_skip_all_skippables(struct json_parse_state_s *state) {

/* This should really be checked on access, not in front of every call.
*/
if (state->offset == size) {
if (state->offset >= size) {
state->error = json_parse_error_premature_end_of_buffer;
return 1;
}
Expand Down Expand Up @@ -953,7 +957,7 @@ int json_get_object_size(struct json_parse_state_s *state,
}
}

/* if we parsed at least once element previously, grok for a comma. */
/* if we parsed at least one element previously, grok for a comma. */
if (allow_comma) {
if (',' == src[state->offset]) {
/* skip comma. */
Expand Down
10 changes: 10 additions & 0 deletions test/main.cpp
Expand Up @@ -940,6 +940,16 @@ UTEST(random, nan_overrun) {
ASSERT_FALSE(root);
}

UTEST(random, array_overrun) {
const char payload[40] = {'{', '"', 'k', '"', ' ', ':', ' ', 't', 'r', 'u',
'e', '/', ' ', '"', 'b', '"', ' ', ':', ' ', '[',
'f', 'a', 'l', 's', 'e', ',', ' ', 'n', 'u', 'l',
'l', ',', ' ', '"', 'f', 'o', 'o', '"', ']', '}'};
struct json_value_s *const root =
json_parse_ex(payload, 40, 0x2ffff, 0, 0, 0);
ASSERT_FALSE(root);
}

#define assert(x) ASSERT_TRUE(x)

UTEST(generated, readme){
Expand Down

0 comments on commit bdcf2e1

Please sign in to comment.