浏览代码

Fix erroneous state check in the decoder

If the input contained a mismatched end-of-array/object, the stack
could become empty before a call to dec_curr, which would look
beyond the bounds of the stack. If the value at this invalid
position happened to be st_array, we would pop too much from the
stack and overwrite the data that came before it.

This commit fixes this by letting dec_pop return the previous
state or st_invalid if the stack is empty, letting us exit
gracefully if the state isn't what we expect it to be.

dec_pop_assert is identical to the old dec_pop, tearing down the
emulator on internal errors.
pull/184/head
John Högberg 6 年前
提交者 Paul J. Davis
父节点
当前提交
0a72ec40ba
共有 1 个文件被更改,包括 40 次插入29 次删除
  1. +40
    -29
      c_src/decoder.c

+ 40
- 29
c_src/decoder.c 查看文件

@ -140,7 +140,8 @@ dec_error(Decoder* d, const char* atom)
char char
dec_curr(Decoder* d) dec_curr(Decoder* d)
{ {
return d->st_data[d->st_top-1];
assert(d->st_top > 0);
return d->st_data[d->st_top - 1];
} }
int int
@ -168,12 +169,25 @@ dec_push(Decoder* d, char val)
d->st_data[d->st_top++] = val; d->st_data[d->st_top++] = val;
} }
char
dec_pop(Decoder* d) {
char current = st_invalid;
if (d->st_top > 0) {
current = d->st_data[d->st_top - 1];
d->st_data[d->st_top - 1] = st_invalid;
d->st_top--;
}
return current;
}
void void
dec_pop(Decoder* d, char val)
dec_pop_assert(Decoder* d, char val)
{ {
assert(d->st_data[d->st_top-1] == val && "popped invalid state.");
d->st_data[d->st_top-1] = st_invalid;
d->st_top--;
char current = dec_pop(d);
assert(current == val && "popped invalid state.");
(void)current;
} }
int int
@ -774,7 +788,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
goto done; goto done;
} }
val = d->null_term; val = d->null_term;
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
d->i += 4; d->i += 4;
break; break;
case 't': case 't':
@ -787,7 +801,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
goto done; goto done;
} }
val = d->atoms->atom_true; val = d->atoms->atom_true;
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
d->i += 4; d->i += 4;
break; break;
case 'f': case 'f':
@ -800,7 +814,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
goto done; goto done;
} }
val = d->atoms->atom_false; val = d->atoms->atom_false;
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
d->i += 5; d->i += 5;
break; break;
case '\"': case '\"':
@ -808,7 +822,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = dec_error(d, "invalid_string"); ret = dec_error(d, "invalid_string");
goto done; goto done;
} }
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
break; break;
case '-': case '-':
case '0': case '0':
@ -825,7 +839,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = dec_error(d, "invalid_number"); ret = dec_error(d, "invalid_number");
goto done; goto done;
} }
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
break; break;
case '{': case '{':
dec_push(d, st_object); dec_push(d, st_object);
@ -846,13 +860,12 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = dec_error(d, "invalid_json"); ret = dec_error(d, "invalid_json");
goto done; goto done;
} }
dec_pop(d, st_value);
if(dec_curr(d) != st_array) {
dec_pop_assert(d, st_value);
if(dec_pop(d) != st_array) {
ret = dec_error(d, "invalid_json"); ret = dec_error(d, "invalid_json");
goto done; goto done;
} }
dec_pop(d, st_array);
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
val = curr; // curr is [] val = curr; // curr is []
if(!enif_get_list_cell(env, objs, &curr, &objs)) { if(!enif_get_list_cell(env, objs, &curr, &objs)) {
ret = dec_error(d, "internal_error"); ret = dec_error(d, "internal_error");
@ -885,7 +898,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = dec_error(d, "invalid_string"); ret = dec_error(d, "invalid_string");
goto done; goto done;
} }
dec_pop(d, st_key);
dec_pop_assert(d, st_key);
dec_push(d, st_colon); dec_push(d, st_colon);
curr = enif_make_list_cell(env, val, curr); curr = enif_make_list_cell(env, val, curr);
break; break;
@ -894,9 +907,9 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = dec_error(d, "invalid_json"); ret = dec_error(d, "invalid_json");
goto done; goto done;
} }
dec_pop(d, st_key);
dec_pop(d, st_object);
dec_pop(d, st_value);
dec_pop_assert(d, st_key);
dec_pop_assert(d, st_object);
dec_pop_assert(d, st_value);
val = make_empty_object(env, d->return_maps); val = make_empty_object(env, d->return_maps);
if(!enif_get_list_cell(env, objs, &curr, &objs)) { if(!enif_get_list_cell(env, objs, &curr, &objs)) {
ret = dec_error(d, "internal_error"); ret = dec_error(d, "internal_error");
@ -925,7 +938,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
d->i++; d->i++;
break; break;
case ':': case ':':
dec_pop(d, st_colon);
dec_pop_assert(d, st_colon);
dec_push(d, st_value); dec_push(d, st_value);
d->i++; d->i++;
break; break;
@ -944,7 +957,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
d->i++; d->i++;
break; break;
case ',': case ',':
dec_pop(d, st_comma);
dec_pop_assert(d, st_comma);
switch(dec_curr(d)) { switch(dec_curr(d)) {
case st_object: case st_object:
dec_push(d, st_key); dec_push(d, st_key);
@ -959,13 +972,12 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
d->i++; d->i++;
break; break;
case '}': case '}':
dec_pop(d, st_comma);
if(dec_curr(d) != st_object) {
dec_pop_assert(d, st_comma);
if(dec_pop(d) != st_object) {
ret = dec_error(d, "invalid_json"); ret = dec_error(d, "invalid_json");
goto done; goto done;
} }
dec_pop(d, st_object);
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
if(!make_object(env, curr, &val, if(!make_object(env, curr, &val,
d->return_maps, d->dedupe_keys)) { d->return_maps, d->dedupe_keys)) {
ret = dec_error(d, "internal_object_error"); ret = dec_error(d, "internal_object_error");
@ -984,13 +996,12 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
d->i++; d->i++;
break; break;
case ']': case ']':
dec_pop(d, st_comma);
if(dec_curr(d) != st_array) {
dec_pop_assert(d, st_comma);
if(dec_pop(d) != st_array) {
ret = dec_error(d, "invalid_json"); ret = dec_error(d, "invalid_json");
goto done; goto done;
} }
dec_pop(d, st_array);
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
val = make_array(env, curr); val = make_array(env, curr);
if(!enif_get_list_cell(env, objs, &curr, &objs)) { if(!enif_get_list_cell(env, objs, &curr, &objs)) {
ret = dec_error(d, "internal_error"); ret = dec_error(d, "internal_error");
@ -1039,7 +1050,7 @@ decode_done:
goto done; goto done;
} }
if(dec_curr(d) != st_done) {
if(dec_pop(d) != st_done) {
ret = dec_error(d, "truncated_json"); ret = dec_error(d, "truncated_json");
} else if(d->is_partial) { } else if(d->is_partial) {
ret = enif_make_tuple2(env, d->atoms->atom_partial, val); ret = enif_make_tuple2(env, d->atoms->atom_partial, val);

正在加载...
取消
保存