aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/analyzer')
-rw-r--r--gcc/analyzer/sm-malloc.cc81
1 files changed, 44 insertions, 37 deletions
diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc
index 1ea9b30..16883d3 100644
--- a/gcc/analyzer/sm-malloc.cc
+++ b/gcc/analyzer/sm-malloc.cc
@@ -1498,8 +1498,11 @@ public:
deref_before_check (const malloc_state_machine &sm, tree arg)
: malloc_diagnostic (sm, arg),
m_deref_enode (NULL),
+ m_deref_expr (NULL),
m_check_enode (NULL)
- {}
+ {
+ gcc_assert (arg);
+ }
const char *get_kind () const final override { return "deref_before_check"; }
@@ -1560,6 +1563,15 @@ public:
if (linemap_location_from_macro_definition_p (line_table, check_loc))
return false;
+ /* Reject if m_deref_expr is sufficiently different from m_arg
+ for cases where the dereference is spelled differently from
+ the check, which is probably two different ways to get the
+ same svalue, and thus not worth reporting. */
+ if (!m_deref_expr)
+ return false;
+ if (!sufficiently_similar_p (m_deref_expr, m_arg))
+ return false;
+
/* Reject the warning if the deref's BB doesn't dominate that
of the check, so that we don't warn e.g. for shared cleanup
code that checks a pointer for NULL, when that code is sometimes
@@ -1572,15 +1584,10 @@ public:
m_deref_enode->get_supernode ()->m_bb))
return false;
- if (m_arg)
- return warning_at (rich_loc, get_controlling_option (),
- "check of %qE for NULL after already"
- " dereferencing it",
- m_arg);
- else
- return warning_at (rich_loc, get_controlling_option (),
- "check of pointer for NULL after already"
- " dereferencing it");
+ return warning_at (rich_loc, get_controlling_option (),
+ "check of %qE for NULL after already"
+ " dereferencing it",
+ m_arg);
}
label_text describe_state_change (const evdesc::state_change &change)
@@ -1591,11 +1598,9 @@ public:
{
m_first_deref_event = change.m_event_id;
m_deref_enode = change.m_event.get_exploded_node ();
- if (m_arg)
- return change.formatted_print ("pointer %qE is dereferenced here",
- m_arg);
- else
- return label_text::borrow ("pointer is dereferenced here");
+ m_deref_expr = change.m_expr;
+ return change.formatted_print ("pointer %qE is dereferenced here",
+ m_arg);
}
return malloc_diagnostic::describe_state_change (change);
}
@@ -1604,31 +1609,32 @@ public:
{
m_check_enode = ev.m_event.get_exploded_node ();
if (m_first_deref_event.known_p ())
- {
- if (m_arg)
- return ev.formatted_print ("pointer %qE is checked for NULL here but"
- " it was already dereferenced at %@",
- m_arg, &m_first_deref_event);
- else
- return ev.formatted_print ("pointer is checked for NULL here but"
- " it was already dereferenced at %@",
- &m_first_deref_event);
- }
+ return ev.formatted_print ("pointer %qE is checked for NULL here but"
+ " it was already dereferenced at %@",
+ m_arg, &m_first_deref_event);
else
- {
- if (m_arg)
- return ev.formatted_print ("pointer %qE is checked for NULL here but"
- " it was already dereferenced",
- m_arg);
- else
- return ev.formatted_print ("pointer is checked for NULL here but"
- " it was already dereferenced");
- }
+ return ev.formatted_print ("pointer %qE is checked for NULL here but"
+ " it was already dereferenced",
+ m_arg);
}
private:
+ static bool sufficiently_similar_p (tree expr_a, tree expr_b)
+ {
+ pretty_printer *pp_a = global_dc->printer->clone ();
+ pretty_printer *pp_b = global_dc->printer->clone ();
+ pp_printf (pp_a, "%qE", expr_a);
+ pp_printf (pp_b, "%qE", expr_b);
+ bool result = (strcmp (pp_formatted_text (pp_a), pp_formatted_text (pp_b))
+ == 0);
+ delete pp_a;
+ delete pp_b;
+ return result;
+ }
+
diagnostic_event_id_t m_first_deref_event;
const exploded_node *m_deref_enode;
+ tree m_deref_expr;
const exploded_node *m_check_enode;
};
@@ -2141,9 +2147,10 @@ maybe_complain_about_deref_before_check (sm_context *sm_ctxt,
return;
tree diag_ptr = sm_ctxt->get_diagnostic_tree (ptr);
- sm_ctxt->warn
- (node, stmt, ptr,
- make_unique<deref_before_check> (*this, diag_ptr));
+ if (diag_ptr)
+ sm_ctxt->warn
+ (node, stmt, ptr,
+ make_unique<deref_before_check> (*this, diag_ptr));
sm_ctxt->set_next_state (stmt, ptr, m_stop);
}