From c8d9c099b78f5771a0faa420828be4e574040736 Mon Sep 17 00:00:00 2001 From: Alexander Motzkau Date: Tue, 14 Feb 2023 22:24:25 +0100 Subject: [PATCH] Fix crash (bad stack) when calling coroutines with efun::trace() When efun::trace() is active, the stack pointer was modified in a wrong way when executing a yield() statement. --- src/interpret.c | 4 ++- test/t-trace-coroutine.c | 60 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 test/t-trace-coroutine.c diff --git a/src/interpret.c b/src/interpret.c index a2f9f50a..cd0c2c8a 100644 --- a/src/interpret.c +++ b/src/interpret.c @@ -10042,6 +10042,8 @@ eval_instruction (bytecode_p first_instruction sp = restore_argument_frames(sp-1, &ap)+1; if (sp < inter_sp) *sp = *inter_sp; + + tracedepth++; } SET_TRACE_EXEC(); @@ -11389,7 +11391,7 @@ again: tracedepth--; /* We leave this level */ if (trace_level) - do_trace_return(sp); + do_trace_return(inter_sp); pop_control_stack(); diff --git a/test/t-trace-coroutine.c b/test/t-trace-coroutine.c new file mode 100644 index 00000000..2fd09d16 --- /dev/null +++ b/test/t-trace-coroutine.c @@ -0,0 +1,60 @@ +#include "/inc/base.inc" +#include "/inc/client.inc" + +#include "/sys/trace.h" + +/* We test calling coroutines while efun::trace() is active. */ + +void run_server() +{ + efun::trace(TRACE_CALL_OTHER|TRACE_RETURN|TRACE_ARGS); + + coroutine cr = async function void() + { + yield("A"); + yield("B"); + yield("C"); + }; + + foreach(string str: cr) + if (!stringp(str)) + { + efun::shutdown(1); + return; + } + + efun::trace(TRACE_NOTHING); + + /* The test succeeds, if we didn't crash. */ + call_out(#'efun::shutdown,0,0); +} + +void run_client() +{ + input_to("client_input"); +} + +void client_input(string str) +{ + input_to("client_input"); +} + +void run_test() +{ + msg("\nRunning test for tracing with coroutines:\n" + "-----------------------------------------\n"); + + /* For efun::trace() we need an interactive object. */ + connect_self("run_server", "run_client"); +} + +string *epilog(int eflag) +{ + run_test(); + return 0; +} + +int valid_trace(string what, int|string arg) +{ + return 1; +}