summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-10-18 18:06:54 +0200
committerJo-Philipp Wich <jo@mein.io>2020-10-18 18:09:21 +0200
commit898a28de86600b62ddd5f971b910eaadc222bbb7 (patch)
tree7d4e18f136e50517f154c372f057937f1992ee77
parentd815d0e0ee00de41e792246ba1baddf1d68b0f59 (diff)
ast, eval: add recursion limit
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--ast.c9
-rw-r--r--ast.h1
-rw-r--r--eval.c5
-rw-r--r--tests/02_runtime/06_recursion25
4 files changed, 37 insertions, 3 deletions
diff --git a/ast.c b/ast.c
index 72fa6e9..2e1c169 100644
--- a/ast.c
+++ b/ast.c
@@ -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);
diff --git a/ast.h b/ast.h
index f86d93f..26eee73 100644
--- a/ast.h
+++ b/ast.h
@@ -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 {
diff --git a/eval.c b/eval.c
index 2230bb9..3d76774 100644
--- a/eval.c
+++ b/eval.c
@@ -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 --