diff options
author | Richard Guenther <rguenther@suse.de> | 2016-11-14 15:42:40 +0100 |
---|---|---|
committer | Richard Guenther <rguenther@suse.de> | 2016-11-14 15:42:40 +0100 |
commit | ca94f8c64654980144e88fb19b04adf5f023aa55 (patch) | |
tree | ef90f8461d210f78e7f7b0ba89923a5eda7b3758 /gcc/gimple-ssa-isolate-paths.c | |
parent | 9e872f3fe8b4f6624e2edf5ee55a833e53f290c8 (diff) | |
parent | 5dc46e164993bbf658f61069823a1b37a2d715eb (diff) | |
download | gcc-gimplefe.tar.gz |
Merge remote-tracking branch 'trunk' of git://gcc.gnu.org/git/gcc into gimplefegimplefe
Diffstat (limited to 'gcc/gimple-ssa-isolate-paths.c')
-rw-r--r-- | gcc/gimple-ssa-isolate-paths.c | 171 |
1 files changed, 123 insertions, 48 deletions
diff --git a/gcc/gimple-ssa-isolate-paths.c b/gcc/gimple-ssa-isolate-paths.c index 9d2fc8a30c0..84048d3daf9 100644 --- a/gcc/gimple-ssa-isolate-paths.c +++ b/gcc/gimple-ssa-isolate-paths.c @@ -206,6 +206,124 @@ isolate_path (basic_block bb, basic_block duplicate, return duplicate; } +/* Return TRUE if STMT is a div/mod operation using DIVISOR as the divisor. + FALSE otherwise. */ + +static bool +is_divmod_with_given_divisor (gimple *stmt, tree divisor) +{ + /* Only assignments matter. */ + if (!is_gimple_assign (stmt)) + return false; + + /* Check for every DIV/MOD expression. */ + enum tree_code rhs_code = gimple_assign_rhs_code (stmt); + if (rhs_code == TRUNC_DIV_EXPR + || rhs_code == FLOOR_DIV_EXPR + || rhs_code == CEIL_DIV_EXPR + || rhs_code == EXACT_DIV_EXPR + || rhs_code == ROUND_DIV_EXPR + || rhs_code == TRUNC_MOD_EXPR + || rhs_code == FLOOR_MOD_EXPR + || rhs_code == CEIL_MOD_EXPR + || rhs_code == ROUND_MOD_EXPR) + { + /* Pointer equality is fine when DIVISOR is an SSA_NAME, but + not sufficient for constants which may have different types. */ + if (operand_equal_p (gimple_assign_rhs2 (stmt), divisor, 0)) + return true; + } + return false; +} + +/* NAME is an SSA_NAME that we have already determined has the value 0 or NULL. + + Return TRUE if USE_STMT uses NAME in a way where a 0 or NULL value results + in undefined behavior, FALSE otherwise + + LOC is used for issuing diagnostics. This case represents potential + undefined behavior exposed by path splitting and that's reflected in + the diagnostic. */ + +bool +stmt_uses_name_in_undefined_way (gimple *use_stmt, tree name, location_t loc) +{ + /* If we are working with a non pointer type, then see + if this use is a DIV/MOD operation using NAME as the + divisor. */ + if (!POINTER_TYPE_P (TREE_TYPE (name))) + { + if (!flag_non_call_exceptions) + return is_divmod_with_given_divisor (use_stmt, name); + return false; + } + + /* NAME is a pointer, so see if it's used in a context where it must + be non-NULL. */ + bool by_dereference + = infer_nonnull_range_by_dereference (use_stmt, name); + + if (by_dereference + || infer_nonnull_range_by_attribute (use_stmt, name)) + { + + if (by_dereference) + { + warning_at (loc, OPT_Wnull_dereference, + "potential null pointer dereference"); + if (!flag_isolate_erroneous_paths_dereference) + return false; + } + else + { + if (!flag_isolate_erroneous_paths_attribute) + return false; + } + return true; + } + return false; +} + +/* Return TRUE if USE_STMT uses 0 or NULL in a context which results in + undefined behavior, FALSE otherwise. + + These cases are explicit in the IL. */ + +bool +stmt_uses_0_or_null_in_undefined_way (gimple *stmt) +{ + if (!flag_non_call_exceptions + && is_divmod_with_given_divisor (stmt, integer_zero_node)) + return true; + + /* By passing null_pointer_node, we can use the + infer_nonnull_range functions to detect explicit NULL + pointer dereferences and other uses where a non-NULL + value is required. */ + + bool by_dereference + = infer_nonnull_range_by_dereference (stmt, null_pointer_node); + if (by_dereference + || infer_nonnull_range_by_attribute (stmt, null_pointer_node)) + { + if (by_dereference) + { + location_t loc = gimple_location (stmt); + warning_at (loc, OPT_Wnull_dereference, + "null pointer dereference"); + if (!flag_isolate_erroneous_paths_dereference) + return false; + } + else + { + if (!flag_isolate_erroneous_paths_attribute) + return false; + } + return true; + } + return false; +} + /* Look for PHI nodes which feed statements in the same block where the value of the PHI node implies the statement is erroneous. @@ -243,11 +361,6 @@ find_implicit_erroneous_behavior (void) gphi *phi = si.phi (); tree lhs = gimple_phi_result (phi); - /* If the result is not a pointer, then there is no need to - examine the arguments. */ - if (!POINTER_TYPE_P (TREE_TYPE (lhs))) - continue; - /* PHI produces a pointer result. See if any of the PHI's arguments are NULL. @@ -315,29 +428,12 @@ find_implicit_erroneous_behavior (void) if (gimple_bb (use_stmt) != bb) continue; - bool by_dereference - = infer_nonnull_range_by_dereference (use_stmt, lhs); + location_t loc = gimple_location (use_stmt) + ? gimple_location (use_stmt) + : gimple_phi_arg_location (phi, i); - if (by_dereference - || infer_nonnull_range_by_attribute (use_stmt, lhs)) + if (stmt_uses_name_in_undefined_way (use_stmt, lhs, loc)) { - location_t loc = gimple_location (use_stmt) - ? gimple_location (use_stmt) - : gimple_phi_arg_location (phi, i); - - if (by_dereference) - { - warning_at (loc, OPT_Wnull_dereference, - "potential null pointer dereference"); - if (!flag_isolate_erroneous_paths_dereference) - continue; - } - else - { - if (!flag_isolate_erroneous_paths_attribute) - continue; - } - duplicate = isolate_path (bb, duplicate, e, use_stmt, lhs, false); @@ -383,29 +479,8 @@ find_explicit_erroneous_behavior (void) { gimple *stmt = gsi_stmt (si); - /* By passing null_pointer_node, we can use the - infer_nonnull_range functions to detect explicit NULL - pointer dereferences and other uses where a non-NULL - value is required. */ - - bool by_dereference - = infer_nonnull_range_by_dereference (stmt, null_pointer_node); - if (by_dereference - || infer_nonnull_range_by_attribute (stmt, null_pointer_node)) + if (stmt_uses_0_or_null_in_undefined_way (stmt)) { - if (by_dereference) - { - warning_at (gimple_location (stmt), OPT_Wnull_dereference, - "null pointer dereference"); - if (!flag_isolate_erroneous_paths_dereference) - continue; - } - else - { - if (!flag_isolate_erroneous_paths_attribute) - continue; - } - insert_trap (&si, null_pointer_node); bb = gimple_bb (gsi_stmt (si)); |