Hi, Instrumented function pointer may be propagated into not instrumented indirect call and vice versa. It requires additional call modifications (either remove bounds or change callee). Bootstrapped and tested on x86_64-unknown-linux-gnu. OK for trunk?
Thanks, Ilya -- gcc/ 2015-03-12 Ilya Enkovich <ilya.enkov...@intel.com> * cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Add redirection for instrumented calls. * tree-chkp.h (chkp_copy_call_skip_bounds): New. (chkp_redirect_edge): New. * tree-chkp.c (chkp_copy_call_skip_bounds): New. (chkp_redirect_edge): New. gcc/testsuite/ 2015-03-12 Ilya Enkovich <ilya.enkov...@intel.com> * gcc.target/i386/mpx/chkp-fix-calls-1.c: New. * gcc.target/i386/mpx/chkp-fix-calls-2.c: New. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 5ca1901..a0b0465 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1278,14 +1278,25 @@ cgraph_edge::redirect_call_stmt_to_callee (void) { cgraph_edge *e = this; - tree decl = gimple_call_fndecl (e->call_stmt); - tree lhs = gimple_call_lhs (e->call_stmt); + tree decl; + tree lhs; gcall *new_stmt; gimple_stmt_iterator gsi; + bool skip_bounds = false; #ifdef ENABLE_CHECKING cgraph_node *node; #endif + /* We might propagate instrumented function pointer into + not instrumented function and vice versa. In such a + case we need to either fix function declaration or + remove bounds from call statement. */ + if (callee) + skip_bounds = chkp_redirect_edge (e); + + decl = gimple_call_fndecl (e->call_stmt); + lhs = gimple_call_lhs (e->call_stmt); + if (e->speculative) { cgraph_edge *e2; @@ -1391,7 +1402,8 @@ cgraph_edge::redirect_call_stmt_to_callee (void) } if (e->indirect_unknown_callee - || decl == e->callee->decl) + || (decl == e->callee->decl + && !skip_bounds)) return e->call_stmt; #ifdef ENABLE_CHECKING @@ -1416,13 +1428,19 @@ cgraph_edge::redirect_call_stmt_to_callee (void) } } - if (e->callee->clone.combined_args_to_skip) + if (e->callee->clone.combined_args_to_skip + || skip_bounds) { int lp_nr; - new_stmt - = gimple_call_copy_skip_args (e->call_stmt, - e->callee->clone.combined_args_to_skip); + new_stmt = e->call_stmt; + if (e->callee->clone.combined_args_to_skip) + new_stmt + = gimple_call_copy_skip_args (new_stmt, + e->callee->clone.combined_args_to_skip); + if (skip_bounds) + new_stmt = chkp_copy_call_skip_bounds (new_stmt); + gimple_call_set_fndecl (new_stmt, e->callee->decl); gimple_call_set_fntype (new_stmt, gimple_call_fntype (e->call_stmt)); diff --git a/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-1.c b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-1.c new file mode 100644 index 0000000..cb4d229 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fcheck-pointer-bounds -mmpx" } */ + +#include "math.h" + +double +test1 (double x, double y, double (*fn)(double, double)) +{ + return fn (x, y); +} + +double +test2 (double x, double y) +{ + return test1 (x, y, copysign); +} diff --git a/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-2.c b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-2.c new file mode 100644 index 0000000..951e7de --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcheck-pointer-bounds -mmpx -fno-inline" } */ + +#include "math.h" + +double +test1 (double x, double y, double (*fn)(double, double)) +{ + return fn (x, y); +} + +double +test2 (double x, double y) +{ + return test1 (x, y, copysign); +} diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c index d2df4ba..2d2090f 100644 --- a/gcc/tree-chkp.c +++ b/gcc/tree-chkp.c @@ -500,6 +500,62 @@ chkp_expand_bounds_reset_for_mem (tree mem, tree ptr) expand_normal (bndstx); } +/* Build a GIMPLE_CALL identical to CALL but skipping bounds + arguments. */ + +gcall * +chkp_copy_call_skip_bounds (gcall *call) +{ + bitmap bounds; + unsigned i; + + bitmap_obstack_initialize (NULL); + bounds = BITMAP_ALLOC (NULL); + + for (i = 0; i < gimple_call_num_args (call); i++) + if (POINTER_BOUNDS_P (gimple_call_arg (call, i))) + bitmap_set_bit (bounds, i); + + call = gimple_call_copy_skip_args (call, bounds); + gimple_call_set_with_bounds (call, false); + + BITMAP_FREE (bounds); + bitmap_obstack_release (NULL); + + return call; +} + +/* Redirect edge E to the correct node according to call_stmt. + Return 1 if bounds removal from call_stmt should be done + instead of redirection. */ + +bool +chkp_redirect_edge (cgraph_edge *e) +{ + bool instrumented = false; + + if (e->callee->instrumentation_clone + || chkp_function_instrumented_p (e->callee->decl)) + instrumented = true; + + if (instrumented + && !gimple_call_with_bounds_p (e->call_stmt)) + e->redirect_callee (cgraph_node::get_create (e->callee->orig_decl)); + else if (!instrumented + && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCL) + && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCU) + && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDSTX) + && gimple_call_with_bounds_p (e->call_stmt)) + { + if (e->callee->instrumented_version) + e->redirect_callee (e->callee->instrumented_version); + else + return true; + } + + return false; +} + /* Mark statement S to not be instrumented. */ static void chkp_mark_stmt (gimple s) diff --git a/gcc/tree-chkp.h b/gcc/tree-chkp.h index 86f3618..40e2489 100644 --- a/gcc/tree-chkp.h +++ b/gcc/tree-chkp.h @@ -54,5 +54,7 @@ extern void chkp_copy_bounds_for_assign (gimple assign, extern bool chkp_gimple_call_builtin_p (gimple call, enum built_in_function code); extern void chkp_expand_bounds_reset_for_mem (tree mem, tree ptr); +extern gcall *chkp_copy_call_skip_bounds (gcall *call); +extern bool chkp_redirect_edge (cgraph_edge *e); #endif /* GCC_TREE_CHKP_H */