LCOV - code coverage report
Current view: top level - gcc/analyzer - diagnostic-manager.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 85.8 % 1326 1138
Test Date: 2026-05-11 19:44:49 Functions: 92.3 % 78 72
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-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.