LCOV - code coverage report
Current view: top level - gcc/analyzer - diagnostic-manager.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 86.0 % 1322 1137
Test Date: 2025-06-21 16:26:05 Functions: 86.9 % 84 73
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Classes for saving, deduplicating, and emitting analyzer diagnostics.
       2                 :             :    Copyright (C) 2019-2025 Free Software Foundation, Inc.
       3                 :             :    Contributed by David Malcolm <dmalcolm@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 "analyzer/common.h"
      22                 :             : 
      23                 :             : #include "cfg.h"
      24                 :             : #include "basic-block.h"
      25                 :             : #include "gimple.h"
      26                 :             : #include "gimple-pretty-print.h"
      27                 :             : #include "gimple-iterator.h"
      28                 :             : #include "inlining-iterator.h"
      29                 :             : #include "cgraph.h"
      30                 :             : #include "digraph.h"
      31                 :             : #include "gcc-rich-location.h"
      32                 :             : #include "diagnostic-format-sarif.h"
      33                 :             : 
      34                 :             : #include "analyzer/analyzer-logging.h"
      35                 :             : #include "analyzer/sm.h"
      36                 :             : #include "analyzer/pending-diagnostic.h"
      37                 :             : #include "analyzer/diagnostic-manager.h"
      38                 :             : #include "analyzer/call-string.h"
      39                 :             : #include "analyzer/program-point.h"
      40                 :             : #include "analyzer/store.h"
      41                 :             : #include "analyzer/region-model.h"
      42                 :             : #include "analyzer/constraint-manager.h"
      43                 :             : #include "analyzer/supergraph.h"
      44                 :             : #include "analyzer/program-state.h"
      45                 :             : #include "analyzer/exploded-graph.h"
      46                 :             : #include "analyzer/trimmed-graph.h"
      47                 :             : #include "analyzer/feasible-graph.h"
      48                 :             : #include "analyzer/checker-path.h"
      49                 :             : #include "analyzer/reachability.h"
      50                 :             : 
      51                 :             : #if ENABLE_ANALYZER
      52                 :             : 
      53                 :             : namespace ana {
      54                 :             : 
      55                 :             : class feasible_worklist;
      56                 :             : 
      57                 :             : /* State for finding the shortest feasible exploded_path for a
      58                 :             :    saved_diagnostic.
      59                 :             :    This is shared between all diagnostics, so that we avoid repeating work.  */
      60                 :             : 
      61                 :             : class epath_finder
      62                 :             : {
      63                 :             : public:
      64                 :        1547 :   epath_finder (const exploded_graph &eg)
      65                 :        1547 :   : m_eg (eg),
      66                 :        1547 :     m_sep (NULL)
      67                 :             :   {
      68                 :             :     /* This is shared by all diagnostics, but only needed if
      69                 :             :        !flag_analyzer_feasibility.  */
      70                 :        1547 :     if (!flag_analyzer_feasibility)
      71                 :           4 :       m_sep = new shortest_exploded_paths (eg, eg.get_origin (),
      72                 :           4 :                                            SPS_FROM_GIVEN_ORIGIN);
      73                 :        1547 :   }
      74                 :             : 
      75                 :        1551 :   ~epath_finder () { delete m_sep; }
      76                 :             : 
      77                 :      175296 :   logger *get_logger () const { return m_eg.get_logger (); }
      78                 :             : 
      79                 :             :   std::unique_ptr<exploded_path>
      80                 :             :   get_best_epath (const exploded_node *target_enode,
      81                 :             :                   const gimple *target_stmt,
      82                 :             :                   const pending_diagnostic &pd,
      83                 :             :                   const char *desc, unsigned diag_idx,
      84                 :             :                   std::unique_ptr<feasibility_problem> *out_problem);
      85                 :             : 
      86                 :             : private:
      87                 :             :   DISABLE_COPY_AND_ASSIGN(epath_finder);
      88                 :             : 
      89                 :             :   std::unique_ptr<exploded_path>
      90                 :             :   explore_feasible_paths (const exploded_node *target_enode,
      91                 :             :                           const gimple *target_stmt,
      92                 :             :                           const pending_diagnostic &pd,
      93                 :             :                           const char *desc, unsigned diag_idx);
      94                 :             :   bool
      95                 :             :   process_worklist_item (feasible_worklist *worklist,
      96                 :             :                          const trimmed_graph &tg,
      97                 :             :                          feasible_graph *fg,
      98                 :             :                          const exploded_node *target_enode,
      99                 :             :                          const gimple *target_stmt,
     100                 :             :                          const pending_diagnostic &pd,
     101                 :             :                          unsigned diag_idx,
     102                 :             :                          std::unique_ptr<exploded_path> *out_best_path) const;
     103                 :             :   void dump_trimmed_graph (const exploded_node *target_enode,
     104                 :             :                            const char *desc, unsigned diag_idx,
     105                 :             :                            const trimmed_graph &tg,
     106                 :             :                            const shortest_paths<eg_traits, exploded_path> &sep);
     107                 :             :   void dump_feasible_graph (const exploded_node *target_enode,
     108                 :             :                             const char *desc, unsigned diag_idx,
     109                 :             :                             const feasible_graph &fg);
     110                 :             :   void dump_feasible_path (const exploded_node *target_enode,
     111                 :             :                            unsigned diag_idx,
     112                 :             :                            const feasible_graph &fg,
     113                 :             :                            const feasible_node &fnode) const;
     114                 :             : 
     115                 :             :   const exploded_graph &m_eg;
     116                 :             :   shortest_exploded_paths *m_sep;
     117                 :             : };
     118                 :             : 
     119                 :             : /* class epath_finder.  */
     120                 :             : 
     121                 :             : /* Get the "best" exploded_path for reaching ENODE from the origin,
     122                 :             :    returning ownership of it to the caller.
     123                 :             : 
     124                 :             :    If TARGET_STMT is non-NULL, then check for reaching that stmt
     125                 :             :    within ENODE.
     126                 :             : 
     127                 :             :    Ideally we want to report the shortest feasible path.
     128                 :             :    Return NULL if we could not find a feasible path
     129                 :             :    (when flag_analyzer_feasibility is true).
     130                 :             : 
     131                 :             :    If flag_analyzer_feasibility is false, then simply return the
     132                 :             :    shortest path.
     133                 :             : 
     134                 :             :    Use DESC and DIAG_IDX when logging.
     135                 :             : 
     136                 :             :    Write any feasibility_problem to *OUT_PROBLEM.  */
     137                 :             : 
     138                 :             : std::unique_ptr<exploded_path>
     139                 :        6741 : epath_finder::get_best_epath (const exploded_node *enode,
     140                 :             :                               const gimple *target_stmt,
     141                 :             :                               const pending_diagnostic &pd,
     142                 :             :                               const char *desc, unsigned diag_idx,
     143                 :             :                               std::unique_ptr<feasibility_problem> *out_problem)
     144                 :             : {
     145                 :        6741 :   logger *logger = get_logger ();
     146                 :        6741 :   LOG_SCOPE (logger);
     147                 :             : 
     148                 :        6741 :   unsigned snode_idx = enode->get_supernode ()->m_index;
     149                 :        6741 :   if (logger)
     150                 :           0 :     logger->log ("considering %qs at EN: %i, SN: %i (sd: %i)",
     151                 :           0 :                  desc, enode->m_index, snode_idx, diag_idx);
     152                 :             : 
     153                 :             :   /* State-merging means that not every path in the egraph corresponds
     154                 :             :      to a feasible one w.r.t. states.
     155                 :             : 
     156                 :             :      We want to find the shortest feasible path from the origin to ENODE
     157                 :             :      in the egraph.  */
     158                 :             : 
     159                 :        6741 :   if (flag_analyzer_feasibility)
     160                 :             :     {
     161                 :             :       /* Attempt to find the shortest feasible path using feasible_graph.  */
     162                 :        6737 :       if (logger)
     163                 :           0 :         logger->log ("trying to find shortest feasible path");
     164                 :        6737 :       if (std::unique_ptr<exploded_path> epath
     165                 :        6737 :             = explore_feasible_paths (enode, target_stmt, pd, desc, diag_idx))
     166                 :             :         {
     167                 :        6464 :           if (logger)
     168                 :           0 :             logger->log ("accepting %qs at EN: %i, SN: %i (sd: %i)"
     169                 :             :                          " with feasible path (length: %i)",
     170                 :           0 :                          desc, enode->m_index, snode_idx, diag_idx,
     171                 :             :                          epath->length ());
     172                 :        6464 :           return epath;
     173                 :             :         }
     174                 :             :       else
     175                 :             :         {
     176                 :         273 :           if (logger)
     177                 :           0 :             logger->log ("rejecting %qs at EN: %i, SN: %i (sd: %i)"
     178                 :             :                          " due to not finding feasible path",
     179                 :           0 :                          desc, enode->m_index, snode_idx, diag_idx);
     180                 :         273 :           return NULL;
     181                 :        6737 :         }
     182                 :             :     }
     183                 :             :   else
     184                 :             :     {
     185                 :             :       /* As a crude approximation to shortest feasible path, simply find
     186                 :             :          the shortest path, and note whether it is feasible.
     187                 :             :          There could be longer feasible paths within the egraph, so this
     188                 :             :          approach would lead to diagnostics being falsely rejected
     189                 :             :          (PR analyzer/96374).  */
     190                 :           4 :       if (logger)
     191                 :           0 :         logger->log ("trying to find shortest path ignoring feasibility");
     192                 :           4 :       gcc_assert (m_sep);
     193                 :           4 :       std::unique_ptr<exploded_path> epath
     194                 :           4 :         = std::make_unique<exploded_path> (m_sep->get_shortest_path (enode));
     195                 :           4 :       if (epath->feasible_p (logger, out_problem, m_eg.get_engine (), &m_eg))
     196                 :             :         {
     197                 :           0 :           if (logger)
     198                 :           0 :             logger->log ("accepting %qs at EN: %i, SN: %i (sn: %i)"
     199                 :             :                          " with feasible path (length: %i)",
     200                 :           0 :                          desc, enode->m_index, snode_idx, diag_idx,
     201                 :             :                          epath->length ());
     202                 :             :         }
     203                 :             :       else
     204                 :             :         {
     205                 :           4 :           if (logger)
     206                 :           0 :             logger->log ("accepting %qs at EN: %i, SN: %i (sn: %i) (length: %i)"
     207                 :             :                          " despite infeasible path (due to %qs)",
     208                 :           0 :                          desc, enode->m_index, snode_idx, diag_idx,
     209                 :             :                          epath->length (),
     210                 :             :                          "-fno-analyzer-feasibility");
     211                 :             :         }
     212                 :           4 :       return epath;
     213                 :           4 :     }
     214                 :        6741 : }
     215                 :             : 
     216                 :             : /* A class for managing the worklist of feasible_nodes in
     217                 :             :    epath_finder::explore_feasible_paths, prioritizing them
     218                 :             :    so that shorter paths appear earlier in the queue.  */
     219                 :             : 
     220                 :       13474 : class feasible_worklist
     221                 :             : {
     222                 :             : public:
     223                 :        6737 :   feasible_worklist (const shortest_paths<eg_traits, exploded_path> &sep)
     224                 :       13474 :   : m_queue (key_t (*this, NULL)),
     225                 :        6737 :     m_sep (sep)
     226                 :             :   {
     227                 :        6737 :   }
     228                 :             : 
     229                 :      155077 :   feasible_node *take_next () { return m_queue.extract_min (); }
     230                 :             : 
     231                 :      158540 :   void add_node (feasible_node *fnode)
     232                 :             :   {
     233                 :      317080 :     m_queue.insert (key_t (*this, fnode), fnode);
     234                 :      151803 :   }
     235                 :             : 
     236                 :             : private:
     237                 :             :   struct key_t
     238                 :             :   {
     239                 :      165277 :     key_t (const feasible_worklist &w, feasible_node *fnode)
     240                 :        6737 :     : m_worklist (w), m_fnode (fnode)
     241                 :             :     {}
     242                 :             : 
     243                 :      148898 :     bool operator< (const key_t &other) const
     244                 :             :     {
     245                 :      148898 :       return cmp (*this, other) < 0;
     246                 :             :     }
     247                 :             : 
     248                 :       54085 :     bool operator== (const key_t &other) const
     249                 :             :     {
     250                 :       54085 :       return cmp (*this, other) == 0;
     251                 :             :     }
     252                 :             : 
     253                 :       54085 :     bool operator> (const key_t &other) const
     254                 :             :     {
     255                 :       54085 :       return !(*this == other || *this < other);
     256                 :             :     }
     257                 :             : 
     258                 :             :   private:
     259                 :      202983 :     static int cmp (const key_t &ka, const key_t &kb)
     260                 :             :     {
     261                 :             :       /* Choose the node for which if the remaining path were feasible,
     262                 :             :          it would be the shortest path (summing the length of the
     263                 :             :          known-feasible path so far with that of the remaining
     264                 :             :          possibly-feasible path).  */
     265                 :      202983 :       int ca = ka.m_worklist.get_estimated_cost (ka.m_fnode);
     266                 :      202983 :       int cb = kb.m_worklist.get_estimated_cost (kb.m_fnode);
     267                 :      202983 :       return ca - cb;
     268                 :             :     }
     269                 :             : 
     270                 :             :     const feasible_worklist &m_worklist;
     271                 :             :     feasible_node *m_fnode;
     272                 :             :   };
     273                 :             : 
     274                 :             :   /* Get the estimated length of a path involving FNODE from
     275                 :             :      the origin to the target enode.
     276                 :             :      Sum the length of the known-feasible path so far with
     277                 :             :      that of the remaining possibly-feasible path.  */
     278                 :             : 
     279                 :      405966 :   int get_estimated_cost (const feasible_node *fnode) const
     280                 :             :   {
     281                 :      405966 :     unsigned length_so_far = fnode->get_path_length ();
     282                 :      405966 :     int shortest_remaining_path
     283                 :      405966 :       = m_sep.get_shortest_distance (fnode->get_inner_node ());
     284                 :             : 
     285                 :      405966 :     gcc_assert (shortest_remaining_path >= 0);
     286                 :             :     /* This should be true since we're only exploring nodes within
     287                 :             :        the trimmed graph (and we anticipate it being much smaller
     288                 :             :        than this, and thus not overflowing the sum).  */
     289                 :      405966 :     gcc_assert (shortest_remaining_path < INT_MAX);
     290                 :             : 
     291                 :      405966 :     return length_so_far + shortest_remaining_path;
     292                 :             :   }
     293                 :             : 
     294                 :             :   /* Priority queue, backed by a fibonacci_heap.  */
     295                 :             :   typedef fibonacci_heap<key_t, feasible_node> queue_t;
     296                 :             :   queue_t m_queue;
     297                 :             :   const shortest_paths<eg_traits, exploded_path> &m_sep;
     298                 :             : };
     299                 :             : 
     300                 :             : /* When we're building the exploded graph we want to simplify
     301                 :             :    overly-complicated symbolic values down to "UNKNOWN" to try to avoid
     302                 :             :    state explosions and unbounded chains of exploration.
     303                 :             : 
     304                 :             :    However, when we're building the feasibility graph for a diagnostic
     305                 :             :    (actually a tree), we don't want UNKNOWN values, as conditions on them
     306                 :             :    are also unknown: we don't want to have a contradiction such as a path
     307                 :             :    where (VAL != 0) and then (VAL == 0) along the same path.
     308                 :             : 
     309                 :             :    Hence this is an RAII class for temporarily disabling complexity-checking
     310                 :             :    in the region_model_manager, for use within
     311                 :             :    epath_finder::explore_feasible_paths.
     312                 :             : 
     313                 :             :    We also disable the creation of unknown_svalue instances during feasibility
     314                 :             :    checking, instead creating unique svalues, to avoid paradoxes in paths.  */
     315                 :             : 
     316                 :             : class auto_checking_feasibility
     317                 :             : {
     318                 :             : public:
     319                 :        6737 :   auto_checking_feasibility (region_model_manager *mgr) : m_mgr (mgr)
     320                 :             :   {
     321                 :        6737 :     m_mgr->begin_checking_feasibility ();
     322                 :        6737 :   }
     323                 :        6737 :   ~auto_checking_feasibility ()
     324                 :             :   {
     325                 :        6737 :     m_mgr->end_checking_feasibility ();
     326                 :             :   }
     327                 :             : private:
     328                 :             :   region_model_manager *m_mgr;
     329                 :             : };
     330                 :             : 
     331                 :             : /* Attempt to find the shortest feasible path from the origin to
     332                 :             :    TARGET_ENODE by iteratively building a feasible_graph, in which
     333                 :             :    every path to a feasible_node is feasible by construction.
     334                 :             : 
     335                 :             :    If TARGET_STMT is non-NULL, then check for reaching that stmt
     336                 :             :    within TARGET_ENODE.
     337                 :             : 
     338                 :             :    We effectively explore the tree of feasible paths in order of shortest
     339                 :             :    path until we either find a feasible path to TARGET_ENODE, or hit
     340                 :             :    a limit and give up.
     341                 :             : 
     342                 :             :    Preliminaries:
     343                 :             :    - Find the shortest path from each node to the TARGET_ENODE (without
     344                 :             :    checking feasibility), so that we can prioritize our worklist.
     345                 :             :    - Construct a trimmed_graph: the subset of nodes/edges that
     346                 :             :    are on a path that eventually reaches TARGET_ENODE.  We will only need
     347                 :             :    to consider these when considering the shortest feasible path.
     348                 :             : 
     349                 :             :    Build a feasible_graph, in which every path to a feasible_node
     350                 :             :    is feasible by construction.
     351                 :             :    We use a worklist to flatten the exploration into an iteration.
     352                 :             :    Starting at the origin, find feasible out-edges within the trimmed graph.
     353                 :             :    At each stage, choose the node for which if the remaining path were feasible,
     354                 :             :    it would be the shortest path (summing the length of the known-feasible path
     355                 :             :    so far with that of the remaining possibly-feasible path).
     356                 :             :    This way, the first feasible path we find to TARGET_ENODE is the shortest.
     357                 :             :    We start by trying the shortest possible path, but if that fails,
     358                 :             :    we explore progressively longer paths, eventually trying iterations through
     359                 :             :    loops.  The exploration is captured in the feasible_graph, which can be
     360                 :             :    dumped as a .dot file to visualize the exploration.  The indices of the
     361                 :             :    feasible_nodes show the order in which they were created.
     362                 :             : 
     363                 :             :    This is something of a brute-force approach, but the trimmed_graph
     364                 :             :    hopefully keeps the complexity manageable.
     365                 :             : 
     366                 :             :    Terminate with failure when the number of infeasible edges exceeds
     367                 :             :    a threshold (--param=analyzer-max-infeasible-edges=).
     368                 :             :    This is guaranteed to eventually lead to terminatation, as
     369                 :             :    we can't keep creating feasible nodes without eventually
     370                 :             :    either reaching an infeasible edge, or reaching the
     371                 :             :    TARGET_ENODE.  Specifically, there can't be a cycle of
     372                 :             :    feasible edges that doesn't reach the target_enode without
     373                 :             :    an out-edge that either fails feasibility or gets closer
     374                 :             :    to the TARGET_ENODE: on each iteration we are either:
     375                 :             :    - effectively getting closer to the TARGET_ENODE (which can't
     376                 :             :      continue forever without reaching the target), or
     377                 :             :    - getting monotonically closer to the termination threshold.  */
     378                 :             : 
     379                 :             : std::unique_ptr<exploded_path>
     380                 :        6737 : epath_finder::explore_feasible_paths (const exploded_node *target_enode,
     381                 :             :                                       const gimple *target_stmt,
     382                 :             :                                       const pending_diagnostic &pd,
     383                 :             :                                       const char *desc, unsigned diag_idx)
     384                 :             : {
     385                 :        6737 :   logger *logger = get_logger ();
     386                 :        6737 :   LOG_SCOPE (logger);
     387                 :             : 
     388                 :        6737 :   region_model_manager *mgr = m_eg.get_engine ()->get_model_manager ();
     389                 :             : 
     390                 :             :   /* Determine the shortest path to TARGET_ENODE from each node in
     391                 :             :      the exploded graph.  */
     392                 :        6737 :   shortest_paths<eg_traits, exploded_path> sep
     393                 :        6737 :     (m_eg, target_enode, SPS_TO_GIVEN_TARGET);
     394                 :             : 
     395                 :             :   /* Construct a trimmed_graph: the subset of nodes/edges that
     396                 :             :      are on a path that eventually reaches TARGET_ENODE.
     397                 :             :      We only need to consider these when considering the shortest
     398                 :             :      feasible path.  */
     399                 :        6737 :   trimmed_graph tg (m_eg, target_enode);
     400                 :             : 
     401                 :        6737 :   if (flag_dump_analyzer_feasibility)
     402                 :           8 :     dump_trimmed_graph (target_enode, desc, diag_idx, tg, sep);
     403                 :             : 
     404                 :        6737 :   feasible_graph fg;
     405                 :        6737 :   feasible_worklist worklist (sep);
     406                 :             : 
     407                 :             :   /* Populate the worklist with the origin node.  */
     408                 :        6737 :   {
     409                 :        6737 :     feasibility_state init_state (mgr, m_eg.get_supergraph ());
     410                 :        6737 :     feasible_node *origin = fg.add_node (m_eg.get_origin (), init_state, 0);
     411                 :        6737 :     worklist.add_node (origin);
     412                 :        6737 :   }
     413                 :             : 
     414                 :             :   /* Iteratively explore the tree of feasible paths in order of shortest
     415                 :             :      path until we either find a feasible path to TARGET_ENODE, or hit
     416                 :             :      a limit.  */
     417                 :             : 
     418                 :             :   /* Set this if we find a feasible path to TARGET_ENODE.  */
     419                 :        6737 :   std::unique_ptr<exploded_path> best_path = NULL;
     420                 :             : 
     421                 :        6737 :   {
     422                 :        6737 :     auto_checking_feasibility sentinel (mgr);
     423                 :             : 
     424                 :      155077 :     while (process_worklist_item (&worklist, tg, &fg, target_enode, target_stmt,
     425                 :             :                                   pd, diag_idx, &best_path))
     426                 :             :       {
     427                 :             :         /* Empty; the work is done within process_worklist_item.  */
     428                 :             :       }
     429                 :        6737 :   }
     430                 :             : 
     431                 :        6737 :   if (logger)
     432                 :             :     {
     433                 :           0 :       logger->log ("tg for sd: %i:", diag_idx);
     434                 :           0 :       logger->inc_indent ();
     435                 :           0 :       tg.log_stats (logger);
     436                 :           0 :       logger->dec_indent ();
     437                 :             : 
     438                 :           0 :       logger->log ("fg for sd: %i:", diag_idx);
     439                 :           0 :       logger->inc_indent ();
     440                 :           0 :       fg.log_stats (logger);
     441                 :           0 :       logger->dec_indent ();
     442                 :             :     }
     443                 :             : 
     444                 :             :   /* Dump the feasible_graph.  */
     445                 :        6737 :   if (flag_dump_analyzer_feasibility)
     446                 :           8 :     dump_feasible_graph (target_enode, desc, diag_idx, fg);
     447                 :             : 
     448                 :        6737 :   return best_path;
     449                 :       13474 : }
     450                 :             : 
     451                 :             : /* Process the next item in WORKLIST, potentially adding new items
     452                 :             :    based on feasible out-edges, and extending FG accordingly.
     453                 :             :    Use TG to ignore out-edges that don't lead to TARGET_ENODE.
     454                 :             :    Return true if the worklist processing should continue.
     455                 :             :    Return false if the processing of the worklist should stop
     456                 :             :    (either due to reaching TARGET_ENODE, or hitting a limit).
     457                 :             :    Write to *OUT_BEST_PATH if stopping due to finding a feasible path
     458                 :             :    to TARGET_ENODE.
     459                 :             :    Use PD to provide additional restrictions on feasibility of
     460                 :             :    the final path in the feasible_graph before converting to
     461                 :             :    an exploded_path.  */
     462                 :             : 
     463                 :             : bool
     464                 :      155077 : epath_finder::
     465                 :             : process_worklist_item (feasible_worklist *worklist,
     466                 :             :                        const trimmed_graph &tg,
     467                 :             :                        feasible_graph *fg,
     468                 :             :                        const exploded_node *target_enode,
     469                 :             :                        const gimple *target_stmt,
     470                 :             :                        const pending_diagnostic &pd,
     471                 :             :                        unsigned diag_idx,
     472                 :             :                        std::unique_ptr<exploded_path> *out_best_path) const
     473                 :             : {
     474                 :      155077 :   logger *logger = get_logger ();
     475                 :             : 
     476                 :      155077 :   feasible_node *fnode = worklist->take_next ();
     477                 :      155077 :   if (!fnode)
     478                 :             :     {
     479                 :          50 :       if (logger)
     480                 :           0 :         logger->log ("drained worklist for sd: %i"
     481                 :             :                      " without finding feasible path",
     482                 :             :                      diag_idx);
     483                 :          50 :       return false;
     484                 :             :     }
     485                 :             : 
     486                 :      155027 :   log_scope s (logger, "fg worklist item",
     487                 :             :                "considering FN: %i (EN: %i) for sd: %i",
     488                 :      155027 :                fnode->get_index (), fnode->get_inner_node ()->m_index,
     489                 :      155027 :                diag_idx);
     490                 :             : 
     491                 :             :   /* Iterate through all out-edges from this item.  */
     492                 :      155027 :   unsigned i;
     493                 :      155027 :   exploded_edge *succ_eedge;
     494                 :      365802 :   FOR_EACH_VEC_ELT (fnode->get_inner_node ()->m_succs, i, succ_eedge)
     495                 :             :     {
     496                 :      217462 :       log_scope s (logger, "edge", "considering edge: EN:%i -> EN:%i",
     497                 :      217462 :                    succ_eedge->m_src->m_index,
     498                 :      217462 :                    succ_eedge->m_dest->m_index);
     499                 :             :       /* Reject edges that aren't in the trimmed graph.  */
     500                 :      217462 :       if (!tg.contains_p (succ_eedge))
     501                 :             :         {
     502                 :       57079 :           if (logger)
     503                 :           0 :             logger->log ("rejecting: not in trimmed graph");
     504                 :       57079 :           continue;
     505                 :             :         }
     506                 :             : 
     507                 :      160383 :       feasibility_state succ_state (fnode->get_state ());
     508                 :      160383 :       std::unique_ptr<rejected_constraint> rc;
     509                 :      160383 :       if (succ_state.maybe_update_for_edge (logger, succ_eedge, nullptr, &rc))
     510                 :             :         {
     511                 :      158371 :           gcc_assert (rc == NULL);
     512                 :      158371 :           feasible_node *succ_fnode
     513                 :      158371 :             = fg->add_node (succ_eedge->m_dest,
     514                 :             :                             succ_state,
     515                 :      158371 :                             fnode->get_path_length () + 1);
     516                 :      158371 :           if (logger)
     517                 :           0 :             logger->log ("accepting as FN: %i", succ_fnode->get_index ());
     518                 :      158371 :           fg->add_edge (new feasible_edge (fnode, succ_fnode, succ_eedge));
     519                 :             : 
     520                 :             :           /* Have we reached TARGET_ENODE?  */
     521                 :      158371 :           if (succ_fnode->get_inner_node () == target_enode)
     522                 :             :             {
     523                 :        6568 :               if (logger)
     524                 :           0 :                 logger->log ("success: got feasible path to EN: %i (sd: %i)"
     525                 :             :                              " (length: %i)",
     526                 :           0 :                              target_enode->m_index, diag_idx,
     527                 :             :                              succ_fnode->get_path_length ());
     528                 :        6568 :               if (!pd.check_valid_fpath_p (*succ_fnode, target_stmt))
     529                 :             :                 {
     530                 :         104 :                   if (logger)
     531                 :           0 :                     logger->log ("rejecting feasible path due to"
     532                 :             :                                  " pending_diagnostic");
     533                 :         104 :                   return false;
     534                 :             :                 }
     535                 :        6464 :               *out_best_path = fg->make_epath (succ_fnode);
     536                 :        6464 :               if (flag_dump_analyzer_feasibility)
     537                 :           8 :                 dump_feasible_path (target_enode, diag_idx, *fg, *succ_fnode);
     538                 :             : 
     539                 :             :               /* Success: stop the worklist iteration.  */
     540                 :        6464 :               return false;
     541                 :             :             }
     542                 :             :           else
     543                 :      151803 :             worklist->add_node (succ_fnode);
     544                 :             :         }
     545                 :             :       else
     546                 :             :         {
     547                 :        2012 :           if (logger)
     548                 :           0 :             logger->log ("infeasible");
     549                 :        2012 :           gcc_assert (rc);
     550                 :        2012 :           fg->add_feasibility_problem (fnode,
     551                 :             :                                        succ_eedge,
     552                 :             :                                        std::move (rc));
     553                 :             : 
     554                 :             :           /* Give up if there have been too many infeasible edges.  */
     555                 :        2012 :           if (fg->get_num_infeasible ()
     556                 :        2012 :               > (unsigned)param_analyzer_max_infeasible_edges)
     557                 :             :             {
     558                 :         119 :               if (logger)
     559                 :           0 :                 logger->log ("too many infeasible edges (%i); giving up",
     560                 :             :                              fg->get_num_infeasible ());
     561                 :         119 :               return false;
     562                 :             :             }
     563                 :             :         }
     564                 :      217462 :     }
     565                 :             : 
     566                 :             :   /* Continue the worklist iteration.  */
     567                 :             :   return true;
     568                 :      155027 : }
     569                 :             : 
     570                 :             : /* Helper class for epath_finder::dump_trimmed_graph
     571                 :             :    to dump extra per-node information.
     572                 :             :    Use SEP to add the length of the shortest path from each
     573                 :             :    node to the target node to each node's dump.  */
     574                 :             : 
     575                 :             : class dump_eg_with_shortest_path : public eg_traits::dump_args_t
     576                 :             : {
     577                 :             : public:
     578                 :           8 :   dump_eg_with_shortest_path
     579                 :             :     (const exploded_graph &eg,
     580                 :             :      const shortest_paths<eg_traits, exploded_path> &sep)
     581                 :           8 :   : dump_args_t (eg),
     582                 :           8 :     m_sep (sep)
     583                 :             :   {
     584                 :             :   }
     585                 :             : 
     586                 :         124 :   void dump_extra_info (const exploded_node *enode,
     587                 :             :                         pretty_printer *pp) const final override
     588                 :             :   {
     589                 :         240 :     pp_printf (pp, "sp: %i", m_sep.get_shortest_path (enode).length ());
     590                 :         124 :     pp_newline (pp);
     591                 :         124 :   }
     592                 :             : 
     593                 :             : private:
     594                 :             :   const shortest_paths<eg_traits, exploded_path> &m_sep;
     595                 :             : };
     596                 :             : 
     597                 :             : /* Dump TG to "BASE_NAME.DESC.DIAG_IDX.to-enN.tg.dot",
     598                 :             :    annotating each node with the length of the shortest path
     599                 :             :    from that node to TARGET_ENODE (using SEP).  */
     600                 :             : 
     601                 :             : void
     602                 :           8 : epath_finder::
     603                 :             : dump_trimmed_graph (const exploded_node *target_enode,
     604                 :             :                     const char *desc, unsigned diag_idx,
     605                 :             :                     const trimmed_graph &tg,
     606                 :             :                     const shortest_paths<eg_traits, exploded_path> &sep)
     607                 :             : {
     608                 :           8 :   auto_timevar tv (TV_ANALYZER_DUMP);
     609                 :           8 :   dump_eg_with_shortest_path inner_args (m_eg, sep);
     610                 :           8 :   trimmed_graph::dump_args_t args (inner_args);
     611                 :           8 :   pretty_printer pp;
     612                 :           8 :   pp_printf (&pp, "%s.%s.%i.to-en%i.tg.dot",
     613                 :           8 :              dump_base_name, desc, diag_idx, target_enode->m_index);
     614                 :           8 :   char *filename = xstrdup (pp_formatted_text (&pp));
     615                 :           8 :   tg.dump_dot (filename, NULL, args);
     616                 :           8 :   free (filename);
     617                 :           8 : }
     618                 :             : 
     619                 :             : /* Dump FG to "BASE_NAME.DESC.DIAG_IDX.to-enN.fg.dot".  */
     620                 :             : 
     621                 :             : void
     622                 :           8 : epath_finder::dump_feasible_graph (const exploded_node *target_enode,
     623                 :             :                                    const char *desc, unsigned diag_idx,
     624                 :             :                                    const feasible_graph &fg)
     625                 :             : {
     626                 :           8 :   auto_timevar tv (TV_ANALYZER_DUMP);
     627                 :           8 :   exploded_graph::dump_args_t inner_args (m_eg);
     628                 :           8 :   feasible_graph::dump_args_t args (inner_args);
     629                 :           8 :   pretty_printer pp;
     630                 :           8 :   pp_printf (&pp, "%s.%s.%i.to-en%i.fg.dot",
     631                 :           8 :              dump_base_name, desc, diag_idx, target_enode->m_index);
     632                 :           8 :   char *filename = xstrdup (pp_formatted_text (&pp));
     633                 :           8 :   fg.dump_dot (filename, NULL, args);
     634                 :           8 :   free (filename);
     635                 :           8 : }
     636                 :             : 
     637                 :             : /* Dump the path to FNODE to "BASE_NAME.DIAG_IDX.to-enN.fpath.txt".  */
     638                 :             : 
     639                 :             : void
     640                 :           8 : epath_finder::dump_feasible_path (const exploded_node *target_enode,
     641                 :             :                                   unsigned diag_idx,
     642                 :             :                                   const feasible_graph &fg,
     643                 :             :                                   const feasible_node &fnode) const
     644                 :             : {
     645                 :           8 :   auto_timevar tv (TV_ANALYZER_DUMP);
     646                 :           8 :   pretty_printer pp;
     647                 :           8 :   pp_printf (&pp, "%s.%i.to-en%i.fpath.txt",
     648                 :           8 :              dump_base_name, diag_idx, target_enode->m_index);
     649                 :           8 :   char *filename = xstrdup (pp_formatted_text (&pp));
     650                 :           8 :   fg.dump_feasible_path (fnode, filename);
     651                 :           8 :   free (filename);
     652                 :           8 : }
     653                 :             : 
     654                 :             : /* class saved_diagnostic.  */
     655                 :             : 
     656                 :             : /* saved_diagnostic's ctor.  */
     657                 :             : 
     658                 :        6741 : saved_diagnostic::saved_diagnostic (const state_machine *sm,
     659                 :             :                                     const pending_location &ploc,
     660                 :             :                                     tree var,
     661                 :             :                                     const svalue *sval,
     662                 :             :                                     state_machine::state_t state,
     663                 :             :                                     std::unique_ptr<pending_diagnostic> d,
     664                 :        6741 :                                     unsigned idx)
     665                 :        6741 : : m_sm (sm), m_enode (ploc.m_enode), m_snode (ploc.m_snode),
     666                 :        6741 :   m_stmt (ploc.m_stmt),
     667                 :             :   /* stmt_finder could be on-stack; we want our own copy that can
     668                 :             :      outlive that.  */
     669                 :        6741 :   m_stmt_finder (ploc.m_finder ? ploc.m_finder->clone () : nullptr),
     670                 :        6741 :   m_loc (ploc.m_loc),
     671                 :        6741 :   m_var (var), m_sval (sval), m_state (state),
     672                 :        6741 :   m_d (std::move (d)), m_trailing_eedge (nullptr),
     673                 :        6741 :   m_idx (idx),
     674                 :        6741 :   m_best_epath (nullptr), m_problem (nullptr),
     675                 :        6741 :   m_notes ()
     676                 :             : {
     677                 :             :   /* We must have an enode in order to be able to look for paths
     678                 :             :      through the exploded_graph to this diagnostic.  */
     679                 :        6741 :   gcc_assert (m_enode);
     680                 :        6741 : }
     681                 :             : 
     682                 :             : bool
     683                 :       40004 : saved_diagnostic::operator== (const saved_diagnostic &other) const
     684                 :             : {
     685                 :       42651 :   if (m_notes.length () != other.m_notes.length ())
     686                 :             :     return false;
     687                 :       39421 :   for (unsigned i = 0; i < m_notes.length (); i++)
     688                 :         898 :     if (!m_notes[i]->equal_p (*other.m_notes[i]))
     689                 :             :       return false;
     690                 :       38523 :   return (m_sm == other.m_sm
     691                 :             :           /* We don't compare m_enode.  */
     692                 :       34452 :           && m_snode == other.m_snode
     693                 :        9698 :           && m_stmt == other.m_stmt
     694                 :             :           /* We don't compare m_stmt_finder.  */
     695                 :        7600 :           && m_loc == other.m_loc
     696                 :        7600 :           && pending_diagnostic::same_tree_p (m_var, other.m_var)
     697                 :        6692 :           && m_state == other.m_state
     698                 :        6629 :           && m_d->equal_p (*other.m_d)
     699                 :       44991 :           && m_trailing_eedge == other.m_trailing_eedge);
     700                 :             : }
     701                 :             : 
     702                 :             : /* Add PN to this diagnostic, taking ownership of it.  */
     703                 :             : 
     704                 :             : void
     705                 :         224 : saved_diagnostic::add_note (std::unique_ptr<pending_note> pn)
     706                 :             : {
     707                 :         224 :   gcc_assert (pn);
     708                 :         224 :   m_notes.safe_push (pn.release ());
     709                 :         224 : }
     710                 :             : 
     711                 :             : /* Add EVENT to this diagnostic.  */
     712                 :             : 
     713                 :             : void
     714                 :         188 : saved_diagnostic::add_event (std::unique_ptr<checker_event> event)
     715                 :             : {
     716                 :         188 :   gcc_assert (event);
     717                 :         188 :   m_saved_events.safe_push (event.release ());
     718                 :         188 : }
     719                 :             : 
     720                 :             : /* Return a new json::object of the form
     721                 :             :    {"sm": optional str,
     722                 :             :     "enode": int,
     723                 :             :     "snode": int,
     724                 :             :     "sval": optional str,
     725                 :             :     "state": optional str,
     726                 :             :     "path_length": optional int,
     727                 :             :     "pending_diagnostic": str,
     728                 :             :     "idx": int}.  */
     729                 :             : 
     730                 :             : std::unique_ptr<json::object>
     731                 :           0 : saved_diagnostic::to_json () const
     732                 :             : {
     733                 :           0 :   auto sd_obj = std::make_unique<json::object> ();
     734                 :             : 
     735                 :           0 :   if (m_sm)
     736                 :           0 :     sd_obj->set_string ("sm", m_sm->get_name ());
     737                 :           0 :   sd_obj->set_integer ("enode", m_enode->m_index);
     738                 :           0 :   sd_obj->set_integer ("snode", m_snode->m_index);
     739                 :           0 :   if (m_sval)
     740                 :           0 :     sd_obj->set ("sval", m_sval->to_json ());
     741                 :           0 :   if (m_state)
     742                 :           0 :     sd_obj->set ("state", m_state->to_json ());
     743                 :           0 :   if (m_best_epath)
     744                 :           0 :     sd_obj->set_integer ("path_length", get_epath_length ());
     745                 :           0 :   sd_obj->set_string ("pending_diagnostic", m_d->get_kind ());
     746                 :           0 :   sd_obj->set_integer ("idx", m_idx);
     747                 :             : 
     748                 :             :   /* We're not yet JSONifying the following fields:
     749                 :             :      const gimple *m_stmt;
     750                 :             :      stmt_finder *m_stmt_finder;
     751                 :             :      tree m_var;
     752                 :             :      exploded_edge *m_trailing_eedge;
     753                 :             :      enum status m_status;
     754                 :             :      feasibility_problem *m_problem;
     755                 :             :      auto_delete_vec <pending_note> m_notes;
     756                 :             :   */
     757                 :             : 
     758                 :           0 :   return sd_obj;
     759                 :             : }
     760                 :             : 
     761                 :             : /* Dump this to PP in a form suitable for use as an id in .dot output.  */
     762                 :             : 
     763                 :             : void
     764                 :          40 : saved_diagnostic::dump_dot_id (pretty_printer *pp) const
     765                 :             : {
     766                 :          40 :   pp_printf (pp, "sd_%i", m_idx);
     767                 :          40 : }
     768                 :             : 
     769                 :             : /* Dump this to PP in a form suitable for use as a node in .dot output.  */
     770                 :             : 
     771                 :             : void
     772                 :          20 : saved_diagnostic::dump_as_dot_node (pretty_printer *pp) const
     773                 :             : {
     774                 :          20 :   dump_dot_id (pp);
     775                 :          20 :   pp_printf (pp,
     776                 :             :              " [shape=none,margin=0,style=filled,fillcolor=\"red\",label=\"");
     777                 :          20 :   pp_write_text_to_stream (pp);
     778                 :             : 
     779                 :             :   /* Node label.  */
     780                 :          20 :   pp_printf (pp, "DIAGNOSTIC: %s (sd: %i)\n",
     781                 :          20 :              m_d->get_kind (), m_idx);
     782                 :          20 :   if (m_sm)
     783                 :             :     {
     784                 :          20 :       pp_printf (pp, "sm: %s", m_sm->get_name ());
     785                 :          20 :       if (m_state)
     786                 :             :         {
     787                 :          20 :           pp_printf (pp, "; state: ");
     788                 :          20 :           m_state->dump_to_pp (pp);
     789                 :             :         }
     790                 :          20 :       pp_newline (pp);
     791                 :             :     }
     792                 :          20 :   if (m_stmt)
     793                 :             :     {
     794                 :          20 :       pp_string (pp, "stmt: ");
     795                 :          20 :       pp_gimple_stmt_1 (pp, m_stmt, 0, (dump_flags_t)0);
     796                 :          20 :       pp_newline (pp);
     797                 :             :     }
     798                 :          20 :   if (m_var)
     799                 :          20 :     pp_printf (pp, "var: %qE\n", m_var);
     800                 :          20 :   if (m_sval)
     801                 :             :     {
     802                 :          20 :       pp_string (pp, "sval: ");
     803                 :          20 :       m_sval->dump_to_pp (pp, true);
     804                 :          20 :       pp_newline (pp);
     805                 :             :     }
     806                 :          20 :   if (m_best_epath)
     807                 :           4 :     pp_printf (pp, "path length: %i\n", get_epath_length ());
     808                 :             : 
     809                 :          20 :   pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
     810                 :          20 :   pp_string (pp, "\"];\n\n");
     811                 :             : 
     812                 :             :   /* Show links to duplicates.  */
     813                 :          20 :   for (auto iter : m_duplicates)
     814                 :             :     {
     815                 :           0 :       dump_dot_id (pp);
     816                 :           0 :       pp_string (pp, " -> ");
     817                 :           0 :       iter->dump_dot_id (pp);
     818                 :           0 :       pp_string (pp, " [style=\"dotted\" arrowhead=\"none\"];");
     819                 :           0 :       pp_newline (pp);
     820                 :             :     }
     821                 :          20 : }
     822                 :             : 
     823                 :             : /* Use PF to find the best exploded_path for this saved_diagnostic,
     824                 :             :    and store it in m_best_epath.
     825                 :             :    If we don't have a specific location in m_loc and m_stmt is still NULL,
     826                 :             :    use m_stmt_finder on the epath to populate m_stmt.
     827                 :             :    Return true if a best path was found.  */
     828                 :             : 
     829                 :             : bool
     830                 :        6741 : saved_diagnostic::calc_best_epath (epath_finder *pf)
     831                 :             : {
     832                 :        6741 :   logger *logger = pf->get_logger ();
     833                 :        6741 :   LOG_SCOPE (logger);
     834                 :        6741 :   m_problem = NULL;
     835                 :             : 
     836                 :        6741 :   m_best_epath = pf->get_best_epath (m_enode, m_stmt,
     837                 :        6741 :                                      *m_d, m_d->get_kind (), m_idx,
     838                 :        6741 :                                      &m_problem);
     839                 :             : 
     840                 :             :   /* Handle failure to find a feasible path.  */
     841                 :        6741 :   if (m_best_epath == NULL)
     842                 :             :     return false;
     843                 :             : 
     844                 :        6468 :   gcc_assert (m_best_epath);
     845                 :        6468 :   if (m_loc == UNKNOWN_LOCATION)
     846                 :             :     {
     847                 :        6381 :       if (m_stmt == NULL)
     848                 :             :         {
     849                 :         848 :           gcc_assert (m_stmt_finder);
     850                 :         848 :           m_stmt = m_stmt_finder->find_stmt (*m_best_epath);
     851                 :             :         }
     852                 :        6381 :       gcc_assert (m_stmt);
     853                 :             :     }
     854                 :             : 
     855                 :             :   return true;
     856                 :        6741 : }
     857                 :             : 
     858                 :             : unsigned
     859                 :        7568 : saved_diagnostic::get_epath_length () const
     860                 :             : {
     861                 :        7568 :   gcc_assert (m_best_epath);
     862                 :        7568 :   return m_best_epath->length ();
     863                 :             : }
     864                 :             : 
     865                 :             : /* Record that OTHER (and its duplicates) are duplicates
     866                 :             :    of this saved_diagnostic.  */
     867                 :             : 
     868                 :             : void
     869                 :        2486 : saved_diagnostic::add_duplicate (saved_diagnostic *other)
     870                 :             : {
     871                 :        2486 :   gcc_assert (other);
     872                 :        2486 :   m_duplicates.reserve (m_duplicates.length ()
     873                 :        2510 :                         + other->m_duplicates.length ()
     874                 :             :                         + 1);
     875                 :        2486 :   m_duplicates.splice (other->m_duplicates);
     876                 :        2486 :   other->m_duplicates.truncate (0);
     877                 :        2486 :   m_duplicates.safe_push (other);
     878                 :        2486 : }
     879                 :             : 
     880                 :             : /* Walk up the sedges of each of the two paths.
     881                 :             :    If the two sequences of sedges do not perfectly correspond,
     882                 :             :    then paths are incompatible.
     883                 :             :    If there is at least one sedge that either cannot be paired up
     884                 :             :    or its counterpart is not equal, then the paths are incompatible
     885                 :             :    and this function returns FALSE.
     886                 :             :    Otherwise return TRUE.
     887                 :             : 
     888                 :             :    Incompatible paths:
     889                 :             : 
     890                 :             :        <cond Y>
     891                 :             :        /      \
     892                 :             :       /        \
     893                 :             :     true      false
     894                 :             :      |          |
     895                 :             :     ...        ...
     896                 :             :      |          |
     897                 :             :     ...       stmt x
     898                 :             :      |
     899                 :             :    stmt x
     900                 :             : 
     901                 :             :    Both LHS_PATH and RHS_PATH final enodes should be
     902                 :             :    over the same gimple statement.  */
     903                 :             : 
     904                 :             : static bool
     905                 :          57 : compatible_epath_p (const exploded_path *lhs_path,
     906                 :             :                     const exploded_path *rhs_path)
     907                 :             : {
     908                 :          57 :   gcc_assert (lhs_path);
     909                 :          57 :   gcc_assert (rhs_path);
     910                 :          57 :   gcc_assert (rhs_path->length () > 0);
     911                 :          57 :   gcc_assert (rhs_path->length () > 0);
     912                 :          57 :   int lhs_eedge_idx = lhs_path->length () - 1;
     913                 :          57 :   int rhs_eedge_idx = rhs_path->length () - 1;
     914                 :          57 :   const exploded_edge *lhs_eedge;
     915                 :          57 :   const exploded_edge *rhs_eedge;
     916                 :             : 
     917                 :         254 :   while (lhs_eedge_idx >= 0 && rhs_eedge_idx >= 0)
     918                 :             :     {
     919                 :         786 :       while (lhs_eedge_idx >= 0)
     920                 :             :         {
     921                 :             :           /* Find LHS_PATH's next superedge.  */
     922                 :         749 :           lhs_eedge = lhs_path->m_edges[lhs_eedge_idx];
     923                 :         749 :           if (lhs_eedge->m_sedge)
     924                 :             :             break;
     925                 :             :           else
     926                 :         532 :             lhs_eedge_idx--;
     927                 :             :         }
     928                 :         786 :       while (rhs_eedge_idx >= 0)
     929                 :             :         {
     930                 :             :           /* Find RHS_PATH's next superedge.  */
     931                 :         749 :           rhs_eedge = rhs_path->m_edges[rhs_eedge_idx];
     932                 :         749 :           if (rhs_eedge->m_sedge)
     933                 :             :             break;
     934                 :             :           else
     935                 :         532 :             rhs_eedge_idx--;
     936                 :             :         }
     937                 :             : 
     938                 :         254 :       if (lhs_eedge->m_sedge && rhs_eedge->m_sedge)
     939                 :             :         {
     940                 :         217 :           if (lhs_eedge->m_sedge != rhs_eedge->m_sedge)
     941                 :             :             /* Both superedges do not match.
     942                 :             :                Superedges are not dependent on the exploded path, so even
     943                 :             :                different epaths will have similar sedges if they follow
     944                 :             :                the same outcome of a conditional node.  */
     945                 :             :             return false;
     946                 :             : 
     947                 :         197 :           lhs_eedge_idx--;
     948                 :         197 :           rhs_eedge_idx--;
     949                 :         197 :           continue;
     950                 :             :         }
     951                 :          37 :       else if (lhs_eedge->m_sedge == nullptr && rhs_eedge->m_sedge == nullptr)
     952                 :             :         /* Both paths were drained up entirely.
     953                 :             :            No discriminant was found.  */
     954                 :             :         return true;
     955                 :             : 
     956                 :             :       /* A superedge was found for only one of the two paths.  */
     957                 :             :       return false;
     958                 :             :     }
     959                 :             : 
     960                 :             :   /* A superedge was found for only one of the two paths.  */
     961                 :           0 :   if (lhs_eedge_idx >= 0 || rhs_eedge_idx >= 0)
     962                 :             :     return false;
     963                 :             : 
     964                 :             :   /* Both paths were drained up entirely.
     965                 :             :      No discriminant was found.  */
     966                 :             :   return true;
     967                 :             : }
     968                 :             : 
     969                 :             : 
     970                 :             : /* Return true if this diagnostic supercedes OTHER, and that OTHER should
     971                 :             :    therefore not be emitted.  */
     972                 :             : 
     973                 :             : bool
     974                 :       28883 : saved_diagnostic::supercedes_p (const saved_diagnostic &other) const
     975                 :             : {
     976                 :             :   /* They should be at the same stmt.  */
     977                 :       28883 :   if (m_stmt != other.m_stmt)
     978                 :             :     return false;
     979                 :             :   /* return early if OTHER won't be superseded anyway.  */
     980                 :        5165 :   if (!m_d->supercedes_p (*other.m_d))
     981                 :             :     return false;
     982                 :             : 
     983                 :             :   /* If the two saved_diagnostics' path are not compatible
     984                 :             :      then they cannot supersede one another.  */
     985                 :          57 :   return compatible_epath_p (m_best_epath.get (), other.m_best_epath.get ());
     986                 :             : }
     987                 :             : 
     988                 :             : /* Move any saved checker_events from this saved_diagnostic to
     989                 :             :    the end of DST_PATH.  */
     990                 :             : 
     991                 :             : void
     992                 :        3945 : saved_diagnostic::add_any_saved_events (checker_path &dst_path)
     993                 :             : {
     994                 :        4383 :   for (auto &event : m_saved_events)
     995                 :             :     {
     996                 :         146 :       dst_path.add_event (std::unique_ptr<checker_event> (event));
     997                 :         146 :       event = nullptr;
     998                 :             :     }
     999                 :        3945 : }
    1000                 :             : 
    1001                 :             : /* Emit any pending notes owned by this diagnostic.  */
    1002                 :             : 
    1003                 :             : void
    1004                 :        3877 : saved_diagnostic::emit_any_notes () const
    1005                 :             : {
    1006                 :        4392 :   for (auto pn : m_notes)
    1007                 :         177 :     pn->emit ();
    1008                 :        3877 : }
    1009                 :             : 
    1010                 :             : /* For SARIF output, add additional properties to the "result" object
    1011                 :             :    for this diagnostic.
    1012                 :             :    This extra data is intended for use when debugging the analyzer.  */
    1013                 :             : 
    1014                 :             : void
    1015                 :          21 : saved_diagnostic::maybe_add_sarif_properties (sarif_object &result_obj) const
    1016                 :             : {
    1017                 :          21 :   sarif_property_bag &props = result_obj.get_or_create_properties ();
    1018                 :             : #define PROPERTY_PREFIX "gcc/analyzer/saved_diagnostic/"
    1019                 :          21 :   if (m_sm)
    1020                 :           9 :     props.set_string (PROPERTY_PREFIX "sm", m_sm->get_name ());
    1021                 :          21 :   props.set_integer (PROPERTY_PREFIX "enode", m_enode->m_index);
    1022                 :          21 :   props.set_integer (PROPERTY_PREFIX "snode", m_snode->m_index);
    1023                 :          21 :   if (m_stmt)
    1024                 :             :     {
    1025                 :          21 :       pretty_printer pp;
    1026                 :          21 :       pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
    1027                 :          21 :       props.set_string (PROPERTY_PREFIX "stmt", pp_formatted_text (&pp));
    1028                 :          21 :     }
    1029                 :          21 :   if (m_var)
    1030                 :           9 :     props.set (PROPERTY_PREFIX "var", tree_to_json (m_var));
    1031                 :          21 :   if (m_sval)
    1032                 :           9 :     props.set (PROPERTY_PREFIX "sval", m_sval->to_json ());
    1033                 :          21 :   if (m_state)
    1034                 :           9 :     props.set (PROPERTY_PREFIX "state", m_state->to_json ());
    1035                 :             :   // TODO: m_best_epath
    1036                 :          21 :   props.set_integer (PROPERTY_PREFIX "idx", m_idx);
    1037                 :          21 :   if (m_duplicates.length () > 0)
    1038                 :             :     {
    1039                 :           4 :       auto duplicates_arr = std::make_unique<json::array> ();
    1040                 :          16 :       for (auto iter : m_duplicates)
    1041                 :             :         {
    1042                 :           4 :           auto sd_obj = std::make_unique<sarif_object> ();
    1043                 :           4 :           iter->maybe_add_sarif_properties (*sd_obj);
    1044                 :           4 :           duplicates_arr->append (std::move (sd_obj));
    1045                 :           4 :         }
    1046                 :           4 :       props.set<json::array> (PROPERTY_PREFIX "duplicates",
    1047                 :             :                               std::move (duplicates_arr));
    1048                 :           4 :     }
    1049                 :             : #undef PROPERTY_PREFIX
    1050                 :             : 
    1051                 :             : #define PROPERTY_PREFIX "gcc/analyzer/pending_diagnostic/"
    1052                 :          21 :   props.set_string (PROPERTY_PREFIX "kind", m_d->get_kind ());
    1053                 :             : #undef PROPERTY_PREFIX
    1054                 :             : 
    1055                 :             :   /* Potentially add pending_diagnostic-specific properties.  */
    1056                 :          21 :   m_d->maybe_add_sarif_properties (result_obj);
    1057                 :          21 : }
    1058                 :             : 
    1059                 :             : /* State for building a checker_path from a particular exploded_path.
    1060                 :             :    In particular, this precomputes reachability information: the set of
    1061                 :             :    source enodes for which a path be found to the diagnostic enode.  */
    1062                 :             : 
    1063                 :        3945 : class path_builder
    1064                 :             : {
    1065                 :             : public:
    1066                 :        3945 :   path_builder (const exploded_graph &eg,
    1067                 :             :                 const exploded_path &epath,
    1068                 :             :                 const feasibility_problem *problem,
    1069                 :             :                 const saved_diagnostic &sd)
    1070                 :        3945 :   : m_eg (eg),
    1071                 :        3945 :     m_diag_enode (epath.get_final_enode ()),
    1072                 :        3945 :     m_sd (sd),
    1073                 :        3945 :     m_reachability (eg, m_diag_enode),
    1074                 :        3945 :     m_feasibility_problem (problem)
    1075                 :        3945 :   {}
    1076                 :             : 
    1077                 :           0 :   const exploded_node *get_diag_node () const { return m_diag_enode; }
    1078                 :             : 
    1079                 :       24350 :   pending_diagnostic *get_pending_diagnostic () const
    1080                 :             :   {
    1081                 :         211 :     return m_sd.m_d.get ();
    1082                 :             :   }
    1083                 :             : 
    1084                 :        2978 :   bool reachable_from_p (const exploded_node *src_enode) const
    1085                 :             :   {
    1086                 :        5956 :     return m_reachability.reachable_from_p (src_enode);
    1087                 :             :   }
    1088                 :             : 
    1089                 :      267587 :   const extrinsic_state &get_ext_state () const { return m_eg.get_ext_state (); }
    1090                 :             : 
    1091                 :       50970 :   const feasibility_problem *get_feasibility_problem () const
    1092                 :             :   {
    1093                 :       50970 :     return m_feasibility_problem;
    1094                 :             :   }
    1095                 :             : 
    1096                 :        5168 :   const state_machine *get_sm () const { return m_sd.m_sm; }
    1097                 :             : 
    1098                 :             : private:
    1099                 :             :   typedef reachability<eg_traits> enode_reachability;
    1100                 :             : 
    1101                 :             :   const exploded_graph &m_eg;
    1102                 :             : 
    1103                 :             :   /* The enode where the diagnostic occurs.  */
    1104                 :             :   const exploded_node *m_diag_enode;
    1105                 :             : 
    1106                 :             :   const saved_diagnostic &m_sd;
    1107                 :             : 
    1108                 :             :   /* Precompute all enodes from which the diagnostic is reachable.  */
    1109                 :             :   enode_reachability m_reachability;
    1110                 :             : 
    1111                 :             :   const feasibility_problem *m_feasibility_problem;
    1112                 :             : };
    1113                 :             : 
    1114                 :             : /* Determine the emission location for PD at STMT in FUN.  */
    1115                 :             : 
    1116                 :             : static location_t
    1117                 :       13711 : get_emission_location (const gimple *stmt, function *fun,
    1118                 :             :                        const pending_diagnostic &pd)
    1119                 :             : {
    1120                 :       13711 :   location_t loc = get_stmt_location (stmt, fun);
    1121                 :             : 
    1122                 :             :   /* Allow the pending_diagnostic to fix up the location.  */
    1123                 :       13711 :   loc = pd.fixup_location (loc, true);
    1124                 :             : 
    1125                 :       13711 :   return loc;
    1126                 :             : }
    1127                 :             : 
    1128                 :             : /* class diagnostic_manager.  */
    1129                 :             : 
    1130                 :             : /* diagnostic_manager's ctor.  */
    1131                 :             : 
    1132                 :        3313 : diagnostic_manager::diagnostic_manager (logger *logger, engine *eng,
    1133                 :        3313 :                                         int verbosity)
    1134                 :        3313 : : log_user (logger), m_eng (eng), m_verbosity (verbosity),
    1135                 :        3313 :   m_num_disabled_diagnostics (0)
    1136                 :             : {
    1137                 :        3313 : }
    1138                 :             : 
    1139                 :             : /* Queue pending_diagnostic D at ENODE for later emission.
    1140                 :             :    Return true/false signifying if the diagnostic was actually added.  */
    1141                 :             : 
    1142                 :             : bool
    1143                 :       10813 : diagnostic_manager::add_diagnostic (const state_machine *sm,
    1144                 :             :                                     const pending_location &ploc,
    1145                 :             :                                     tree var,
    1146                 :             :                                     const svalue *sval,
    1147                 :             :                                     state_machine::state_t state,
    1148                 :             :                                     std::unique_ptr<pending_diagnostic> d)
    1149                 :             : {
    1150                 :       10813 :   LOG_FUNC (get_logger ());
    1151                 :             : 
    1152                 :             :   /* We must have an enode in order to be able to look for paths
    1153                 :             :      through the exploded_graph to the diagnostic.  */
    1154                 :       10813 :   gcc_assert (ploc.m_enode);
    1155                 :             : 
    1156                 :             :   /* If this warning is ultimately going to be rejected by a -Wno-analyzer-*
    1157                 :             :      flag, reject it now.
    1158                 :             :      We can only do this for diagnostics where we already know the stmt,
    1159                 :             :      and thus can determine the emission location.  */
    1160                 :       10813 :   if (ploc.m_stmt)
    1161                 :             :     {
    1162                 :        9845 :       location_t loc
    1163                 :        9845 :         = get_emission_location (ploc.m_stmt, ploc.m_snode->m_fun, *d);
    1164                 :        9845 :       int option = d->get_controlling_option ();
    1165                 :        9845 :       if (!warning_enabled_at (loc, option))
    1166                 :             :         {
    1167                 :        4072 :           if (get_logger ())
    1168                 :           0 :             get_logger ()->log ("rejecting disabled warning %qs",
    1169                 :           0 :                                 d->get_kind ());
    1170                 :        4072 :           m_num_disabled_diagnostics++;
    1171                 :        4072 :           return false;
    1172                 :             :         }
    1173                 :             :     }
    1174                 :             : 
    1175                 :        6741 :   saved_diagnostic *sd
    1176                 :             :     = new saved_diagnostic (sm, ploc, var, sval, state, std::move (d),
    1177                 :       11935 :                             m_saved_diagnostics.length ());
    1178                 :        6741 :   m_saved_diagnostics.safe_push (sd);
    1179                 :        6741 :   ploc.m_enode->add_diagnostic (sd);
    1180                 :        6741 :   if (get_logger ())
    1181                 :           0 :     log ("adding saved diagnostic %i at SN %i to EN %i: %qs",
    1182                 :             :          sd->get_index (),
    1183                 :           0 :          ploc.m_snode->m_index, ploc.m_enode->m_index, sd->m_d->get_kind ());
    1184                 :             :   return true;
    1185                 :       10813 : }
    1186                 :             : 
    1187                 :             : /* Queue pending_diagnostic D at ENODE for later emission.
    1188                 :             :    Return true/false signifying if the diagnostic was actually added.
    1189                 :             :    Take ownership of D (or delete it).  */
    1190                 :             : 
    1191                 :             : bool
    1192                 :        3565 : diagnostic_manager::add_diagnostic (const pending_location &ploc,
    1193                 :             :                                     std::unique_ptr<pending_diagnostic> d)
    1194                 :             : {
    1195                 :        3565 :   gcc_assert (ploc.m_enode);
    1196                 :        3565 :   return add_diagnostic (NULL, ploc, NULL_TREE, NULL, 0, std::move (d));
    1197                 :             : }
    1198                 :             : 
    1199                 :             : /* Add PN to the most recent saved_diagnostic.  */
    1200                 :             : 
    1201                 :             : void
    1202                 :         224 : diagnostic_manager::add_note (std::unique_ptr<pending_note> pn)
    1203                 :             : {
    1204                 :         224 :   LOG_FUNC (get_logger ());
    1205                 :         224 :   gcc_assert (pn);
    1206                 :             : 
    1207                 :             :   /* Get most recent saved_diagnostic.  */
    1208                 :         224 :   gcc_assert (m_saved_diagnostics.length () > 0);
    1209                 :         224 :   saved_diagnostic *sd = m_saved_diagnostics[m_saved_diagnostics.length () - 1];
    1210                 :         224 :   sd->add_note (std::move (pn));
    1211                 :         224 : }
    1212                 :             : 
    1213                 :             : /* Add EVENT to the most recent saved_diagnostic.  */
    1214                 :             : 
    1215                 :             : void
    1216                 :         188 : diagnostic_manager::add_event (std::unique_ptr<checker_event> event)
    1217                 :             : {
    1218                 :         188 :   LOG_FUNC (get_logger ());
    1219                 :         188 :   gcc_assert (event);
    1220                 :             : 
    1221                 :             :   /* Get most recent saved_diagnostic.  */
    1222                 :         188 :   gcc_assert (m_saved_diagnostics.length () > 0);
    1223                 :         188 :   saved_diagnostic *sd = m_saved_diagnostics[m_saved_diagnostics.length () - 1];
    1224                 :         188 :   sd->add_event (std::move (event));
    1225                 :         188 : }
    1226                 :             : 
    1227                 :             : /* Return a new json::object of the form
    1228                 :             :    {"diagnostics"  : [obj for saved_diagnostic]}.  */
    1229                 :             : 
    1230                 :             : std::unique_ptr<json::object>
    1231                 :           0 : diagnostic_manager::to_json () const
    1232                 :             : {
    1233                 :           0 :   auto dm_obj = std::make_unique<json::object> ();
    1234                 :             : 
    1235                 :           0 :   {
    1236                 :           0 :     auto sd_arr = std::make_unique<json::array> ();
    1237                 :           0 :     int i;
    1238                 :           0 :     saved_diagnostic *sd;
    1239                 :           0 :     FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
    1240                 :           0 :       sd_arr->append (sd->to_json ());
    1241                 :           0 :     dm_obj->set ("diagnostics", std::move (sd_arr));
    1242                 :           0 :   }
    1243                 :             : 
    1244                 :           0 :   return dm_obj;
    1245                 :             : }
    1246                 :             : 
    1247                 :             : /* A class for identifying sets of duplicated pending_diagnostic.
    1248                 :             : 
    1249                 :             :    We want to find the simplest saved_diagnostic amongst those that share a
    1250                 :             :    dedupe_key.  */
    1251                 :             : 
    1252                 :             : class dedupe_key
    1253                 :             : {
    1254                 :             : public:
    1255                 :        6468 :   dedupe_key (const saved_diagnostic &sd)
    1256                 :        6468 :   : m_sd (sd), m_stmt (sd.m_stmt), m_loc (sd.m_loc)
    1257                 :             :   {
    1258                 :        6468 :     gcc_assert (m_stmt || m_loc != UNKNOWN_LOCATION);
    1259                 :        6468 :   }
    1260                 :             : 
    1261                 :       48235 :   hashval_t hash () const
    1262                 :             :   {
    1263                 :       48235 :     inchash::hash hstate;
    1264                 :       48235 :     hstate.add_ptr (m_stmt);
    1265                 :             :     // TODO: m_sd
    1266                 :       48235 :     return hstate.end ();
    1267                 :             :   }
    1268                 :       40004 :   bool operator== (const dedupe_key &other) const
    1269                 :             :   {
    1270                 :       40004 :     return (m_sd == other.m_sd
    1271                 :        6468 :             && m_stmt == other.m_stmt
    1272                 :       46472 :             && m_loc == other.m_loc);
    1273                 :             :   }
    1274                 :             : 
    1275                 :       59298 :   location_t get_location () const
    1276                 :             :   {
    1277                 :       59298 :     if (m_loc != UNKNOWN_LOCATION)
    1278                 :             :       return m_loc;
    1279                 :       57822 :     gcc_assert (m_stmt);
    1280                 :       57822 :     return m_stmt->location;
    1281                 :             :   }
    1282                 :             : 
    1283                 :             :   /* A qsort comparator for use by dedupe_winners::emit_best
    1284                 :             :      to sort them into location_t order.  */
    1285                 :             : 
    1286                 :             :   static int
    1287                 :       29649 :   comparator (const void *p1, const void *p2)
    1288                 :             :   {
    1289                 :       29649 :     const dedupe_key *pk1 = *(const dedupe_key * const *)p1;
    1290                 :       29649 :     const dedupe_key *pk2 = *(const dedupe_key * const *)p2;
    1291                 :             : 
    1292                 :       29649 :     location_t loc1 = pk1->get_location ();
    1293                 :       29649 :     location_t loc2 = pk2->get_location ();
    1294                 :             : 
    1295                 :       29649 :     if (int cmp = linemap_compare_locations (line_table, loc2, loc1))
    1296                 :             :       return cmp;
    1297                 :        1292 :     if (int cmp = ((int)pk1->m_sd.get_epath_length ()
    1298                 :        1292 :                    - (int)pk2->m_sd.get_epath_length ()))
    1299                 :             :       return cmp;
    1300                 :         977 :     if (int cmp = strcmp (pk1->m_sd.m_d->get_kind (),
    1301                 :         977 :                           pk2->m_sd.m_d->get_kind ()))
    1302                 :             :       return cmp;
    1303                 :             :     return 0;
    1304                 :             :   }
    1305                 :             : 
    1306                 :             :   const saved_diagnostic &m_sd;
    1307                 :             :   const gimple *m_stmt;
    1308                 :             :   location_t m_loc;
    1309                 :             : };
    1310                 :             : 
    1311                 :             : /* Traits for use by dedupe_winners.  */
    1312                 :             : 
    1313                 :             : class dedupe_hash_map_traits
    1314                 :             : {
    1315                 :             : public:
    1316                 :             :   typedef const dedupe_key *key_type;
    1317                 :             :   typedef saved_diagnostic *value_type;
    1318                 :             :   typedef saved_diagnostic *compare_type;
    1319                 :             : 
    1320                 :       48235 :   static inline hashval_t hash (const key_type &v)
    1321                 :             :   {
    1322                 :       48235 :     return v->hash ();
    1323                 :             :   }
    1324                 :       40004 :   static inline bool equal_keys (const key_type &k1, const key_type &k2)
    1325                 :             :   {
    1326                 :       40004 :     return *k1 == *k2;
    1327                 :             :   }
    1328                 :             :   template <typename T>
    1329                 :             :   static inline void remove (T &)
    1330                 :             :   {
    1331                 :             :     // TODO
    1332                 :             :   }
    1333                 :             :   template <typename T>
    1334                 :          37 :   static inline void mark_deleted (T &entry)
    1335                 :             :   {
    1336                 :          37 :     entry.m_key = reinterpret_cast<key_type> (1);
    1337                 :             :   }
    1338                 :             :   template <typename T>
    1339                 :           0 :   static inline void mark_empty (T &entry)
    1340                 :             :   {
    1341                 :           0 :     entry.m_key = NULL;
    1342                 :             :   }
    1343                 :             :   template <typename T>
    1344                 :       91758 :   static inline bool is_deleted (const T &entry)
    1345                 :             :   {
    1346                 :       91758 :     return entry.m_key == reinterpret_cast<key_type> (1);
    1347                 :             :   }
    1348                 :             :   template <typename T>
    1349                 :      436502 :   static inline bool is_empty (const T &entry)
    1350                 :             :   {
    1351                 :      436502 :     return entry.m_key == NULL;
    1352                 :             :   }
    1353                 :             :   static const bool empty_zero_p = true;
    1354                 :             : };
    1355                 :             : 
    1356                 :             : /* A class for deduplicating diagnostics and finding (and emitting) the
    1357                 :             :    best saved_diagnostic within each partition.  */
    1358                 :             : 
    1359                 :             : class dedupe_winners
    1360                 :             : {
    1361                 :             : public:
    1362                 :        1547 :   ~dedupe_winners ()
    1363                 :             :   {
    1364                 :             :     /* Delete all keys, but not the saved_diagnostics.  */
    1365                 :        5492 :     for (map_t::iterator iter = m_map.begin ();
    1366                 :        5492 :          iter != m_map.end ();
    1367                 :        3945 :          ++iter)
    1368                 :        3945 :       delete (*iter).first;
    1369                 :        1547 :   }
    1370                 :             : 
    1371                 :             :   /* Determine an exploded_path for SD using PF and, if it's feasible,
    1372                 :             :      determine if SD is the best seen so far for its dedupe_key.
    1373                 :             :      Record the winning SD for each dedupe_key.  */
    1374                 :             : 
    1375                 :        6741 :   void add (logger *logger,
    1376                 :             :             epath_finder *pf,
    1377                 :             :             saved_diagnostic *sd)
    1378                 :             :   {
    1379                 :             :     /* Determine best epath for SD.  */
    1380                 :        6741 :     if (!sd->calc_best_epath (pf))
    1381                 :         273 :       return;
    1382                 :             : 
    1383                 :        6468 :     dedupe_key *key = new dedupe_key (*sd);
    1384                 :        6468 :     if (saved_diagnostic **slot = m_map.get (key))
    1385                 :             :       {
    1386                 :        2486 :         if (logger)
    1387                 :           0 :           logger->log ("already have this dedupe_key");
    1388                 :             : 
    1389                 :        2486 :         saved_diagnostic *cur_best_sd = *slot;
    1390                 :             : 
    1391                 :        2486 :         if (sd->get_epath_length () < cur_best_sd->get_epath_length ())
    1392                 :             :           {
    1393                 :             :             /* We've got a shorter path for the key; replace
    1394                 :             :                the current candidate, marking it as a duplicate of SD.  */
    1395                 :          47 :             if (logger)
    1396                 :           0 :               logger->log ("length %i is better than existing length %i;"
    1397                 :             :                            " taking over this dedupe_key",
    1398                 :             :                            sd->get_epath_length (),
    1399                 :             :                            cur_best_sd->get_epath_length ());
    1400                 :          47 :             sd->add_duplicate (cur_best_sd);
    1401                 :          47 :             *slot = sd;
    1402                 :             :           }
    1403                 :             :         else
    1404                 :             :           /* We haven't beaten the current best candidate; add SD
    1405                 :             :              as a duplicate of it.  */
    1406                 :             :           {
    1407                 :        2439 :             if (logger)
    1408                 :           0 :               logger->log ("length %i isn't better than existing length %i;"
    1409                 :             :                            " dropping this candidate",
    1410                 :             :                            sd->get_epath_length (),
    1411                 :             :                            cur_best_sd->get_epath_length ());
    1412                 :        2439 :             cur_best_sd->add_duplicate (sd);
    1413                 :             :           }
    1414                 :        2486 :         delete key;
    1415                 :             :       }
    1416                 :             :     else
    1417                 :             :       {
    1418                 :             :         /* This is the first candidate for this key.  */
    1419                 :        3982 :         m_map.put (key, sd);
    1420                 :        3982 :         if (logger)
    1421                 :           0 :           logger->log ("first candidate for this dedupe_key");
    1422                 :             :       }
    1423                 :             :   }
    1424                 :             : 
    1425                 :             :   /* Handle interactions between the dedupe winners, so that some
    1426                 :             :      diagnostics can supercede others (of different kinds).
    1427                 :             : 
    1428                 :             :      We want use-after-free to supercede use-of-unitialized-value,
    1429                 :             :      so that if we have these at the same stmt, we don't emit
    1430                 :             :      a use-of-uninitialized, just the use-after-free.  */
    1431                 :             : 
    1432                 :        1547 :   void handle_interactions (diagnostic_manager *dm)
    1433                 :             :   {
    1434                 :        1547 :     LOG_SCOPE (dm->get_logger ());
    1435                 :        1547 :     auto_vec<const dedupe_key *> superceded;
    1436                 :        5529 :     for (auto outer : m_map)
    1437                 :             :       {
    1438                 :        3982 :         const saved_diagnostic *outer_sd = outer.second;
    1439                 :       65656 :         for (auto inner : m_map)
    1440                 :             :           {
    1441                 :       28883 :             const saved_diagnostic *inner_sd = inner.second;
    1442                 :       28883 :             if (inner_sd->supercedes_p (*outer_sd))
    1443                 :             :               {
    1444                 :          37 :                 superceded.safe_push (outer.first);
    1445                 :          37 :                 if (dm->get_logger ())
    1446                 :           0 :                   dm->log ("sd[%i] \"%s\" superceded by sd[%i] \"%s\"",
    1447                 :           0 :                            outer_sd->get_index (), outer_sd->m_d->get_kind (),
    1448                 :           0 :                            inner_sd->get_index (), inner_sd->m_d->get_kind ());
    1449                 :             :                 break;
    1450                 :             :               }
    1451                 :             :           }
    1452                 :             :       }
    1453                 :        1658 :     for (auto iter : superceded)
    1454                 :          37 :       m_map.remove (iter);
    1455                 :        1547 :   }
    1456                 :             : 
    1457                 :             :  /* Emit the simplest diagnostic within each set.  */
    1458                 :             : 
    1459                 :        1547 :   void emit_best (diagnostic_manager *dm,
    1460                 :             :                   const exploded_graph &eg)
    1461                 :             :   {
    1462                 :        1547 :     LOG_SCOPE (dm->get_logger ());
    1463                 :             : 
    1464                 :             :     /* Get keys into a vec for sorting.  */
    1465                 :        1547 :     auto_vec<const dedupe_key *> keys (m_map.elements ());
    1466                 :        1547 :     for (map_t::iterator iter = m_map.begin ();
    1467                 :        5492 :          iter != m_map.end ();
    1468                 :        3945 :          ++iter)
    1469                 :        3945 :       keys.quick_push ((*iter).first);
    1470                 :             : 
    1471                 :        3040 :     dm->log ("# keys after de-duplication: %i", keys.length ());
    1472                 :             : 
    1473                 :             :     /* Sort into a good emission order.  */
    1474                 :        1547 :     keys.qsort (dedupe_key::comparator);
    1475                 :             : 
    1476                 :             :     /* Emit the best saved_diagnostics for each key.  */
    1477                 :             :     int i;
    1478                 :             :     const dedupe_key *key;
    1479                 :        6985 :     FOR_EACH_VEC_ELT (keys, i, key)
    1480                 :             :       {
    1481                 :        3945 :         saved_diagnostic **slot = m_map.get (key);
    1482                 :        3945 :         gcc_assert (*slot);
    1483                 :        3945 :         saved_diagnostic *sd = *slot;
    1484                 :        3945 :         dm->emit_saved_diagnostic (eg, *sd);
    1485                 :             :       }
    1486                 :        1547 :   }
    1487                 :             : 
    1488                 :             : private:
    1489                 :             :   /* This maps from each dedupe_key to a current best saved_diagnostic.  */
    1490                 :             : 
    1491                 :             :   typedef hash_map<const dedupe_key *, saved_diagnostic *,
    1492                 :             :                    dedupe_hash_map_traits> map_t;
    1493                 :             :   map_t m_map;
    1494                 :             : };
    1495                 :             : 
    1496                 :             : /* Emit all saved diagnostics.  */
    1497                 :             : 
    1498                 :             : void
    1499                 :        3313 : diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg)
    1500                 :             : {
    1501                 :        3313 :   LOG_SCOPE (get_logger ());
    1502                 :        3313 :   auto_timevar tv (TV_ANALYZER_DIAGNOSTICS);
    1503                 :        4860 :   log ("# saved diagnostics: %i", m_saved_diagnostics.length ());
    1504                 :        3313 :   log ("# disabled diagnostics: %i", m_num_disabled_diagnostics);
    1505                 :        3313 :   if (get_logger ())
    1506                 :             :     {
    1507                 :             :       unsigned i;
    1508                 :             :       saved_diagnostic *sd;
    1509                 :           2 :       FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
    1510                 :           0 :         log ("[%i] sd: %qs at EN: %i, SN: %i",
    1511                 :           0 :              i, sd->m_d->get_kind (), sd->m_enode->m_index,
    1512                 :           0 :              sd->m_snode->m_index);
    1513                 :             :     }
    1514                 :             : 
    1515                 :        3313 :   if (m_saved_diagnostics.length () == 0)
    1516                 :        1766 :     return;
    1517                 :             : 
    1518                 :             :   /* Compute the shortest_paths once, sharing it between all diagnostics.  */
    1519                 :        1547 :   epath_finder pf (eg);
    1520                 :             : 
    1521                 :             :   /* Iterate through all saved diagnostics, adding them to a dedupe_winners
    1522                 :             :      instance.  This partitions the saved diagnostics by dedupe_key,
    1523                 :             :      generating exploded_paths for them, and retaining the best one in each
    1524                 :             :      partition.  */
    1525                 :        1547 :   dedupe_winners best_candidates;
    1526                 :             : 
    1527                 :        1547 :   int i;
    1528                 :        1547 :   saved_diagnostic *sd;
    1529                 :        9835 :   FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
    1530                 :        6741 :     best_candidates.add (get_logger (), &pf, sd);
    1531                 :             : 
    1532                 :        1547 :   best_candidates.handle_interactions (this);
    1533                 :             : 
    1534                 :             :   /* For each dedupe-key, call emit_saved_diagnostic on the "best"
    1535                 :             :      saved_diagnostic.  */
    1536                 :        1547 :   best_candidates.emit_best (this, eg);
    1537                 :        3313 : }
    1538                 :             : 
    1539                 :             : /* Custom subclass of diagnostic_metadata which, for SARIF output,
    1540                 :             :    populates the property bag of the diagnostic's "result" object
    1541                 :             :    with information from the saved_diagnostic and the
    1542                 :             :    pending_diagnostic.  */
    1543                 :             : 
    1544                 :        3945 : class pending_diagnostic_metadata : public diagnostic_metadata
    1545                 :             : {
    1546                 :             : public:
    1547                 :        3945 :   pending_diagnostic_metadata (const saved_diagnostic &sd)
    1548                 :        3945 :   : m_sd (sd)
    1549                 :             :   {
    1550                 :             :   }
    1551                 :             : 
    1552                 :             :   void
    1553                 :          17 :   maybe_add_sarif_properties (sarif_object &result_obj) const override
    1554                 :             :   {
    1555                 :          17 :     m_sd.maybe_add_sarif_properties (result_obj);
    1556                 :          17 :   }
    1557                 :             : 
    1558                 :             : private:
    1559                 :             :   const saved_diagnostic &m_sd;
    1560                 :             : };
    1561                 :             : 
    1562                 :             : /* Given a saved_diagnostic SD with m_best_epath through EG,
    1563                 :             :    create an checker_path of suitable events and use it to call
    1564                 :             :    SD's underlying pending_diagnostic "emit" vfunc to emit a diagnostic.  */
    1565                 :             : 
    1566                 :             : void
    1567                 :        3945 : diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
    1568                 :             :                                            saved_diagnostic &sd)
    1569                 :             : {
    1570                 :        3945 :   LOG_SCOPE (get_logger ());
    1571                 :        3945 :   log ("sd[%i]: %qs at SN: %i",
    1572                 :        3945 :        sd.get_index (), sd.m_d->get_kind (), sd.m_snode->m_index);
    1573                 :        5683 :   log ("num dupes: %i", sd.get_num_dupes ());
    1574                 :             : 
    1575                 :        3945 :   const exploded_path *epath = sd.get_best_epath ();
    1576                 :        3945 :   gcc_assert (epath);
    1577                 :             : 
    1578                 :             :   /* Precompute all enodes from which the diagnostic is reachable.  */
    1579                 :        3945 :   path_builder pb (eg, *epath, sd.get_feasibility_problem (), sd);
    1580                 :             : 
    1581                 :             :   /* This is the diagnostic_path subclass that will be built for
    1582                 :             :      the diagnostic.  */
    1583                 :        3945 :   checker_path emission_path (get_logical_location_manager (),
    1584                 :        3945 :                               get_logger ());
    1585                 :             : 
    1586                 :             :   /* Populate emission_path with a full description of EPATH.  */
    1587                 :        3945 :   build_emission_path (pb, *epath, &emission_path);
    1588                 :             : 
    1589                 :             :   /* Now prune it to just cover the most pertinent events.  */
    1590                 :        3945 :   prune_path (&emission_path, sd.m_sm, sd.m_sval, sd.m_state);
    1591                 :             : 
    1592                 :             :   /* Add any saved events to the path, giving contextual information
    1593                 :             :      about what the analyzer was simulating as the diagnostic was
    1594                 :             :      generated.  These don't get pruned, as they are probably pertinent.  */
    1595                 :        3945 :   sd.add_any_saved_events (emission_path);
    1596                 :             : 
    1597                 :             :   /* Add a final event to the path, covering the diagnostic itself.
    1598                 :             :      We use the final enode from the epath, which might be different from
    1599                 :             :      the sd.m_enode, as the dedupe code doesn't care about enodes, just
    1600                 :             :      snodes.  */
    1601                 :        3945 :   {
    1602                 :        3945 :     const exploded_node *const enode = epath->get_final_enode ();
    1603                 :        3945 :     const gimple *stmt = sd.m_stmt;
    1604                 :        3945 :     event_loc_info loc_info (get_stmt_location (stmt, enode->get_function ()),
    1605                 :        3945 :                              enode->get_function ()->decl,
    1606                 :        3945 :                              enode->get_stack_depth ());
    1607                 :        3945 :     if (sd.m_stmt_finder)
    1608                 :         587 :       sd.m_stmt_finder->update_event_loc_info (loc_info);
    1609                 :        3945 :     sd.m_d->add_final_event (sd.m_sm, enode, loc_info,
    1610                 :             :                              sd.m_var, sd.m_state, &emission_path);
    1611                 :             :   }
    1612                 :             : 
    1613                 :             :   /* The "final" event might not be final; if the saved_diagnostic has a
    1614                 :             :      trailing eedge stashed, add any events for it.  This is for use
    1615                 :             :      in handling longjmp, to show where a longjmp is rewinding to.  */
    1616                 :        3945 :   if (sd.m_trailing_eedge)
    1617                 :           4 :     add_events_for_eedge (pb, *sd.m_trailing_eedge, &emission_path, NULL);
    1618                 :             : 
    1619                 :        3945 :   emission_path.inject_any_inlined_call_events (get_logger ());
    1620                 :             : 
    1621                 :        3945 :   emission_path.prepare_for_emission (sd.m_d.get ());
    1622                 :             : 
    1623                 :        3945 :   location_t loc = sd.m_loc;
    1624                 :        3945 :   if (loc == UNKNOWN_LOCATION)
    1625                 :        3866 :     loc = get_emission_location (sd.m_stmt, sd.m_snode->m_fun, *sd.m_d);
    1626                 :             : 
    1627                 :             :   /* Allow the pending_diagnostic to fix up the locations of events.  */
    1628                 :        3945 :   emission_path.fixup_locations (sd.m_d.get ());
    1629                 :             : 
    1630                 :        3945 :   gcc_rich_location rich_loc (loc);
    1631                 :        3945 :   rich_loc.set_path (&emission_path);
    1632                 :             : 
    1633                 :        3945 :   auto_diagnostic_group d;
    1634                 :        3945 :   auto_cfun sentinel (sd.m_snode->m_fun);
    1635                 :        3945 :   pending_diagnostic_metadata m (sd);
    1636                 :        3945 :   diagnostic_emission_context diag_ctxt (sd, rich_loc, m, get_logger ());
    1637                 :        3945 :   if (sd.m_d->emit (diag_ctxt))
    1638                 :             :     {
    1639                 :        3877 :       sd.emit_any_notes ();
    1640                 :             : 
    1641                 :        3877 :       unsigned num_dupes = sd.get_num_dupes ();
    1642                 :        3877 :       if (flag_analyzer_show_duplicate_count && num_dupes > 0)
    1643                 :          10 :         inform_n (loc, num_dupes,
    1644                 :             :                   "%i duplicate", "%i duplicates",
    1645                 :             :                   num_dupes);
    1646                 :        3877 :       if (flag_dump_analyzer_exploded_paths)
    1647                 :             :         {
    1648                 :           0 :           auto_timevar tv (TV_ANALYZER_DUMP);
    1649                 :           0 :           pretty_printer pp;
    1650                 :           0 :           pp_printf (&pp, "%s.%i.%s.epath.txt",
    1651                 :           0 :                      dump_base_name, sd.get_index (), sd.m_d->get_kind ());
    1652                 :           0 :           char *filename = xstrdup (pp_formatted_text (&pp));
    1653                 :           0 :           epath->dump_to_file (filename, eg.get_ext_state ());
    1654                 :           0 :           inform (loc, "exploded path written to %qs", filename);
    1655                 :           0 :           free (filename);
    1656                 :           0 :         }
    1657                 :             :     }
    1658                 :        3945 : }
    1659                 :             : 
    1660                 :             : const logical_location_manager &
    1661                 :        3945 : diagnostic_manager::get_logical_location_manager () const
    1662                 :             : {
    1663                 :        3945 :   gcc_assert (global_dc);
    1664                 :        3945 :   auto mgr = global_dc->get_logical_location_manager ();
    1665                 :        3945 :   gcc_assert (mgr);
    1666                 :        3945 :   return *mgr;
    1667                 :             : }
    1668                 :             : 
    1669                 :             : /* Emit a "path" of events to EMISSION_PATH describing the exploded path
    1670                 :             :    EPATH within EG.  */
    1671                 :             : 
    1672                 :             : void
    1673                 :        3945 : diagnostic_manager::build_emission_path (const path_builder &pb,
    1674                 :             :                                          const exploded_path &epath,
    1675                 :             :                                          checker_path *emission_path) const
    1676                 :             : {
    1677                 :        3945 :   LOG_SCOPE (get_logger ());
    1678                 :             : 
    1679                 :        3945 :   interesting_t interest;
    1680                 :        3945 :   pb.get_pending_diagnostic ()->mark_interesting_stuff (&interest);
    1681                 :             : 
    1682                 :             :   /* Add region creation events for any globals of interest, at the
    1683                 :             :      beginning of the path.  */
    1684                 :        3945 :   {
    1685                 :        7873 :     for (auto reg : interest.m_region_creation)
    1686                 :        1328 :       switch (reg->get_memory_space ())
    1687                 :             :         {
    1688                 :        1108 :         default:
    1689                 :        1108 :           continue;
    1690                 :         220 :         case MEMSPACE_CODE:
    1691                 :         220 :         case MEMSPACE_GLOBALS:
    1692                 :         220 :         case MEMSPACE_READONLY_DATA:
    1693                 :         220 :           {
    1694                 :         220 :             const region *base_reg = reg->get_base_region ();
    1695                 :         220 :             if (tree decl = base_reg->maybe_get_decl ())
    1696                 :         211 :               if (DECL_P (decl)
    1697                 :         211 :                   && DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION)
    1698                 :             :                 {
    1699                 :         211 :                   emission_path->add_region_creation_events
    1700                 :         211 :                     (pb.get_pending_diagnostic (),
    1701                 :             :                      reg, NULL,
    1702                 :         211 :                      event_loc_info (DECL_SOURCE_LOCATION (decl),
    1703                 :             :                                      NULL_TREE,
    1704                 :         211 :                                      0),
    1705                 :         211 :                      m_verbosity > 3);
    1706                 :             :                 }
    1707                 :             :           }
    1708                 :        1108 :         }
    1709                 :             :   }
    1710                 :             : 
    1711                 :             :   /* Walk EPATH, adding events as appropriate.  */
    1712                 :       54907 :   for (unsigned i = 0; i < epath.m_edges.length (); i++)
    1713                 :             :     {
    1714                 :       50962 :       const exploded_edge *eedge = epath.m_edges[i];
    1715                 :       50962 :       add_events_for_eedge (pb, *eedge, emission_path, &interest);
    1716                 :             :     }
    1717                 :        3945 :   add_event_on_final_node (pb, epath.get_final_enode (),
    1718                 :             :                            emission_path, &interest);
    1719                 :        3945 : }
    1720                 :             : 
    1721                 :             : /* Emit a region_creation_event when requested on the last statement in
    1722                 :             :    the path.
    1723                 :             : 
    1724                 :             :    If a region_creation_event should be emitted on the last statement of the
    1725                 :             :    path, we need to peek to the successors to get whether the final enode
    1726                 :             :    created a region.
    1727                 :             : */
    1728                 :             : 
    1729                 :             : void
    1730                 :        3945 : diagnostic_manager::add_event_on_final_node (const path_builder &pb,
    1731                 :             :                                              const exploded_node *final_enode,
    1732                 :             :                                              checker_path *emission_path,
    1733                 :             :                                              interesting_t *interest) const
    1734                 :             : {
    1735                 :        3945 :   const program_point &src_point = final_enode->get_point ();
    1736                 :        3945 :   const int src_stack_depth = src_point.get_stack_depth ();
    1737                 :        3945 :   const program_state &src_state = final_enode->get_state ();
    1738                 :        3945 :   const region_model *src_model = src_state.m_region_model;
    1739                 :             : 
    1740                 :        3945 :   unsigned j;
    1741                 :        3945 :   exploded_edge *e;
    1742                 :        6878 :   FOR_EACH_VEC_ELT (final_enode->m_succs, j, e)
    1743                 :             :   {
    1744                 :        2994 :     exploded_node *dst = e->m_dest;
    1745                 :        2994 :     const program_state &dst_state = dst->get_state ();
    1746                 :        2994 :     const region_model *dst_model = dst_state.m_region_model;
    1747                 :        2994 :     if (src_model->get_dynamic_extents ()
    1748                 :        2994 :         != dst_model->get_dynamic_extents ())
    1749                 :             :       {
    1750                 :             :         unsigned i;
    1751                 :             :         const region *reg;
    1752                 :             :         bool emitted = false;
    1753                 :         270 :         FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
    1754                 :             :           {
    1755                 :          68 :             const region *base_reg = reg->get_base_region ();
    1756                 :          68 :             const svalue *old_extents
    1757                 :          68 :         = src_model->get_dynamic_extents (base_reg);
    1758                 :          68 :             const svalue *new_extents
    1759                 :          68 :         = dst_model->get_dynamic_extents (base_reg);
    1760                 :          68 :             if (old_extents == NULL && new_extents != NULL)
    1761                 :          61 :               switch (base_reg->get_kind ())
    1762                 :             :                 {
    1763                 :             :                 default:
    1764                 :             :                   break;
    1765                 :          61 :                 case RK_HEAP_ALLOCATED:
    1766                 :          61 :                 case RK_ALLOCA:
    1767                 :          61 :                   emission_path->add_region_creation_events
    1768                 :          61 :                     (pb.get_pending_diagnostic (),
    1769                 :             :                      reg,
    1770                 :             :                      dst_model,
    1771                 :          61 :                      event_loc_info (src_point.get_location (),
    1772                 :             :                                      src_point.get_fndecl (),
    1773                 :          61 :                                      src_stack_depth),
    1774                 :             :                      false);
    1775                 :          61 :                   emitted = true;
    1776                 :          61 :                   break;
    1777                 :             :                 }
    1778                 :             :           }
    1779                 :         202 :         if (emitted)
    1780                 :             :           break;
    1781                 :             :       }
    1782                 :             :   }
    1783                 :        3945 : }
    1784                 :             : 
    1785                 :             : /* Subclass of state_change_visitor that creates state_change_event
    1786                 :             :    instances.  */
    1787                 :             : 
    1788                 :       50966 : class state_change_event_creator : public state_change_visitor
    1789                 :             : {
    1790                 :             : public:
    1791                 :       50966 :   state_change_event_creator (const path_builder &pb,
    1792                 :             :                               const exploded_edge &eedge,
    1793                 :             :                               checker_path *emission_path)
    1794                 :       50966 :     : m_pb (pb),
    1795                 :       50966 :       m_eedge (eedge),
    1796                 :       50966 :       m_emission_path (emission_path)
    1797                 :             :   {}
    1798                 :             : 
    1799                 :          97 :   bool on_global_state_change (const state_machine &sm,
    1800                 :             :                                state_machine::state_t src_sm_val,
    1801                 :             :                                state_machine::state_t dst_sm_val)
    1802                 :             :     final override
    1803                 :             :   {
    1804                 :          97 :     if (&sm != m_pb.get_sm ())
    1805                 :             :       return false;
    1806                 :          55 :     const exploded_node *src_node = m_eedge.m_src;
    1807                 :          55 :     const program_point &src_point = src_node->get_point ();
    1808                 :          55 :     const int src_stack_depth = src_point.get_stack_depth ();
    1809                 :          55 :     const exploded_node *dst_node = m_eedge.m_dest;
    1810                 :          55 :     const gimple *stmt = src_point.get_stmt ();
    1811                 :          55 :     const supernode *supernode = src_point.get_supernode ();
    1812                 :          55 :     const program_state &dst_state = dst_node->get_state ();
    1813                 :             : 
    1814                 :          55 :     int stack_depth = src_stack_depth;
    1815                 :             : 
    1816                 :          55 :     m_emission_path->add_event
    1817                 :          55 :       (std::make_unique<state_change_event> (supernode,
    1818                 :             :                                              stmt,
    1819                 :             :                                              stack_depth,
    1820                 :             :                                              sm,
    1821                 :         110 :                                              nullptr,
    1822                 :             :                                              src_sm_val,
    1823                 :             :                                              dst_sm_val,
    1824                 :          55 :                                              nullptr,
    1825                 :             :                                              dst_state,
    1826                 :             :                                              src_node));
    1827                 :          55 :     return false;
    1828                 :             :   }
    1829                 :             : 
    1830                 :        5071 :   bool on_state_change (const state_machine &sm,
    1831                 :             :                         state_machine::state_t src_sm_val,
    1832                 :             :                         state_machine::state_t dst_sm_val,
    1833                 :             :                         const svalue *sval,
    1834                 :             :                         const svalue *dst_origin_sval) final override
    1835                 :             :   {
    1836                 :        5071 :     if (&sm != m_pb.get_sm ())
    1837                 :             :       return false;
    1838                 :        4146 :     const exploded_node *src_node = m_eedge.m_src;
    1839                 :        4146 :     const program_point &src_point = src_node->get_point ();
    1840                 :        4146 :     const int src_stack_depth = src_point.get_stack_depth ();
    1841                 :        4146 :     const exploded_node *dst_node = m_eedge.m_dest;
    1842                 :        4146 :     const gimple *stmt = src_point.get_stmt ();
    1843                 :        4146 :     const supernode *supernode = src_point.get_supernode ();
    1844                 :        4146 :     const program_state &dst_state = dst_node->get_state ();
    1845                 :             : 
    1846                 :        4146 :     int stack_depth = src_stack_depth;
    1847                 :             : 
    1848                 :        4146 :     if (m_eedge.m_sedge
    1849                 :         312 :         && m_eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE)
    1850                 :             :       {
    1851                 :         312 :         supernode = src_point.get_supernode ();
    1852                 :         312 :         stmt = supernode->get_last_stmt ();
    1853                 :         312 :         stack_depth = src_stack_depth;
    1854                 :             :       }
    1855                 :             : 
    1856                 :             :     /* Bulletproofing for state changes at calls/returns;
    1857                 :             :        TODO: is there a better way? */
    1858                 :        4146 :     if (!stmt)
    1859                 :             :       return false;
    1860                 :             : 
    1861                 :        4083 :     m_emission_path->add_event
    1862                 :        4083 :       (std::make_unique<state_change_event> (supernode,
    1863                 :             :                                              stmt,
    1864                 :             :                                              stack_depth,
    1865                 :             :                                              sm,
    1866                 :             :                                              sval,
    1867                 :             :                                              src_sm_val,
    1868                 :             :                                              dst_sm_val,
    1869                 :             :                                              dst_origin_sval,
    1870                 :             :                                              dst_state,
    1871                 :             :                                              src_node));
    1872                 :        4083 :     return false;
    1873                 :             :   }
    1874                 :             : 
    1875                 :             :   const path_builder &m_pb;
    1876                 :             :   const exploded_edge &m_eedge;
    1877                 :             :   checker_path *m_emission_path;
    1878                 :             : };
    1879                 :             : 
    1880                 :             : /* Compare SRC_STATE and DST_STATE (which use EXT_STATE), and call
    1881                 :             :    VISITOR's on_state_change for every sm-state change that occurs
    1882                 :             :    to a tree, and on_global_state_change for every global state change
    1883                 :             :    that occurs.
    1884                 :             : 
    1885                 :             :    This determines the state changes that ought to be reported to
    1886                 :             :    the user: a combination of the effects of changes to sm_state_map
    1887                 :             :    (which maps svalues to sm-states), and of region_model changes
    1888                 :             :    (which map trees to svalues).
    1889                 :             : 
    1890                 :             :    Bail out early and return true if any call to on_global_state_change
    1891                 :             :    or on_state_change returns true, otherwise return false.
    1892                 :             : 
    1893                 :             :    This is split out to make it easier to experiment with changes to
    1894                 :             :    exploded_node granularity (so that we can observe what state changes
    1895                 :             :    lead to state_change_events being emitted).  */
    1896                 :             : 
    1897                 :             : bool
    1898                 :       50966 : for_each_state_change (const program_state &src_state,
    1899                 :             :                        const program_state &dst_state,
    1900                 :             :                        const extrinsic_state &ext_state,
    1901                 :             :                        state_change_visitor *visitor)
    1902                 :             : {
    1903                 :      101932 :   gcc_assert (src_state.m_checker_states.length ()
    1904                 :             :               == ext_state.get_num_checkers ());
    1905                 :      101932 :   gcc_assert (dst_state.m_checker_states.length ()
    1906                 :             :               == ext_state.get_num_checkers ());
    1907                 :      405200 :   for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
    1908                 :             :     {
    1909                 :      354234 :       const state_machine &sm = ext_state.get_sm (i);
    1910                 :      354234 :       const sm_state_map &src_smap = *src_state.m_checker_states[i];
    1911                 :      354234 :       const sm_state_map &dst_smap = *dst_state.m_checker_states[i];
    1912                 :             : 
    1913                 :             :       /* Add events for any global state changes.  */
    1914                 :      354234 :       if (src_smap.get_global_state () != dst_smap.get_global_state ())
    1915                 :          97 :         if (visitor->on_global_state_change (sm,
    1916                 :             :                                              src_smap.get_global_state (),
    1917                 :             :                                              dst_smap.get_global_state ()))
    1918                 :             :           return true;
    1919                 :             : 
    1920                 :             :       /* Add events for per-svalue state changes.  */
    1921                 :      412909 :       for (sm_state_map::iterator_t iter = dst_smap.begin ();
    1922                 :      767143 :            iter != dst_smap.end ();
    1923                 :       58675 :            ++iter)
    1924                 :             :         {
    1925                 :       58675 :           const svalue *sval = (*iter).first;
    1926                 :       58675 :           state_machine::state_t dst_sm_val = (*iter).second.m_state;
    1927                 :       58675 :           state_machine::state_t src_sm_val
    1928                 :       58675 :             = src_smap.get_state (sval, ext_state);
    1929                 :       58675 :           if (dst_sm_val != src_sm_val)
    1930                 :             :             {
    1931                 :        5071 :               const svalue *origin_sval = (*iter).second.m_origin;
    1932                 :        5071 :               if (visitor->on_state_change (sm, src_sm_val, dst_sm_val,
    1933                 :             :                                             sval, origin_sval))
    1934                 :           0 :                 return true;
    1935                 :             :             }
    1936                 :             :         }
    1937                 :             :     }
    1938                 :             :   return false;
    1939                 :             : }
    1940                 :             : 
    1941                 :             : /* An sm_context for adding state_change_event on assignments to NULL,
    1942                 :             :    where the default state isn't m_start.  Storing such state in the
    1943                 :             :    sm_state_map would lead to bloat of the exploded_graph, so we want
    1944                 :             :    to leave it as a default state, and inject state change events here
    1945                 :             :    when we have a diagnostic.
    1946                 :             :    Find transitions of constants, for handling on_zero_assignment.  */
    1947                 :             : 
    1948                 :      189489 : struct null_assignment_sm_context : public sm_context
    1949                 :             : {
    1950                 :      189489 :   null_assignment_sm_context (int sm_idx,
    1951                 :             :                               const state_machine &sm,
    1952                 :             :                               const program_state *old_state,
    1953                 :             :                               const program_state *new_state,
    1954                 :             :                               const gimple *stmt,
    1955                 :             :                               const program_point *point,
    1956                 :             :                               checker_path *emission_path,
    1957                 :             :                               const extrinsic_state &ext_state)
    1958                 :      189489 :   : sm_context (sm_idx, sm), m_old_state (old_state), m_new_state (new_state),
    1959                 :      189489 :     m_stmt (stmt), m_point (point), m_emission_path (emission_path),
    1960                 :      189489 :     m_ext_state (ext_state)
    1961                 :             :   {
    1962                 :             :   }
    1963                 :             : 
    1964                 :           0 :   tree get_fndecl_for_call (const gcall &/*call*/) final override
    1965                 :             :   {
    1966                 :           0 :     return NULL_TREE;
    1967                 :             :   }
    1968                 :             : 
    1969                 :       10274 :   state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
    1970                 :             :                                     tree var) final override
    1971                 :             :   {
    1972                 :       10274 :     const svalue *var_old_sval
    1973                 :       10274 :       = m_old_state->m_region_model->get_rvalue (var, NULL);
    1974                 :       10274 :     const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx];
    1975                 :             : 
    1976                 :       10274 :     state_machine::state_t current
    1977                 :       10274 :       = old_smap->get_state (var_old_sval, m_ext_state);
    1978                 :             : 
    1979                 :       10274 :     return current;
    1980                 :             :   }
    1981                 :             : 
    1982                 :          48 :   state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
    1983                 :             :                                     const svalue *sval) final override
    1984                 :             :   {
    1985                 :          48 :     const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx];
    1986                 :          48 :     state_machine::state_t current = old_smap->get_state (sval, m_ext_state);
    1987                 :          48 :     return current;
    1988                 :             :   }
    1989                 :             : 
    1990                 :        3782 :   void set_next_state (const gimple *stmt,
    1991                 :             :                        tree var,
    1992                 :             :                        state_machine::state_t to,
    1993                 :             :                        tree origin ATTRIBUTE_UNUSED) final override
    1994                 :             :   {
    1995                 :        3782 :     state_machine::state_t from = get_state (stmt, var);
    1996                 :        3782 :     if (from != m_sm.get_start_state ())
    1997                 :        3278 :       return;
    1998                 :        2766 :     if (!is_transition_to_null (to))
    1999                 :             :       return;
    2000                 :             : 
    2001                 :         504 :     const svalue *var_new_sval
    2002                 :         504 :       = m_new_state->m_region_model->get_rvalue (var, NULL);
    2003                 :             : 
    2004                 :         504 :     const supernode *supernode = m_point->get_supernode ();
    2005                 :         504 :     int stack_depth = m_point->get_stack_depth ();
    2006                 :             : 
    2007                 :         504 :     m_emission_path->add_event
    2008                 :         504 :       (std::make_unique<state_change_event> (supernode,
    2009                 :         504 :                                              m_stmt,
    2010                 :             :                                              stack_depth,
    2011                 :             :                                              m_sm,
    2012                 :             :                                              var_new_sval,
    2013                 :             :                                              from, to,
    2014                 :        1008 :                                              nullptr,
    2015                 :         504 :                                              *m_new_state,
    2016                 :        1008 :                                              nullptr));
    2017                 :             :   }
    2018                 :             : 
    2019                 :           9 :   void set_next_state (const gimple *stmt,
    2020                 :             :                        const svalue *sval,
    2021                 :             :                        state_machine::state_t to,
    2022                 :             :                        tree origin ATTRIBUTE_UNUSED) final override
    2023                 :             :   {
    2024                 :           9 :     state_machine::state_t from = get_state (stmt, sval);
    2025                 :           9 :     if (from != m_sm.get_start_state ())
    2026                 :           9 :       return;
    2027                 :           0 :     if (!is_transition_to_null (to))
    2028                 :             :       return;
    2029                 :             : 
    2030                 :           0 :     const supernode *supernode = m_point->get_supernode ();
    2031                 :           0 :     int stack_depth = m_point->get_stack_depth ();
    2032                 :             : 
    2033                 :           0 :     m_emission_path->add_event
    2034                 :           0 :       (std::make_unique<state_change_event> (supernode,
    2035                 :           0 :                                              m_stmt,
    2036                 :             :                                              stack_depth,
    2037                 :             :                                              m_sm,
    2038                 :             :                                              sval,
    2039                 :             :                                              from, to,
    2040                 :           0 :                                              nullptr,
    2041                 :           0 :                                              *m_new_state,
    2042                 :           0 :                                              nullptr));
    2043                 :             :   }
    2044                 :             : 
    2045                 :        1010 :   void warn (const supernode *, const gimple *,
    2046                 :             :              tree, std::unique_ptr<pending_diagnostic>) final override
    2047                 :             :   {
    2048                 :        1010 :   }
    2049                 :           0 :   void warn (const supernode *, const gimple *,
    2050                 :             :              const svalue *, std::unique_ptr<pending_diagnostic>) final override
    2051                 :             :   {
    2052                 :           0 :   }
    2053                 :             : 
    2054                 :        1010 :   tree get_diagnostic_tree (tree expr) final override
    2055                 :             :   {
    2056                 :        1010 :     return expr;
    2057                 :             :   }
    2058                 :             : 
    2059                 :           0 :   tree get_diagnostic_tree (const svalue *sval) final override
    2060                 :             :   {
    2061                 :           0 :     return m_new_state->m_region_model->get_representative_tree (sval);
    2062                 :             :   }
    2063                 :             : 
    2064                 :       27077 :   state_machine::state_t get_global_state () const final override
    2065                 :             :   {
    2066                 :       27077 :     return 0;
    2067                 :             :   }
    2068                 :             : 
    2069                 :           0 :   void set_global_state (state_machine::state_t) final override
    2070                 :             :   {
    2071                 :             :     /* No-op.  */
    2072                 :           0 :   }
    2073                 :             : 
    2074                 :           0 :   void clear_all_per_svalue_state () final override
    2075                 :             :   {
    2076                 :             :     /* No-op.  */
    2077                 :           0 :   }
    2078                 :             : 
    2079                 :           0 :   void on_custom_transition (custom_transition *) final override
    2080                 :             :   {
    2081                 :           0 :   }
    2082                 :             : 
    2083                 :       27114 :   tree is_zero_assignment (const gimple *stmt) final override
    2084                 :             :   {
    2085                 :       51670 :     const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
    2086                 :       27114 :     if (!assign_stmt)
    2087                 :             :      return NULL_TREE;
    2088                 :       54228 :     if (const svalue *sval
    2089                 :       27114 :         = m_new_state->m_region_model->get_gassign_result (assign_stmt, NULL))
    2090                 :       26181 :       if (tree cst = sval->maybe_get_constant ())
    2091                 :        5762 :         if (::zerop(cst))
    2092                 :        2558 :           return gimple_assign_lhs (assign_stmt);
    2093                 :             :     return NULL_TREE;
    2094                 :             :   }
    2095                 :             : 
    2096                 :        3353 :   const program_state *get_old_program_state () const final override
    2097                 :             :   {
    2098                 :        3353 :     return m_old_state;
    2099                 :             :   }
    2100                 :           0 :   const program_state *get_new_program_state () const final override
    2101                 :             :   {
    2102                 :           0 :     return m_new_state;
    2103                 :             :   }
    2104                 :             : 
    2105                 :             :   /* We only care about transitions to the "null" state
    2106                 :             :      within sm-malloc.  Special-case this.  */
    2107                 :        2766 :   static bool is_transition_to_null (state_machine::state_t s)
    2108                 :             :   {
    2109                 :        2766 :     return !strcmp (s->get_name (), "null");
    2110                 :             :   }
    2111                 :             : 
    2112                 :             :   const program_state *m_old_state;
    2113                 :             :   const program_state *m_new_state;
    2114                 :             :   const gimple *m_stmt;
    2115                 :             :   const program_point *m_point;
    2116                 :             :   checker_path *m_emission_path;
    2117                 :             :   const extrinsic_state &m_ext_state;
    2118                 :             : };
    2119                 :             : 
    2120                 :             : /* Subroutine of diagnostic_manager::build_emission_path.
    2121                 :             :    Add any events for EEDGE to EMISSION_PATH.  */
    2122                 :             : 
    2123                 :             : void
    2124                 :       50966 : diagnostic_manager::add_events_for_eedge (const path_builder &pb,
    2125                 :             :                                           const exploded_edge &eedge,
    2126                 :             :                                           checker_path *emission_path,
    2127                 :             :                                           interesting_t *interest) const
    2128                 :             : {
    2129                 :       50966 :   const exploded_node *src_node = eedge.m_src;
    2130                 :       50966 :   const program_point &src_point = src_node->get_point ();
    2131                 :       50966 :   const int src_stack_depth = src_point.get_stack_depth ();
    2132                 :       50966 :   const exploded_node *dst_node = eedge.m_dest;
    2133                 :       50966 :   const program_point &dst_point = dst_node->get_point ();
    2134                 :       50966 :   const int dst_stack_depth = dst_point.get_stack_depth ();
    2135                 :       50966 :   if (get_logger ())
    2136                 :             :     {
    2137                 :           0 :       get_logger ()->start_log_line ();
    2138                 :           0 :       pretty_printer *pp = get_logger ()->get_printer ();
    2139                 :           0 :       pp_printf (pp, "EN %i -> EN %i: ",
    2140                 :           0 :                  eedge.m_src->m_index,
    2141                 :           0 :                  eedge.m_dest->m_index);
    2142                 :           0 :       src_point.print (pp, format (false));
    2143                 :           0 :       pp_string (pp, "-> ");
    2144                 :           0 :       dst_point.print (pp, format (false));
    2145                 :           0 :       get_logger ()->end_log_line ();
    2146                 :             :     }
    2147                 :       50966 :   const program_state &src_state = src_node->get_state ();
    2148                 :       50966 :   const program_state &dst_state = dst_node->get_state ();
    2149                 :             : 
    2150                 :             :   /* Add state change events for the states that have changed.
    2151                 :             :      We add these before events for superedges, so that if we have a
    2152                 :             :      state_change_event due to following an edge, we'll get this sequence
    2153                 :             :      of events:
    2154                 :             : 
    2155                 :             :       | if (!ptr)
    2156                 :             :       |    ~
    2157                 :             :       |    |
    2158                 :             :       |    (1) assuming 'ptr' is non-NULL  (state_change_event)
    2159                 :             :       |    (2) following 'false' branch... (start_cfg_edge_event)
    2160                 :             :      ...
    2161                 :             :       | do_something (ptr);
    2162                 :             :       | ~~~~~~~~~~~~~^~~~~
    2163                 :             :       |              |
    2164                 :             :       |              (3) ...to here        (end_cfg_edge_event).  */
    2165                 :       50966 :   state_change_event_creator visitor (pb, eedge, emission_path);
    2166                 :       50966 :   for_each_state_change (src_state, dst_state, pb.get_ext_state (),
    2167                 :             :                          &visitor);
    2168                 :             : 
    2169                 :             :   /* Allow non-standard edges to add events, e.g. when rewinding from
    2170                 :             :      longjmp to a setjmp.  */
    2171                 :       50966 :   if (eedge.m_custom_info)
    2172                 :         581 :     eedge.m_custom_info->add_events_to_path (emission_path, eedge);
    2173                 :             : 
    2174                 :             :   /* Add events for superedges, function entries, and for statements.  */
    2175                 :       50966 :   switch (dst_point.get_kind ())
    2176                 :             :     {
    2177                 :             :     default:
    2178                 :             :       break;
    2179                 :       18068 :     case PK_BEFORE_SUPERNODE:
    2180                 :       18068 :       if (src_point.get_kind () == PK_AFTER_SUPERNODE)
    2181                 :             :         {
    2182                 :       14088 :           if (eedge.m_sedge)
    2183                 :       13977 :             add_events_for_superedge (pb, eedge, emission_path);
    2184                 :             :         }
    2185                 :             :       /* Add function entry events.  */
    2186                 :       18068 :       if (dst_point.get_supernode ()->entry_p ())
    2187                 :             :         {
    2188                 :        5169 :           pb.get_pending_diagnostic ()->add_function_entry_event
    2189                 :        5169 :             (eedge, emission_path);
    2190                 :             :           /* Create region_creation_events for on-stack regions within
    2191                 :             :              this frame.  */
    2192                 :        5169 :           if (interest)
    2193                 :             :             {
    2194                 :             :               unsigned i;
    2195                 :             :               const region *reg;
    2196                 :        6669 :               FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
    2197                 :        1500 :                 if (const frame_region *frame = reg->maybe_get_frame_region ())
    2198                 :        1002 :                   if (frame->get_fndecl () == dst_point.get_fndecl ())
    2199                 :             :                     {
    2200                 :         851 :                       const region *base_reg = reg->get_base_region ();
    2201                 :         851 :                       if (tree decl = base_reg->maybe_get_decl ())
    2202                 :         750 :                         if (DECL_P (decl)
    2203                 :         750 :                             && DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION)
    2204                 :             :                           {
    2205                 :         746 :                             emission_path->add_region_creation_events
    2206                 :        1492 :                               (pb.get_pending_diagnostic (),
    2207                 :         746 :                                reg, dst_state.m_region_model,
    2208                 :        1492 :                                event_loc_info (DECL_SOURCE_LOCATION (decl),
    2209                 :             :                                                dst_point.get_fndecl (),
    2210                 :         746 :                                                dst_stack_depth),
    2211                 :         746 :                                m_verbosity > 3);
    2212                 :             :                           }
    2213                 :             :                     }
    2214                 :             :             }
    2215                 :             :         }
    2216                 :             :       break;
    2217                 :       18283 :     case PK_BEFORE_STMT:
    2218                 :       18283 :       {
    2219                 :       18283 :         const gimple *stmt = dst_point.get_stmt ();
    2220                 :       18283 :         const gcall *call = dyn_cast <const gcall *> (stmt);
    2221                 :        8412 :         if (call && is_setjmp_call_p (*call))
    2222                 :          20 :           emission_path->add_event
    2223                 :          20 :             (std::make_unique<setjmp_event>
    2224                 :          20 :                (event_loc_info (stmt->location,
    2225                 :             :                                 dst_point.get_fndecl (),
    2226                 :          20 :                                 dst_stack_depth),
    2227                 :             :                 dst_node,
    2228                 :             :                 *call));
    2229                 :             :         else
    2230                 :       18263 :           emission_path->add_event
    2231                 :       18263 :             (std::make_unique<statement_event> (stmt,
    2232                 :       36526 :                                                 dst_point.get_fndecl (),
    2233                 :             :                                                 dst_stack_depth, dst_state));
    2234                 :             : 
    2235                 :             :         /* Create state change events for assignment to NULL.
    2236                 :             :            Iterate through the stmts in dst_enode, adding state change
    2237                 :             :            events for them.  */
    2238                 :       18283 :         if (dst_state.m_region_model)
    2239                 :             :           {
    2240                 :       18283 :             log_scope s (get_logger (), "processing run of stmts");
    2241                 :       18283 :             program_state iter_state (dst_state);
    2242                 :       18283 :             program_point iter_point (dst_point);
    2243                 :       71426 :             while (1)
    2244                 :             :               {
    2245                 :       71426 :                 const gimple *stmt = iter_point.get_stmt ();
    2246                 :       71426 :                 if (const gassign *assign = dyn_cast<const gassign *> (stmt))
    2247                 :             :                   {
    2248                 :       27132 :                     const extrinsic_state &ext_state = pb.get_ext_state ();
    2249                 :       27132 :                     program_state old_state (iter_state);
    2250                 :       27132 :                     iter_state.m_region_model->on_assignment (assign, NULL);
    2251                 :      216621 :                     for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
    2252                 :             :                       {
    2253                 :      189489 :                         const state_machine &sm = ext_state.get_sm (i);
    2254                 :      189489 :                         null_assignment_sm_context sm_ctxt (i, sm,
    2255                 :             :                                                             &old_state,
    2256                 :             :                                                             &iter_state,
    2257                 :             :                                                             stmt,
    2258                 :             :                                                             &iter_point,
    2259                 :             :                                                             emission_path,
    2260                 :      189489 :                                                             pb.get_ext_state ());
    2261                 :      189489 :                         sm.on_stmt (sm_ctxt, dst_point.get_supernode (), stmt);
    2262                 :             :                         // TODO: what about phi nodes?
    2263                 :      189489 :                       }
    2264                 :       27132 :                   }
    2265                 :       71426 :                 iter_point.next_stmt ();
    2266                 :       71426 :                 if (iter_point.get_kind () == PK_AFTER_SUPERNODE
    2267                 :       71883 :                     || (dst_node->m_succs.length () > 1
    2268                 :             :                         && (iter_point
    2269                 :         457 :                             == dst_node->m_succs[0]->m_dest->get_point ())))
    2270                 :             :                   break;
    2271                 :             :               }
    2272                 :             : 
    2273                 :       18283 :           }
    2274                 :             :       }
    2275                 :       18283 :       break;
    2276                 :             :     }
    2277                 :             : 
    2278                 :             :   /* Look for changes in dynamic extents, which will identify
    2279                 :             :      the creation of heap-based regions and alloca regions.  */
    2280                 :       50966 :   if (interest)
    2281                 :             :     {
    2282                 :       50962 :       const region_model *src_model = src_state.m_region_model;
    2283                 :       50962 :       const region_model *dst_model = dst_state.m_region_model;
    2284                 :       50962 :       if (src_model->get_dynamic_extents ()
    2285                 :       50962 :           != dst_model->get_dynamic_extents ())
    2286                 :             :         {
    2287                 :             :           unsigned i;
    2288                 :             :           const region *reg;
    2289                 :        2733 :           FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
    2290                 :             :             {
    2291                 :         382 :               const region *base_reg = reg->get_base_region ();
    2292                 :         382 :               const svalue *old_extents
    2293                 :         382 :                 = src_model->get_dynamic_extents (base_reg);
    2294                 :         382 :               const svalue *new_extents
    2295                 :         382 :                 = dst_model->get_dynamic_extents (base_reg);
    2296                 :         382 :               if (old_extents == NULL && new_extents != NULL)
    2297                 :         277 :                 switch (base_reg->get_kind ())
    2298                 :             :                   {
    2299                 :             :                   default:
    2300                 :             :                     break;
    2301                 :         241 :                   case RK_HEAP_ALLOCATED:
    2302                 :         241 :                   case RK_ALLOCA:
    2303                 :         241 :                     emission_path->add_region_creation_events
    2304                 :         241 :                       (pb.get_pending_diagnostic (),
    2305                 :             :                        reg, dst_model,
    2306                 :         241 :                        event_loc_info (src_point.get_location (),
    2307                 :             :                                        src_point.get_fndecl (),
    2308                 :         241 :                                        src_stack_depth),
    2309                 :         241 :                        m_verbosity > 3);
    2310                 :         241 :                     break;
    2311                 :             :                   }
    2312                 :             :             }
    2313                 :             :         }
    2314                 :             :     }
    2315                 :             : 
    2316                 :       50966 :   if (pb.get_feasibility_problem ()
    2317                 :       50966 :       && &pb.get_feasibility_problem ()->m_eedge == &eedge)
    2318                 :             :     {
    2319                 :           4 :       pretty_printer pp;
    2320                 :           4 :       pp_format_decoder (&pp) = default_tree_printer;
    2321                 :           4 :       pp_string (&pp,
    2322                 :             :                  "this path would have been rejected as infeasible"
    2323                 :             :                  " at this edge: ");
    2324                 :           4 :       pb.get_feasibility_problem ()->dump_to_pp (&pp);
    2325                 :           4 :       emission_path->add_event
    2326                 :           4 :         (std::make_unique<precanned_custom_event>
    2327                 :           4 :            (event_loc_info (dst_point.get_location (),
    2328                 :             :                             dst_point.get_fndecl (),
    2329                 :           4 :                             dst_stack_depth),
    2330                 :           4 :             pp_formatted_text (&pp)));
    2331                 :           4 :     }
    2332                 :       50966 : }
    2333                 :             : 
    2334                 :             : /* Return true if EEDGE is a significant edge in the path to the diagnostic
    2335                 :             :    for PB.
    2336                 :             : 
    2337                 :             :    Consider all of the sibling out-eedges from the same source enode
    2338                 :             :    as EEDGE.
    2339                 :             :    If there's no path from the destinations of those eedges to the
    2340                 :             :    diagnostic enode, then we have to take this eedge and thus it's
    2341                 :             :    significant.
    2342                 :             : 
    2343                 :             :    Conversely if there is a path from the destination of any other sibling
    2344                 :             :    eedge to the diagnostic enode, then this edge is insignificant.
    2345                 :             : 
    2346                 :             :    Example 1: redundant if-else:
    2347                 :             : 
    2348                 :             :      (A) if (...)            A
    2349                 :             :      (B)   ...              / \
    2350                 :             :          else              B   C
    2351                 :             :      (C)   ...              \ /
    2352                 :             :      (D) [DIAGNOSTIC]        D
    2353                 :             : 
    2354                 :             :      D is reachable by either B or C, so neither of these edges
    2355                 :             :      are significant.
    2356                 :             : 
    2357                 :             :    Example 2: pertinent if-else:
    2358                 :             : 
    2359                 :             :      (A) if (...)                         A
    2360                 :             :      (B)   ...                           / \
    2361                 :             :          else                           B   C
    2362                 :             :      (C)   [NECESSARY CONDITION]        |   |
    2363                 :             :      (D) [POSSIBLE DIAGNOSTIC]          D1  D2
    2364                 :             : 
    2365                 :             :      D becomes D1 and D2 in the exploded graph, where the diagnostic occurs
    2366                 :             :      at D2.  D2 is only reachable via C, so the A -> C edge is significant.
    2367                 :             : 
    2368                 :             :    Example 3: redundant loop:
    2369                 :             : 
    2370                 :             :      (A) while (...)          +-->A
    2371                 :             :      (B)   ...                |  / \
    2372                 :             :      (C) ...                  +-B  C
    2373                 :             :      (D) [DIAGNOSTIC]              |
    2374                 :             :                                    D
    2375                 :             : 
    2376                 :             :      D is reachable from both B and C, so the A->C edge is not significant.  */
    2377                 :             : 
    2378                 :             : bool
    2379                 :       13464 : diagnostic_manager::significant_edge_p (const path_builder &pb,
    2380                 :             :                                         const exploded_edge &eedge) const
    2381                 :             : {
    2382                 :       13464 :   int i;
    2383                 :       13464 :   exploded_edge *sibling;
    2384                 :       28610 :   FOR_EACH_VEC_ELT (eedge.m_src->m_succs, i, sibling)
    2385                 :             :     {
    2386                 :       15903 :       if (sibling == &eedge)
    2387                 :       12925 :         continue;
    2388                 :        2978 :       if (pb.reachable_from_p (sibling->m_dest))
    2389                 :             :         {
    2390                 :         757 :           if (get_logger ())
    2391                 :           0 :             get_logger ()->log ("  edge EN: %i -> EN: %i is insignificant as"
    2392                 :             :                                 " EN: %i is also reachable via"
    2393                 :             :                                 " EN: %i -> EN: %i",
    2394                 :           0 :                                 eedge.m_src->m_index, eedge.m_dest->m_index,
    2395                 :           0 :                                 pb.get_diag_node ()->m_index,
    2396                 :           0 :                                 sibling->m_src->m_index,
    2397                 :             :                                 sibling->m_dest->m_index);
    2398                 :         757 :           return false;
    2399                 :             :         }
    2400                 :             :     }
    2401                 :             : 
    2402                 :             :   return true;
    2403                 :             : }
    2404                 :             : 
    2405                 :             : /* Subroutine of diagnostic_manager::add_events_for_eedge
    2406                 :             :    where EEDGE has an underlying superedge i.e. a CFG edge,
    2407                 :             :    or an interprocedural call/return.
    2408                 :             :    Add any events for the superedge to EMISSION_PATH.  */
    2409                 :             : 
    2410                 :             : void
    2411                 :       13977 : diagnostic_manager::add_events_for_superedge (const path_builder &pb,
    2412                 :             :                                               const exploded_edge &eedge,
    2413                 :             :                                               checker_path *emission_path)
    2414                 :             :   const
    2415                 :             : {
    2416                 :       13977 :   gcc_assert (eedge.m_sedge);
    2417                 :             : 
    2418                 :             :   /* Give diagnostics an opportunity to override this function.  */
    2419                 :       13977 :   pending_diagnostic *pd = pb.get_pending_diagnostic ();
    2420                 :       13977 :   if (pd->maybe_add_custom_events_for_superedge (eedge, emission_path))
    2421                 :             :     return;
    2422                 :             : 
    2423                 :             :   /* Don't add events for insignificant edges at verbosity levels below 3.  */
    2424                 :       13591 :   if (m_verbosity < 3)
    2425                 :       13464 :     if (!significant_edge_p (pb, eedge))
    2426                 :             :       return;
    2427                 :             : 
    2428                 :       12834 :   const exploded_node *src_node = eedge.m_src;
    2429                 :       12834 :   const program_point &src_point = src_node->get_point ();
    2430                 :       12834 :   const exploded_node *dst_node = eedge.m_dest;
    2431                 :       12834 :   const program_point &dst_point = dst_node->get_point ();
    2432                 :       12834 :   const int src_stack_depth = src_point.get_stack_depth ();
    2433                 :       12834 :   const int dst_stack_depth = dst_point.get_stack_depth ();
    2434                 :       12834 :   const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
    2435                 :             : 
    2436                 :       12834 :   switch (eedge.m_sedge->m_kind)
    2437                 :             :     {
    2438                 :       10848 :     case SUPEREDGE_CFG_EDGE:
    2439                 :       10848 :       {
    2440                 :       21696 :         if (auto eh_dispatch_try_sedge
    2441                 :       10848 :               = eedge.m_sedge->dyn_cast_eh_dispatch_try_cfg_superedge ())
    2442                 :             :           {
    2443                 :          66 :             if (eh_dispatch_try_sedge->get_eh_catch ())
    2444                 :             :               {
    2445                 :          63 :                 const region_model *model = src_node->get_state ().m_region_model;
    2446                 :          63 :                 auto curr_thrown_exception_node
    2447                 :          63 :                   = model->get_current_thrown_exception ();
    2448                 :           0 :                 gcc_assert (curr_thrown_exception_node);
    2449                 :          63 :                 tree type = curr_thrown_exception_node->maybe_get_type ();
    2450                 :          63 :                 emission_path->add_event
    2451                 :          63 :                   (std::make_unique<catch_cfg_edge_event>
    2452                 :          63 :                    (eedge,
    2453                 :          63 :                     event_loc_info (dst_point.get_supernode ()->get_start_location (),
    2454                 :             :                                     dst_point.get_fndecl (),
    2455                 :          63 :                                     dst_stack_depth),
    2456                 :             :                     type));
    2457                 :          63 :                 return;
    2458                 :             :               }
    2459                 :             :             else
    2460                 :             :               {
    2461                 :             :                 /* We have the "uncaught exception" sedge, from eh_dispatch
    2462                 :             :                    to a block containing resx.
    2463                 :             :                    Don't add any events for this, so that we can consolidate
    2464                 :             :                    adjacent stack unwinding events.  */
    2465                 :             :                 return;
    2466                 :             :               }
    2467                 :             :           }
    2468                 :             : 
    2469                 :       10782 :         emission_path->add_event
    2470                 :       10782 :           (std::make_unique<start_cfg_edge_event>
    2471                 :       10782 :              (eedge,
    2472                 :       10782 :               event_loc_info
    2473                 :             :                 (last_stmt ? last_stmt->location : UNKNOWN_LOCATION,
    2474                 :             :                  src_point.get_fndecl (),
    2475                 :       10782 :                  src_stack_depth)));
    2476                 :       10782 :         emission_path->add_event
    2477                 :       10782 :           (std::make_unique<end_cfg_edge_event>
    2478                 :       10782 :              (eedge,
    2479                 :       10782 :               event_loc_info (dst_point.get_supernode ()->get_start_location (),
    2480                 :             :                               dst_point.get_fndecl (),
    2481                 :       10782 :                               dst_stack_depth)));
    2482                 :             :       }
    2483                 :       10782 :       break;
    2484                 :             : 
    2485                 :        1177 :     case SUPEREDGE_CALL:
    2486                 :        1177 :       pd->add_call_event (eedge, emission_path);
    2487                 :        1177 :       break;
    2488                 :             : 
    2489                 :         160 :     case SUPEREDGE_INTRAPROCEDURAL_CALL:
    2490                 :         160 :       {
    2491                 :             :         /* TODO: add a subclass for this, or generate events for the
    2492                 :             :            summary.  */
    2493                 :         160 :         emission_path->add_event
    2494                 :         160 :           (std::make_unique<debug_event>
    2495                 :         160 :              (event_loc_info (last_stmt
    2496                 :             :                               ? last_stmt->location
    2497                 :             :                               : UNKNOWN_LOCATION,
    2498                 :             :                               src_point.get_fndecl (),
    2499                 :         160 :                               src_stack_depth),
    2500                 :             :               "call summary"));
    2501                 :             :       }
    2502                 :         160 :       break;
    2503                 :             : 
    2504                 :         649 :     case SUPEREDGE_RETURN:
    2505                 :         649 :       {
    2506                 :         649 :         const return_superedge *return_edge
    2507                 :         649 :           = as_a <const return_superedge *> (eedge.m_sedge);
    2508                 :             : 
    2509                 :         649 :         const gcall &call_stmt = return_edge->get_call_stmt ();
    2510                 :         649 :         emission_path->add_event
    2511                 :         649 :           (std::make_unique<return_event>
    2512                 :         649 :              (eedge,
    2513                 :         649 :               event_loc_info (call_stmt.location,
    2514                 :             :                               dst_point.get_fndecl (),
    2515                 :         649 :                               dst_stack_depth)));
    2516                 :             :       }
    2517                 :         649 :       break;
    2518                 :             :     }
    2519                 :             : }
    2520                 :             : 
    2521                 :             : /* Prune PATH, based on the verbosity level, to the most pertinent
    2522                 :             :    events for a diagnostic that involves VAR ending in state STATE
    2523                 :             :    (for state machine SM).
    2524                 :             : 
    2525                 :             :    PATH is updated in place, and the redundant checker_events are deleted.
    2526                 :             : 
    2527                 :             :    As well as deleting events, call record_critical_state on events in
    2528                 :             :    which state critical to the pending_diagnostic is being handled; see
    2529                 :             :    the comment for diagnostic_manager::prune_for_sm_diagnostic.  */
    2530                 :             : 
    2531                 :             : void
    2532                 :        3945 : diagnostic_manager::prune_path (checker_path *path,
    2533                 :             :                                 const state_machine *sm,
    2534                 :             :                                 const svalue *sval,
    2535                 :             :                                 state_machine::state_t state) const
    2536                 :             : {
    2537                 :        3945 :   LOG_FUNC (get_logger ());
    2538                 :        3945 :   path->maybe_log (get_logger (), "path");
    2539                 :        3945 :   prune_for_sm_diagnostic (path, sm, sval, state);
    2540                 :        3945 :   prune_interproc_events (path);
    2541                 :        3945 :   if (! flag_analyzer_show_events_in_system_headers)
    2542                 :        3943 :     prune_system_headers (path);
    2543                 :        3945 :   consolidate_conditions (path);
    2544                 :        3945 :   consolidate_unwind_events (path);
    2545                 :        3945 :   finish_pruning (path);
    2546                 :        3945 :   path->maybe_log (get_logger (), "pruned");
    2547                 :        3945 : }
    2548                 :             : 
    2549                 :             : /* A cheap test to determine if EXPR can be the expression of interest in
    2550                 :             :    an sm-diagnostic, so that we can reject cases where we have a non-lvalue.
    2551                 :             :    We don't have always have a model when calling this, so we can't use
    2552                 :             :    tentative_region_model_context, so there can be false positives.  */
    2553                 :             : 
    2554                 :             : static bool
    2555                 :           0 : can_be_expr_of_interest_p (tree expr)
    2556                 :             : {
    2557                 :           0 :   if (!expr)
    2558                 :             :     return false;
    2559                 :             : 
    2560                 :             :   /* Reject constants.  */
    2561                 :           0 :   if (CONSTANT_CLASS_P (expr))
    2562                 :           0 :     return false;
    2563                 :             : 
    2564                 :             :   /* Otherwise assume that it can be an lvalue.  */
    2565                 :             :   return true;
    2566                 :             : }
    2567                 :             : 
    2568                 :             : /* First pass of diagnostic_manager::prune_path: apply verbosity level,
    2569                 :             :    pruning unrelated state change events.
    2570                 :             : 
    2571                 :             :    Iterate backwards through PATH, skipping state change events that aren't
    2572                 :             :    VAR but update the pertinent VAR when state-copying occurs.
    2573                 :             : 
    2574                 :             :    As well as deleting events, call record_critical_state on events in
    2575                 :             :    which state critical to the pending_diagnostic is being handled, so
    2576                 :             :    that the event's get_desc vfunc can potentially supply a more precise
    2577                 :             :    description of the event to the user.
    2578                 :             :    e.g. improving
    2579                 :             :      "calling 'foo' from 'bar'"
    2580                 :             :    to
    2581                 :             :      "passing possibly-NULL pointer 'ptr' to 'foo' from 'bar' as param 1"
    2582                 :             :    when the diagnostic relates to later dereferencing 'ptr'.  */
    2583                 :             : 
    2584                 :             : void
    2585                 :        3945 : diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
    2586                 :             :                                              const state_machine *sm,
    2587                 :             :                                              const svalue *sval,
    2588                 :             :                                              state_machine::state_t state) const
    2589                 :             : {
    2590                 :        3945 :   int idx = path->num_events () - 1;
    2591                 :      111649 :   while (idx >= 0 && idx < (signed)path->num_events ())
    2592                 :             :     {
    2593                 :       53852 :       checker_event *base_event = path->get_checker_event (idx);
    2594                 :       53852 :       if (get_logger ())
    2595                 :             :         {
    2596                 :           0 :           if (sm)
    2597                 :             :             {
    2598                 :           0 :               if (sval)
    2599                 :             :                 {
    2600                 :           0 :                   label_text sval_desc = sval->get_desc ();
    2601                 :           0 :                   log ("considering event %i (%s), with sval: %qs, state: %qs",
    2602                 :             :                        idx, event_kind_to_string (base_event->get_kind ()),
    2603                 :             :                        sval_desc.get (), state->get_name ());
    2604                 :           0 :                 }
    2605                 :             :               else
    2606                 :           0 :                 log ("considering event %i (%s), with global state: %qs",
    2607                 :             :                      idx, event_kind_to_string (base_event->get_kind ()),
    2608                 :             :                      state->get_name ());
    2609                 :             :             }
    2610                 :             :           else
    2611                 :           0 :             log ("considering event %i", idx);
    2612                 :             :         }
    2613                 :             : 
    2614                 :       53852 :       switch (base_event->get_kind ())
    2615                 :             :         {
    2616                 :           0 :         default:
    2617                 :           0 :           gcc_unreachable ();
    2618                 :             : 
    2619                 :         160 :         case event_kind::debug:
    2620                 :         160 :           if (m_verbosity < 4)
    2621                 :             :             {
    2622                 :         160 :               log ("filtering event %i: debug event", idx);
    2623                 :         160 :               path->delete_event (idx);
    2624                 :             :             }
    2625                 :             :           break;
    2626                 :             : 
    2627                 :             :         case event_kind::custom:
    2628                 :             :           /* Don't filter custom events.  */
    2629                 :             :           break;
    2630                 :             : 
    2631                 :       18263 :         case event_kind::stmt:
    2632                 :       18263 :           {
    2633                 :       18263 :             if (m_verbosity < 4)
    2634                 :             :               {
    2635                 :       18263 :                 log ("filtering event %i: statement event", idx);
    2636                 :       18263 :                 path->delete_event (idx);
    2637                 :             :               }
    2638                 :             :           }
    2639                 :             :           break;
    2640                 :             : 
    2641                 :             :         case event_kind::region_creation:
    2642                 :             :           /* Don't filter these.  */
    2643                 :             :           break;
    2644                 :             : 
    2645                 :        5169 :         case event_kind::function_entry:
    2646                 :        5169 :           if (m_verbosity < 1)
    2647                 :             :             {
    2648                 :          33 :               log ("filtering event %i: function entry", idx);
    2649                 :          33 :               path->delete_event (idx);
    2650                 :             :             }
    2651                 :             :           break;
    2652                 :             : 
    2653                 :        4642 :         case event_kind::state_change:
    2654                 :        4642 :           {
    2655                 :        4642 :             state_change_event *state_change = (state_change_event *)base_event;
    2656                 :        4642 :             gcc_assert (state_change->m_dst_state.m_region_model);
    2657                 :             : 
    2658                 :        4642 :             if (state_change->m_sval == sval)
    2659                 :             :               {
    2660                 :        2299 :                 if (state_change->m_origin)
    2661                 :             :                   {
    2662                 :           0 :                     if (get_logger ())
    2663                 :             :                       {
    2664                 :           0 :                         label_text sval_desc = sval->get_desc ();
    2665                 :           0 :                         label_text origin_sval_desc
    2666                 :           0 :                           = state_change->m_origin->get_desc ();
    2667                 :           0 :                         log ("event %i:"
    2668                 :             :                              " switching var of interest from %qs to %qs",
    2669                 :             :                              idx, sval_desc.get (),
    2670                 :             :                              origin_sval_desc.get ());
    2671                 :           0 :                       }
    2672                 :           0 :                     sval = state_change->m_origin;
    2673                 :             :                   }
    2674                 :        2299 :                 log ("event %i: switching state of interest from %qs to %qs",
    2675                 :        2299 :                      idx, state_change->m_to->get_name (),
    2676                 :        2299 :                      state_change->m_from->get_name ());
    2677                 :        2299 :                 state = state_change->m_from;
    2678                 :             :               }
    2679                 :        2343 :             else if (m_verbosity < 4)
    2680                 :             :               {
    2681                 :        2343 :                 if (get_logger ())
    2682                 :             :                   {
    2683                 :           0 :                     if (state_change->m_sval)
    2684                 :             :                       {
    2685                 :           0 :                         label_text change_sval_desc
    2686                 :           0 :                           = state_change->m_sval->get_desc ();
    2687                 :           0 :                         if (sval)
    2688                 :             :                           {
    2689                 :           0 :                             label_text sval_desc = sval->get_desc ();
    2690                 :           0 :                             log ("filtering event %i:"
    2691                 :             :                                  " state change to %qs unrelated to %qs",
    2692                 :             :                                  idx, change_sval_desc.get (),
    2693                 :             :                                  sval_desc.get ());
    2694                 :           0 :                           }
    2695                 :             :                         else
    2696                 :           0 :                           log ("filtering event %i: state change to %qs",
    2697                 :             :                                idx, change_sval_desc.get ());
    2698                 :           0 :                       }
    2699                 :             :                     else
    2700                 :           0 :                       log ("filtering event %i: global state change", idx);
    2701                 :             :                   }
    2702                 :        2343 :                 path->delete_event (idx);
    2703                 :             :               }
    2704                 :             :           }
    2705                 :             :           break;
    2706                 :             : 
    2707                 :       10782 :         case event_kind::start_cfg_edge:
    2708                 :       10782 :           {
    2709                 :       10782 :             cfg_edge_event *event = (cfg_edge_event *)base_event;
    2710                 :             : 
    2711                 :             :             /* TODO: is this edge significant to var?
    2712                 :             :                See if var can be in other states in the dest, but not
    2713                 :             :                in other states in the src?
    2714                 :             :                Must have multiple sibling edges.  */
    2715                 :             : 
    2716                 :       10782 :             if (event->should_filter_p (m_verbosity))
    2717                 :             :               {
    2718                 :        8157 :                 log ("filtering events %i and %i: CFG edge", idx, idx + 1);
    2719                 :        8157 :                 path->delete_event (idx);
    2720                 :             :                 /* Also delete the corresponding event_kind::end_cfg_edge.  */
    2721                 :        8157 :                 gcc_assert (path->get_checker_event (idx)->get_kind ()
    2722                 :             :                             == event_kind::end_cfg_edge);
    2723                 :        8157 :                 path->delete_event (idx);
    2724                 :             :               }
    2725                 :             :           }
    2726                 :             :           break;
    2727                 :             : 
    2728                 :             :         case event_kind::end_cfg_edge:
    2729                 :             :           /* These come in pairs with event_kind::start_cfg_edge events and are
    2730                 :             :              filtered when their start event is filtered.  */
    2731                 :             :           break;
    2732                 :             : 
    2733                 :             :         case event_kind::catch_:
    2734                 :             :         case event_kind::throw_:
    2735                 :             :         case event_kind::unwind:
    2736                 :             :           /* Don't filter these.  */
    2737                 :             :           break;
    2738                 :             : 
    2739                 :        1210 :         case event_kind::call_edge:
    2740                 :        1210 :           {
    2741                 :        1210 :             call_event *event = (call_event *)base_event;
    2742                 :        1210 :             const region_model *callee_model
    2743                 :        1210 :               = event->m_eedge.m_dest->get_state ().m_region_model;
    2744                 :        1210 :             const region_model *caller_model
    2745                 :        1210 :               = event->m_eedge.m_src->get_state ().m_region_model;
    2746                 :        1210 :             tree callee_var = callee_model->get_representative_tree (sval);
    2747                 :        1210 :             callsite_expr expr;
    2748                 :             : 
    2749                 :        1210 :             tree caller_var;
    2750                 :        1210 :             if(event->m_sedge)
    2751                 :             :               {
    2752                 :        1177 :                 const callgraph_superedge& cg_superedge
    2753                 :        1177 :                   = event->get_callgraph_superedge ();
    2754                 :        1177 :                 if (cg_superedge.m_cedge)
    2755                 :        1177 :                   caller_var
    2756                 :        1177 :                     = cg_superedge.map_expr_from_callee_to_caller (callee_var,
    2757                 :             :                                                                    &expr);
    2758                 :             :                 else
    2759                 :           0 :                   caller_var = caller_model->get_representative_tree (sval);
    2760                 :             :               }
    2761                 :             :             else
    2762                 :          33 :               caller_var = caller_model->get_representative_tree (sval);
    2763                 :             : 
    2764                 :        1210 :             if (caller_var)
    2765                 :             :               {
    2766                 :         230 :                 if (get_logger ())
    2767                 :             :                   {
    2768                 :           0 :                     label_text sval_desc = sval->get_desc ();
    2769                 :           0 :                     log ("event %i:"
    2770                 :             :                          " recording critical state for %qs at call"
    2771                 :             :                          " from %qE in callee to %qE in caller",
    2772                 :             :                          idx, sval_desc.get (), callee_var, caller_var);
    2773                 :           0 :                   }
    2774                 :         230 :                 if (expr.param_p ())
    2775                 :         197 :                   event->record_critical_state (caller_var, state);
    2776                 :             :               }
    2777                 :             :           }
    2778                 :        1210 :           break;
    2779                 :             : 
    2780                 :         667 :         case event_kind::return_edge:
    2781                 :         667 :           {
    2782                 :         667 :             if (sval)
    2783                 :             :               {
    2784                 :         487 :                 return_event *event = (return_event *)base_event;
    2785                 :         487 :                 const region_model *caller_model
    2786                 :         487 :                   = event->m_eedge.m_dest->get_state ().m_region_model;
    2787                 :         487 :                 tree caller_var = caller_model->get_representative_tree (sval);
    2788                 :         487 :                 const region_model *callee_model
    2789                 :         487 :                   = event->m_eedge.m_src->get_state ().m_region_model;
    2790                 :         487 :                 callsite_expr expr;
    2791                 :             : 
    2792                 :         487 :                 tree callee_var;
    2793                 :         487 :                 if (event->m_sedge)
    2794                 :             :                   {
    2795                 :         469 :                     const callgraph_superedge& cg_superedge
    2796                 :         469 :                       = event->get_callgraph_superedge ();
    2797                 :         469 :                     if (cg_superedge.m_cedge)
    2798                 :         469 :                       callee_var
    2799                 :         469 :                         = cg_superedge.map_expr_from_caller_to_callee (caller_var,
    2800                 :             :                                                                        &expr);
    2801                 :             :                     else
    2802                 :           0 :                       callee_var = callee_model->get_representative_tree (sval);
    2803                 :             :                   }
    2804                 :             :                 else
    2805                 :          18 :                   callee_var = callee_model->get_representative_tree (sval);
    2806                 :             : 
    2807                 :         487 :                 if (callee_var)
    2808                 :             :                   {
    2809                 :         166 :                     if (get_logger ())
    2810                 :             :                       {
    2811                 :           0 :                         label_text sval_desc = sval->get_desc ();
    2812                 :           0 :                         log ("event %i:"
    2813                 :             :                              " recording critical state for %qs at return"
    2814                 :             :                              " from %qE in caller to %qE in callee",
    2815                 :             :                              idx, sval_desc.get (), callee_var, callee_var);
    2816                 :           0 :                       }
    2817                 :         166 :                     if (expr.return_value_p ())
    2818                 :          69 :                       event->record_critical_state (callee_var, state);
    2819                 :             :                   }
    2820                 :             :               }
    2821                 :             :           }
    2822                 :             :           break;
    2823                 :             : 
    2824                 :             :         case event_kind::inlined_call:
    2825                 :             :           /* We don't expect to see these yet, as they're added later.
    2826                 :             :              We'd want to keep them around.  */
    2827                 :             :           break;
    2828                 :             : 
    2829                 :             :         case event_kind::setjmp_:
    2830                 :             :           /* TODO: only show setjmp_events that matter i.e. those for which
    2831                 :             :              there is a later rewind event using them.  */
    2832                 :             :         case event_kind::rewind_from_longjmp:
    2833                 :             :         case event_kind::rewind_to_setjmp:
    2834                 :             :           break;
    2835                 :             : 
    2836                 :             :         case event_kind::warning:
    2837                 :             :           /* Always show the final "warning" event in the path.  */
    2838                 :             :           break;
    2839                 :             :         }
    2840                 :       53852 :       idx--;
    2841                 :             :     }
    2842                 :        3945 : }
    2843                 :             : 
    2844                 :             : /* Subroutine of diagnostic_manager::prune_for_sm_diagnostic.
    2845                 :             :    If *EXPR is not suitable to be the expression of interest in
    2846                 :             :    an sm-diagnostic, set *EXPR to NULL and log.  */
    2847                 :             : 
    2848                 :             : void
    2849                 :           0 : diagnostic_manager::update_for_unsuitable_sm_exprs (tree *expr) const
    2850                 :             : {
    2851                 :           0 :   gcc_assert (expr);
    2852                 :           0 :   if (*expr && !can_be_expr_of_interest_p (*expr))
    2853                 :             :     {
    2854                 :           0 :       log ("new var %qE is unsuitable; setting var to NULL", *expr);
    2855                 :           0 :       *expr = NULL_TREE;
    2856                 :             :     }
    2857                 :           0 : }
    2858                 :             : 
    2859                 :             : /* Second pass of diagnostic_manager::prune_path: remove redundant
    2860                 :             :    interprocedural information.
    2861                 :             : 
    2862                 :             :    For example, given:
    2863                 :             :      (1)- calling "f2" from "f1"
    2864                 :             :      (2)--- entry to "f2"
    2865                 :             :      (3)--- calling "f3" from "f2"
    2866                 :             :      (4)----- entry to "f3"
    2867                 :             :      (5)--- returning to "f2" to "f3"
    2868                 :             :      (6)- returning to "f1" to "f2"
    2869                 :             :    with no other intervening events, then none of these events are
    2870                 :             :    likely to be interesting to the user.
    2871                 :             : 
    2872                 :             :    Prune [..., call, function-entry, return, ...] triples repeatedly
    2873                 :             :    until nothing has changed.  For the example above, this would
    2874                 :             :    remove events (3, 4, 5), and then remove events (1, 2, 6).  */
    2875                 :             : 
    2876                 :             : void
    2877                 :        3945 : diagnostic_manager::prune_interproc_events (checker_path *path) const
    2878                 :             : {
    2879                 :        3945 :   bool changed = false;
    2880                 :        4178 :   do
    2881                 :             :     {
    2882                 :        4178 :       changed = false;
    2883                 :        4178 :       int idx = (signed)path->num_events () - 1;
    2884                 :       22785 :       while (idx >= 0)
    2885                 :             :         {
    2886                 :             :           /* Prune [..., call, function-entry, return, ...] triples.  */
    2887                 :       18607 :           if (idx + 2 < (signed)path->num_events ()
    2888                 :       10503 :               && path->get_checker_event (idx)->is_call_p ()
    2889                 :        1013 :               && path->get_checker_event (idx + 1)->is_function_entry_p ()
    2890                 :       19612 :               && path->get_checker_event (idx + 2)->is_return_p ())
    2891                 :             :             {
    2892                 :         299 :               if (get_logger ())
    2893                 :             :                 {
    2894                 :           0 :                   label_text desc
    2895                 :           0 :                     (path->get_checker_event (idx)->get_desc
    2896                 :           0 :                        (*global_dc->get_reference_printer ()));
    2897                 :           0 :                   log ("filtering events %i-%i:"
    2898                 :             :                        " irrelevant call/entry/return: %s",
    2899                 :             :                        idx, idx + 2, desc.get ());
    2900                 :           0 :                 }
    2901                 :         299 :               path->delete_event (idx + 2);
    2902                 :         299 :               path->delete_event (idx + 1);
    2903                 :         299 :               path->delete_event (idx);
    2904                 :         299 :               changed = true;
    2905                 :         299 :               idx--;
    2906                 :         299 :               continue;
    2907                 :         299 :             }
    2908                 :             : 
    2909                 :             :           /* Prune [..., call, return, ...] pairs
    2910                 :             :              (for -fanalyzer-verbosity=0).  */
    2911                 :       18308 :           if (idx + 1 < (signed)path->num_events ()
    2912                 :       13991 :               && path->get_checker_event (idx)->is_call_p ()
    2913                 :       19356 :               && path->get_checker_event (idx + 1)->is_return_p ())
    2914                 :             :             {
    2915                 :           4 :               if (get_logger ())
    2916                 :             :                 {
    2917                 :           0 :                   label_text desc
    2918                 :           0 :                     (path->get_checker_event (idx)->get_desc
    2919                 :           0 :                      (*global_dc->get_reference_printer ()));
    2920                 :           0 :                   log ("filtering events %i-%i:"
    2921                 :             :                        " irrelevant call/return: %s",
    2922                 :             :                        idx, idx + 1, desc.get ());
    2923                 :           0 :                 }
    2924                 :           4 :               path->delete_event (idx + 1);
    2925                 :           4 :               path->delete_event (idx);
    2926                 :           4 :               changed = true;
    2927                 :           4 :               idx--;
    2928                 :           4 :               continue;
    2929                 :           4 :             }
    2930                 :             : 
    2931                 :       18304 :           idx--;
    2932                 :             :         }
    2933                 :             : 
    2934                 :             :     }
    2935                 :             :   while (changed);
    2936                 :        3945 : }
    2937                 :             : 
    2938                 :             : /* Remove everything within [call point, IDX]. For consistency,
    2939                 :             :    IDX should represent the return event of the frame to delete,
    2940                 :             :    or if there is none it should be the last event of the frame.
    2941                 :             :    After this function, IDX designates the event prior to calling
    2942                 :             :    this frame.  */
    2943                 :             : 
    2944                 :             : static void
    2945                 :           4 : prune_frame (checker_path *path, int &idx)
    2946                 :             : {
    2947                 :           4 :   gcc_assert (idx >= 0);
    2948                 :           4 :   int nesting = 1;
    2949                 :           4 :   if (path->get_checker_event (idx)->is_return_p ())
    2950                 :           4 :     nesting = 0;
    2951                 :          28 :   do
    2952                 :             :     {
    2953                 :          28 :       if (path->get_checker_event (idx)->is_call_p ())
    2954                 :           8 :         nesting--;
    2955                 :          20 :       else if (path->get_checker_event (idx)->is_return_p ())
    2956                 :           8 :         nesting++;
    2957                 :             : 
    2958                 :          28 :       path->delete_event (idx--);
    2959                 :          28 :     } while (idx >= 0 && nesting != 0);
    2960                 :           4 : }
    2961                 :             : 
    2962                 :             : /* This function is called when fanalyzer-show-events-in-system-headers
    2963                 :             :    is disabled and will prune the diagnostic of all events within a
    2964                 :             :    system header, only keeping the entry and exit events to the header.
    2965                 :             :    This should be called after diagnostic_manager::prune_interproc_events
    2966                 :             :    so that sucessive events [system header call, system header return]
    2967                 :             :    are preserved thereafter.
    2968                 :             : 
    2969                 :             :    Given a diagnostics path diving into a system header in the form
    2970                 :             :    [
    2971                 :             :      prefix events...,
    2972                 :             :      system header call,
    2973                 :             :        system header entry,
    2974                 :             :        events within system headers...,
    2975                 :             :      system header return,
    2976                 :             :      suffix events...
    2977                 :             :    ]
    2978                 :             : 
    2979                 :             :    then transforms it into
    2980                 :             :    [
    2981                 :             :      prefix events...,
    2982                 :             :      system header call,
    2983                 :             :      system header return,
    2984                 :             :      suffix events...
    2985                 :             :    ].  */
    2986                 :             : 
    2987                 :             : void
    2988                 :        3943 : diagnostic_manager::prune_system_headers (checker_path *path) const
    2989                 :             : {
    2990                 :        3943 :   int idx = (signed)path->num_events () - 1;
    2991                 :       19727 :   while (idx >= 0)
    2992                 :             :     {
    2993                 :       15784 :       const checker_event *event = path->get_checker_event (idx);
    2994                 :             :       /* Prune everything between
    2995                 :             :          [..., system entry, (...), system return, ...].  */
    2996                 :       15784 :       if (event->is_return_p ()
    2997                 :       15784 :           && in_system_header_at (event->get_location ()))
    2998                 :             :       {
    2999                 :           4 :         int ret_idx = idx;
    3000                 :           4 :         prune_frame (path, idx);
    3001                 :             : 
    3002                 :           4 :         if (get_logger ())
    3003                 :             :         {
    3004                 :           0 :           log ("filtering system headers events %i-%i:",
    3005                 :             :                idx, ret_idx);
    3006                 :             :         }
    3007                 :             :         // Delete function entry within system headers.
    3008                 :           4 :         if (idx >= 0)
    3009                 :             :           {
    3010                 :           4 :             event = path->get_checker_event (idx);
    3011                 :           4 :             if (event->is_function_entry_p ()
    3012                 :           4 :                 && in_system_header_at (event->get_location ()))
    3013                 :             :               {
    3014                 :           4 :                 if (get_logger ())
    3015                 :             :                   {
    3016                 :           0 :                     label_text desc
    3017                 :           0 :                       (event->get_desc (*global_dc->get_reference_printer ()));
    3018                 :           0 :                     log ("filtering event %i:"
    3019                 :             :                          "system header entry event: %s",
    3020                 :             :                          idx, desc.get ());
    3021                 :           0 :                   }
    3022                 :             : 
    3023                 :           4 :                 path->delete_event (idx);
    3024                 :             :               }
    3025                 :             :           }
    3026                 :             :       }
    3027                 :             : 
    3028                 :       15784 :       idx--;
    3029                 :             :     }
    3030                 :        3943 : }
    3031                 :             : 
    3032                 :             : /* Return true iff event IDX within PATH is on the same line as REF_EXP_LOC.  */
    3033                 :             : 
    3034                 :             : static bool
    3035                 :        2688 : same_line_as_p (const expanded_location &ref_exp_loc,
    3036                 :             :                 checker_path *path, unsigned idx)
    3037                 :             : {
    3038                 :        2688 :   const checker_event *ev = path->get_checker_event (idx);
    3039                 :        2688 :   expanded_location idx_exp_loc = expand_location (ev->get_location ());
    3040                 :        2688 :   gcc_assert (ref_exp_loc.file);
    3041                 :        2688 :   if (idx_exp_loc.file == NULL)
    3042                 :             :     return false;
    3043                 :        2670 :   if (strcmp (ref_exp_loc.file, idx_exp_loc.file))
    3044                 :             :     return false;
    3045                 :        2670 :   return ref_exp_loc.line == idx_exp_loc.line;
    3046                 :             : }
    3047                 :             : 
    3048                 :             : /* This path-readability optimization reduces the verbosity of compound
    3049                 :             :    conditional statements (without needing to reconstruct the AST, which
    3050                 :             :    has already been lost).
    3051                 :             : 
    3052                 :             :    For example, it converts:
    3053                 :             : 
    3054                 :             :     |   61 |   if (cp[0] != '\0' && cp[0] != '#')
    3055                 :             :     |      |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    3056                 :             :     |      |      |              |    |
    3057                 :             :     |      |      |              |    (6) ...to here
    3058                 :             :     |      |      |              (7) following ‘true’ branch...
    3059                 :             :     |      |      (5) following ‘true’ branch...
    3060                 :             :     |   62 |     {
    3061                 :             :     |   63 |       alias = cp++;
    3062                 :             :     |      |               ~~~~
    3063                 :             :     |      |                 |
    3064                 :             :     |      |                 (8) ...to here
    3065                 :             : 
    3066                 :             :    into:
    3067                 :             : 
    3068                 :             :     |   61 |   if (cp[0] != '\0' && cp[0] != '#')
    3069                 :             :     |      |      ~
    3070                 :             :     |      |      |
    3071                 :             :     |      |      (5) following ‘true’ branch...
    3072                 :             :     |   62 |     {
    3073                 :             :     |   63 |       alias = cp++;
    3074                 :             :     |      |               ~~~~
    3075                 :             :     |      |                 |
    3076                 :             :     |      |                 (6) ...to here
    3077                 :             : 
    3078                 :             :    by combining events 5-8 into new events 5-6.
    3079                 :             : 
    3080                 :             :    Find runs of consecutive (start_cfg_edge_event, end_cfg_edge_event) pairs
    3081                 :             :    in which all events apart from the final end_cfg_edge_event are on the same
    3082                 :             :    line, and for which either all the CFG edges are TRUE edges, or all are
    3083                 :             :    FALSE edges.
    3084                 :             : 
    3085                 :             :    Consolidate each such run into a
    3086                 :             :      (start_consolidated_cfg_edges_event, end_consolidated_cfg_edges_event)
    3087                 :             :    pair.  */
    3088                 :             : 
    3089                 :             : void
    3090                 :        3945 : diagnostic_manager::consolidate_conditions (checker_path *path) const
    3091                 :             : {
    3092                 :             :   /* Don't simplify edges if we're debugging them.  */
    3093                 :        3945 :   if (flag_analyzer_verbose_edges)
    3094                 :             :     return;
    3095                 :             : 
    3096                 :       11672 :   for (int start_idx = 0;
    3097                 :       31234 :        start_idx < (signed)path->num_events () - 1;
    3098                 :             :        start_idx++)
    3099                 :             :     {
    3100                 :       11672 :       if (path->cfg_edge_pair_at_p (start_idx))
    3101                 :             :         {
    3102                 :        2532 :           const checker_event *old_start_ev
    3103                 :        2532 :             = path->get_checker_event (start_idx);
    3104                 :        2532 :           expanded_location start_exp_loc
    3105                 :        2532 :             = expand_location (old_start_ev->get_location ());
    3106                 :        2532 :           if (start_exp_loc.file == NULL)
    3107                 :        2272 :             continue;
    3108                 :        2532 :           if (!same_line_as_p (start_exp_loc, path, start_idx + 1))
    3109                 :        2272 :             continue;
    3110                 :             : 
    3111                 :             :           /* Are we looking for a run of all TRUE edges, or all FALSE edges?  */
    3112                 :         260 :           gcc_assert (old_start_ev->get_kind () == event_kind::start_cfg_edge);
    3113                 :         260 :           const start_cfg_edge_event *old_start_cfg_ev
    3114                 :             :             = (const start_cfg_edge_event *)old_start_ev;
    3115                 :         260 :           const cfg_superedge& first_cfg_sedge
    3116                 :         260 :             = old_start_cfg_ev->get_cfg_superedge ();
    3117                 :         260 :           bool edge_sense;
    3118                 :         260 :           if (first_cfg_sedge.true_value_p ())
    3119                 :             :             edge_sense = true;
    3120                 :          81 :           else if (first_cfg_sedge.false_value_p ())
    3121                 :             :             edge_sense = false;
    3122                 :             :           else
    3123                 :           0 :             continue;
    3124                 :             : 
    3125                 :             :           /* Find a run of CFG start/end event pairs from
    3126                 :             :                [start_idx, next_idx)
    3127                 :             :              where all apart from the final event are on the same line,
    3128                 :             :              and all are either TRUE or FALSE edges, matching the initial.  */
    3129                 :         260 :           int next_idx = start_idx + 2;
    3130                 :         260 :           while (path->cfg_edge_pair_at_p (next_idx)
    3131                 :         353 :                  && same_line_as_p (start_exp_loc, path, next_idx))
    3132                 :             :             {
    3133                 :         106 :               const checker_event *iter_ev
    3134                 :         106 :                 = path->get_checker_event (next_idx);
    3135                 :         106 :               gcc_assert (iter_ev->get_kind () == event_kind::start_cfg_edge);
    3136                 :         106 :               const start_cfg_edge_event *iter_cfg_ev
    3137                 :             :                 = (const start_cfg_edge_event *)iter_ev;
    3138                 :         106 :               const cfg_superedge& iter_cfg_sedge
    3139                 :         106 :                 = iter_cfg_ev->get_cfg_superedge ();
    3140                 :         106 :               if (edge_sense)
    3141                 :             :                 {
    3142                 :          52 :                   if (!iter_cfg_sedge.true_value_p ())
    3143                 :             :                     break;
    3144                 :             :                 }
    3145                 :             :               else
    3146                 :             :                 {
    3147                 :          54 :                   if (!iter_cfg_sedge.false_value_p ())
    3148                 :             :                     break;
    3149                 :             :                 }
    3150                 :          93 :               next_idx += 2;
    3151                 :             :             }
    3152                 :             : 
    3153                 :             :           /* If we have more than one pair in the run, consolidate.  */
    3154                 :         260 :           if (next_idx > start_idx + 2)
    3155                 :             :             {
    3156                 :          90 :               const checker_event *old_end_ev
    3157                 :          90 :                 = path->get_checker_event (next_idx - 1);
    3158                 :          90 :               log ("consolidating CFG edge events %i-%i into %i-%i",
    3159                 :             :                    start_idx, next_idx - 1, start_idx, start_idx +1);
    3160                 :          90 :               start_consolidated_cfg_edges_event *new_start_ev
    3161                 :             :                 = new start_consolidated_cfg_edges_event
    3162                 :          90 :                 (event_loc_info (old_start_ev->get_location (),
    3163                 :             :                                  old_start_ev->get_fndecl (),
    3164                 :          90 :                                  old_start_ev->get_stack_depth ()),
    3165                 :          90 :                  edge_sense);
    3166                 :          90 :               checker_event *new_end_ev
    3167                 :             :                 = new end_consolidated_cfg_edges_event
    3168                 :          90 :                 (event_loc_info (old_end_ev->get_location (),
    3169                 :             :                                  old_end_ev->get_fndecl (),
    3170                 :          90 :                                  old_end_ev->get_stack_depth ()));
    3171                 :          90 :               path->replace_event (start_idx, new_start_ev);
    3172                 :          90 :               path->replace_event (start_idx + 1, new_end_ev);
    3173                 :          90 :               path->delete_events (start_idx + 2, next_idx - (start_idx + 2));
    3174                 :             :             }
    3175                 :             :         }
    3176                 :             :     }
    3177                 :             : }
    3178                 :             : 
    3179                 :             : /* Consolidate runs of consecutive unwind_event.  */
    3180                 :             : 
    3181                 :             : void
    3182                 :        3945 : diagnostic_manager::consolidate_unwind_events (checker_path *path) const
    3183                 :             : {
    3184                 :             :   /* Don't simplify edges if we're debugging them.  */
    3185                 :        3945 :   if (flag_analyzer_verbose_edges)
    3186                 :             :     return;
    3187                 :             : 
    3188                 :       11666 :   for (int start_idx = 0;
    3189                 :       31222 :        start_idx < (signed)path->num_events () - 1;
    3190                 :             :        start_idx++)
    3191                 :             :     {
    3192                 :             :       /* Find a run of consecutive unwind_event instances.  */
    3193                 :       11666 :       if (path->get_checker_event (start_idx)->get_kind ()
    3194                 :             :           != event_kind::unwind)
    3195                 :       11657 :         continue;
    3196                 :           9 :       int iter_idx = start_idx + 1;
    3197                 :          15 :       while (iter_idx < (int)path->num_events ())
    3198                 :          15 :         if (path->get_checker_event (iter_idx)->get_kind ()
    3199                 :             :             == event_kind::unwind)
    3200                 :           6 :           ++iter_idx;
    3201                 :             :         else
    3202                 :             :           break;
    3203                 :             : 
    3204                 :             :       /* iter_idx should now be one after the last unwind_event in the run.  */
    3205                 :           9 :       const int last_idx = iter_idx - 1;
    3206                 :           9 :       if (last_idx == start_idx)
    3207                 :           3 :         continue;
    3208                 :             : 
    3209                 :           6 :       gcc_assert (last_idx > start_idx);
    3210                 :             : 
    3211                 :           6 :       log ("consolidating unwind events %i-%i into %i",
    3212                 :             :            start_idx, last_idx, start_idx);
    3213                 :             : 
    3214                 :           6 :       unwind_event *first_event
    3215                 :           6 :         = (unwind_event *)path->get_checker_event (start_idx);
    3216                 :           6 :       const unwind_event *last_event
    3217                 :           6 :         = (const unwind_event *)path->get_checker_event (last_idx);
    3218                 :           6 :       first_event->m_num_frames += last_event->m_num_frames;
    3219                 :           6 :       path->delete_events (start_idx + 1, last_idx - start_idx);
    3220                 :             :     }
    3221                 :             : }
    3222                 :             : 
    3223                 :             : /* Final pass of diagnostic_manager::prune_path.
    3224                 :             : 
    3225                 :             :    If all we're left with is in one function, then filter function entry
    3226                 :             :    events.  */
    3227                 :             : 
    3228                 :             : void
    3229                 :        3945 : diagnostic_manager::finish_pruning (checker_path *path) const
    3230                 :             : {
    3231                 :        3945 :   if (!path->interprocedural_p ())
    3232                 :             :     {
    3233                 :        3174 :       int idx = path->num_events () - 1;
    3234                 :       24184 :       while (idx >= 0 && idx < (signed)path->num_events ())
    3235                 :             :         {
    3236                 :       10505 :           checker_event *base_event = path->get_checker_event (idx);
    3237                 :       10505 :           if (base_event->get_kind () == event_kind::function_entry)
    3238                 :             :             {
    3239                 :        3169 :               log ("filtering event %i:"
    3240                 :             :                    " function entry for purely intraprocedural path", idx);
    3241                 :        3169 :               path->delete_event (idx);
    3242                 :             :             }
    3243                 :       10505 :           idx--;
    3244                 :             :         }
    3245                 :             :     }
    3246                 :        3945 : }
    3247                 :             : 
    3248                 :             : } // namespace ana
    3249                 :             : 
    3250                 :             : #endif /* #if ENABLE_ANALYZER */
        

Generated by: LCOV version 2.1-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.