From 94aecf41d6d39c3e83d33ddd018db0497465f61f Mon Sep 17 00:00:00 2001 From: Kjell Winblad Date: Wed, 6 Jan 2021 16:44:42 +0100 Subject: YCF: better debug support for checking nested yielding functions Add support for checking for pointers to any of the stack frames belonging to nested yielding functions. --- erts/lib_src/yielding_c_fun/README.md | 26 +++++++++++++++++- .../test/examples/debug_ptr_to_stack.c | 5 ++++ .../test_only_output_yielding_funs_ptr_to_stack.c | 31 ++++++++++++++++------ erts/lib_src/yielding_c_fun/test/test.sh | 1 + erts/lib_src/yielding_c_fun/ycf_yield_fun.c | 4 +++ 5 files changed, 58 insertions(+), 9 deletions(-) (limited to 'erts/lib_src') diff --git a/erts/lib_src/yielding_c_fun/README.md b/erts/lib_src/yielding_c_fun/README.md index 2cba57a3e8..b57c2847bc 100644 --- a/erts/lib_src/yielding_c_fun/README.md +++ b/erts/lib_src/yielding_c_fun/README.md @@ -145,7 +145,7 @@ Usage: yielding_c_fun [-h] * `-fexternal function_name` - YCF expects that a yielding verison of the function called + YCF expects that a yielding version of the function called `function_name` is generated externally. Calls to the function called `function_name` from yielding functions calls the externally generated yielding version of the function called `function_name`. @@ -167,6 +167,30 @@ Usage: yielding_c_fun [-h] to data that is allocated on the call stack. The program crashes with an error message if any such pointer is found. + The generated debug code depends on that a function called + `ycf_debug_get_stack_start()` is declared somewhere in the + program. The `ycf_debug_get_stack_start()` functions should return a + value of type `void*`. Example: + + static _Thread_local void* ycf_debug_global_stack_start_ptr = NULL; + void* ycf_debug_get_stack_start() { + return ycf_debug_global_stack_start_ptr; + } + + If `ycf_debug_get_stack_start()` returns `NULL`, the value of the + `ycf_yield_state` parameter will be used as the start of the stack (it + is assumed that the stack grows towards lower addresses). If + `ycf_debug_get_stack_start()` returns something different than `NULL`, + that value will be used as the start of the stack. To check that + nested yielding functions do not have pointers to the call stack, + one have to make sure that `ycf_debug_get_stack_start()` returns + something different than `NULL` (otherwise, each function will just + check for pointers to its own frame). Example: + + ycf_debug_global_stack_start_ptr = &wb; + ret = fun_ycf_gen_yielding(&nr_of_reductions,&wb,NULL,allocator,freer,NULL,0,NULL,1); + ycf_debug_global_stack_start_ptr = NULL; + * `-only_yielding_funs` Print only the generated functions and struct declarations. The diff --git a/erts/lib_src/yielding_c_fun/test/examples/debug_ptr_to_stack.c b/erts/lib_src/yielding_c_fun/test/examples/debug_ptr_to_stack.c index 76d500de24..cda48d8b2e 100644 --- a/erts/lib_src/yielding_c_fun/test/examples/debug_ptr_to_stack.c +++ b/erts/lib_src/yielding_c_fun/test/examples/debug_ptr_to_stack.c @@ -1,6 +1,11 @@ #include #include +void* ycf_debug_global_stack_top_ptr = NULL; +void* ycf_debug_get_stack_start(){ + return ycf_debug_global_stack_top_ptr; +} + #define YCF_YIELD() int fun(){ diff --git a/erts/lib_src/yielding_c_fun/test/examples/test_only_output_yielding_funs_ptr_to_stack.c b/erts/lib_src/yielding_c_fun/test/examples/test_only_output_yielding_funs_ptr_to_stack.c index 66ed83858f..78973496e8 100644 --- a/erts/lib_src/yielding_c_fun/test/examples/test_only_output_yielding_funs_ptr_to_stack.c +++ b/erts/lib_src/yielding_c_fun/test/examples/test_only_output_yielding_funs_ptr_to_stack.c @@ -1,25 +1,38 @@ + #include #include +void* ycf_debug_global_stack_start_ptr = NULL; +void* ycf_debug_get_stack_start(){ + return ycf_debug_global_stack_start_ptr; +} #define YCF_YIELD() -int empty_fun(){ - return 1; +int fun2(char* to_stack_in_other_fun){ + char value = *to_stack_in_other_fun; + YCF_YIELD(); + if (value == 42) { + return 1; + } else { + return 0; + } } #include "tmp.ycf.h" static int fun(char x){ - char array[10]; - array[4] = 42; - char *to_stack = &array[4]; + char array[1]; + array[0] = 42; + char *to_stack = &array[0]; x = x + 1; /* x == 2*/ - YCF_YIELD(); printf("ptr to: %d", (int)(*to_stack)); x = x + 1; /* x == 3*/ { - int hej = !!empty_fun(); - return x + hej; + int hej = 0; + hej = fun2(to_stack); + YCF_YIELD(); + to_stack = NULL; + return x + hej; } } @@ -43,7 +56,9 @@ int main( int argc, const char* argv[] ) (void)fun; #ifdef YCF_YIELD_CODE_GENERATED do{ + ycf_debug_global_stack_start_ptr = &wb; ret = fun_ycf_gen_yielding(&nr_of_reductions,&wb,NULL,allocator,freer,NULL,0,NULL,1); + ycf_debug_global_stack_start_ptr = NULL; if(wb != NULL){ printf("TRAPPED\n"); } diff --git a/erts/lib_src/yielding_c_fun/test/test.sh b/erts/lib_src/yielding_c_fun/test/test.sh index e380d040b5..e1b392d969 100755 --- a/erts/lib_src/yielding_c_fun/test/test.sh +++ b/erts/lib_src/yielding_c_fun/test/test.sh @@ -166,6 +166,7 @@ yielding_c_fun.bin $GC $RR -yield \ -debug \ -only_yielding_funs \ -fnoauto fun \ + -fnoauto fun2 \ -output_file_name $TMP_INC_FILE \ "$DIR/examples/test_only_output_yielding_funs_ptr_to_stack.c" $CC $CC_ARGS -I "$TMP_DIR" "$DIR/examples/test_only_output_yielding_funs_ptr_to_stack.c" -o $TMP_CC_OUT diff --git a/erts/lib_src/yielding_c_fun/ycf_yield_fun.c b/erts/lib_src/yielding_c_fun/ycf_yield_fun.c index 286a13cabf..8f3fe94441 100644 --- a/erts/lib_src/yielding_c_fun/ycf_yield_fun.c +++ b/erts/lib_src/yielding_c_fun/ycf_yield_fun.c @@ -870,9 +870,13 @@ void ast_add_yield_code_generated_define(ycf_node* source_out_tree/*Will be chan " return bottom();\n" " }\n" "}\n" + "void* ycf_debug_get_stack_start();\n" "#include \n" "static void ycf_debug_check_block(char* struct_name, void* stack_start, void* stack_end, void* block, size_t block_size) {\n" " char* p;\n" + " if (ycf_debug_get_stack_start() != NULL) {\n" + " stack_end = ycf_debug_get_stack_start();\n" + " }\n" " for (p = block; p < (((char*)block) + block_size); p += sizeof(void*)) {\n" " if(*((char**)p) > (char*)stack_start && *((char**)p) <= (char*)stack_end){\n" " fprintf(stderr, \"Pointer to stack in yielded functions state!!!!! (pointer_address=%p, pointer_value=%p, struct %s,offset=%lu)\\n\", (void*)p, *((void**)p), struct_name, (unsigned long)(p-(size_t)block));\n" -- cgit v1.2.1