1
0
mirror of https://github.com/stedolan/jq.git synced 2024-05-11 05:55:39 +00:00

detect invalid path expression (fix #862)

This commit is contained in:
David Tolnay
2015-07-22 20:48:26 -07:00
parent 5856a2d2c0
commit 16e8d0b1ab
4 changed files with 129 additions and 11 deletions

View File

@@ -34,6 +34,7 @@ struct jq_state {
stack_ptr fork_top;
jv path;
jv value_at_path;
int subexp_nest;
int debug_trace_enabled;
int initial_execution;
@@ -191,6 +192,7 @@ struct forkpoint {
stack_ptr saved_data_stack;
stack_ptr saved_curr_frame;
int path_len, subexp_nest;
jv value_at_path;
uint16_t* return_address;
};
@@ -210,20 +212,33 @@ void stack_save(jq_state *jq, uint16_t* retaddr, struct stack_pos sp){
fork->saved_curr_frame = jq->curr_frame;
fork->path_len =
jv_get_kind(jq->path) == JV_KIND_ARRAY ? jv_array_length(jv_copy(jq->path)) : 0;
fork->value_at_path = jv_copy(jq->value_at_path);
fork->subexp_nest = jq->subexp_nest;
fork->return_address = retaddr;
jq->stk_top = sp.saved_data_stack;
jq->curr_frame = sp.saved_curr_frame;
}
void path_append(jq_state* jq, jv component) {
static int path_intact(jq_state *jq, jv curr) {
if (jq->subexp_nest == 0 && jv_get_kind(jq->path) == JV_KIND_ARRAY) {
return jv_identical(curr, jv_copy(jq->value_at_path));
} else {
jv_free(curr);
return 1;
}
}
static void path_append(jq_state* jq, jv component, jv value_at_path) {
if (jq->subexp_nest == 0 && jv_get_kind(jq->path) == JV_KIND_ARRAY) {
int n1 = jv_array_length(jv_copy(jq->path));
jq->path = jv_array_append(jq->path, component);
int n2 = jv_array_length(jv_copy(jq->path));
assert(n2 == n1 + 1);
jv_free(jq->value_at_path);
jq->value_at_path = value_at_path;
} else {
jv_free(component);
jv_free(value_at_path);
}
}
@@ -253,6 +268,8 @@ uint16_t* stack_restore(jq_state *jq){
} else {
assert(path_len == 0);
}
jv_free(jq->value_at_path);
jq->value_at_path = fork->value_at_path;
jq->subexp_nest = fork->subexp_nest;
jq->fork_top = stack_pop_block(&jq->stk, jq->fork_top, sizeof(struct forkpoint));
return retaddr;
@@ -271,6 +288,8 @@ static void jq_reset(jq_state *jq) {
if (jv_get_kind(jq->path) != JV_KIND_INVALID)
jv_free(jq->path);
jq->path = jv_null();
jv_free(jq->value_at_path);
jq->value_at_path = jv_null();
jq->subexp_nest = 0;
}
@@ -536,17 +555,29 @@ jv jq_next(jq_state *jq) {
stack_save(jq, pc - 1, stack_get_pos(jq));
stack_push(jq, jv_number(jq->subexp_nest));
stack_push(jq, v);
stack_push(jq, jq->value_at_path);
stack_push(jq, jv_copy(v));
jq->path = jv_array();
jq->value_at_path = v; // next INDEX operation must index into v
jq->subexp_nest = 0;
break;
}
case PATH_END: {
jv v = stack_pop(jq);
// detect invalid path expression like path(.a | reverse)
if (!path_intact(jq, jv_copy(v))) {
char errbuf[30];
jv msg = jv_string_fmt(
"Invalid path expression with result %s",
jv_dump_string_trunc(v, errbuf, sizeof(errbuf)));
set_error(jq, jv_invalid_with_msg(msg));
goto do_backtrack;
}
jv_free(v); // discard value, only keep path
jv old_value_at_path = stack_pop(jq);
int old_subexp_nest = (int)jv_number_value(stack_pop(jq));
jv path = jq->path;
@@ -558,6 +589,8 @@ jv jq_next(jq_state *jq) {
stack_push(jq, path);
jq->subexp_nest = old_subexp_nest;
jv_free(jq->value_at_path);
jq->value_at_path = old_value_at_path;
break;
}
@@ -572,11 +605,23 @@ jv jq_next(jq_state *jq) {
case INDEX_OPT: {
jv t = stack_pop(jq);
jv k = stack_pop(jq);
path_append(jq, jv_copy(k));
jv v = jv_get(t, k);
// detect invalid path expression like path(reverse | .a)
if (!path_intact(jq, jv_copy(t))) {
char keybuf[15];
char objbuf[30];
jv msg = jv_string_fmt(
"Invalid path expression near attempt to access element %s of %s",
jv_dump_string_trunc(k, keybuf, sizeof(keybuf)),
jv_dump_string_trunc(t, objbuf, sizeof(objbuf)));
set_error(jq, jv_invalid_with_msg(msg));
goto do_backtrack;
}
jv v = jv_get(t, jv_copy(k));
if (jv_is_valid(v)) {
path_append(jq, k, jv_copy(v));
stack_push(jq, v);
} else {
jv_free(k);
if (opcode == INDEX)
set_error(jq, v);
else
@@ -605,9 +650,21 @@ jv jq_next(jq_state *jq) {
}
case EACH:
case EACH_OPT:
case EACH_OPT: {
jv container = stack_pop(jq);
// detect invalid path expression like path(reverse | .[])
if (!path_intact(jq, jv_copy(container))) {
char errbuf[30];
jv msg = jv_string_fmt(
"Invalid path expression near attempt to iterate through %s",
jv_dump_string_trunc(container, errbuf, sizeof(errbuf)));
set_error(jq, jv_invalid_with_msg(msg));
goto do_backtrack;
}
stack_push(jq, container);
stack_push(jq, jv_number(-1));
// fallthrough
}
case ON_BACKTRACK(EACH):
case ON_BACKTRACK(EACH_OPT): {
int idx = jv_number_value(stack_pop(jq));
@@ -653,14 +710,14 @@ jv jq_next(jq_state *jq) {
} else if (is_last) {
// we don't need to make a backtrack point
jv_free(container);
path_append(jq, key);
path_append(jq, key, jv_copy(value));
stack_push(jq, value);
} else {
struct stack_pos spos = stack_get_pos(jq);
stack_push(jq, container);
stack_push(jq, jv_number(idx));
stack_save(jq, pc - 1, spos);
path_append(jq, key);
path_append(jq, key, jv_copy(value));
stack_push(jq, value);
}
break;
@@ -880,6 +937,7 @@ jq_state *jq_init(void) {
jq->attrs = jv_object();
jq->path = jv_null();
jq->value_at_path = jv_null();
return jq;
}

31
jv.c
View File

@@ -137,10 +137,7 @@ static void jvp_invalid_free(jv x) {
*/
jv jv_number(double x) {
jv j;
j.kind_flags = JV_KIND_NUMBER;
j.size = 0;
j.u.number = x;
jv j = {JV_KIND_NUMBER, 0, 0, 0, {.number = x}};
return j;
}
@@ -1291,6 +1288,32 @@ int jv_equal(jv a, jv b) {
return r;
}
int jv_identical(jv a, jv b) {
int r;
if (a.kind_flags != b.kind_flags
|| a.offset != b.offset
|| a.size != b.size) {
r = 0;
} else {
switch (jv_get_kind(a)) {
case JV_KIND_ARRAY:
case JV_KIND_STRING:
case JV_KIND_OBJECT:
r = a.u.ptr == b.u.ptr;
break;
case JV_KIND_NUMBER:
r = a.u.number == b.u.number;
break;
default:
r = 1;
break;
}
}
jv_free(a);
jv_free(b);
return r;
}
int jv_contains(jv a, jv b) {
int r = 1;
if (jv_get_kind(a) != jv_get_kind(b)) {

1
jv.h
View File

@@ -46,6 +46,7 @@ void jv_free(jv);
int jv_get_refcnt(jv);
int jv_equal(jv, jv);
int jv_identical(jv, jv);
int jv_contains(jv, jv);
jv jv_invalid(void);

View File

@@ -695,6 +695,26 @@ path(.)
42
[]
try path(.a | map(select(.b == 0))) catch .
{"a":[{"b":0}]}
"Invalid path expression with result [{\"b\":0}]"
try path(.a | map(select(.b == 0)) | .[0]) catch .
{"a":[{"b":0}]}
"Invalid path expression near attempt to access element 0 of [{\"b\":0}]"
try path(.a | map(select(.b == 0)) | .c) catch .
{"a":[{"b":0}]}
"Invalid path expression near attempt to access element \"c\" of [{\"b\":0}]"
try path(.a | map(select(.b == 0)) | .[]) catch .
{"a":[{"b":0}]}
"Invalid path expression near attempt to iterate through [{\"b\":0}]"
path(.a[path(.b)[0]])
{"a":{"b":0}}
["a","b"]
[paths]
[1,[[],{"a":2}]]
[[0],[1],[1,0],[1,1],[1,1,"a"]]
@@ -783,6 +803,22 @@ def inc(x): x |= .+1; inc(.[].a)
{"foo":[11], "bar":42}
{"foo":[11,null,{"bar":1}], "bar":42}
try ((map(select(.a == 1))[].b) = 10) catch .
[{"a":0},{"a":1}]
"Invalid path expression near attempt to iterate through [{\"a\":1}]"
try ((map(select(.a == 1))[].a) |= .+1) catch .
[{"a":0},{"a":1}]
"Invalid path expression near attempt to iterate through [{\"a\":1}]"
def x: .[1,2]; x=10
[0,1,2]
[0,10,10]
try (def x: reverse; x=10) catch .
[0,1,2]
"Invalid path expression with result [2,1,0]"
#
# Conditionals
#