Re: [PATCH] Optionally trap on impossible devirtualization
On Fri, Apr 25, 2014 at 5:35 PM, Martin Jambor mjam...@suse.cz wrote: Hi, the patch below might be useful for testcase preparation and debugging compiler bugs such as PR 60965. When -ftrap-on-impossible-devirtualization is supplied on the command line, it makes the devirtualization produce __builtin_trap instead of __builtin_unreachable when it comes to the conclusion that there is no legal target of a virtual call. Apart from dealing with our bugs, it may be even useful to debug compiled programs when a user triggers some sort of illegal devirtualization, typically by missing a type check somewhere. Currently the compiled program might simply take a wrong branch, with the patch it will abort. Bootstrapped and tested (with the option on) on x86_64-linux, I have also successfully LTO built Firefox with it. If I add some documentation, would like to see this in trunk? It's useful for debugging, so yes. Not sure about the option name though. Maybe we should have a generic -ftrap-on-unreachable flag instead and handle all __builtin_unreachable () like that (for example by folding or by simply make __builtin_unreachable () alias to __builtin_trap ()). Richard. Thanks, Martin 2014-04-03 Martin Jambor mjam...@suse.cz * cgraph.c (verify_edge_corresponds_to_fndecl): Also always accept builtin_trap. * cgraphclones.c (cgraph_clone_node): Do not redirect calls to builtin_trap. * cgraphunit.c (walk_polymorphic_call_targets): Use ipa_impossible_devirt_target_node. * common.opt (ftrap-on-impossible-devirtualization): New option. * gimple-fold.c (fold_gimple_assign): Use ipa_impossible_devirt_target_decl. (gimple_fold_call): Likewise. (gimple_get_virt_method_for_vtable): Likewise. * ipa-cp.c (ipa_get_indirect_edge_target_1): Check also for builtin_trap, use ipa_impossible_devirt_target_decl. * ipa-devirt.c (ipa_impossible_devirt_target_decl): New function. (ipa_impossible_devirt_target_node): Likewise. * ipa-prop.c (ipa_make_edge_direct_to_target): Use ipa_impossible_devirt_target_decl. (try_make_edge_direct_virtual_call): Check also for builtin_trap, use ipa_impossible_devirt_target_decl. * ipa-utils.h (ipa_impossible_devirt_target_decl): Declare. (ipa_impossible_devirt_target_node): Likewise. * ipa.c (walk_polymorphic_call_targets): Use ipa_impossible_devirt_target_node. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index be3661a..25e0775 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -2664,9 +2664,10 @@ verify_edge_corresponds_to_fndecl (struct cgraph_edge *e, tree decl) return false; /* Optimizers can redirect unreachable calls or calls triggering undefined - behaviour to builtin_unreachable. */ + behaviour to builtin_unreachable or builtin_trap. */ if (DECL_BUILT_IN_CLASS (e-callee-decl) == BUILT_IN_NORMAL - DECL_FUNCTION_CODE (e-callee-decl) == BUILT_IN_UNREACHABLE) + (DECL_FUNCTION_CODE (e-callee-decl) == BUILT_IN_UNREACHABLE + || DECL_FUNCTION_CODE (e-callee-decl) == BUILT_IN_TRAP)) return false; node = cgraph_function_or_thunk_node (node, NULL); diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c index cd2d73d..e7bebe3 100644 --- a/gcc/cgraphclones.c +++ b/gcc/cgraphclones.c @@ -449,8 +449,9 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, be unreachable during the clonning procedure. */ if (!e-callee || DECL_BUILT_IN_CLASS (e-callee-decl) != BUILT_IN_NORMAL - || DECL_FUNCTION_CODE (e-callee-decl) != BUILT_IN_UNREACHABLE) -redirect_edge_duplicating_thunks (e, new_node, args_to_skip); + || (DECL_FUNCTION_CODE (e-callee-decl) != BUILT_IN_UNREACHABLE + DECL_FUNCTION_CODE (e-callee-decl) != BUILT_IN_TRAP)) +cgraph_redirect_edge_callee (e, new_node); } diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 06283fc..6c56c90 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -892,8 +892,7 @@ walk_polymorphic_call_targets (pointer_set_t *reachable_call_targets, if (targets.length () == 1) target = targets[0]; else - target = cgraph_get_create_node - (builtin_decl_implicit (BUILT_IN_UNREACHABLE)); + target = ipa_impossible_devirt_target_node (); if (cgraph_dump_file) { diff --git a/gcc/common.opt b/gcc/common.opt index da275e5..3e8b359 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1019,6 +1019,10 @@ fdevirtualize Common Report Var(flag_devirtualize) Optimization Try to convert virtual calls to direct ones. +ftrap-on-impossible-devirtualization +Common Report Var(flag_trap_impossible_devirt) +Convert virtual calls that cannot have any target to builtin_trap. +
Re: [PATCH] Optionally trap on impossible devirtualization
On Mon, Apr 28, 2014 at 11:05:06AM +0200, Richard Biener wrote: On Fri, Apr 25, 2014 at 5:35 PM, Martin Jambor mjam...@suse.cz wrote: Hi, the patch below might be useful for testcase preparation and debugging compiler bugs such as PR 60965. When -ftrap-on-impossible-devirtualization is supplied on the command line, it makes the devirtualization produce __builtin_trap instead of __builtin_unreachable when it comes to the conclusion that there is no legal target of a virtual call. Apart from dealing with our bugs, it may be even useful to debug compiled programs when a user triggers some sort of illegal devirtualization, typically by missing a type check somewhere. Currently the compiled program might simply take a wrong branch, with the patch it will abort. Bootstrapped and tested (with the option on) on x86_64-linux, I have also successfully LTO built Firefox with it. If I add some documentation, would like to see this in trunk? It's useful for debugging, so yes. Not sure about the option name though. Maybe we should have a generic -ftrap-on-unreachable flag instead and handle all __builtin_unreachable () like that (for example by folding or by simply make __builtin_unreachable () alias to __builtin_trap ()). -fsanitize=unreachable should already do that. With -fsanitize=unreachable -fsanitize-undefined-trap-on-error it should fold __builtin_unreachable () to __builtin_trap (), otherwise to __ubsan_handle_builtin_unreachable () call. So, from this POV, the new option is redundant. Jakub
Re: [PATCH] Optionally trap on impossible devirtualization
On Mon, Apr 28, 2014 at 11:10:41AM +0200, Jakub Jelinek wrote: On Mon, Apr 28, 2014 at 11:05:06AM +0200, Richard Biener wrote: On Fri, Apr 25, 2014 at 5:35 PM, Martin Jambor mjam...@suse.cz wrote: Hi, the patch below might be useful for testcase preparation and debugging compiler bugs such as PR 60965. When -ftrap-on-impossible-devirtualization is supplied on the command line, it makes the devirtualization produce __builtin_trap instead of __builtin_unreachable when it comes to the conclusion that there is no legal target of a virtual call. Apart from dealing with our bugs, it may be even useful to debug compiled programs when a user triggers some sort of illegal devirtualization, typically by missing a type check somewhere. Currently the compiled program might simply take a wrong branch, with the patch it will abort. Bootstrapped and tested (with the option on) on x86_64-linux, I have also successfully LTO built Firefox with it. If I add some documentation, would like to see this in trunk? It's useful for debugging, so yes. Not sure about the option name though. Maybe we should have a generic -ftrap-on-unreachable flag instead and handle all __builtin_unreachable () like that (for example by folding or by simply make __builtin_unreachable () alias to __builtin_trap ()). -fsanitize=unreachable should already do that. With -fsanitize=unreachable -fsanitize-undefined-trap-on-error it should fold __builtin_unreachable () to __builtin_trap (), otherwise to __ubsan_handle_builtin_unreachable () call. So, from this POV, the new option is redundant. That sounds like good news except that it does not work, at least not for me when I tried it on the testcase from comment #2 from PR 60965. The behavior of the executable is just the same, I do not get any traps. Is this supposed to work at -O2? If so, should I file a ubsan bug? (If not, then I suppose some additional non-ubsan mechanism for this might be also useful.) Thanks, Martin
Re: [PATCH] Optionally trap on impossible devirtualization
On Mon, Apr 28, 2014 at 11:10:41AM +0200, Jakub Jelinek wrote: On Mon, Apr 28, 2014 at 11:05:06AM +0200, Richard Biener wrote: On Fri, Apr 25, 2014 at 5:35 PM, Martin Jambor mjam...@suse.cz wrote: Hi, the patch below might be useful for testcase preparation and debugging compiler bugs such as PR 60965. When -ftrap-on-impossible-devirtualization is supplied on the command line, it makes the devirtualization produce __builtin_trap instead of __builtin_unreachable when it comes to the conclusion that there is no legal target of a virtual call. Apart from dealing with our bugs, it may be even useful to debug compiled programs when a user triggers some sort of illegal devirtualization, typically by missing a type check somewhere. Currently the compiled program might simply take a wrong branch, with the patch it will abort. Bootstrapped and tested (with the option on) on x86_64-linux, I have also successfully LTO built Firefox with it. If I add some documentation, would like to see this in trunk? It's useful for debugging, so yes. Not sure about the option name though. Maybe we should have a generic -ftrap-on-unreachable flag instead and handle all __builtin_unreachable () like that (for example by folding or by simply make __builtin_unreachable () alias to __builtin_trap ()). -fsanitize=unreachable should already do that. With -fsanitize=unreachable -fsanitize-undefined-trap-on-error it should fold __builtin_unreachable () to __builtin_trap (), otherwise to __ubsan_handle_builtin_unreachable () call. So, from this POV, the new option is redundant. That sounds like good news except that it does not work, at least not for me when I tried it on the testcase from comment #2 from PR 60965. The behavior of the executable is just the same, I do not get any traps. Is this supposed to work at -O2? If so, should I file a ubsan bug? (If not, then I suppose some additional non-ubsan mechanism for this might be also useful.) As i wrote in the other email, I think the problem is when the transformation happen and if we re-fold the statement. Indeed, we ought to fix this. (It works in one of the PRs I looked into, but only for mainline, not for 4.9) Honza Thanks, Martin
[PATCH] Optionally trap on impossible devirtualization
Hi, the patch below might be useful for testcase preparation and debugging compiler bugs such as PR 60965. When -ftrap-on-impossible-devirtualization is supplied on the command line, it makes the devirtualization produce __builtin_trap instead of __builtin_unreachable when it comes to the conclusion that there is no legal target of a virtual call. Apart from dealing with our bugs, it may be even useful to debug compiled programs when a user triggers some sort of illegal devirtualization, typically by missing a type check somewhere. Currently the compiled program might simply take a wrong branch, with the patch it will abort. Bootstrapped and tested (with the option on) on x86_64-linux, I have also successfully LTO built Firefox with it. If I add some documentation, would like to see this in trunk? Thanks, Martin 2014-04-03 Martin Jambor mjam...@suse.cz * cgraph.c (verify_edge_corresponds_to_fndecl): Also always accept builtin_trap. * cgraphclones.c (cgraph_clone_node): Do not redirect calls to builtin_trap. * cgraphunit.c (walk_polymorphic_call_targets): Use ipa_impossible_devirt_target_node. * common.opt (ftrap-on-impossible-devirtualization): New option. * gimple-fold.c (fold_gimple_assign): Use ipa_impossible_devirt_target_decl. (gimple_fold_call): Likewise. (gimple_get_virt_method_for_vtable): Likewise. * ipa-cp.c (ipa_get_indirect_edge_target_1): Check also for builtin_trap, use ipa_impossible_devirt_target_decl. * ipa-devirt.c (ipa_impossible_devirt_target_decl): New function. (ipa_impossible_devirt_target_node): Likewise. * ipa-prop.c (ipa_make_edge_direct_to_target): Use ipa_impossible_devirt_target_decl. (try_make_edge_direct_virtual_call): Check also for builtin_trap, use ipa_impossible_devirt_target_decl. * ipa-utils.h (ipa_impossible_devirt_target_decl): Declare. (ipa_impossible_devirt_target_node): Likewise. * ipa.c (walk_polymorphic_call_targets): Use ipa_impossible_devirt_target_node. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index be3661a..25e0775 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -2664,9 +2664,10 @@ verify_edge_corresponds_to_fndecl (struct cgraph_edge *e, tree decl) return false; /* Optimizers can redirect unreachable calls or calls triggering undefined - behaviour to builtin_unreachable. */ + behaviour to builtin_unreachable or builtin_trap. */ if (DECL_BUILT_IN_CLASS (e-callee-decl) == BUILT_IN_NORMAL - DECL_FUNCTION_CODE (e-callee-decl) == BUILT_IN_UNREACHABLE) + (DECL_FUNCTION_CODE (e-callee-decl) == BUILT_IN_UNREACHABLE + || DECL_FUNCTION_CODE (e-callee-decl) == BUILT_IN_TRAP)) return false; node = cgraph_function_or_thunk_node (node, NULL); diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c index cd2d73d..e7bebe3 100644 --- a/gcc/cgraphclones.c +++ b/gcc/cgraphclones.c @@ -449,8 +449,9 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, be unreachable during the clonning procedure. */ if (!e-callee || DECL_BUILT_IN_CLASS (e-callee-decl) != BUILT_IN_NORMAL - || DECL_FUNCTION_CODE (e-callee-decl) != BUILT_IN_UNREACHABLE) -redirect_edge_duplicating_thunks (e, new_node, args_to_skip); + || (DECL_FUNCTION_CODE (e-callee-decl) != BUILT_IN_UNREACHABLE + DECL_FUNCTION_CODE (e-callee-decl) != BUILT_IN_TRAP)) +cgraph_redirect_edge_callee (e, new_node); } diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 06283fc..6c56c90 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -892,8 +892,7 @@ walk_polymorphic_call_targets (pointer_set_t *reachable_call_targets, if (targets.length () == 1) target = targets[0]; else - target = cgraph_get_create_node - (builtin_decl_implicit (BUILT_IN_UNREACHABLE)); + target = ipa_impossible_devirt_target_node (); if (cgraph_dump_file) { diff --git a/gcc/common.opt b/gcc/common.opt index da275e5..3e8b359 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1019,6 +1019,10 @@ fdevirtualize Common Report Var(flag_devirtualize) Optimization Try to convert virtual calls to direct ones. +ftrap-on-impossible-devirtualization +Common Report Var(flag_trap_impossible_devirt) +Convert virtual calls that cannot have any target to builtin_trap. + fdiagnostics-show-location= Common Joined RejectNegative Enum(diagnostic_prefixing_rule) -fdiagnostics-show-location=[once|every-line] How often to emit source location at the beginning of line-wrapped diagnostics diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 6402cce..e0dfcb9 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -392,7 +392,7 @@ fold_gimple_assign (gimple_stmt_iterator *si) if (targets.length () ==