diff options
author | Jo-Philipp Wich <jo@mein.io> | 2020-10-18 18:06:54 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2020-10-18 18:09:21 +0200 |
commit | 898a28de86600b62ddd5f971b910eaadc222bbb7 (patch) | |
tree | 7d4e18f136e50517f154c372f057937f1992ee77 | |
parent | d815d0e0ee00de41e792246ba1baddf1d68b0f59 (diff) |
ast, eval: add recursion limit
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r-- | ast.c | 9 | ||||
-rw-r--r-- | ast.h | 1 | ||||
-rw-r--r-- | eval.c | 5 | ||||
-rw-r--r-- | tests/02_runtime/06_recursion | 25 |
4 files changed, 37 insertions, 3 deletions
@@ -405,7 +405,7 @@ add_stacktrace(struct json_object *a, struct ut_source *source, const char *func __attribute__((format(printf, 3, 4))) struct json_object * ut_new_exception(struct ut_state *s, uint32_t off, const char *fmt, ...) { - struct ut_callstack *callstack; + struct ut_callstack *callstack, *prevcall; struct json_object *a; struct ut_op *op; va_list ap; @@ -425,8 +425,11 @@ ut_new_exception(struct ut_state *s, uint32_t off, const char *fmt, ...) s->function ? s->function->name : NULL, off); - for (callstack = s->callstack ? s->callstack->next : NULL; callstack; callstack = callstack->next) - if (callstack->off) + for (callstack = s->callstack ? s->callstack->next : NULL, prevcall = NULL; + callstack != NULL; + prevcall = callstack, callstack = callstack->next) + if (callstack->off && + (!prevcall || callstack->source != prevcall->source || callstack->off != prevcall->off)) add_stacktrace(a, callstack->source, callstack->funcname, callstack->off); json_object_object_add(op->val, "stacktrace", a); @@ -135,6 +135,7 @@ struct ut_state { struct ut_source *sources, *source; struct ut_callstack *callstack; struct ut_function *function; + size_t calldepth; }; struct ut_extended_type { @@ -981,12 +981,16 @@ ut_invoke(struct ut_state *state, uint32_t off, struct json_object *this, op = ut_get_op(state, off); + if (state->calldepth >= 1000) + return ut_new_exception(state, op->off, "Runtime error: Too much recursion"); + callstack.next = state->callstack; callstack.source = state->source; callstack.funcname = state->function ? state->function->name : NULL; callstack.off = op ? op->off : 0; callstack.ctx = json_object_get(this ? this : state->ctx); state->callstack = &callstack; + state->calldepth++; /* is native function */ if (tag->type == T_CFUNC) { @@ -1042,6 +1046,7 @@ ut_invoke(struct ut_state *state, uint32_t off, struct json_object *this, json_object_put(callstack.ctx); state->callstack = callstack.next; + state->calldepth--; return rv; } diff --git a/tests/02_runtime/06_recursion b/tests/02_runtime/06_recursion index e707c86..028feba 100644 --- a/tests/02_runtime/06_recursion +++ b/tests/02_runtime/06_recursion @@ -33,3 +33,28 @@ Testing recursive invocations. test(1); %} -- End -- + + +2. Testing infinite recursion. + +-- Expect stderr -- +Runtime error: Too much recursion +In test(), line 3, byte 7: + at function test ([stdin]:3:7) + at main function ([stdin]:6:6) + + ` test();` + Near here --^ + + +-- End -- + +-- Testcase -- +{% + function test() { + test(); + } + + test(); +%} +-- End -- |