summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-10-15 18:13:51 +0200
committerJo-Philipp Wich <jo@mein.io>2020-10-15 18:47:39 +0200
commit6bbc6137d2bc0ec79e740ea50e6edee0496bcf85 (patch)
treecd61c61242b83000bbe34d1c14bf52fd9edd2318
parentbbeeb113926ba117791f67d49487edb908bf8893 (diff)
eval: fix potential segfault in for() loops
When a for() loop body, initializer, test or increment expression compiles further code, e.g. by invoking invoke() or require(), the opcode pool will be reallocated, potentially changing the addresses of all opcodes. This might lead to an invalid memory access when previously cached opcode pointers are accessed later on. Solve this issue by obtaining the relative offsets of the corresponding opcodes, avoiding the need for pointer dereferences. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--eval.c36
1 files changed, 17 insertions, 19 deletions
diff --git a/eval.c b/eval.c
index 2dbb4c8..1eff9fc 100644
--- a/eval.c
+++ b/eval.c
@@ -469,12 +469,12 @@ ut_execute_if(struct ut_state *state, uint32_t off)
static struct json_object *
ut_execute_for(struct ut_state *state, uint32_t off)
{
- struct json_object *scope, *val, *item, *rv = NULL;
+ struct json_object *scope, *val, *item, *iv, *rv = NULL;
struct ut_op *loop = ut_get_op(state, off);
struct ut_op *init = ut_get_child(state, off, 0);
- struct ut_op *test = ut_get_child(state, off, 1);
- struct ut_op *incr = ut_get_child(state, off, 2);
- struct ut_op *body = ut_get_child(state, off, 3);
+ uint32_t test = loop ? loop->tree.operand[1] : 0;
+ uint32_t incr = loop ? loop->tree.operand[2] : 0;
+ uint32_t body = loop ? loop->tree.operand[3] : 0;
struct ut_op *ivar, *tag;
size_t arridx, arrlen;
bool local = false;
@@ -496,28 +496,26 @@ ut_execute_for(struct ut_state *state, uint32_t off)
return ut_new_exception(state, init->off,
"Syntax error: invalid for-in left-hand side");
+ iv = ivar->val;
+ scope = local ? state->scope->scope : ut_getref(state, ut_get_off(state, ivar), NULL);
+
+ if (ut_is_type(scope, T_EXCEPTION))
+ return scope;
+
val = ut_execute_op(state, init->tree.operand[1]);
if (ut_is_type(val, T_EXCEPTION))
return val;
- scope = local ? state->scope->scope : ut_getref(state, ut_get_off(state, ivar), NULL);
-
- if (ut_is_type(scope, T_EXCEPTION)) {
- json_object_put(val);
-
- return scope;
- }
-
if (json_object_is_type(val, json_type_array)) {
for (arridx = 0, arrlen = json_object_array_length(val);
arridx < arrlen; arridx++) {
item = json_object_array_get_idx(val, arridx);
- ut_setval(scope, ivar->val, item);
+ ut_setval(scope, iv, item);
json_object_put(rv);
- rv = ut_execute_op_sequence(state, ut_get_off(state, body));
+ rv = ut_execute_op_sequence(state, body);
tag = json_object_get_userdata(rv);
switch (tag ? tag->type : 0) {
@@ -537,10 +535,10 @@ ut_execute_for(struct ut_state *state, uint32_t off)
}
else if (json_object_is_type(val, json_type_object)) {
json_object_object_foreach(val, key, item) {
- ut_setval(scope, ivar->val, xjs_new_string(key));
+ ut_setval(scope, iv, xjs_new_string(key));
json_object_put(rv);
- rv = ut_execute_op_sequence(state, ut_get_off(state, body));
+ rv = ut_execute_op_sequence(state, body);
tag = json_object_get_userdata(rv);
switch (tag ? tag->type : 0) {
@@ -574,10 +572,10 @@ ut_execute_for(struct ut_state *state, uint32_t off)
json_object_put(val);
}
- while (test ? ut_test_condition(state, ut_get_off(state, test)) : true) {
+ while (test ? ut_test_condition(state, test) : true) {
json_object_put(rv);
- rv = ut_execute_op_sequence(state, ut_get_off(state, body));
+ rv = ut_execute_op_sequence(state, body);
tag = json_object_get_userdata(rv);
switch (tag ? tag->type : 0) {
@@ -592,7 +590,7 @@ ut_execute_for(struct ut_state *state, uint32_t off)
}
if (incr) {
- val = ut_execute_op_sequence(state, ut_get_off(state, incr));
+ val = ut_execute_op_sequence(state, incr);
if (ut_is_type(val, T_EXCEPTION)) {
json_object_put(rv);