Home | History | Annotate | Line # | Download | only in analyzer
checker-path.cc revision 1.1.1.1
      1 /* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
      2    Copyright (C) 2019-2020 Free Software Foundation, Inc.
      3    Contributed by David Malcolm <dmalcolm (at) redhat.com>.
      4 
      5 This file is part of GCC.
      6 
      7 GCC is free software; you can redistribute it and/or modify it
      8 under the terms of the GNU General Public License as published by
      9 the Free Software Foundation; either version 3, or (at your option)
     10 any later version.
     11 
     12 GCC is distributed in the hope that it will be useful, but
     13 WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15 General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with GCC; see the file COPYING3.  If not see
     19 <http://www.gnu.org/licenses/>.  */
     20 
     21 #include "config.h"
     22 #include "system.h"
     23 #include "coretypes.h"
     24 #include "tree.h"
     25 #include "function.h"
     26 #include "basic-block.h"
     27 #include "gimple.h"
     28 #include "gimple-pretty-print.h"
     29 #include "fold-const.h"
     30 #include "function.h"
     31 #include "diagnostic-path.h"
     32 #include "options.h"
     33 #include "cgraph.h"
     34 #include "function.h"
     35 #include "cfg.h"
     36 #include "digraph.h"
     37 #include "alloc-pool.h"
     38 #include "fibonacci_heap.h"
     39 #include "diagnostic-event-id.h"
     40 #include "shortest-paths.h"
     41 #include "analyzer/analyzer.h"
     42 #include "analyzer/analyzer-logging.h"
     43 #include "analyzer/sm.h"
     44 #include "sbitmap.h"
     45 #include "bitmap.h"
     46 #include "tristate.h"
     47 #include "ordered-hash-map.h"
     48 #include "selftest.h"
     49 #include "analyzer/region-model.h"
     50 #include "analyzer/program-state.h"
     51 #include "analyzer/checker-path.h"
     52 #include "gimple-iterator.h"
     53 #include "analyzer/supergraph.h"
     54 #include "analyzer/pending-diagnostic.h"
     55 #include "analyzer/diagnostic-manager.h"
     56 #include "analyzer/constraint-manager.h"
     57 #include "analyzer/diagnostic-manager.h"
     58 #include "analyzer/checker-path.h"
     59 #include "analyzer/call-string.h"
     60 #include "analyzer/program-point.h"
     61 #include "analyzer/exploded-graph.h"
     62 
     63 #if ENABLE_ANALYZER
     64 
     65 namespace ana {
     66 
     67 /* Get a string for EK.  */
     68 
     69 const char *
     70 event_kind_to_string (enum event_kind ek)
     71 {
     72   switch (ek)
     73     {
     74     default:
     75       gcc_unreachable ();
     76     case EK_DEBUG:
     77       return "EK_DEBUG";
     78     case EK_CUSTOM:
     79       return "EK_CUSTOM";
     80     case EK_STMT:
     81       return "EK_STMT";
     82     case EK_FUNCTION_ENTRY:
     83       return "EK_FUNCTION_ENTRY";
     84     case EK_STATE_CHANGE:
     85       return "EK_STATE_CHANGE";
     86     case EK_START_CFG_EDGE:
     87       return "EK_START_CFG_EDGE";
     88     case EK_END_CFG_EDGE:
     89       return "EK_END_CFG_EDGE";
     90     case EK_CALL_EDGE:
     91       return "EK_CALL_EDGE";
     92     case EK_RETURN_EDGE:
     93       return "EK_RETURN_EDGE";
     94     case EK_SETJMP:
     95       return "EK_SETJMP";
     96     case EK_REWIND_FROM_LONGJMP:
     97       return "EK_REWIND_FROM_LONGJMP";
     98     case EK_REWIND_TO_SETJMP:
     99       return "EK_REWIND_TO_SETJMP";
    100     case EK_WARNING:
    101       return "EK_WARNING";
    102     }
    103 }
    104 
    105 /* class checker_event : public diagnostic_event.  */
    106 
    107 /* Dump this event to PP (for debugging/logging purposes).  */
    108 
    109 void
    110 checker_event::dump (pretty_printer *pp) const
    111 {
    112   label_text event_desc (get_desc (false));
    113   pp_printf (pp, "\"%s\" (depth %i, m_loc=%x)",
    114 	     event_desc.m_buffer,
    115 	     get_stack_depth (),
    116 	     get_location ());
    117   event_desc.maybe_free ();
    118 }
    119 
    120 /* Hook for being notified when this event has its final id EMISSION_ID
    121    and is about to emitted for PD.
    122 
    123    Base implementation of checker_event::prepare_for_emission vfunc;
    124    subclasses that override this should chain up to it.
    125 
    126    Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
    127    side-effects of the call to get_desc take place before
    128    pending_diagnostic::emit is called.
    129 
    130    For example, state_change_event::get_desc can call
    131    pending_diagnostic::describe_state_change; free_of_non_heap can use this
    132    to tweak the message (TODO: would be neater to simply capture the
    133    pertinent data within the sm-state).  */
    134 
    135 void
    136 checker_event::prepare_for_emission (checker_path *,
    137 				     pending_diagnostic *pd,
    138 				     diagnostic_event_id_t emission_id)
    139 {
    140   m_pending_diagnostic = pd;
    141   m_emission_id = emission_id;
    142 
    143   label_text desc = get_desc (false);
    144   desc.maybe_free ();
    145 }
    146 
    147 /* class debug_event : public checker_event.  */
    148 
    149 /* Implementation of diagnostic_event::get_desc vfunc for
    150    debug_event.
    151    Use the saved string as the event's description.  */
    152 
    153 label_text
    154 debug_event::get_desc (bool) const
    155 {
    156   return label_text::borrow (m_desc);
    157 }
    158 
    159 /* class custom_event : public checker_event.  */
    160 
    161 /* Implementation of diagnostic_event::get_desc vfunc for
    162    custom_event.
    163    Use the saved string as the event's description.  */
    164 
    165 label_text
    166 custom_event::get_desc (bool) const
    167 {
    168   return label_text::borrow (m_desc);
    169 }
    170 
    171 /* class statement_event : public checker_event.  */
    172 
    173 /* statement_event's ctor.  */
    174 
    175 statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
    176 				  const program_state &dst_state)
    177 : checker_event (EK_STMT, gimple_location (stmt), fndecl, depth),
    178   m_stmt (stmt),
    179   m_dst_state (dst_state)
    180 {
    181 }
    182 
    183 /* Implementation of diagnostic_event::get_desc vfunc for
    184    statement_event.
    185    Use the statement's dump form as the event's description.  */
    186 
    187 label_text
    188 statement_event::get_desc (bool) const
    189 {
    190   pretty_printer pp;
    191   pp_string (&pp, "stmt: ");
    192   pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
    193   return label_text::take (xstrdup (pp_formatted_text (&pp)));
    194 }
    195 
    196 /* class function_entry_event : public checker_event.  */
    197 
    198 /* Implementation of diagnostic_event::get_desc vfunc for
    199    function_entry_event.
    200 
    201    Use a string such as "entry to 'foo'" as the event's description.  */
    202 
    203 label_text
    204 function_entry_event::get_desc (bool can_colorize) const
    205 {
    206   return make_label_text (can_colorize, "entry to %qE", m_fndecl);
    207 }
    208 
    209 /* class state_change_event : public checker_event.  */
    210 
    211 /* state_change_event's ctor.  */
    212 
    213 state_change_event::state_change_event (const supernode *node,
    214 					const gimple *stmt,
    215 					int stack_depth,
    216 					const state_machine &sm,
    217 					tree var,
    218 					state_machine::state_t from,
    219 					state_machine::state_t to,
    220 					tree origin,
    221 					const program_state &dst_state)
    222 : checker_event (EK_STATE_CHANGE,
    223 		 stmt->location, node->m_fun->decl,
    224 		 stack_depth),
    225   m_node (node), m_stmt (stmt), m_sm (sm),
    226   m_var (var), m_from (from), m_to (to),
    227   m_origin (origin),
    228   m_dst_state (dst_state)
    229 {
    230 }
    231 
    232 /* Implementation of diagnostic_event::get_desc vfunc for
    233    state_change_event.
    234 
    235    Attempt to generate a nicer human-readable description.
    236    For greatest precision-of-wording, give the pending diagnostic
    237    a chance to describe this state change (in terms of the
    238    diagnostic).
    239    Note that we only have a pending_diagnostic set on the event once
    240    the diagnostic is about to being emitted, so the description for
    241    an event can change.  */
    242 
    243 label_text
    244 state_change_event::get_desc (bool can_colorize) const
    245 {
    246   if (m_pending_diagnostic)
    247     {
    248       label_text custom_desc
    249 	= m_pending_diagnostic->describe_state_change
    250 	    (evdesc::state_change (can_colorize, m_var, m_origin,
    251 				   m_from, m_to, m_emission_id, *this));
    252       if (custom_desc.m_buffer)
    253 	{
    254 	  if (flag_analyzer_verbose_state_changes)
    255 	    {
    256 	      /* Append debug version.  */
    257 	      label_text result;
    258 	      if (m_origin)
    259 		result = make_label_text
    260 		  (can_colorize,
    261 		   "%s (state of %qE: %qs -> %qs, origin: %qE)",
    262 		   custom_desc.m_buffer,
    263 		   m_var,
    264 		   m_sm.get_state_name (m_from),
    265 		   m_sm.get_state_name (m_to),
    266 		   m_origin);
    267 	      else
    268 		result = make_label_text
    269 		  (can_colorize,
    270 		   "%s (state of %qE: %qs -> %qs, origin: NULL)",
    271 		   custom_desc.m_buffer,
    272 		   m_var,
    273 		   m_sm.get_state_name (m_from),
    274 		   m_sm.get_state_name (m_to));
    275 	      custom_desc.maybe_free ();
    276 	      return result;
    277 	    }
    278 	  else
    279 	    return custom_desc;
    280 	}
    281     }
    282 
    283   /* Fallback description.  */
    284   if (m_var)
    285     {
    286       if (m_origin)
    287 	return make_label_text
    288 	  (can_colorize,
    289 	   "state of %qE: %qs -> %qs (origin: %qE)",
    290 	   m_var,
    291 	   m_sm.get_state_name (m_from),
    292 	   m_sm.get_state_name (m_to),
    293 	   m_origin);
    294       else
    295 	return make_label_text
    296 	  (can_colorize,
    297 	   "state of %qE: %qs -> %qs (origin: NULL)",
    298 	   m_var,
    299 	   m_sm.get_state_name (m_from),
    300 	   m_sm.get_state_name (m_to));
    301     }
    302   else
    303     {
    304       gcc_assert (m_origin == NULL_TREE);
    305       return make_label_text
    306 	(can_colorize,
    307 	 "global state: %qs -> %qs",
    308 	 m_sm.get_state_name (m_from),
    309 	 m_sm.get_state_name (m_to));
    310     }
    311 }
    312 
    313 /* class superedge_event : public checker_event.  */
    314 
    315 /* Get the callgraph_superedge for this superedge_event, which must be
    316    for an interprocedural edge, rather than a CFG edge.  */
    317 
    318 const callgraph_superedge&
    319 superedge_event::get_callgraph_superedge () const
    320 {
    321   gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
    322   return *m_sedge->dyn_cast_callgraph_superedge ();
    323 }
    324 
    325 /* Determine if this event should be filtered at the given verbosity
    326    level.  */
    327 
    328 bool
    329 superedge_event::should_filter_p (int verbosity) const
    330 {
    331   switch (m_sedge->m_kind)
    332     {
    333     case SUPEREDGE_CFG_EDGE:
    334       {
    335 	if (verbosity < 2)
    336 	  return true;
    337 
    338 	if (verbosity < 4)
    339 	  {
    340 	    /* Filter events with empty descriptions.  This ought to filter
    341 	       FALLTHRU, but retain true/false/switch edges.  */
    342 	    label_text desc = get_desc (false);
    343 	    gcc_assert (desc.m_buffer);
    344 	    if (desc.m_buffer[0] == '\0')
    345 	      return true;
    346 	    desc.maybe_free ();
    347 	  }
    348       }
    349       break;
    350 
    351     default:
    352       break;
    353     }
    354   return false;
    355 }
    356 
    357 /* superedge_event's ctor.  */
    358 
    359 superedge_event::superedge_event (enum event_kind kind,
    360 				  const exploded_edge &eedge,
    361 				  location_t loc, tree fndecl, int depth)
    362 : checker_event (kind, loc, fndecl, depth),
    363   m_eedge (eedge), m_sedge (eedge.m_sedge),
    364   m_var (NULL_TREE), m_critical_state (0)
    365 {
    366 }
    367 
    368 /* class cfg_edge_event : public superedge_event.  */
    369 
    370 /* Get the cfg_superedge for this cfg_edge_event.  */
    371 
    372 const cfg_superedge &
    373 cfg_edge_event::get_cfg_superedge () const
    374 {
    375   return *m_sedge->dyn_cast_cfg_superedge ();
    376 }
    377 
    378 /* cfg_edge_event's ctor.  */
    379 
    380 cfg_edge_event::cfg_edge_event (enum event_kind kind,
    381 				const exploded_edge &eedge,
    382 				location_t loc, tree fndecl, int depth)
    383 : superedge_event (kind, eedge, loc, fndecl, depth)
    384 {
    385   gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
    386 }
    387 
    388 /* class start_cfg_edge_event : public cfg_edge_event.  */
    389 
    390 /* Implementation of diagnostic_event::get_desc vfunc for
    391    start_cfg_edge_event.
    392 
    393    If -fanalyzer-verbose-edges, then generate low-level descriptions, such
    394    as
    395      "taking 'true' edge SN:7 -> SN:8".
    396 
    397    Otherwise, generate strings using the label of the underlying CFG if
    398    any, such as:
    399      "following 'true' branch..." or
    400      "following 'case 3' branch..."
    401      "following 'default' branch..."
    402 
    403    For conditionals, attempt to supply a description of the condition that
    404    holds, such as:
    405      "following 'false' branch (when 'ptr' is non-NULL)..."
    406 
    407    Failing that, return an empty description (which will lead to this event
    408    being filtered).  */
    409 
    410 label_text
    411 start_cfg_edge_event::get_desc (bool can_colorize) const
    412 {
    413   bool user_facing = !flag_analyzer_verbose_edges;
    414   char *edge_desc = m_sedge->get_description (user_facing);
    415   if (user_facing)
    416     {
    417       if (edge_desc && strlen (edge_desc) > 0)
    418 	{
    419 	  label_text cond_desc = maybe_describe_condition (can_colorize);
    420 	  label_text result;
    421 	  if (cond_desc.m_buffer)
    422 	    {
    423 	      result = make_label_text (can_colorize,
    424 					"following %qs branch (%s)...",
    425 					edge_desc, cond_desc.m_buffer);
    426 	      cond_desc.maybe_free ();
    427 	    }
    428 	  else
    429 	    {
    430 	      result = make_label_text (can_colorize,
    431 					"following %qs branch...",
    432 					edge_desc);
    433 	    }
    434 	  free (edge_desc);
    435 	  return result;
    436 	}
    437       else
    438 	{
    439 	  free (edge_desc);
    440 	  return label_text::borrow ("");
    441 	}
    442     }
    443   else
    444     {
    445       if (strlen (edge_desc) > 0)
    446 	{
    447 	  label_text result
    448 	    = make_label_text (can_colorize,
    449 			       "taking %qs edge SN:%i -> SN:%i",
    450 			       edge_desc,
    451 			       m_sedge->m_src->m_index,
    452 			       m_sedge->m_dest->m_index);
    453 	  free (edge_desc);
    454 	  return result;
    455 	}
    456       else
    457 	{
    458 	  free (edge_desc);
    459 	  return make_label_text (can_colorize,
    460 				  "taking edge SN:%i -> SN:%i",
    461 				  m_sedge->m_src->m_index,
    462 				  m_sedge->m_dest->m_index);
    463 	}
    464     }
    465 }
    466 
    467 /* Attempt to generate a description of any condition that holds at this edge.
    468 
    469    The intent is to make the user-facing messages more clear, especially for
    470    cases where there's a single or double-negative, such as
    471    when describing the false branch of an inverted condition.
    472 
    473    For example, rather than printing just:
    474 
    475       |  if (!ptr)
    476       |     ~
    477       |     |
    478       |     (1) following 'false' branch...
    479 
    480    it's clearer to spell out the condition that holds:
    481 
    482       |  if (!ptr)
    483       |     ~
    484       |     |
    485       |     (1) following 'false' branch (when 'ptr' is non-NULL)...
    486                                           ^^^^^^^^^^^^^^^^^^^^^^
    487 
    488    In the above example, this function would generate the highlighted
    489    string: "when 'ptr' is non-NULL".
    490 
    491    If the edge is not a condition, or it's not clear that a description of
    492    the condition would be helpful to the user, return NULL.  */
    493 
    494 label_text
    495 start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
    496 {
    497   const cfg_superedge& cfg_sedge = get_cfg_superedge ();
    498 
    499   if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
    500     {
    501       const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
    502       if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
    503 	{
    504 	  enum tree_code op = gimple_cond_code (cond_stmt);
    505 	  tree lhs = gimple_cond_lhs (cond_stmt);
    506 	  tree rhs = gimple_cond_rhs (cond_stmt);
    507 	  if (cfg_sedge.false_value_p ())
    508 	    op = invert_tree_comparison (op, false /* honor_nans */);
    509 	  return maybe_describe_condition (can_colorize,
    510 					   lhs, op, rhs);
    511 	}
    512     }
    513   return label_text::borrow (NULL);
    514 }
    515 
    516 /* Subroutine of maybe_describe_condition above.
    517 
    518    Attempt to generate a user-facing description of the condition
    519    LHS OP RHS, but only if it is likely to make it easier for the
    520    user to understand a condition.  */
    521 
    522 label_text
    523 start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
    524 						tree lhs,
    525 						enum tree_code op,
    526 						tree rhs)
    527 {
    528   /* In theory we could just build a tree via
    529        fold_build2 (op, boolean_type_node, lhs, rhs)
    530      and print it with %qE on it, but this leads to warts such as
    531      parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'.  */
    532 
    533   /* Special-case: describe testing the result of strcmp, as figuring
    534      out what the "true" or "false" path is can be confusing to the user.  */
    535   if (TREE_CODE (lhs) == SSA_NAME
    536       && zerop (rhs))
    537     {
    538       if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
    539 	if (is_special_named_call_p (call, "strcmp", 2))
    540 	  {
    541 	    if (op == EQ_EXPR)
    542 	      return label_text::borrow ("when the strings are equal");
    543 	    if (op == NE_EXPR)
    544 	      return label_text::borrow ("when the strings are non-equal");
    545 	  }
    546     }
    547 
    548   /* Only attempt to generate text for sufficiently simple expressions.  */
    549   if (!should_print_expr_p (lhs))
    550     return label_text::borrow (NULL);
    551   if (!should_print_expr_p (rhs))
    552     return label_text::borrow (NULL);
    553 
    554   /* Special cases for pointer comparisons against NULL.  */
    555   if (POINTER_TYPE_P (TREE_TYPE (lhs))
    556       && POINTER_TYPE_P (TREE_TYPE (rhs))
    557       && zerop (rhs))
    558     {
    559       if (op == EQ_EXPR)
    560 	return make_label_text (can_colorize, "when %qE is NULL",
    561 				lhs);
    562       if (op == NE_EXPR)
    563 	return make_label_text (can_colorize, "when %qE is non-NULL",
    564 				lhs);
    565     }
    566 
    567   return make_label_text (can_colorize, "when %<%E %s %E%>",
    568 			  lhs, op_symbol_code (op), rhs);
    569 }
    570 
    571 /* Subroutine of maybe_describe_condition.
    572 
    573    Return true if EXPR is we will get suitable user-facing output
    574    from %E on it.  */
    575 
    576 bool
    577 start_cfg_edge_event::should_print_expr_p (tree expr)
    578 {
    579   if (TREE_CODE (expr) == SSA_NAME)
    580     {
    581       if (SSA_NAME_VAR (expr))
    582 	return should_print_expr_p (SSA_NAME_VAR (expr));
    583       else
    584 	return false;
    585     }
    586 
    587   if (DECL_P (expr))
    588     return true;
    589 
    590   if (CONSTANT_CLASS_P (expr))
    591     return true;
    592 
    593   return false;
    594 }
    595 
    596 /* class call_event : public superedge_event.  */
    597 
    598 /* call_event's ctor.  */
    599 
    600 call_event::call_event (const exploded_edge &eedge,
    601 			location_t loc, tree fndecl, int depth)
    602 : superedge_event (EK_CALL_EDGE, eedge, loc, fndecl, depth)
    603 {
    604   gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
    605 }
    606 
    607 /* Implementation of diagnostic_event::get_desc vfunc for
    608    call_event.
    609 
    610    If this call event passes critical state for an sm-based warning,
    611    allow the diagnostic to generate a precise description, such as:
    612 
    613      "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
    614 
    615    Otherwise, generate a description of the form
    616    "calling 'foo' from 'bar'".  */
    617 
    618 label_text
    619 call_event::get_desc (bool can_colorize) const
    620 {
    621   if (m_critical_state && m_pending_diagnostic)
    622     {
    623       gcc_assert (m_var);
    624       label_text custom_desc
    625 	= m_pending_diagnostic->describe_call_with_state
    626 	    (evdesc::call_with_state (can_colorize,
    627 				      m_sedge->m_src->m_fun->decl,
    628 				      m_sedge->m_dest->m_fun->decl,
    629 				      m_var,
    630 				      m_critical_state));
    631       if (custom_desc.m_buffer)
    632 	return custom_desc;
    633     }
    634 
    635   return make_label_text (can_colorize,
    636 			  "calling %qE from %qE",
    637 			  m_sedge->m_dest->m_fun->decl,
    638 			  m_sedge->m_src->m_fun->decl);
    639 }
    640 
    641 /* Override of checker_event::is_call_p for calls.  */
    642 
    643 bool
    644 call_event::is_call_p () const
    645 {
    646   return true;
    647 }
    648 
    649 /* class return_event : public superedge_event.  */
    650 
    651 /* return_event's ctor.  */
    652 
    653 return_event::return_event (const exploded_edge &eedge,
    654 			    location_t loc, tree fndecl, int depth)
    655 : superedge_event (EK_RETURN_EDGE, eedge, loc, fndecl, depth)
    656 {
    657   gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
    658 }
    659 
    660 /* Implementation of diagnostic_event::get_desc vfunc for
    661    return_event.
    662 
    663    If this return event returns critical state for an sm-based warning,
    664    allow the diagnostic to generate a precise description, such as:
    665 
    666       "possible of NULL to 'foo' from 'bar'"
    667 
    668    Otherwise, generate a description of the form
    669    "returning to 'foo' from 'bar'.  */
    670 
    671 label_text
    672 return_event::get_desc (bool can_colorize) const
    673 {
    674   /*  For greatest precision-of-wording, if this is returning the
    675       state involved in the pending diagnostic, give the pending
    676       diagnostic a chance to describe this return (in terms of
    677       itself).  */
    678   if (m_critical_state && m_pending_diagnostic)
    679     {
    680       label_text custom_desc
    681 	= m_pending_diagnostic->describe_return_of_state
    682 	    (evdesc::return_of_state (can_colorize,
    683 				      m_sedge->m_dest->m_fun->decl,
    684 				      m_sedge->m_src->m_fun->decl,
    685 				      m_critical_state));
    686       if (custom_desc.m_buffer)
    687 	return custom_desc;
    688     }
    689   return make_label_text (can_colorize,
    690 			  "returning to %qE from %qE",
    691 			  m_sedge->m_dest->m_fun->decl,
    692 			  m_sedge->m_src->m_fun->decl);
    693 }
    694 
    695 /* Override of checker_event::is_return_p for returns.  */
    696 
    697 bool
    698 return_event::is_return_p () const
    699 {
    700   return true;
    701 }
    702 
    703 /* class setjmp_event : public checker_event.  */
    704 
    705 /* Implementation of diagnostic_event::get_desc vfunc for
    706    setjmp_event.  */
    707 
    708 label_text
    709 setjmp_event::get_desc (bool can_colorize) const
    710 {
    711   return make_label_text (can_colorize,
    712 			  "%qs called here",
    713 			  get_user_facing_name (m_setjmp_call));
    714 }
    715 
    716 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
    717 
    718    Record this setjmp's event ID into the path, so that rewind events can
    719    use it.  */
    720 
    721 void
    722 setjmp_event::prepare_for_emission (checker_path *path,
    723 				    pending_diagnostic *pd,
    724 				    diagnostic_event_id_t emission_id)
    725 {
    726   checker_event::prepare_for_emission (path, pd, emission_id);
    727   path->record_setjmp_event (m_enode, emission_id);
    728 }
    729 
    730 /* class rewind_event : public checker_event.  */
    731 
    732 /* Get the fndecl containing the site of the longjmp call.  */
    733 
    734 tree
    735 rewind_event::get_longjmp_caller () const
    736 {
    737   return m_eedge->m_src->get_function ()->decl;
    738 }
    739 
    740 /* Get the fndecl containing the site of the setjmp call.  */
    741 
    742 tree
    743 rewind_event::get_setjmp_caller () const
    744 {
    745   return m_eedge->m_dest->get_function ()->decl;
    746 }
    747 
    748 /* rewind_event's ctor.  */
    749 
    750 rewind_event::rewind_event (const exploded_edge *eedge,
    751 			    enum event_kind kind,
    752 			    location_t loc, tree fndecl, int depth,
    753 			    const rewind_info_t *rewind_info)
    754 : checker_event (kind, loc, fndecl, depth),
    755   m_rewind_info (rewind_info),
    756   m_eedge (eedge)
    757 {
    758   gcc_assert (m_eedge->m_custom_info == m_rewind_info);
    759 }
    760 
    761 /* class rewind_from_longjmp_event : public rewind_event.  */
    762 
    763 /* Implementation of diagnostic_event::get_desc vfunc for
    764    rewind_from_longjmp_event.  */
    765 
    766 label_text
    767 rewind_from_longjmp_event::get_desc (bool can_colorize) const
    768 {
    769   const char *src_name
    770     = get_user_facing_name (m_rewind_info->get_longjmp_call ());
    771 
    772   if (get_longjmp_caller () == get_setjmp_caller ())
    773     /* Special-case: purely intraprocedural rewind.  */
    774     return make_label_text (can_colorize,
    775 			    "rewinding within %qE from %qs...",
    776 			    get_longjmp_caller (),
    777 			    src_name);
    778   else
    779     return make_label_text (can_colorize,
    780 			    "rewinding from %qs in %qE...",
    781 			    src_name,
    782 			    get_longjmp_caller ());
    783 }
    784 
    785 /* class rewind_to_setjmp_event : public rewind_event.  */
    786 
    787 /* Implementation of diagnostic_event::get_desc vfunc for
    788    rewind_to_setjmp_event.  */
    789 
    790 label_text
    791 rewind_to_setjmp_event::get_desc (bool can_colorize) const
    792 {
    793   const char *dst_name
    794     = get_user_facing_name (m_rewind_info->get_setjmp_call ());
    795 
    796   /* If we can, identify the ID of the setjmp_event.  */
    797   if (m_original_setjmp_event_id.known_p ())
    798     {
    799       if (get_longjmp_caller () == get_setjmp_caller ())
    800 	/* Special-case: purely intraprocedural rewind.  */
    801 	return make_label_text (can_colorize,
    802 				"...to %qs (saved at %@)",
    803 				dst_name,
    804 				&m_original_setjmp_event_id);
    805       else
    806 	return make_label_text (can_colorize,
    807 				"...to %qs in %qE (saved at %@)",
    808 				dst_name,
    809 				get_setjmp_caller (),
    810 				&m_original_setjmp_event_id);
    811     }
    812   else
    813     {
    814       if (get_longjmp_caller () == get_setjmp_caller ())
    815 	/* Special-case: purely intraprocedural rewind.  */
    816 	return make_label_text (can_colorize,
    817 				"...to %qs",
    818 				dst_name,
    819 				get_setjmp_caller ());
    820       else
    821 	return make_label_text (can_colorize,
    822 				"...to %qs in %qE",
    823 				dst_name,
    824 				get_setjmp_caller ());
    825     }
    826 }
    827 
    828 /* Implementation of checker_event::prepare_for_emission vfunc for
    829    rewind_to_setjmp_event.
    830 
    831    Attempt to look up the setjmp event ID that recorded the jmp_buf
    832    for this rewind.  */
    833 
    834 void
    835 rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
    836 					      pending_diagnostic *pd,
    837 					      diagnostic_event_id_t emission_id)
    838 {
    839   checker_event::prepare_for_emission (path, pd, emission_id);
    840   path->get_setjmp_event (m_rewind_info->get_enode_origin (),
    841 			  &m_original_setjmp_event_id);
    842 }
    843 
    844 /* class warning_event : public checker_event.  */
    845 
    846 /* Implementation of diagnostic_event::get_desc vfunc for
    847    warning_event.
    848 
    849    If the pending diagnostic implements describe_final_event, use it,
    850    generating a precise description e.g.
    851      "second 'free' here; first 'free' was at (7)"
    852 
    853    Otherwise generate a generic description.  */
    854 
    855 label_text
    856 warning_event::get_desc (bool can_colorize) const
    857 {
    858   if (m_pending_diagnostic)
    859     {
    860       label_text ev_desc
    861 	= m_pending_diagnostic->describe_final_event
    862 	    (evdesc::final_event (can_colorize, m_var, m_state));
    863       if (ev_desc.m_buffer)
    864 	{
    865 	  if (m_sm && flag_analyzer_verbose_state_changes)
    866 	    {
    867 	      label_text result
    868 		= make_label_text (can_colorize,
    869 				   "%s (%qE is in state %qs)",
    870 				   ev_desc.m_buffer,
    871 				   m_var,m_sm->get_state_name (m_state));
    872 	      ev_desc.maybe_free ();
    873 	      return result;
    874 	    }
    875 	  else
    876 	    return ev_desc;
    877 	}
    878     }
    879 
    880   if (m_sm)
    881     return make_label_text (can_colorize,
    882 			    "here (%qE is in state %qs)",
    883 			    m_var,
    884 			    m_sm->get_state_name (m_state));
    885   else
    886     return label_text::borrow ("here");
    887 }
    888 
    889 /* Print a single-line representation of this path to PP.  */
    890 
    891 void
    892 checker_path::dump (pretty_printer *pp) const
    893 {
    894   pp_character (pp, '[');
    895 
    896   checker_event *e;
    897   int i;
    898   FOR_EACH_VEC_ELT (m_events, i, e)
    899     {
    900       if (i > 0)
    901 	pp_string (pp, ", ");
    902       label_text event_desc (e->get_desc (false));
    903       pp_printf (pp, "\"%s\"", event_desc.m_buffer);
    904       event_desc.maybe_free ();
    905     }
    906   pp_character (pp, ']');
    907 }
    908 
    909 /* Print a multiline form of this path to LOGGER, prefixing it with DESC.  */
    910 
    911 void
    912 checker_path::maybe_log (logger *logger, const char *desc) const
    913 {
    914   if (!logger)
    915     return;
    916   logger->start_log_line ();
    917   logger->log_partial ("%s: ", desc);
    918   dump (logger->get_printer ());
    919   logger->end_log_line ();
    920   for (unsigned i = 0; i < m_events.length (); i++)
    921     {
    922       logger->start_log_line ();
    923       logger->log_partial ("%s[%i]: %s ", desc, i,
    924 			   event_kind_to_string (m_events[i]->m_kind));
    925       m_events[i]->dump (logger->get_printer ());
    926       logger->end_log_line ();
    927     }
    928 }
    929 
    930 /* Print a multiline form of this path to STDERR.  */
    931 
    932 DEBUG_FUNCTION void
    933 checker_path::debug () const
    934 {
    935   checker_event *e;
    936   int i;
    937   FOR_EACH_VEC_ELT (m_events, i, e)
    938     {
    939       label_text event_desc (e->get_desc (false));
    940       fprintf (stderr,
    941 	       "[%i]: %s \"%s\"\n",
    942 	       i,
    943 	       event_kind_to_string (m_events[i]->m_kind),
    944 	       event_desc.m_buffer);
    945       event_desc.maybe_free ();
    946     }
    947 }
    948 
    949 /* Add a warning_event to the end of this path.  */
    950 
    951 void
    952 checker_path::add_final_event (const state_machine *sm,
    953 			       const exploded_node *enode, const gimple *stmt,
    954 			       tree var, state_machine::state_t state)
    955 {
    956   checker_event *end_of_path
    957     = new warning_event (stmt->location,
    958 			 enode->get_function ()->decl,
    959 			 enode->get_stack_depth (),
    960 			 sm, var, state);
    961   add_event (end_of_path);
    962 }
    963 
    964 } // namespace ana
    965 
    966 #endif /* #if ENABLE_ANALYZER */
    967