summaryrefslogtreecommitdiff
path: root/erts/lib_src
diff options
context:
space:
mode:
authorKjell Winblad <kjellwinblad@gmail.com>2021-01-06 16:44:42 +0100
committerKjell Winblad <kjellwinblad@gmail.com>2021-02-12 13:54:26 +0100
commit94aecf41d6d39c3e83d33ddd018db0497465f61f (patch)
tree89e5aff40fb83047eb036af3fe37c46af33f294c /erts/lib_src
parentbb1207ebb454d23d69de7b309c1db0b43b61667a (diff)
downloaderlang-94aecf41d6d39c3e83d33ddd018db0497465f61f.tar.gz
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.
Diffstat (limited to 'erts/lib_src')
-rw-r--r--erts/lib_src/yielding_c_fun/README.md26
-rw-r--r--erts/lib_src/yielding_c_fun/test/examples/debug_ptr_to_stack.c5
-rw-r--r--erts/lib_src/yielding_c_fun/test/examples/test_only_output_yielding_funs_ptr_to_stack.c31
-rwxr-xr-xerts/lib_src/yielding_c_fun/test/test.sh1
-rw-r--r--erts/lib_src/yielding_c_fun/ycf_yield_fun.c4
5 files changed, 58 insertions, 9 deletions
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 <stdio.h>
#include <stdlib.h>
+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 <stdio.h>
#include <stdlib.h>
+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 <signal.h>\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"