diff options
-rw-r--r-- | gcc/analyzer/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/analyzer/region-model.cc | 71 | ||||
-rw-r--r-- | gcc/analyzer/region-model.h | 8 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/expect-1.c | 32 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/malloc-4.c | 20 | ||||
-rw-r--r-- | gcc/testsuite/gfortran.dg/analyzer/pr93993.f90 | 6 |
7 files changed, 152 insertions, 9 deletions
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 4f3e08e4dc4..c4724cb090d 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,6 +1,22 @@ 2020-03-04 David Malcolm <dmalcolm@redhat.com> PR analyzer/93993 + * region-model.cc (region_model::on_call_pre): Handle + BUILT_IN_EXPECT and its variants. + (region_model::add_any_constraints_from_ssa_def_stmt): Split out + gassign handling into add_any_constraints_from_gassign; add gcall + handling. + (region_model::add_any_constraints_from_gassign): New function, + based on the above. Add handling for NOP_EXPR. + (region_model::add_any_constraints_from_gcall): New function. + (region_model::get_representative_path_var): Handle views. + * region-model.h + (region_model::add_any_constraints_from_ssa_def_stmt): New decl. + (region_model::add_any_constraints_from_gassign): New decl. + +2020-03-04 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/93993 * checker-path.h (state_change_event::get_lvalue): Add ctxt param and pass it to region_model::get_value call. * diagnostic-manager.cc (get_any_origin): Pass a diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index b2179bd220a..6813117968f 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -4204,6 +4204,19 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt) } return false; } + else if (gimple_call_builtin_p (call, BUILT_IN_EXPECT) + || gimple_call_builtin_p (call, BUILT_IN_EXPECT_WITH_PROBABILITY) + || gimple_call_internal_p (call, IFN_BUILTIN_EXPECT)) + { + /* __builtin_expect's return value is its initial argument. */ + if (!lhs_rid.null_p ()) + { + tree initial_arg = gimple_call_arg (call, 0); + svalue_id sid = get_rvalue (initial_arg, ctxt); + set_value (lhs_rid, sid, ctxt); + } + return false; + } else if (is_named_call_p (callee_fndecl, "strlen", call, 1)) { region_id buf_rid = deref_rvalue (gimple_call_arg (call, 0), ctxt); @@ -5447,28 +5460,46 @@ region_model::add_any_constraints_from_ssa_def_stmt (tree lhs, if (TREE_CODE (lhs) != SSA_NAME) return; - if (rhs != boolean_false_node) + if (!zerop (rhs)) return; if (op != NE_EXPR && op != EQ_EXPR) return; + gimple *def_stmt = SSA_NAME_DEF_STMT (lhs); + if (const gassign *assign = dyn_cast<gassign *> (def_stmt)) + add_any_constraints_from_gassign (op, rhs, assign, ctxt); + else if (gcall *call = dyn_cast<gcall *> (def_stmt)) + add_any_constraints_from_gcall (op, rhs, call, ctxt); +} + +/* Add any constraints for an SSA_NAME defined by ASSIGN + where the result OP RHS. */ + +void +region_model::add_any_constraints_from_gassign (enum tree_code op, + tree rhs, + const gassign *assign, + region_model_context *ctxt) +{ /* We have either - "LHS != false" (i.e. LHS is true), or - "LHS == false" (i.e. LHS is false). */ bool is_true = op == NE_EXPR; - gimple *def_stmt = SSA_NAME_DEF_STMT (lhs); - gassign *assign = dyn_cast<gassign *> (def_stmt); - if (!assign) - return; - enum tree_code rhs_code = gimple_assign_rhs_code (assign); switch (rhs_code) { default: break; + + case NOP_EXPR: + { + add_constraint (gimple_assign_rhs1 (assign), op, rhs, ctxt); + } + break; + case BIT_AND_EXPR: { if (is_true) @@ -5514,6 +5545,24 @@ region_model::add_any_constraints_from_ssa_def_stmt (tree lhs, } } +/* Add any constraints for an SSA_NAME defined by CALL + where the result OP RHS. */ + +void +region_model::add_any_constraints_from_gcall (enum tree_code op, + tree rhs, + const gcall *call, + region_model_context *ctxt) +{ + if (gimple_call_builtin_p (call, BUILT_IN_EXPECT) + || gimple_call_builtin_p (call, BUILT_IN_EXPECT_WITH_PROBABILITY) + || gimple_call_internal_p (call, IFN_BUILTIN_EXPECT)) + { + /* __builtin_expect's return value is its initial argument. */ + add_constraint (gimple_call_arg (call, 0), op, rhs, ctxt); + } +} + /* Determine what is known about the condition "LHS OP RHS" within this model. Use CTXT for reporting any diagnostics associated with the accesses. */ @@ -5608,6 +5657,16 @@ region_model::get_representative_path_var (region_id rid) const region *parent_reg = get_region (parent_rid); if (parent_reg) { + if (reg->is_view_p ()) + { + path_var parent_pv = get_representative_path_var (parent_rid); + if (parent_pv.m_tree && reg->get_type ()) + return path_var (build1 (NOP_EXPR, + TREE_TYPE (reg->get_type ()), + parent_pv.m_tree), + parent_pv.m_stack_depth); + } + if (parent_reg->get_kind () == RK_STRUCT) { map_region *parent_map_region = (map_region *)parent_reg; diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index f3cf45566d1..6d49f00cfe3 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -1850,6 +1850,14 @@ class region_model enum tree_code op, tree rhs, region_model_context *ctxt); + void add_any_constraints_from_gassign (enum tree_code op, + tree rhs, + const gassign *assign, + region_model_context *ctxt); + void add_any_constraints_from_gcall (enum tree_code op, + tree rhs, + const gcall *call, + region_model_context *ctxt); void update_for_call_superedge (const call_superedge &call_edge, region_model_context *ctxt); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d44d3c7cbe5..af4470d6303 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,6 +1,14 @@ 2020-03-04 David Malcolm <dmalcolm@redhat.com> PR analyzer/93993 + * gcc.dg/analyzer/expect-1.c: New test. + * gcc.dg/analyzer/malloc-4.c: New test. + * gfortran.dg/analyzer/pr93993.f90: Remove xfail from dg-bogus. + Move location of leak warning and update message. + +2020-03-04 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/93993 * gfortran.dg/analyzer/pr93993.f90: New test. 2020-03-04 Martin Liska <mliska@suse.cz> diff --git a/gcc/testsuite/gcc.dg/analyzer/expect-1.c b/gcc/testsuite/gcc.dg/analyzer/expect-1.c new file mode 100644 index 00000000000..e538f77741d --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/expect-1.c @@ -0,0 +1,32 @@ +#define NULL ((void*)0) + +void *test_1 (void) +{ + int *p = (int *)__builtin_malloc (sizeof (int)); + if (__builtin_expect (p != NULL, 1)) + { + *p = 42; + return p; + } + return NULL; +} + +void *test_2 (void) +{ + int *p = (int *)__builtin_malloc (sizeof (int)); + if (__builtin_expect (p == NULL, 1)) + return NULL; + + *p = 42; + return p; +} + +void *test_3 (void) +{ + int *p = (int *)__builtin_malloc (sizeof (int)); + if (__builtin_expect_with_probability (p == NULL, 1, 0.5f)) + return NULL; + + *p = 42; + return p; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-4.c b/gcc/testsuite/gcc.dg/analyzer/malloc-4.c new file mode 100644 index 00000000000..94d2825a33e --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/malloc-4.c @@ -0,0 +1,20 @@ +/* { dg-additional-options "-Wno-incompatible-pointer-types" } */ + +#include <stdlib.h> + +struct foo; +struct bar; +void *hv (struct foo **tm) +{ + void *p = __builtin_malloc (4); + *tm = p; + if (!p) + abort (); + return p; /* { dg-warning "leak of 'tm'" } */ +} + +void a5 (void) +{ + struct bar *qb = NULL; + hv (&qb); +} /* { dg-warning "leak of '\\(struct foo\\)qb'" } */ diff --git a/gcc/testsuite/gfortran.dg/analyzer/pr93993.f90 b/gcc/testsuite/gfortran.dg/analyzer/pr93993.f90 index 8d5261c0eb9..230b99e4fcd 100644 --- a/gcc/testsuite/gfortran.dg/analyzer/pr93993.f90 +++ b/gcc/testsuite/gfortran.dg/analyzer/pr93993.f90 @@ -16,9 +16,9 @@ contains type (et(real_kind=za)), allocatable, target :: tm type (et(real_kind=za)), pointer :: ce - allocate (tm) ! { dg-bogus "dereference of possibly-NULL" "" { xfail *-*-* } } + allocate (tm) ! { dg-bogus "dereference of possibly-NULL" } ce => tm - end function hv ! { dg-warning "leak of 'tm'" } + end function hv end module gg @@ -30,4 +30,4 @@ program a5 type (et(real_kind=za)), pointer :: vt vt => hv (qb) -end program a5 +end program a5 ! { dg-warning "leak of '.*qb'" } |