I am trying to implement a coroutine, but in my code, I specified ctx_main
for uc_lick
, but after the execution of the subroutine routine2
corresponding to ucontext_t
, the program exits directly instead of returning to the main
function to continue execution.
I have read the linux manual. According to my understanding, it should be possible to return to the main
function after the subroutine is executed, but currently only routine1
returns to main after the execution, and the program exits directly after routine2
is executed.
And the exit status code is the return value of the last function in routine2
(19, the return value of printf
). Why is this happening?
#include <stdio.h>
#include <ucontext.h>
typedef void (*coroutine_func)();
#define STACK_SIZE (1<<15)
ucontext_t ctx_main;
ucontext_t c1, c2;
ucontext_t create_ctx(coroutine_func func, ucontext_t *ret_ctx) {
ucontext_t ctx;
getcontext(&ctx);
char stack[STACK_SIZE];
ctx.uc_stack.ss_sp = stack;
ctx.uc_stack.ss_size = sizeof(stack);
ctx.uc_link = ret_ctx;
makecontext(&ctx, func, 0);
return ctx;
}
void routine1() {
printf("routine1 running\n");
swapcontext(&c1, &c2);
printf("routine1 returning\n");
}
void routine2() {
printf("routine2 running\n");
swapcontext(&c2, &c1);
printf("routine2 returning\n"); // return value is 19
}
int main() {
c1 = create_ctx(routine1, &ctx_main);
c2 = create_ctx(routine2, &ctx_main);
swapcontext(&ctx_main, &c1);
swapcontext(&ctx_main, &c2);
// Will not run to here, exit after routine2 is executed.
printf("main exiting.\n");
return 0;
}
result:
routine1 running
routine2 running
routine1 returning
routine2 returning
Process finished with exit code 19
CodePudding user response:
You are using a variable after it stops existing.
ucontext_t create_ctx(coroutine_func func, ucontext_t *ret_ctx) {
char stack[STACK_SIZE]; // allocated on stack
ctx.uc_stack.ss_sp = stack;
return ctx; // ss_sp is invalid pointer
} // variable stack stops existing
You have to allocate memory with enough lifetime. For example:
char *stack = malloc(STACK_SIZE);
ctx.uc_stack.ss_sp = stack;
ctx.uc_stack.ss_size = STACK_SIZE;
How to check: compile with sanitizer options, they will help you debug your programs:
gcc -D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS -fstack-clash-protection -fstack-protector-all -fstack-protector-strong -ggdb3 -grecord-gcc-switches -fcf-protection -O -Wall -Wextra -Wwrite-strings -Wno-unused-function -Wno-unused-parameter -Wno-implicit-function-declaration -fsanitize=address,undefined,pointer-compare,pointer-subtract /tmp/1.c
==1265711==WARNING: ASan doesn't fully support makecontext/swapcontext functions and may produce false positives in some cases!
routine1 running
routine2 running
routine2 returning
*** stack smashing detected ***: terminated