LCOV - code coverage report
Current view: top level - gcc/analyzer - ops.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 85.7 % 1038 890
Test Date: 2026-02-28 14:20:25 Functions: 87.0 % 115 100
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Operations within the code being analyzed.
       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 "gimple-pretty-print.h"
      24              : #include "gimple-iterator.h"
      25              : #include "tree-cfg.h"
      26              : #include "tree-dfa.h"
      27              : #include "fold-const.h"
      28              : #include "cgraph.h"
      29              : #include "text-art/dump.h"
      30              : #include "text-art/tree-widget.h"
      31              : 
      32              : #include "analyzer/ops.h"
      33              : #include "analyzer/call-details.h"
      34              : #include "analyzer/exploded-graph.h"
      35              : #include "analyzer/checker-path.h"
      36              : #include "analyzer/impl-sm-context.h"
      37              : #include "analyzer/constraint-manager.h"
      38              : #include "analyzer/call-summary.h"
      39              : #include "analyzer/call-info.h"
      40              : #include "analyzer/analysis-plan.h"
      41              : 
      42              : #if ENABLE_ANALYZER
      43              : 
      44              : namespace ana {
      45              : 
      46        20468 : event_loc_info::event_loc_info (const exploded_node *enode)
      47              : {
      48        20468 :   if (enode)
      49              :     {
      50        20468 :       m_loc = enode->get_location ();
      51        20468 :       m_fndecl = enode->get_point ().get_fndecl ();
      52        40891 :       m_depth = enode->get_stack_depth ();
      53              :     }
      54              :   else
      55              :     {
      56            0 :       m_loc = UNKNOWN_LOCATION;
      57            0 :       m_fndecl = NULL_TREE;
      58            0 :       m_depth = 0;
      59              :     }
      60        20468 : }
      61              : 
      62          425 : event_loc_info::event_loc_info (const program_point &point)
      63              : {
      64          425 :   m_loc = point.get_location ();
      65          425 :   m_fndecl = point.get_fndecl ();
      66          425 :   m_depth = point.get_stack_depth ();
      67          425 : }
      68              : 
      69              : // struct operation_context
      70              : 
      71              : void
      72            0 : operation_context::dump () const
      73              : {
      74            0 :   fprintf (stderr, "src enode: EN: %i\n", m_src_enode.m_index);
      75            0 :   m_src_enode.dump (m_eg.get_ext_state ());
      76              : 
      77            0 :   fprintf (stderr, "superedge\n");
      78            0 :   pretty_printer pp;
      79            0 :   pp.set_output_stream (stderr);
      80            0 :   m_sedge.dump (&pp);
      81            0 : }
      82              : 
      83              : logger *
      84       454760 : operation_context::get_logger () const
      85              : {
      86       454760 :   return m_eg.get_logger ();
      87              : }
      88              : 
      89              : const extrinsic_state &
      90       297745 : operation_context::get_ext_state () const
      91              : {
      92       297745 :   return m_eg.get_ext_state ();
      93              : }
      94              : 
      95              : const program_point &
      96        24699 : operation_context::get_initial_point () const
      97              : {
      98        24699 :   return m_src_enode.get_point ();
      99              : }
     100              : 
     101              : const program_state &
     102      1207096 : operation_context::get_initial_state () const
     103              : {
     104      1207096 :   return m_src_enode.get_state ();
     105              : }
     106              : 
     107              : const supergraph &
     108         6796 : operation_context::get_supergraph () const
     109              : {
     110         6796 :   return m_eg.get_supergraph ();
     111              : }
     112              : 
     113              : program_point
     114       346599 : operation_context::get_next_intraprocedural_point () const
     115              : {
     116              :   /* All edges are intraprocedural.  */
     117       346599 :   gcc_assert (m_sedge.m_src->get_function ()
     118              :               == m_sedge.m_dest->get_function ());
     119       346599 :   return program_point (m_sedge.m_dest,
     120       346599 :                         m_src_enode.get_point ().get_call_string ());
     121              : }
     122              : 
     123              : void
     124       295847 : operation_context::add_outcome (const program_point &dst_point,
     125              :                                 program_state dst_state,
     126              :                                 bool could_do_work,
     127              :                                 uncertainty_t *uncertainty,
     128              :                                 std::unique_ptr<custom_edge_info> info)
     129              : {
     130       295847 :   const program_state &src_state = get_initial_state ();
     131       295847 :   impl_region_model_context ctxt (m_eg, &m_src_enode,
     132              :                                   &src_state, &dst_state,
     133       295847 :                                   uncertainty, nullptr);
     134       295847 :   program_state::detect_leaks (src_state, dst_state, nullptr,
     135              :                                get_ext_state (), &ctxt);
     136              : 
     137       591694 :   if (exploded_node *dst_enode
     138       295847 :       = m_eg.get_or_create_node (dst_point, dst_state, &m_src_enode))
     139              :     {
     140       294796 :       m_eg.add_edge (&m_src_enode, dst_enode, &m_sedge, could_do_work,
     141              :                      std::move (info));
     142       294796 :       m_eg.detect_infinite_recursion (dst_enode);
     143              :     }
     144       295847 : }
     145              : 
     146       220482 : class op_region_model_context : public impl_region_model_context
     147              : {
     148              : public:
     149       110241 :   op_region_model_context (operation_context &op_ctxt,
     150              :                            program_state &dst_state)
     151       110241 :   : impl_region_model_context (op_ctxt.m_eg,
     152       110241 :                                &op_ctxt.m_src_enode,
     153       110241 :                                &op_ctxt.get_initial_state (),
     154              :                                &dst_state,
     155              :                                nullptr,
     156       110241 :                                &m_path_context)
     157              :   {
     158       110241 :   }
     159              : 
     160        44995 :   bool terminate_path_p () const
     161              :   {
     162        44995 :     return m_path_context.terminate_path_p ();
     163              :   }
     164              : 
     165              : private:
     166        59921 :   class op_path_context : public path_context
     167              :   {
     168              :   public:
     169       110241 :     op_path_context ()
     170       110241 :     : m_terminate_path (false)
     171              :     {
     172              :     }
     173              : 
     174            0 :     void bifurcate (std::unique_ptr<custom_edge_info>) final override
     175              :     {
     176            0 :       gcc_unreachable ();
     177              :     }
     178              : 
     179           42 :     void terminate_path () final override
     180              :     {
     181           42 :       m_terminate_path = true;
     182           42 :     }
     183              : 
     184        44995 :     bool terminate_path_p () const final override
     185              :     {
     186        44995 :       return m_terminate_path;
     187              :     }
     188              :   private:
     189              :     bool m_terminate_path;
     190              :   } m_path_context;
     191              : };
     192              : 
     193              : // class gimple_stmt_op : public operation
     194              : 
     195              : void
     196         1105 : gimple_stmt_op::print_as_edge_label (pretty_printer *pp,
     197              :                                      bool /*user_facing*/) const
     198              : {
     199         1105 :   pp_gimple_stmt_1 (pp, &m_stmt, 0, (dump_flags_t)0);
     200         1105 : }
     201              : 
     202              : bool
     203       181649 : gimple_stmt_op::defines_ssa_name_p (const_tree ssa_name) const
     204              : {
     205       181649 :   return &m_stmt == SSA_NAME_DEF_STMT (ssa_name);
     206              : }
     207              : 
     208              : bool
     209        35247 : gimple_stmt_op::supports_bulk_merge_p () const
     210              : {
     211        35247 :   return false;
     212              : }
     213              : 
     214              : /* Subclass of path_context for use within operation::execute implementations
     215              :    so that we can split states e.g. at "realloc" calls.  */
     216              : 
     217              : class impl_path_context : public path_context
     218              : {
     219              : public:
     220       244137 :   impl_path_context (const program_state *cur_state,
     221              :                      logger *logger)
     222       244137 :   : m_cur_state (cur_state),
     223       244137 :     m_logger (logger),
     224       244137 :     m_terminate_path (false)
     225              :   {
     226              :   }
     227              : 
     228              :   bool bifurcation_p () const
     229              :   {
     230              :     return m_custom_eedge_infos.length () > 0;
     231              :   }
     232              : 
     233        16482 :   const program_state &get_state_at_bifurcation () const
     234              :   {
     235        16482 :     gcc_assert (m_state_at_bifurcation);
     236        16482 :     return *m_state_at_bifurcation;
     237              :   }
     238              : 
     239              :   void
     240         8277 :   bifurcate (std::unique_ptr<custom_edge_info> info) final override
     241              :   {
     242         8277 :     if (m_logger)
     243            0 :       m_logger->log ("bifurcating path");
     244              : 
     245         8277 :     if (m_state_at_bifurcation)
     246              :       /* Verify that the state at bifurcation is consistent when we
     247              :          split into multiple out-edges.  */
     248         1666 :       gcc_assert (*m_state_at_bifurcation == *m_cur_state);
     249              :     else
     250              :       /* Take a copy of the cur_state at the moment when bifurcation
     251              :          happens.  */
     252         6611 :       m_state_at_bifurcation
     253         6611 :         = std::unique_ptr<program_state> (new program_state (*m_cur_state));
     254              : 
     255              :     /* Take ownership of INFO.  */
     256         8277 :     m_custom_eedge_infos.safe_push (info.release ());
     257         8277 :   }
     258              : 
     259         1913 :   void terminate_path () final override
     260              :   {
     261         1913 :     if (m_logger)
     262            2 :       m_logger->log ("terminating path");
     263         1913 :     m_terminate_path = true;
     264         1913 :   }
     265              : 
     266       427739 :   bool terminate_path_p () const final override
     267              :   {
     268       427739 :     return m_terminate_path;
     269              :   }
     270              : 
     271              :   const vec<custom_edge_info *> & get_custom_eedge_infos ()
     272              :   {
     273              :     return m_custom_eedge_infos;
     274              :   }
     275              : 
     276              : private:
     277              :   const program_state *m_cur_state;
     278              : 
     279              :   logger *m_logger;
     280              : 
     281              :   /* Lazily-created copy of the state before the split.  */
     282              :   std::unique_ptr<program_state> m_state_at_bifurcation;
     283              : 
     284              :   auto_vec <custom_edge_info *> m_custom_eedge_infos;
     285              : 
     286              :   bool m_terminate_path;
     287              : };
     288              : 
     289              : DEBUG_FUNCTION void
     290            0 : operation::dump () const
     291              : {
     292            0 :   tree_dump_pretty_printer pp (stderr);
     293            0 :   print_as_edge_label (&pp, false);
     294            0 :   pp_newline (&pp);
     295            0 : }
     296              : 
     297              : void
     298       250628 : operation::handle_on_stmt_for_state_machines (operation_context &op_ctxt,
     299              :                                               program_state &dst_state,
     300              :                                               path_context *path_ctxt,
     301              :                                               bool &unknown_side_effects,
     302              :                                               const gimple &stmt)
     303              : {
     304       250628 :   const program_state &old_state = op_ctxt.get_initial_state ();
     305       250628 :   int sm_idx;
     306       250628 :   sm_state_map *smap;
     307      2004086 :   FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
     308              :     {
     309      1753458 :       const state_machine &sm = op_ctxt.m_eg.get_ext_state ().get_sm (sm_idx);
     310      1753458 :       const sm_state_map *old_smap
     311      1753458 :         = old_state.m_checker_states[sm_idx];
     312      1753458 :       sm_state_map *new_smap = dst_state.m_checker_states[sm_idx];
     313      1753458 :       impl_sm_context sm_ctxt (op_ctxt.m_eg, sm_idx, sm,
     314      1753458 :                                &op_ctxt.m_src_enode,
     315              :                                &old_state,
     316              :                                &dst_state,
     317              :                                old_smap, new_smap, path_ctxt,
     318      1753458 :                                unknown_side_effects);
     319              : 
     320              :       /* Allow the state_machine to handle the stmt.  */
     321      1753458 :       if (sm.on_stmt (sm_ctxt, &stmt))
     322        22105 :         unknown_side_effects = false;
     323      1753458 :     }
     324       250628 : }
     325              : 
     326              : void
     327       108776 : gimple_stmt_op::
     328              : walk_load_store_addr_ops (void *data,
     329              :                           walk_stmt_load_store_addr_fn load_cb,
     330              :                           walk_stmt_load_store_addr_fn store_cb,
     331              :                           walk_stmt_load_store_addr_fn addr_cb) const
     332              : {
     333       108776 :   walk_stmt_load_store_addr_ops (const_cast<gimple *>(&m_stmt), data,
     334              :                                  load_cb, store_cb, addr_cb);
     335       108776 : }
     336              : 
     337              : void
     338       155957 : gimple_stmt_op::execute (operation_context &op_ctxt) const
     339              : {
     340       155957 :   auto logger = op_ctxt.get_logger ();
     341       155957 :   LOG_SCOPE (logger);
     342       155957 :   if (logger)
     343              :     {
     344           94 :       logger->start_log_line ();
     345           94 :       pp_gimple_stmt_1 (logger->get_printer (), &get_stmt (), 0,
     346              :                         (dump_flags_t)0);
     347           94 :       logger->end_log_line ();
     348              :     }
     349       155957 :   execute_on_state (op_ctxt,
     350              :                     /* Pass in a copy.  */
     351              :                     op_ctxt.get_initial_state ());
     352       155957 : }
     353              : 
     354              : void
     355       205633 : gimple_stmt_op::execute_on_state (operation_context &op_ctxt,
     356              :                                   program_state dst_state) const
     357              : {
     358       205633 :   auto logger = op_ctxt.get_logger ();
     359       205633 :   LOG_SCOPE (logger);
     360              : 
     361       205633 :   auto dst_point (op_ctxt.get_next_intraprocedural_point ());
     362       205633 :   const program_state &old_state  = op_ctxt.get_initial_state ();
     363              : 
     364       205633 :   bool unknown_side_effects = false;
     365       205633 :   bool could_have_done_work = false;
     366              : 
     367       205633 :   impl_path_context path_ctxt (&dst_state, logger);
     368       205633 :   uncertainty_t uncertainty;
     369       205633 :   impl_region_model_context ctxt (op_ctxt.m_eg,
     370       205633 :                                   &op_ctxt.m_src_enode,
     371              :                                   &old_state,
     372              :                                   &dst_state,
     373              :                                   &uncertainty,
     374              :                                   &path_ctxt,
     375       205633 :                                   &m_stmt,
     376       205633 :                                   &could_have_done_work);
     377              : 
     378       205633 :   dst_state.m_region_model->on_stmt_pre (&get_stmt (),
     379              :                                          &unknown_side_effects,
     380              :                                          &ctxt);
     381              : 
     382       205633 :   handle_on_stmt_for_state_machines (op_ctxt,
     383              :                                      dst_state,
     384              :                                      &path_ctxt,
     385              :                                      unknown_side_effects,
     386              :                                      m_stmt);
     387              : 
     388       205633 :   if (path_ctxt.terminate_path_p ())
     389          678 :     return;
     390              : 
     391       204955 :   if (const gcall *call = dyn_cast <const gcall *> (&m_stmt))
     392        49431 :     dst_state.m_region_model->on_call_post (*call, unknown_side_effects, &ctxt);
     393              : 
     394       204955 :   if (!path_ctxt.terminate_path_p ())
     395       203787 :     op_ctxt.add_outcome (dst_point, dst_state, could_have_done_work,
     396              :                          &uncertainty);
     397              : 
     398              :   /* If we have custom edge infos, "bifurcate" the state
     399              :      accordingly, potentially creating a new state/enode/eedge
     400              :      instances.  For example, to handle a "realloc" call, we
     401              :      might split into 3 states, for the "failure",
     402              :      "resizing in place", and "moving to a new buffer" cases.  */
     403       226346 :   for (auto edge_info_iter : path_ctxt.get_custom_eedge_infos ())
     404              :     {
     405              :       /* Take ownership of the edge infos from the path_ctxt.  */
     406         8241 :       std::unique_ptr<custom_edge_info> edge_info (edge_info_iter);
     407         8241 :       if (logger)
     408              :         {
     409            0 :           logger->start_log_line ();
     410            0 :           logger->log_partial ("bifurcating for edge: ");
     411            0 :           edge_info->print (logger->get_printer ());
     412            0 :           logger->end_log_line ();
     413              :         }
     414         8241 :       program_state bifurcated_new_state
     415         8241 :         (path_ctxt.get_state_at_bifurcation ());
     416              : 
     417              :       /* Apply edge_info to state.  */
     418         8241 :       impl_region_model_context
     419              :         bifurcation_ctxt (op_ctxt.m_eg,
     420         8241 :                           &op_ctxt.m_src_enode,
     421         8241 :                           &path_ctxt.get_state_at_bifurcation (),
     422              :                           &bifurcated_new_state,
     423              :                           nullptr, // uncertainty_t *uncertainty
     424              :                           nullptr, // path_context *path_ctxt
     425         8241 :                           &m_stmt);
     426         8241 :       if (edge_info->update_state (&bifurcated_new_state,
     427              :                                    nullptr, /* no exploded_edge yet.  */
     428              :                                    &bifurcation_ctxt))
     429              :         {
     430         7893 :           if (exploded_node *next2
     431         7893 :               = edge_info->create_enode
     432         7893 :               (op_ctxt.m_eg,
     433              :                dst_point,
     434              :                std::move (bifurcated_new_state),
     435         7893 :                &op_ctxt.m_src_enode,
     436              :                &bifurcation_ctxt))
     437              :             {
     438         7455 :               op_ctxt.m_eg.add_edge (&op_ctxt.m_src_enode, next2, nullptr,
     439              :                                      true /* assume that work could be done */,
     440              :                                      std::move (edge_info));
     441              :             }
     442              :         }
     443         8241 :     }
     444       411266 : }
     445              : 
     446              : bool
     447       106127 : gimple_stmt_op::
     448              : execute_for_feasibility (const exploded_edge &,
     449              :                          feasibility_state &fstate,
     450              :                          region_model_context *ctxt,
     451              :                          std::unique_ptr<rejected_constraint> */*out_rc*/) const
     452              : {
     453       106127 :   region_model &model = fstate.get_model ();
     454       106127 :   bool unknown_side_effects;
     455       106127 :   model.on_stmt_pre (&m_stmt, &unknown_side_effects, ctxt);
     456              : 
     457       106127 :   if (const gcall *call = dyn_cast <const gcall *> (&m_stmt))
     458        21053 :     model.on_call_post (*call, unknown_side_effects, ctxt);
     459              : 
     460       106127 :   return true;
     461              : }
     462              : 
     463              : /* An sm_context for adding state_change_event on assignments to NULL,
     464              :    where the default state isn't m_start.  Storing such state in the
     465              :    sm_state_map would lead to bloat of the exploded_graph, so we want
     466              :    to leave it as a default state, and inject state change events here
     467              :    when we have a diagnostic.
     468              :    Find transitions of constants, for handling on_zero_assignment.  */
     469              : 
     470        94047 : struct null_assignment_sm_context : public sm_context
     471              : {
     472        94047 :   null_assignment_sm_context (int sm_idx,
     473              :                               const state_machine &sm,
     474              :                               const program_state *old_state,
     475              :                               const program_state *new_state,
     476              :                               const gimple *stmt,
     477              :                               const program_point *point,
     478              :                               checker_path *emission_path,
     479              :                               const extrinsic_state &ext_state)
     480        94047 :   : sm_context (sm_idx, sm), m_old_state (old_state), m_new_state (new_state),
     481        94047 :     m_stmt (stmt), m_point (point), m_emission_path (emission_path),
     482        94047 :     m_ext_state (ext_state)
     483              :   {
     484              :   }
     485              : 
     486            0 :   tree get_fndecl_for_call (const gcall &/*call*/) final override
     487              :   {
     488            0 :     return NULL_TREE;
     489              :   }
     490              : 
     491         4353 :   state_machine::state_t get_state (tree var) final override
     492              :   {
     493         4353 :     const svalue *var_old_sval
     494         4353 :       = m_old_state->m_region_model->get_rvalue (var, nullptr);
     495         4353 :     const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx];
     496              : 
     497         4353 :     state_machine::state_t current
     498         4353 :       = old_smap->get_state (var_old_sval, m_ext_state);
     499              : 
     500         4353 :     return current;
     501              :   }
     502              : 
     503            5 :   state_machine::state_t get_state (const svalue *sval) final override
     504              :   {
     505            5 :     const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx];
     506            5 :     state_machine::state_t current = old_smap->get_state (sval, m_ext_state);
     507            5 :     return current;
     508              :   }
     509              : 
     510         1325 :   void set_next_state (tree var,
     511              :                        state_machine::state_t to,
     512              :                        tree origin ATTRIBUTE_UNUSED) final override
     513              :   {
     514         1325 :     state_machine::state_t from = get_state (var);
     515         1325 :     if (from != m_sm.get_start_state ())
     516          906 :       return;
     517         1210 :     if (!is_transition_to_null (to))
     518              :       return;
     519              : 
     520          419 :     const svalue *var_new_sval
     521          419 :       = m_new_state->m_region_model->get_rvalue (var, nullptr);
     522              : 
     523          419 :     m_emission_path->add_event
     524          419 :       (std::make_unique<state_change_event> (event_loc_info (*m_point),
     525          419 :                                              m_stmt,
     526              :                                              m_sm,
     527              :                                              var_new_sval,
     528              :                                              from, to,
     529          838 :                                              nullptr,
     530          419 :                                              *m_new_state,
     531          838 :                                              nullptr));
     532              :   }
     533              : 
     534            0 :   void set_next_state (const svalue *sval,
     535              :                        state_machine::state_t to,
     536              :                        tree origin ATTRIBUTE_UNUSED) final override
     537              :   {
     538            0 :     state_machine::state_t from = get_state (sval);
     539            0 :     if (from != m_sm.get_start_state ())
     540            0 :       return;
     541            0 :     if (!is_transition_to_null (to))
     542              :       return;
     543              : 
     544            0 :     m_emission_path->add_event
     545            0 :       (std::make_unique<state_change_event> (event_loc_info (*m_point),
     546            0 :                                              m_stmt,
     547              :                                              m_sm,
     548              :                                              sval,
     549              :                                              from, to,
     550            0 :                                              nullptr,
     551            0 :                                              *m_new_state,
     552            0 :                                              nullptr));
     553              :   }
     554              : 
     555          115 :   void warn (tree, std::unique_ptr<pending_diagnostic>) final override
     556              :   {
     557          115 :   }
     558            0 :   void warn (const svalue *, std::unique_ptr<pending_diagnostic>) final override
     559              :   {
     560            0 :   }
     561              : 
     562          115 :   tree get_diagnostic_tree (tree expr) final override
     563              :   {
     564          115 :     return expr;
     565              :   }
     566              : 
     567            0 :   tree get_diagnostic_tree (const svalue *sval) final override
     568              :   {
     569            0 :     return m_new_state->m_region_model->get_representative_tree (sval);
     570              :   }
     571              : 
     572        13426 :   state_machine::state_t get_global_state () const final override
     573              :   {
     574        13426 :     return 0;
     575              :   }
     576              : 
     577            0 :   void set_global_state (state_machine::state_t) final override
     578              :   {
     579              :     /* No-op.  */
     580            0 :   }
     581              : 
     582            0 :   void clear_all_per_svalue_state () final override
     583              :   {
     584              :     /* No-op.  */
     585            0 :   }
     586              : 
     587            0 :   void on_custom_transition (custom_transition *) final override
     588              :   {
     589            0 :   }
     590              : 
     591        13473 :   tree is_zero_assignment (const gimple *stmt) final override
     592              :   {
     593        25675 :     const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
     594        13473 :     if (!assign_stmt)
     595              :      return NULL_TREE;
     596        26946 :     if (const svalue *sval
     597        13473 :         = m_new_state->m_region_model->get_gassign_result (assign_stmt, nullptr))
     598        13063 :       if (tree cst = sval->maybe_get_constant ())
     599         2400 :         if (::zerop(cst))
     600         1271 :           return gimple_assign_lhs (assign_stmt);
     601              :     return NULL_TREE;
     602              :   }
     603              : 
     604         1274 :   const program_state *get_old_program_state () const final override
     605              :   {
     606         1274 :     return m_old_state;
     607              :   }
     608            0 :   const program_state *get_new_program_state () const final override
     609              :   {
     610            0 :     return m_new_state;
     611              :   }
     612              : 
     613            0 :   location_t get_emission_location () const final override
     614              :   {
     615            0 :     return UNKNOWN_LOCATION;
     616              :   }
     617              : 
     618              :   /* We only care about transitions to the "null" state
     619              :      within sm-malloc.  Special-case this.  */
     620         1210 :   static bool is_transition_to_null (state_machine::state_t s)
     621              :   {
     622         1210 :     return !strcmp (s->get_name (), "null");
     623              :   }
     624              : 
     625              :   const program_state *m_old_state;
     626              :   const program_state *m_new_state;
     627              :   const gimple *m_stmt;
     628              :   const program_point *m_point;
     629              :   checker_path *m_emission_path;
     630              :   const extrinsic_state &m_ext_state;
     631              : };
     632              : 
     633              : void
     634        13613 : gimple_stmt_op::add_any_events_for_eedge (const exploded_edge &eedge,
     635              :                                           checker_path &out_path) const
     636              : {
     637        13613 :   out_path.add_event
     638        13613 :     (std::make_unique<statement_event> (&get_stmt (),
     639        13613 :                                         eedge.m_dest->get_function ()->decl,
     640        27226 :                                         eedge.m_dest->get_stack_depth (),
     641        13613 :                                         eedge.m_dest->get_state ()));
     642              : 
     643              :   /* Create state change events for assignment to NULL.
     644              :      Iterate through the stmts in dst_enode, adding state change
     645              :      events for them.  */
     646        13613 :   if (const gassign *assign = dyn_cast<const gassign *> (&m_stmt))
     647              :     {
     648        13491 :       const program_point &src_point = eedge.m_src->get_point ();
     649        13491 :       const extrinsic_state &ext_state = out_path.get_ext_state ();
     650       107538 :       for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
     651              :         {
     652        94047 :           const state_machine &sm = ext_state.get_sm (i);
     653        94047 :           null_assignment_sm_context sm_ctxt (i, sm,
     654        94047 :                                               &eedge.m_src->get_state (),
     655        94047 :                                               &eedge.m_dest->get_state (),
     656              :                                               assign,
     657              :                                               &src_point,
     658              :                                               &out_path,
     659        94047 :                                               ext_state);
     660        94047 :           sm.on_stmt (sm_ctxt, assign);
     661              :           // TODO: what about phi nodes?
     662        94047 :         }
     663              :     }
     664        13613 : }
     665              : 
     666              : // class gassign_op : public gimple_stmt_op
     667              : 
     668              : // class greturn_op : public gimple_stmt_op
     669              : 
     670              : void
     671        17151 : greturn_op::execute (operation_context &op_ctxt) const
     672              : {
     673        17151 :   auto logger = op_ctxt.get_logger ();
     674              : 
     675        17151 :   auto dst_point (op_ctxt.get_next_intraprocedural_point ());
     676        17151 :   const program_state &old_state  = op_ctxt.get_initial_state ();
     677        17151 :   program_state dst_state (old_state);
     678              : 
     679        17151 :   impl_path_context path_ctxt (&dst_state, logger);
     680        17151 :   uncertainty_t uncertainty;
     681        17151 :   impl_region_model_context ctxt (op_ctxt.m_eg,
     682        17151 :                                   &op_ctxt.m_src_enode,
     683              : 
     684              :                                   /* TODO: should we be getting the ECs from the
     685              :                                      old state, rather than the new?  */
     686        17151 :                                   &op_ctxt.get_initial_state (),
     687              :                                   &dst_state,
     688              :                                   &uncertainty,
     689              :                                   &path_ctxt,
     690              :                                   nullptr,
     691        17151 :                                   nullptr);
     692              : 
     693        17151 :   tree callee = op_ctxt.get_initial_point ().get_function ()->decl;
     694        17151 :   tree lhs = DECL_RESULT (callee);
     695              : 
     696        34302 :   if (lhs && get_retval ())
     697              :     {
     698         8682 :       region_model *dst_region_model = dst_state.m_region_model;
     699         8682 :       const svalue *sval
     700         8682 :         = dst_region_model->get_rvalue (get_retval (), &ctxt);
     701         8682 :       const region *ret_reg = dst_region_model->get_lvalue (lhs, &ctxt);
     702         8682 :       dst_region_model->set_value (ret_reg, sval, &ctxt);
     703              :     }
     704              : 
     705        17151 :   if (!path_ctxt.terminate_path_p ())
     706        17136 :     op_ctxt.add_outcome (dst_point, dst_state, false, &uncertainty);
     707        34302 : }
     708              : 
     709              : bool
     710         3636 : greturn_op::
     711              : execute_for_feasibility (const exploded_edge &eedge,
     712              :                          feasibility_state &fstate,
     713              :                          region_model_context *ctxt,
     714              :                          std::unique_ptr<rejected_constraint> *) const
     715              : {
     716         3636 :   tree callee = eedge.m_src->get_function ()->decl;
     717         3636 :   tree lhs = DECL_RESULT (callee);
     718              : 
     719         7272 :   if (lhs && get_retval ())
     720              :     {
     721         1421 :       region_model &model = fstate.get_model ();
     722         1421 :       const svalue *sval = model.get_rvalue (get_retval (), ctxt);
     723         1421 :       const region *ret_reg = model.get_lvalue (lhs, ctxt);
     724         1421 :       model.set_value (ret_reg, sval, ctxt);
     725              :     }
     726              : 
     727         3636 :   return true;
     728              : }
     729              : 
     730              : void
     731          969 : greturn_op::add_any_events_for_eedge (const exploded_edge &,
     732              :                                       checker_path &) const
     733              : {
     734              :   // No-op.
     735          969 : }
     736              : 
     737              : // class call_and_return_op : public gimple_stmt_op
     738              : 
     739              : std::unique_ptr<operation>
     740        41878 : call_and_return_op::make (const gcall &call_stmt)
     741              : {
     742        41878 :   if (is_special_named_call_p (call_stmt, "__analyzer_dump", 0))
     743            0 :     return std::make_unique<dump_op> (call_stmt, dump_op::dump_kind::state);
     744        41878 :   else if (is_special_named_call_p (call_stmt, "__analyzer_dump_sarif", 0))
     745            0 :     return std::make_unique<dump_op> (call_stmt, dump_op::dump_kind::sarif);
     746        41878 :   else if (is_special_named_call_p (call_stmt, "__analyzer_dump_dot", 0))
     747            0 :     return std::make_unique<dump_op> (call_stmt, dump_op::dump_kind::dot);
     748        41878 :   else if (is_special_named_call_p (call_stmt, "__analyzer_dump_state", 2))
     749          309 :     return std::make_unique<dump_op> (call_stmt, dump_op::dump_kind::state_2);
     750        41569 :   else if (is_setjmp_call_p (call_stmt))
     751           29 :     return std::make_unique<setjmp_op> (call_stmt);
     752        41540 :   else if (is_longjmp_call_p (call_stmt))
     753           41 :     return std::make_unique<longjmp_op> (call_stmt);
     754        41499 :   else if (is_cxa_throw_p (call_stmt))
     755           73 :     return std::make_unique<cxa_throw_op> (call_stmt, false);
     756        41426 :   else if (is_cxa_rethrow_p (call_stmt))
     757           39 :     return std::make_unique<cxa_throw_op> (call_stmt, true);
     758              : 
     759        41387 :   return std::make_unique<call_and_return_op> (call_stmt);
     760              : }
     761              : 
     762              : /* Resolve a function call by one of:
     763              : 
     764              :    (a) using a call summary to add eedges to new enodes capturing
     765              :    the states after summarized outcomes of the call
     766              : 
     767              :    (b) adding an interprocedural_call edge, effectively "stepping into"
     768              :    the called function, for detailed analysis of that path
     769              : 
     770              :    (c) simulating the effect of the call, adding an eedge to a new
     771              :    enode for the outcome of the call.  */
     772              : 
     773              : void
     774        57224 : call_and_return_op::execute (operation_context &op_ctxt) const
     775              : {
     776              :   /* Can we turn this into an interprocedural call, and execute within
     777              :      the called fuction?  */
     778        57224 :   const program_state &old_state  = op_ctxt.get_initial_state ();
     779        57224 :   program_state dst_state (old_state);
     780        57224 :   op_region_model_context ctxt (op_ctxt, dst_state);
     781        57224 :   ctxt.m_stmt = &get_gcall ();
     782        57224 :   call_details cd (get_gcall (), old_state.m_region_model, &ctxt);
     783              : 
     784              :   /* Regardless of how we handle the call, check any known
     785              :      preconditions.  */
     786        57224 :   {
     787              :     /* Check for any preconditions if it's a known_function.  */
     788        57224 :     if (auto kf = maybe_get_known_function (cd))
     789        33414 :       kf->check_any_preconditions (cd);
     790              : 
     791              :     /* Check for any preconditions using sm-state.  */
     792              :     {
     793              :       int sm_idx;
     794              :       sm_state_map *smap;
     795       457429 :       FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
     796              :         {
     797       400205 :           const state_machine &sm
     798       800410 :             = op_ctxt.m_eg.get_ext_state ().get_sm (sm_idx);
     799       400205 :           const sm_state_map *old_smap
     800       400205 :             = old_state.m_checker_states[sm_idx];
     801       400205 :           sm_state_map *new_smap = dst_state.m_checker_states[sm_idx];
     802       400205 :           impl_sm_context sm_ctxt (op_ctxt.m_eg, sm_idx, sm,
     803       400205 :                                    &op_ctxt.m_src_enode,
     804              :                                    &old_state, &dst_state,
     805       400205 :                                    old_smap, new_smap, nullptr);
     806       400205 :           sm.check_call_preconditions (sm_ctxt, cd);
     807       400205 :         }
     808              :     }
     809              :   }
     810              : 
     811        57224 :   if (tree callee_fndecl = cd.get_fndecl_for_call ())
     812              :     {
     813              :       // Consider using a call summary
     814        53424 :       if (function *called_fn = DECL_STRUCT_FUNCTION (callee_fndecl))
     815         7548 :         if (cgraph_edge *edge = get_any_cgraph_edge (op_ctxt))
     816         7548 :           if (op_ctxt.m_eg.get_analysis_plan ().use_summary_p (edge))
     817              :             {
     818          790 :               per_function_data *called_fn_data
     819          790 :                 = op_ctxt.m_eg.get_per_function_data (called_fn);
     820          790 :               if (called_fn_data)
     821              :                 {
     822          752 :                   replay_call_summaries (op_ctxt, *called_fn,
     823              :                                          *called_fn_data, &ctxt);
     824          752 :                   return;
     825              :                 }
     826              :             }
     827              : 
     828              :       // Do we have an entry snode for this fndecl?
     829        52672 :       if (auto callee_fun = DECL_STRUCT_FUNCTION (callee_fndecl))
     830        13592 :         if (supernode *callee_entry_snode
     831         6796 :             = (op_ctxt.get_supergraph ()
     832         6796 :                .get_node_for_function_entry (*callee_fun)))
     833              :           {
     834         6796 :             const call_string *dst_call_string
     835         6796 :               (op_ctxt.m_src_enode
     836         6796 :                .get_point ()
     837         6796 :                .get_call_string ()
     838         6796 :                .push_call (op_ctxt.m_sedge, *this, *callee_fun));
     839         6796 :             const program_point dst_point
     840         6796 :               (callee_entry_snode, *dst_call_string);
     841         6796 :             auto edge_info
     842              :               = std::make_unique<interprocedural_call> (get_gcall (),
     843         6796 :                                                         *callee_fun);
     844         6796 :             edge_info->update_state (&dst_state, nullptr, &ctxt);
     845         6796 :             op_ctxt.add_outcome (dst_point, dst_state, false, nullptr,
     846        13592 :                                  std::move (edge_info));
     847         6796 :             return;
     848         6796 :           }
     849              :     }
     850              : 
     851              :   /* Resolve intraprocedurally: execute the gcall, but using the
     852              :      dst_state from above so that any preconditions have been applied.  */
     853        49676 :   gimple_stmt_op::execute_on_state (op_ctxt, std::move (dst_state));
     854        57224 : }
     855              : 
     856              : cgraph_edge *
     857         7548 : call_and_return_op::get_any_cgraph_edge (operation_context &op_ctxt) const
     858              : {
     859         7548 :   tree caller_fndecl = op_ctxt.get_initial_point ().get_fndecl ();
     860         7548 :   gcc_assert (caller_fndecl);
     861              : 
     862         7548 :   auto caller_cgnode = cgraph_node::get (caller_fndecl);
     863         7548 :   gcc_assert (caller_cgnode);
     864         7548 :   return caller_cgnode->get_edge (const_cast<gcall *> (&get_gcall ()));
     865              : }
     866              : 
     867              : void
     868         7321 : call_and_return_op::
     869              : add_any_events_for_eedge (const exploded_edge &,
     870              :                           checker_path &) const
     871              : {
     872         7321 : }
     873              : 
     874              : /* Given PARM_TO_FIND, a PARM_DECL, identify its index (writing it
     875              :    to *OUT if OUT is non-NULL), and return the corresponding argument
     876              :    at the callsite.  */
     877              : 
     878              : tree
     879          247 : call_and_return_op::get_arg_for_parm (tree callee_fndecl,
     880              :                                       tree parm_to_find,
     881              :                                       callsite_expr *out) const
     882              : {
     883          247 :   gcc_assert  (TREE_CODE (parm_to_find) == PARM_DECL);
     884              : 
     885          247 :   const gcall &call_stmt = get_gcall ();
     886              : 
     887          247 :   unsigned i = 0;
     888          262 :   for (tree iter_parm = DECL_ARGUMENTS (callee_fndecl); iter_parm;
     889           15 :        iter_parm = DECL_CHAIN (iter_parm), ++i)
     890              :     {
     891          230 :       if (i >= gimple_call_num_args (&call_stmt))
     892              :         return NULL_TREE;
     893          230 :       if (iter_parm == parm_to_find)
     894              :         {
     895          215 :           if (out)
     896          215 :             *out = callsite_expr::from_zero_based_param (i);
     897          215 :           return gimple_call_arg (&call_stmt, i);
     898              :         }
     899              :     }
     900              : 
     901              :   /* Not found.  */
     902              :   return NULL_TREE;
     903              : }
     904              : 
     905              : /* Look for a use of ARG_TO_FIND as an argument at this callsite.
     906              :    If found, return the default SSA def of the corresponding parm within
     907              :    the callee, and if OUT is non-NULL, write the index to *OUT.
     908              :    Only the first match is handled.  */
     909              : 
     910              : tree
     911          431 : call_and_return_op::get_parm_for_arg (tree callee_fndecl,
     912              :                                       tree arg_to_find,
     913              :                                       callsite_expr *out) const
     914              : {
     915          431 :   const gcall &call_stmt = get_gcall ();
     916              : 
     917          431 :   unsigned i = 0;
     918          711 :   for (tree iter_parm = DECL_ARGUMENTS (callee_fndecl); iter_parm;
     919          280 :        iter_parm = DECL_CHAIN (iter_parm), ++i)
     920              :     {
     921          376 :       if (i >= gimple_call_num_args (&call_stmt))
     922              :         return NULL_TREE;
     923          375 :       tree param = gimple_call_arg (&call_stmt, i);
     924          375 :       if (arg_to_find == param)
     925              :         {
     926           95 :           if (out)
     927           95 :             *out = callsite_expr::from_zero_based_param (i);
     928           95 :           return ssa_default_def (DECL_STRUCT_FUNCTION (callee_fndecl),
     929           95 :                                   iter_parm);
     930              :         }
     931              :     }
     932              : 
     933              :   /* Not found.  */
     934              :   return NULL_TREE;
     935              : }
     936              : 
     937              : /* Map caller_expr back to an expr within the callee, or return NULL_TREE.
     938              :    If non-NULL is returned, populate OUT.  */
     939              : 
     940              : tree
     941          431 : call_and_return_op::map_expr_from_caller_to_callee (tree callee_fndecl,
     942              :                                                     tree caller_expr,
     943              :                                                     callsite_expr *out) const
     944              : {
     945              :   /* Is it an argument (actual param)?  If so, convert to
     946              :      parameter (formal param).  */
     947          431 :   tree parm = get_parm_for_arg (callee_fndecl, caller_expr, out);
     948          431 :   if (parm)
     949              :     return parm;
     950              :   /* Otherwise try return value.  */
     951          340 :   if (caller_expr == gimple_call_lhs (&get_gcall ()))
     952              :     {
     953           94 :       if (out)
     954           94 :         *out = callsite_expr::from_return_value ();
     955           94 :       return DECL_RESULT (callee_fndecl);
     956              :     }
     957              : 
     958              :   return NULL_TREE;
     959              : }
     960              : 
     961              : /* Map callee_expr back to an expr within the caller, or return NULL_TREE.
     962              :    If non-NULL is returned, populate OUT.  */
     963              : 
     964              : tree
     965         1193 : call_and_return_op::map_expr_from_callee_to_caller (tree callee_fndecl,
     966              :                                                     tree callee_expr,
     967              :                                                     callsite_expr *out) const
     968              : {
     969         1193 :   if (callee_expr == NULL_TREE)
     970              :     return NULL_TREE;
     971              : 
     972              :   /* If it's a parameter (formal param), get the argument (actual param).  */
     973          384 :   if (TREE_CODE (callee_expr) == PARM_DECL)
     974            7 :     return get_arg_for_parm (callee_fndecl, callee_expr, out);
     975              : 
     976              :   /* Similar for the default SSA name of the PARM_DECL.  */
     977          377 :   if (TREE_CODE (callee_expr) == SSA_NAME
     978          275 :       && SSA_NAME_IS_DEFAULT_DEF (callee_expr)
     979          617 :       && TREE_CODE (SSA_NAME_VAR (callee_expr)) == PARM_DECL)
     980          240 :     return get_arg_for_parm (callee_fndecl, SSA_NAME_VAR (callee_expr), out);
     981              : 
     982              :   /* Otherwise try return value.  */
     983          137 :   if (callee_expr == DECL_RESULT (callee_fndecl))
     984              :     {
     985            0 :       if (out)
     986            0 :         *out = callsite_expr::from_return_value ();
     987            0 :       return gimple_call_lhs (&get_gcall ());
     988              :     }
     989              : 
     990              :   return NULL_TREE;
     991              : }
     992              : 
     993              : const known_function *
     994        57224 : call_and_return_op::maybe_get_known_function (const call_details &cd) const
     995              : {
     996        57224 :   region_model_manager *mgr = cd.get_manager ();
     997        57224 :   known_function_manager *known_fn_mgr = mgr->get_known_function_manager ();
     998              : 
     999        57224 :   if (gimple_call_internal_p (&get_gcall ()))
    1000         3430 :     return known_fn_mgr->get_internal_fn
    1001         3430 :       (gimple_call_internal_fn (&get_gcall ()));
    1002              : 
    1003        53794 :   if (tree callee_fndecl = cd.get_fndecl_for_call ())
    1004        53424 :     return known_fn_mgr->get_match (callee_fndecl, cd);
    1005              : 
    1006              :   return nullptr;
    1007              : }
    1008              : 
    1009              : void
    1010          752 : call_and_return_op::
    1011              : replay_call_summaries (operation_context &op_ctxt,
    1012              :                        function &called_fn,
    1013              :                        per_function_data &called_fn_data,
    1014              :                        region_model_context *ctxt) const
    1015              : {
    1016          752 :   logger *logger = op_ctxt.get_logger ();
    1017          752 :   LOG_SCOPE (logger);
    1018              : 
    1019         3797 :   for (auto summary : called_fn_data.m_summaries)
    1020              :     {
    1021         1541 :       gcc_assert (summary);
    1022         1541 :       replay_call_summary (op_ctxt, called_fn, *summary, ctxt);
    1023              :     }
    1024          752 : }
    1025              : 
    1026              : /* A concrete call_info subclass representing a replay of a call summary.  */
    1027              : 
    1028              : class call_summary_edge_info : public call_info
    1029              : {
    1030              : public:
    1031         1417 :   call_summary_edge_info (const call_details &cd,
    1032              :                           const function &called_fn,
    1033              :                           call_summary &summary,
    1034              :                           const extrinsic_state &ext_state)
    1035         1417 :   : call_info (cd, called_fn),
    1036         1417 :     m_called_fn (called_fn),
    1037         1417 :     m_summary (summary),
    1038         1417 :     m_ext_state (ext_state)
    1039              :   {}
    1040              : 
    1041            0 :   bool update_state (program_state *state,
    1042              :                      const exploded_edge *,
    1043              :                      region_model_context *ctxt) const final override
    1044              :   {
    1045              :     /* Update STATE based on summary_end_state.  */
    1046            0 :     call_details cd (get_call_details (state->m_region_model, ctxt));
    1047            0 :     call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
    1048            0 :     const program_state &summary_end_state = m_summary.get_state ();
    1049            0 :     return state->replay_call_summary (r, summary_end_state);
    1050            0 :   }
    1051              : 
    1052           88 :   bool update_model (region_model *model,
    1053              :                      const exploded_edge *,
    1054              :                      region_model_context *ctxt) const final override
    1055              :   {
    1056              :     /* Update STATE based on summary_end_state.  */
    1057           88 :     call_details cd (get_call_details (model, ctxt));
    1058           88 :     call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
    1059           88 :     const program_state &summary_end_state = m_summary.get_state ();
    1060           88 :     model->replay_call_summary (r, *summary_end_state.m_region_model);
    1061           88 :     return true;
    1062           88 :   }
    1063              : 
    1064           62 :   void print_desc (pretty_printer &pp) const final override
    1065              :   {
    1066           62 :     pp_string (&pp, m_summary.get_desc ().get ());
    1067           62 :   }
    1068              : 
    1069              : private:
    1070              :   const function &m_called_fn;
    1071              :   call_summary &m_summary;
    1072              :   const extrinsic_state &m_ext_state;
    1073              : };
    1074              : 
    1075              : void
    1076         1541 : call_and_return_op::
    1077              : replay_call_summary (operation_context &op_ctxt,
    1078              :                      function &called_fn,
    1079              :                      call_summary &summary,
    1080              :                      region_model_context *ctxt) const
    1081              : {
    1082         1541 :   logger *logger = op_ctxt.get_logger ();
    1083         1541 :   LOG_SCOPE (logger);
    1084         1541 :   if (logger)
    1085            0 :     logger->log ("using %s as summary for call to %qE from %qE",
    1086            0 :                  summary.get_desc ().get (),
    1087              :                  called_fn.decl,
    1088            0 :                  op_ctxt.get_initial_point ().get_function ()->decl);
    1089         1541 :   const extrinsic_state &ext_state = op_ctxt.get_ext_state ();
    1090         1541 :   const program_state &old_state = op_ctxt.get_initial_state ();
    1091         1541 :   const program_state &summary_end_state = summary.get_state ();
    1092         1541 :   if (logger)
    1093              :     {
    1094            0 :       pretty_printer *pp = logger->get_printer ();
    1095              : 
    1096            0 :       logger->start_log_line ();
    1097            0 :       pp_string (pp, "callsite state: ");
    1098            0 :       old_state.dump_to_pp (ext_state, true, false, pp);
    1099            0 :       logger->end_log_line ();
    1100              : 
    1101            0 :       logger->start_log_line ();
    1102            0 :       pp_string (pp, "summary end state: ");
    1103            0 :       summary_end_state.dump_to_pp (ext_state, true, false, pp);
    1104            0 :       logger->end_log_line ();
    1105              :     }
    1106              : 
    1107         1541 :   program_state new_state (old_state);
    1108              : 
    1109         1541 :   call_details cd (get_gcall (), new_state.m_region_model, ctxt);
    1110         1541 :   call_summary_replay r (cd, called_fn, summary, ext_state);
    1111              : 
    1112         1541 :   if (new_state.replay_call_summary (r, summary_end_state))
    1113         1417 :     op_ctxt.add_outcome
    1114         1417 :       (op_ctxt.get_next_intraprocedural_point (),
    1115              :        new_state,
    1116              :        true,
    1117              :        nullptr,
    1118         2834 :        std::make_unique<call_summary_edge_info> (cd,
    1119              :                                                  called_fn,
    1120              :                                                  summary,
    1121              :                                                  ext_state));
    1122         1541 : }
    1123              : 
    1124              : // class dump_op : public call_and_return_op
    1125              : 
    1126              : void
    1127          357 : dump_op::execute (operation_context &op_ctxt) const
    1128              : {
    1129          357 :   const program_state &state = op_ctxt.get_initial_state ();
    1130          357 :   switch (m_dump_kind)
    1131              :     {
    1132            0 :     default:
    1133            0 :       gcc_unreachable ();
    1134            0 :     case dump_kind::state:
    1135              :       /* Handle the builtin "__analyzer_dump" by dumping state
    1136              :          to stderr.  */
    1137            0 :       state.dump (op_ctxt.get_ext_state (), true);
    1138            0 :       break;
    1139            0 :     case dump_kind::sarif:
    1140            0 :       state.dump_sarif (op_ctxt.get_ext_state ());
    1141            0 :       break;
    1142            0 :     case dump_kind::dot:
    1143            0 :       state.dump_dot (op_ctxt.get_ext_state ());
    1144            0 :       break;
    1145          357 :     case dump_kind::state_2:
    1146          357 :       {
    1147          357 :         program_state dst_state (state);
    1148          357 :         op_region_model_context ctxt (op_ctxt, dst_state);
    1149          357 :         dst_state.impl_call_analyzer_dump_state (get_gcall (),
    1150              :                                                  op_ctxt.get_ext_state (),
    1151              :                                                  &ctxt);
    1152          357 :       }
    1153          357 :       break;
    1154              :     }
    1155              : 
    1156          357 :   op_ctxt.add_outcome (op_ctxt.get_next_intraprocedural_point (),
    1157              :                        state, false, nullptr);
    1158          357 : }
    1159              : 
    1160              : // class setjmp_op : public call_and_return_op
    1161              : 
    1162              : void
    1163           34 : setjmp_op::execute (operation_context &op_ctxt) const
    1164              : {
    1165           34 :   program_state dst_state (op_ctxt.get_initial_state ());
    1166           34 :   op_region_model_context ctxt (op_ctxt, dst_state);
    1167           34 :   dst_state.m_region_model->on_setjmp (get_gcall (),
    1168           34 :                                        op_ctxt.m_src_enode,
    1169              :                                        op_ctxt.m_sedge,
    1170              :                                        &ctxt);
    1171           34 :   op_ctxt.add_outcome (op_ctxt.get_next_intraprocedural_point (),
    1172              :                        dst_state, true, nullptr);
    1173           34 : }
    1174              : 
    1175              : void
    1176           20 : setjmp_op::add_any_events_for_eedge (const exploded_edge &eedge,
    1177              :                                      checker_path &out_path) const
    1178              : {
    1179           20 :   out_path.add_event
    1180           20 :     (std::make_unique<setjmp_event>
    1181           40 :        (event_loc_info (eedge.m_src),
    1182           20 :         eedge.m_src,
    1183              :         get_gcall ()));
    1184           20 : }
    1185              : 
    1186              : // class longjmp_op : public call_and_return_op
    1187              : 
    1188              : void
    1189           63 : longjmp_op::execute (operation_context &op_ctxt) const
    1190              : {
    1191           63 :   program_state dst_state (op_ctxt.get_initial_state ());
    1192           63 :   op_region_model_context ctxt (op_ctxt, dst_state);
    1193           63 :   op_ctxt.m_src_enode.on_longjmp (op_ctxt.m_eg, get_gcall (), &dst_state,
    1194              :                                   &ctxt);
    1195           63 : }
    1196              : 
    1197              : // class cxa_throw_op : public call_and_return_op
    1198              : 
    1199              : void
    1200          190 : cxa_throw_op::execute (operation_context &op_ctxt) const
    1201              : {
    1202          190 :   program_state dst_state (op_ctxt.get_initial_state ());
    1203          190 :   op_region_model_context ctxt (op_ctxt, dst_state);
    1204          190 :   program_point after_throw_point (op_ctxt.get_next_intraprocedural_point ());
    1205          190 :   op_ctxt.m_src_enode.on_throw (op_ctxt.m_eg,
    1206              :                                 get_gcall (),
    1207              :                                 after_throw_point,
    1208              :                                 &dst_state,
    1209          190 :                                 m_is_rethrow,
    1210              :                                 &ctxt);
    1211              :   // We don't continue along op_ctxt's superedge
    1212          190 : }
    1213              : 
    1214              : // class control_flow_op : public operation
    1215              : 
    1216              : void
    1217        18088 : control_flow_op::
    1218              : walk_load_store_addr_ops (void *data,
    1219              :                           walk_stmt_load_store_addr_fn load_cb,
    1220              :                           walk_stmt_load_store_addr_fn store_cb,
    1221              :                           walk_stmt_load_store_addr_fn addr_cb) const
    1222              : {
    1223        18088 :   walk_stmt_load_store_addr_ops (const_cast <gimple *> (&m_ctrlflow_stmt),
    1224              :                                  data,
    1225              :                                  load_cb, store_cb, addr_cb);
    1226        18088 : }
    1227              : 
    1228              : void
    1229         2607 : control_flow_op::add_any_events_for_eedge (const exploded_edge &eedge,
    1230              :                                            checker_path &out_path) const
    1231              : {
    1232         2607 :   out_path.add_event
    1233         2607 :     (std::make_unique<start_cfg_edge_event> (eedge,
    1234         5214 :                                              event_loc_info (eedge.m_src),
    1235         2607 :                                              this));
    1236         2607 :   out_path.add_event
    1237         2607 :      (std::make_unique<end_cfg_edge_event> (eedge,
    1238         5214 :                                             event_loc_info (eedge.m_dest),
    1239         2607 :                                             this));
    1240         2607 : }
    1241              : 
    1242              : /* Attempt to generate a description of any condition that holds at this edge.
    1243              : 
    1244              :    The intent is to make the user-facing messages more clear, especially for
    1245              :    cases where there's a single or double-negative, such as
    1246              :    when describing the false branch of an inverted condition.
    1247              : 
    1248              :    For example, rather than printing just:
    1249              : 
    1250              :       |  if (!ptr)
    1251              :       |     ~
    1252              :       |     |
    1253              :       |     (1) following 'false' branch...
    1254              : 
    1255              :    it's clearer to spell out the condition that holds:
    1256              : 
    1257              :       |  if (!ptr)
    1258              :       |     ~
    1259              :       |     |
    1260              :       |     (1) following 'false' branch (when 'ptr' is non-NULL)...
    1261              :                                           ^^^^^^^^^^^^^^^^^^^^^^
    1262              : 
    1263              :    In the above example, this function would generate the highlighted
    1264              :    string: "when 'ptr' is non-NULL".
    1265              : 
    1266              :    If the edge is not a condition, or it's not clear that a description of
    1267              :    the condition would be helpful to the user, return NULL.  */
    1268              : 
    1269              : label_text
    1270          441 : control_flow_op::maybe_describe_condition (bool ) const
    1271              : {
    1272          441 :   return label_text::borrow (nullptr);
    1273              : }
    1274              : 
    1275              : void
    1276        51837 : control_flow_op::execute (operation_context &op_ctxt) const
    1277              : {
    1278        51837 :   auto logger = op_ctxt.get_logger ();
    1279        51837 :   LOG_SCOPE (logger);
    1280              : 
    1281        51837 :   program_state dst_state (op_ctxt.get_initial_state ());
    1282        51837 :   op_region_model_context ctxt (op_ctxt, dst_state);
    1283        51837 :   if (apply_constraints (&op_ctxt.m_sedge,
    1284        51837 :                          *dst_state.m_region_model,
    1285              :                          &ctxt,
    1286              :                          nullptr))
    1287              :     {
    1288        44995 :       bool unknown_side_effects;
    1289        44995 :       handle_on_stmt_for_state_machines (op_ctxt,
    1290              :                                          dst_state,
    1291              :                                          nullptr,
    1292              :                                          unknown_side_effects,
    1293              :                                          m_ctrlflow_stmt);
    1294              : 
    1295        44995 :       if (!ctxt.terminate_path_p ())
    1296              :         {
    1297        44967 :           auto dst_point (op_ctxt.get_next_intraprocedural_point ());
    1298        44967 :           op_ctxt.add_outcome (dst_point, dst_state, false, nullptr);
    1299              :         }
    1300              :     }
    1301        51837 : }
    1302              : 
    1303              : bool
    1304        29116 : control_flow_op::
    1305              : execute_for_feasibility (const exploded_edge &eedge,
    1306              :                          feasibility_state &fstate,
    1307              :                          region_model_context *ctxt,
    1308              :                          std::unique_ptr<rejected_constraint> *out_rc) const
    1309              : {
    1310        29116 :   gcc_assert (eedge.m_sedge);
    1311        29116 :   return apply_constraints (eedge.m_sedge,
    1312              :                             fstate.get_model (),
    1313              :                             ctxt,
    1314        29116 :                             out_rc);
    1315              : }
    1316              : 
    1317              : // class gcond_edge_op : public control_flow_op
    1318              : 
    1319        14898 : gcond_edge_op::gcond_edge_op (::edge cfg_edge,
    1320        14898 :                               const gcond &cond_stmt)
    1321              : : control_flow_op (kind::cond_edge, cfg_edge, cond_stmt),
    1322        14898 :   m_true_value (get_flags () & EDGE_TRUE_VALUE)
    1323              : {
    1324              :   /* Exactly one of EDGE_TRUE_VALUE and EDGE_FALSE_VALUE must
    1325              :      be set on CFG_EDGE.  */
    1326        14898 :   gcc_assert (static_cast<bool> (get_flags () & EDGE_TRUE_VALUE)
    1327              :               ^ static_cast<bool> (get_flags () & EDGE_FALSE_VALUE));
    1328        14898 : }
    1329              : 
    1330              : void
    1331         6926 : gcond_edge_op::print_as_edge_label (pretty_printer *pp,
    1332              :                                     bool user_facing) const
    1333              : {
    1334         6926 :   if (!user_facing)
    1335          228 :     pp_gimple_stmt_1 (pp, &get_ctrlflow_stmt (), 0, (dump_flags_t)0);
    1336              : 
    1337         6926 :   if (m_true_value)
    1338         3735 :     pp_printf (pp, "true");
    1339              :   else
    1340         3191 :     pp_printf (pp, "false");
    1341         6926 : }
    1342              : 
    1343              : label_text
    1344         6698 : gcond_edge_op::maybe_describe_condition (bool can_colorize) const
    1345              : {
    1346         6698 :   const gcond &cond_stmt = get_gcond ();
    1347         6698 :   enum tree_code op = gimple_cond_code (&cond_stmt);
    1348         6698 :   tree lhs = gimple_cond_lhs (&cond_stmt);
    1349         6698 :   tree rhs = gimple_cond_rhs (&cond_stmt);
    1350         6698 :   if (!m_true_value)
    1351         3087 :     op = invert_tree_comparison (op, false /* honor_nans */);
    1352         6698 :   return maybe_describe_condition (can_colorize,
    1353         6698 :                                    lhs, op, rhs);
    1354              : }
    1355              : 
    1356              : /* Subroutine of gcond_edge_op::maybe_describe_condition above.
    1357              : 
    1358              :    Attempt to generate a user-facing description of the condition
    1359              :    LHS OP RHS, but only if it is likely to make it easier for the
    1360              :    user to understand a condition.  */
    1361              : 
    1362              : label_text
    1363         6698 : gcond_edge_op::maybe_describe_condition (bool can_colorize,
    1364              :                                          tree lhs,
    1365              :                                          enum tree_code op,
    1366              :                                          tree rhs)
    1367              : {
    1368              :   /* In theory we could just build a tree via
    1369              :        fold_build2 (op, boolean_type_node, lhs, rhs)
    1370              :      and print it with %qE on it, but this leads to warts such as
    1371              :      parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'.  */
    1372              : 
    1373              :   /* Special-case: describe testing the result of strcmp, as figuring
    1374              :      out what the "true" or "false" path is can be confusing to the user.  */
    1375         6698 :   if (TREE_CODE (lhs) == SSA_NAME
    1376         6698 :       && zerop (rhs))
    1377              :     {
    1378         5097 :       if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
    1379         1872 :         if (is_special_named_call_p (*call, "strcmp", 2))
    1380              :           {
    1381           60 :             if (op == EQ_EXPR)
    1382            9 :               return label_text::borrow ("when the strings are equal");
    1383           51 :             if (op == NE_EXPR)
    1384           51 :               return label_text::borrow ("when the strings are non-equal");
    1385              :           }
    1386              :     }
    1387              : 
    1388              :   /* Only attempt to generate text for sufficiently simple expressions.  */
    1389         6638 :   if (!should_print_expr_p (lhs))
    1390         2651 :     return label_text::borrow (nullptr);
    1391         3987 :   if (!should_print_expr_p (rhs))
    1392           47 :     return label_text::borrow (nullptr);
    1393              : 
    1394              :   /* Special cases for pointer comparisons against NULL.  */
    1395         6357 :   if (POINTER_TYPE_P (TREE_TYPE (lhs))
    1396         1523 :       && POINTER_TYPE_P (TREE_TYPE (rhs))
    1397         5463 :       && zerop (rhs))
    1398              :     {
    1399         1425 :       if (op == EQ_EXPR)
    1400          369 :         return make_label_text (can_colorize, "when %qE is NULL",
    1401          369 :                                 lhs);
    1402         1056 :       if (op == NE_EXPR)
    1403         1056 :         return make_label_text (can_colorize, "when %qE is non-NULL",
    1404         1056 :                                 lhs);
    1405              :     }
    1406              : 
    1407         2515 :   return make_label_text (can_colorize, "when %<%E %s %E%>",
    1408         2515 :                           lhs, op_symbol_code (op), rhs);
    1409              : }
    1410              : 
    1411              : /* Subroutine of maybe_describe_condition.
    1412              : 
    1413              :    Return true if EXPR is we will get suitable user-facing output
    1414              :    from %E on it.  */
    1415              : 
    1416              : bool
    1417        10625 : gcond_edge_op::should_print_expr_p (tree expr)
    1418              : {
    1419        14886 :   if (TREE_CODE (expr) == SSA_NAME)
    1420              :     {
    1421         6959 :       if (SSA_NAME_VAR (expr))
    1422              :         return should_print_expr_p (SSA_NAME_VAR (expr));
    1423              :       else
    1424              :         return false;
    1425              :     }
    1426              : 
    1427         7927 :   if (DECL_P (expr))
    1428              :     return true;
    1429              : 
    1430         3666 :   if (CONSTANT_CLASS_P (expr))
    1431         3666 :     return true;
    1432              : 
    1433              :   return false;
    1434              : }
    1435              : 
    1436              : bool
    1437        72478 : gcond_edge_op::
    1438              : apply_constraints (const superedge *,
    1439              :                    region_model &model,
    1440              :                    region_model_context *ctxt,
    1441              :                    std::unique_ptr<rejected_constraint> *out) const
    1442              : {
    1443        72478 :   const gcond &cond_stmt = get_gcond ();
    1444        72478 :   enum tree_code op = gimple_cond_code (&cond_stmt);
    1445        72478 :   tree lhs = gimple_cond_lhs (&cond_stmt);
    1446        72478 :   tree rhs = gimple_cond_rhs (&cond_stmt);
    1447        72478 :   if (!m_true_value)
    1448        32691 :     op = invert_tree_comparison (op, false /* honor_nans */);
    1449        72478 :   return model.add_constraint (lhs, op, rhs, ctxt, out);
    1450              : }
    1451              : 
    1452              : // class ggoto_edge_op : public control_flow_op
    1453              : 
    1454           32 : ggoto_edge_op::ggoto_edge_op (::edge cfg_edge,
    1455              :                               const ggoto &goto_stmt,
    1456           32 :                               tree dst_label)
    1457              : : control_flow_op (kind::goto_edge, cfg_edge, goto_stmt),
    1458           32 :   m_dst_label (dst_label)
    1459              : {
    1460           32 : }
    1461              : 
    1462              : void
    1463           60 : ggoto_edge_op::print_as_edge_label (pretty_printer *pp,
    1464              :                                     bool user_facing) const
    1465              : {
    1466           60 :   if (!user_facing)
    1467            0 :     pp_gimple_stmt_1 (pp, &get_ctrlflow_stmt (), 0, (dump_flags_t)0);
    1468              : 
    1469           60 :   if (m_dst_label)
    1470           60 :     pp_printf (pp, "%qD", m_dst_label);
    1471           60 : }
    1472              : 
    1473              : label_text
    1474           60 : ggoto_edge_op::maybe_describe_condition (bool) const
    1475              : {
    1476           60 :   return label_text::borrow ("");
    1477              : }
    1478              : 
    1479              : bool
    1480           79 : ggoto_edge_op::
    1481              : apply_constraints (const superedge *,
    1482              :                    region_model &model,
    1483              :                    region_model_context *ctxt,
    1484              :                    std::unique_ptr<rejected_constraint> */*out_rc*/) const
    1485              : {
    1486           79 :   const ggoto &goto_stmt = get_ggoto ();
    1487           79 :   tree dest = gimple_goto_dest (&goto_stmt);
    1488           79 :   const svalue *dest_sval = model.get_rvalue (dest, ctxt);
    1489              : 
    1490              :   /* If we know we were jumping to a specific label.  */
    1491           79 :   if (m_dst_label)
    1492              :     {
    1493           79 :       auto mgr = model.get_manager ();
    1494           79 :       const label_region *dst_label_reg
    1495           79 :         = mgr->get_region_for_label (m_dst_label);
    1496           79 :       const svalue *dst_label_ptr
    1497           79 :         = mgr->get_ptr_svalue (ptr_type_node, dst_label_reg);
    1498              : 
    1499           79 :       if (!model.add_constraint (dest_sval, EQ_EXPR, dst_label_ptr, ctxt))
    1500              :         return false;
    1501              :     }
    1502              : 
    1503              :   return true;
    1504              : }
    1505              : 
    1506              : // class switch_case_op : public control_flow_op
    1507              : 
    1508         2983 : switch_case_op::switch_case_op (function &fun,
    1509              :                                 ::edge cfg_edge,
    1510              :                                 const gswitch &switch_stmt,
    1511         2983 :                                 bounded_ranges_manager &mgr)
    1512         2983 : : control_flow_op (kind::switch_edge, cfg_edge, switch_stmt)
    1513              : {
    1514              :   /* Populate m_case_labels with all cases which go to DST.  */
    1515       542488 :   for (unsigned i = 0; i < gimple_switch_num_labels (&switch_stmt); i++)
    1516              :     {
    1517       539505 :       tree case_ = gimple_switch_label (&switch_stmt, i);
    1518       539505 :       basic_block bb = label_to_block (&fun,
    1519       539505 :                                        CASE_LABEL (case_));
    1520       539505 :       if (bb == cfg_edge->dest)
    1521         3552 :         m_case_labels.push_back (case_);
    1522              :     }
    1523              : 
    1524         2983 :   auto_vec <const bounded_ranges *> case_ranges_vec
    1525         2983 :     (gimple_switch_num_labels (&switch_stmt));
    1526         6535 :   for (auto case_label : m_case_labels)
    1527              :     {
    1528              :       /* Get the ranges for this case label.  */
    1529         3552 :       const bounded_ranges *case_ranges
    1530         3552 :         = mgr.make_case_label_ranges (&switch_stmt, case_label);
    1531         3552 :       case_ranges_vec.quick_push (case_ranges);
    1532              :     }
    1533              : 
    1534         2983 :   m_all_cases_ranges = mgr.get_or_create_union (case_ranges_vec);
    1535         2983 : }
    1536              : 
    1537              : /* Print "case VAL:", "case LOWER ... UPPER:", or "default:" to PP.  */
    1538              : 
    1539              : void
    1540          448 : switch_case_op::print_as_edge_label (pretty_printer *pp,
    1541              :                                      bool user_facing) const
    1542              : {
    1543          448 :   if (user_facing)
    1544              :     {
    1545          888 :       for (unsigned i = 0; i < m_case_labels.size (); ++i)
    1546              :         {
    1547          447 :           if (i > 0)
    1548            6 :             pp_string (pp, ", ");
    1549          447 :           tree case_label = m_case_labels[i];
    1550          447 :           gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
    1551          447 :           tree lower_bound = CASE_LOW (case_label);
    1552          447 :           tree upper_bound = CASE_HIGH (case_label);
    1553          447 :           if (lower_bound)
    1554              :             {
    1555          162 :               pp_printf (pp, "case ");
    1556          162 :               dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0, false);
    1557          162 :               if (upper_bound)
    1558              :                 {
    1559           12 :                   pp_printf (pp, " ... ");
    1560           12 :                   dump_generic_node (pp, upper_bound, 0, (dump_flags_t)0,
    1561              :                                      false);
    1562              :                 }
    1563          162 :               pp_printf (pp, ":");
    1564              :             }
    1565              :           else
    1566          285 :             pp_printf (pp, "default:");
    1567              :         }
    1568              :     }
    1569              :   else
    1570              :     {
    1571            7 :       pp_character (pp, '{');
    1572           15 :       for (unsigned i = 0; i < m_case_labels.size (); ++i)
    1573              :         {
    1574            8 :           if (i > 0)
    1575            1 :             pp_string (pp, ", ");
    1576            8 :           tree case_label = m_case_labels[i];
    1577            8 :           gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
    1578            8 :           tree lower_bound = CASE_LOW (case_label);
    1579            8 :           tree upper_bound = CASE_HIGH (case_label);
    1580            8 :           if (lower_bound)
    1581              :             {
    1582            6 :               if (upper_bound)
    1583              :                 {
    1584            0 :                   pp_character (pp, '[');
    1585            0 :                   dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0,
    1586              :                                      false);
    1587            0 :                   pp_string (pp, ", ");
    1588            0 :                   dump_generic_node (pp, upper_bound, 0, (dump_flags_t)0,
    1589              :                                      false);
    1590            0 :                   pp_character (pp, ']');
    1591              :                 }
    1592              :               else
    1593            6 :                 dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0, false);
    1594              :             }
    1595              :           else
    1596            2 :             pp_printf (pp, "default");
    1597              :         }
    1598            7 :       pp_character (pp, '}');
    1599            7 :       if (implicitly_created_default_p ())
    1600              :         {
    1601            2 :           pp_string (pp, " IMPLICITLY CREATED");
    1602              :         }
    1603              :     }
    1604          448 : }
    1605              : 
    1606              : /* Return true iff SWITCH_STMT has a non-default label that contains
    1607              :    INT_CST.  */
    1608              : 
    1609              : static bool
    1610          142 : has_nondefault_case_for_value_p (const gswitch *switch_stmt, tree int_cst)
    1611              : {
    1612              :   /* We expect the initial label to be the default; skip it.  */
    1613          142 :   gcc_assert (CASE_LOW (gimple_switch_label (switch_stmt, 0)) == NULL_TREE);
    1614          142 :   unsigned min_idx = 1;
    1615          142 :   unsigned max_idx = gimple_switch_num_labels (switch_stmt) - 1;
    1616              : 
    1617              :   /* Binary search: try to find the label containing INT_CST.
    1618              :      This requires the cases to be sorted by CASE_LOW (done by the
    1619              :      gimplifier).  */
    1620          257 :   while (max_idx >= min_idx)
    1621              :     {
    1622          247 :       unsigned case_idx = (min_idx + max_idx) / 2;
    1623          247 :       tree label =  gimple_switch_label (switch_stmt, case_idx);
    1624          247 :       tree low = CASE_LOW (label);
    1625          247 :       gcc_assert (low);
    1626          247 :       tree high = CASE_HIGH (label);
    1627          247 :       if (!high)
    1628          195 :         high = low;
    1629          247 :       if (tree_int_cst_compare (int_cst, low) < 0)
    1630              :         {
    1631              :           /* INT_CST is below the range of this label.  */
    1632           27 :           gcc_assert (case_idx > 0);
    1633           27 :           max_idx = case_idx - 1;
    1634              :         }
    1635          220 :       else if (tree_int_cst_compare (int_cst, high) > 0)
    1636              :         {
    1637              :           /* INT_CST is above the range of this case.  */
    1638           88 :           min_idx = case_idx + 1;
    1639              :         }
    1640              :       else
    1641              :         /* This case contains INT_CST.  */
    1642              :         return true;
    1643              :     }
    1644              :   /* Not found.  */
    1645              :   return false;
    1646              : }
    1647              : 
    1648              : /* Return true iff SWITCH_STMT (which must be on an enum value)
    1649              :    has nondefault cases handling all values in the enum.  */
    1650              : 
    1651              : static bool
    1652           45 : has_nondefault_cases_for_all_enum_values_p (const gswitch *switch_stmt,
    1653              :                                             tree type)
    1654              : {
    1655           45 :   gcc_assert (switch_stmt);
    1656           45 :   gcc_assert (TREE_CODE (type) == ENUMERAL_TYPE);
    1657              : 
    1658           45 :   for (tree enum_val_iter = TYPE_VALUES (type);
    1659          177 :        enum_val_iter;
    1660          132 :        enum_val_iter = TREE_CHAIN (enum_val_iter))
    1661              :     {
    1662          142 :       tree enum_val = TREE_VALUE (enum_val_iter);
    1663          142 :       gcc_assert (TREE_CODE (enum_val) == CONST_DECL);
    1664          142 :       gcc_assert (TREE_CODE (DECL_INITIAL (enum_val)) == INTEGER_CST);
    1665          142 :       if (!has_nondefault_case_for_value_p (switch_stmt,
    1666          142 :                                             DECL_INITIAL (enum_val)))
    1667              :         return false;
    1668              :     }
    1669              :   return true;
    1670              : }
    1671              : 
    1672              : /* Given an EDGE guarded by SWITCH_STMT, determine appropriate constraints
    1673              :    for the edge to be taken.
    1674              : 
    1675              :    If they are feasible, add the constraints and return true.
    1676              : 
    1677              :    Return false if the constraints contradict existing knowledge
    1678              :    (and so the edge should not be taken).
    1679              :    When returning false, if OUT is non-NULL, write a new rejected_constraint
    1680              :    to it.  */
    1681              : 
    1682              : bool
    1683         8072 : switch_case_op::
    1684              : apply_constraints (const superedge *,
    1685              :                    region_model &model,
    1686              :                    region_model_context *ctxt,
    1687              :                    std::unique_ptr<rejected_constraint> *out) const
    1688              : {
    1689         8072 :   const gswitch *switch_stmt = &get_gswitch ();
    1690         8072 :   tree index  = gimple_switch_index (switch_stmt);
    1691         8072 :   const svalue *index_sval = model.get_rvalue (index, ctxt);
    1692         8072 :   bool check_index_type = true;
    1693              : 
    1694              :   /* With -fshort-enum, there may be a type cast.  */
    1695         6812 :   if (ctxt && index_sval->get_kind () == SK_UNARYOP
    1696         8519 :       && TREE_CODE (index_sval->get_type ()) == INTEGER_TYPE)
    1697              :     {
    1698          429 :       const unaryop_svalue *unaryop = as_a <const unaryop_svalue *> (index_sval);
    1699          429 :       if (unaryop->get_op () == NOP_EXPR
    1700          429 :           && is_a <const initial_svalue *> (unaryop->get_arg ()))
    1701          411 :         if (const initial_svalue *initvalop = (as_a <const initial_svalue *>
    1702          411 :                                                (unaryop->get_arg ())))
    1703          411 :           if (initvalop->get_type ()
    1704          411 :               && TREE_CODE (initvalop->get_type ()) == ENUMERAL_TYPE)
    1705              :             {
    1706              :               index_sval = initvalop;
    1707              :               check_index_type = false;
    1708              :             }
    1709              :     }
    1710              : 
    1711              :   /* If we're switching based on an enum type, assume that the user is only
    1712              :      working with values from the enum.  Hence if this is an
    1713              :      implicitly-created "default", assume it doesn't get followed.
    1714              :      This fixes numerous "uninitialized" false positives where we otherwise
    1715              :      consider jumping past the initialization cases.  */
    1716              : 
    1717         8072 :   if (/* Don't check during feasibility-checking (when ctxt is NULL).  */
    1718              :       ctxt
    1719              :       /* Must be an enum value.  */
    1720         6812 :       && index_sval->get_type ()
    1721         6812 :       && (!check_index_type
    1722         6497 :           || TREE_CODE (TREE_TYPE (index)) == ENUMERAL_TYPE)
    1723          663 :       && TREE_CODE (index_sval->get_type ()) == ENUMERAL_TYPE
    1724              :       /* If we have a constant, then we can check it directly.  */
    1725          663 :       && index_sval->get_kind () != SK_CONSTANT
    1726          634 :       && implicitly_created_default_p ()
    1727           45 :       && has_nondefault_cases_for_all_enum_values_p (switch_stmt,
    1728              :                                                      index_sval->get_type ())
    1729              :       /* Don't do this if there's a chance that the index is
    1730              :          attacker-controlled.  */
    1731         8107 :       && !ctxt->possibly_tainted_p (index_sval))
    1732              :     {
    1733           33 :       if (out)
    1734            0 :         *out = std::make_unique <rejected_default_case> (model);
    1735           33 :       return false;
    1736              :     }
    1737              : 
    1738         8039 :   bool sat
    1739        16078 :     = model.get_constraints ()->add_bounded_ranges (index_sval,
    1740         8039 :                                                     m_all_cases_ranges);
    1741         8039 :   if (!sat && out)
    1742           48 :     *out = std::make_unique <rejected_ranges_constraint>
    1743           48 :       (model, index, m_all_cases_ranges);
    1744         8039 :   if (sat && ctxt && !m_all_cases_ranges->empty_p ())
    1745         6202 :     ctxt->on_bounded_ranges (*index_sval, *m_all_cases_ranges);
    1746              :   return sat;
    1747              : }
    1748              : 
    1749              : /* Return true iff this op's edge is purely for an
    1750              :    implicitly-created "default".  */
    1751              : 
    1752              : bool
    1753          659 : switch_case_op::implicitly_created_default_p () const
    1754              : {
    1755          659 :   if (m_case_labels.size () != 1)
    1756              :     return false;
    1757              : 
    1758          592 :   tree case_label = m_case_labels[0];
    1759          592 :   gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
    1760          592 :   if (CASE_LOW (case_label))
    1761              :     return false;
    1762              : 
    1763              :   /* We have a single "default" case.
    1764              :      Assume that it was implicitly created if it has UNKNOWN_LOCATION.  */
    1765          172 :   return EXPR_LOCATION (case_label) == UNKNOWN_LOCATION;
    1766              : }
    1767              : 
    1768              : /* Given an ERT_TRY region, get the eh_catch corresponding to
    1769              :    the label of DST_SNODE, if any.  */
    1770              : 
    1771              : static eh_catch
    1772          179 : get_catch (eh_region eh_reg, supernode *dst_snode)
    1773              : {
    1774          179 :   gcc_assert (eh_reg->type == ERT_TRY);
    1775              : 
    1776          179 :   tree dst_snode_label = dst_snode->get_label ();
    1777          179 :   if (!dst_snode_label)
    1778              :     return nullptr;
    1779              : 
    1780          124 :   for (eh_catch iter = eh_reg->u.eh_try.first_catch;
    1781          184 :        iter;
    1782           60 :        iter = iter->next_catch)
    1783          184 :     if (iter->label == dst_snode_label)
    1784              :       return iter;
    1785              : 
    1786              :   return nullptr;
    1787              : }
    1788              : 
    1789              : class rejected_eh_dispatch : public rejected_constraint
    1790              : {
    1791              : public:
    1792            0 :   rejected_eh_dispatch (const region_model &model)
    1793            0 :   : rejected_constraint (model)
    1794              :   {}
    1795              : 
    1796            0 :   void dump_to_pp (pretty_printer *pp) const final override
    1797              :   {
    1798            0 :     pp_printf (pp, "rejected_eh_dispatch");
    1799            0 :   }
    1800              : };
    1801              : 
    1802              : static bool
    1803          273 : exception_matches_type_p (tree exception_type,
    1804              :                           tree catch_type)
    1805              : {
    1806            0 :   if (catch_type == exception_type)
    1807            0 :     return true;
    1808              : 
    1809              :   /* TODO (PR analyzer/119697): we should also handle subclasses etc;
    1810              :      see the rules in https://en.cppreference.com/w/cpp/language/catch
    1811              : 
    1812              :      It looks like we should be calling (or emulating)
    1813              :      can_convert_eh from the C++ FE, but that's specific to the C++ FE.  */
    1814              : 
    1815              :   return false;
    1816              : }
    1817              : 
    1818              : static bool
    1819          287 : matches_any_exception_type_p (eh_catch ehc, tree exception_type)
    1820              : {
    1821          287 :   if (ehc->type_list == NULL_TREE)
    1822              :     /* All exceptions are caught here.  */
    1823              :     return true;
    1824              : 
    1825          371 :   for (tree iter = ehc->type_list; iter; iter = TREE_CHAIN (iter))
    1826          287 :     if (exception_matches_type_p (TREE_VALUE (iter),
    1827              :                                   exception_type))
    1828              :       return true;
    1829              :   return false;
    1830              : }
    1831              : 
    1832              : // class eh_dispatch_edge_op : public control_flow_op
    1833              : 
    1834              : std::unique_ptr<eh_dispatch_edge_op>
    1835          191 : eh_dispatch_edge_op::make (supernode *src_snode,
    1836              :                            supernode *dst_snode,
    1837              :                            ::edge cfg_edge,
    1838              :                            const geh_dispatch &eh_dispatch_stmt)
    1839              : {
    1840          191 :   const eh_status *eh = src_snode->get_function ()->eh;
    1841          191 :   gcc_assert (eh);
    1842          191 :   int region_idx = gimple_eh_dispatch_region (&eh_dispatch_stmt);
    1843          191 :   gcc_assert (region_idx > 0);
    1844          191 :   gcc_assert ((*eh->region_array)[region_idx]);
    1845          191 :   eh_region eh_reg = (*eh->region_array)[region_idx];
    1846          191 :   gcc_assert (eh_reg);
    1847          191 :   switch (eh_reg->type)
    1848              :     {
    1849            0 :     default:
    1850            0 :       gcc_unreachable ();
    1851            0 :     case ERT_CLEANUP:
    1852              :       // TODO
    1853            0 :       gcc_unreachable ();
    1854          179 :       break;
    1855          179 :     case ERT_TRY:
    1856          179 :       {
    1857          179 :         eh_catch ehc = get_catch (eh_reg, dst_snode);
    1858          179 :         return std::make_unique<eh_dispatch_try_edge_op>
    1859          179 :           (src_snode,
    1860              :            cfg_edge, eh_dispatch_stmt,
    1861          179 :            eh_reg, ehc);
    1862              :       }
    1863           12 :       break;
    1864           12 :     case ERT_ALLOWED_EXCEPTIONS:
    1865           12 :       return std::make_unique<eh_dispatch_allowed_edge_op>
    1866           12 :         (src_snode, dst_snode,
    1867              :          cfg_edge, eh_dispatch_stmt,
    1868           12 :          eh_reg);
    1869            0 :       break;
    1870            0 :     case ERT_MUST_NOT_THROW:
    1871              :       // TODO
    1872            0 :       gcc_unreachable ();
    1873              :       break;
    1874              :     }
    1875              : }
    1876              : 
    1877          191 : eh_dispatch_edge_op::
    1878              : eh_dispatch_edge_op (supernode *src_snode,
    1879              :                      enum kind kind_,
    1880              :                      ::edge cfg_edge,
    1881              :                      const geh_dispatch &geh_dispatch_stmt,
    1882          191 :                      eh_region eh_reg)
    1883              : : control_flow_op (kind_, cfg_edge, geh_dispatch_stmt),
    1884          191 :   m_src_snode (src_snode),
    1885          191 :   m_eh_region (eh_reg)
    1886              : {
    1887          191 : }
    1888              : 
    1889              : bool
    1890          324 : eh_dispatch_edge_op::
    1891              : apply_constraints (const superedge *sedge,
    1892              :                    region_model &model,
    1893              :                    region_model_context *ctxt,
    1894              :                    std::unique_ptr<rejected_constraint> *out) const
    1895              : {
    1896          324 :   const exception_node *current_node = model.get_current_thrown_exception ();
    1897              : 
    1898          321 :   if (!current_node)
    1899              :     return false;
    1900              : 
    1901          321 :   gcc_assert (current_node);
    1902          321 :   tree curr_exception_type = current_node->maybe_get_type ();
    1903          321 :   if (!curr_exception_type)
    1904              :     /* We don't know the specific type.  */
    1905              :     return true;
    1906              : 
    1907          243 :   return apply_eh_constraints (sedge, model, ctxt, curr_exception_type, out);
    1908              : }
    1909              : 
    1910              : // class eh_dispatch_try_edge_op : public eh_dispatch_edge_op
    1911              : 
    1912          179 : eh_dispatch_try_edge_op::
    1913              : eh_dispatch_try_edge_op (supernode *src_snode,
    1914              :                          ::edge cfg_edge,
    1915              :                          const geh_dispatch &geh_dispatch_stmt,
    1916              :                          eh_region eh_reg,
    1917          179 :                          eh_catch ehc)
    1918              : : eh_dispatch_edge_op (src_snode,
    1919              :                        kind::eh_dispatch_try_edge,
    1920              :                        cfg_edge, geh_dispatch_stmt, eh_reg),
    1921          179 :   m_eh_catch (ehc)
    1922              : {
    1923          179 :   gcc_assert (eh_reg->type == ERT_TRY);
    1924          179 : }
    1925              : 
    1926              : void
    1927            0 : eh_dispatch_try_edge_op::print_as_edge_label (pretty_printer *pp,
    1928              :                                               bool user_facing) const
    1929              : {
    1930            0 :   if (!user_facing)
    1931            0 :     pp_string (pp, "ERT_TRY: ");
    1932            0 :   if (m_eh_catch)
    1933              :     {
    1934            0 :       bool first = true;
    1935            0 :       for (tree iter = m_eh_catch->type_list; iter; iter = TREE_CHAIN (iter))
    1936              :         {
    1937            0 :           if (!first)
    1938            0 :             pp_string (pp, ", ");
    1939            0 :           pp_printf (pp, "on catch %qT", TREE_VALUE (iter));
    1940            0 :           first = false;
    1941              :         }
    1942              :     }
    1943              :   else
    1944            0 :     pp_string (pp, "on uncaught exception");
    1945            0 : }
    1946              : 
    1947              : void
    1948           66 : eh_dispatch_try_edge_op::add_any_events_for_eedge (const exploded_edge &eedge,
    1949              :                                                    checker_path &out_path) const
    1950              : {
    1951           66 :   if (m_eh_catch)
    1952              :     {
    1953           63 :       const region_model *model = eedge.m_src->get_state ().m_region_model;
    1954           63 :       auto curr_thrown_exception_node
    1955           63 :         = model->get_current_thrown_exception ();
    1956            0 :       gcc_assert (curr_thrown_exception_node);
    1957           63 :       tree type = curr_thrown_exception_node->maybe_get_type ();
    1958           63 :       out_path.add_event
    1959           63 :         (std::make_unique<catch_cfg_edge_event>
    1960           63 :          (eedge,
    1961          126 :           event_loc_info (eedge.m_dest),
    1962              :           *this,
    1963              :           type));
    1964              :     }
    1965              :   else
    1966              :     {
    1967              :       /* We have the "uncaught exception" sedge, from eh_dispatch
    1968              :          to a block containing resx.
    1969              :          Don't add any events for this, so that we can consolidate
    1970              :          adjacent stack unwinding events.  */
    1971              :     }
    1972           66 : }
    1973              : 
    1974              : bool
    1975          230 : eh_dispatch_try_edge_op::
    1976              : apply_eh_constraints (const superedge *sedge,
    1977              :                       region_model &model,
    1978              :                       region_model_context */*ctxt*/,
    1979              :                       tree exception_type,
    1980              :                       std::unique_ptr<rejected_constraint> *out) const
    1981              : {
    1982              :   /* TODO: can we rely on this ordering?
    1983              :      or do we need to iterate through prev_catch ?  */
    1984              :   /* The exception must not match any of the previous edges.  */
    1985          768 :   for (auto sibling_sedge : get_src_snode ()->m_succs)
    1986              :     {
    1987          308 :       if (sibling_sedge == sedge)
    1988              :         break;
    1989              : 
    1990          139 :       const eh_dispatch_try_edge_op *sibling_edge_op
    1991          139 :         = (const eh_dispatch_try_edge_op *)sibling_sedge->get_op ();
    1992          139 :       if (eh_catch ehc = sibling_edge_op->m_eh_catch)
    1993          139 :         if (matches_any_exception_type_p (ehc, exception_type))
    1994              :           {
    1995              :             /* The earlier sibling matches, so the "unhandled" edge is
    1996              :                not taken.  */
    1997           61 :             if (out)
    1998            0 :               *out = std::make_unique<rejected_eh_dispatch> (model);
    1999           61 :             return false;
    2000              :           }
    2001              :     }
    2002              : 
    2003          169 :   if (eh_catch ehc = m_eh_catch)
    2004              :     {
    2005              :       /* We have an edge that tried to match one or more types.  */
    2006              : 
    2007              :       /* The exception must not match any of the previous edges.  */
    2008              : 
    2009              :       /* It must match this type.  */
    2010          148 :       if (matches_any_exception_type_p (ehc, exception_type))
    2011              :         return true;
    2012              :       else
    2013              :         {
    2014              :           /* Exception type doesn't match.  */
    2015           33 :           if (out)
    2016            0 :             *out = std::make_unique<rejected_eh_dispatch> (model);
    2017           33 :           return false;
    2018              :         }
    2019              :     }
    2020              :   else
    2021              :     {
    2022              :       /* This is the "unhandled exception" edge.
    2023              :          If we get here then no sibling edges matched;
    2024              :          we will follow this edge.  */
    2025              :       return true;
    2026              :     }
    2027              : }
    2028              : 
    2029              : // class eh_dispatch_allowed_edge_op : public eh_dispatch_edge_op
    2030              : 
    2031           12 : eh_dispatch_allowed_edge_op::
    2032              : eh_dispatch_allowed_edge_op (supernode *src_snode,
    2033              :                              supernode *dst_snode,
    2034              :                              ::edge cfg_edge,
    2035              :                              const geh_dispatch &geh_dispatch_stmt,
    2036           12 :                              eh_region eh_reg)
    2037              : : eh_dispatch_edge_op (src_snode,
    2038              :                        kind::eh_dispatch_try_edge,
    2039           12 :                        cfg_edge, geh_dispatch_stmt, eh_reg)
    2040              : {
    2041           12 :   gcc_assert (eh_reg->type == ERT_ALLOWED_EXCEPTIONS);
    2042              : 
    2043              :   /* We expect two sibling out-edges at an eh_dispatch from such a region:
    2044              : 
    2045              :      - one to a bb without a gimple label, with a resx,
    2046              :      for exceptions of expected types
    2047              : 
    2048              :      - one to a bb with a gimple label, with a call to __cxa_unexpected,
    2049              :      for exceptions of unexpected types.
    2050              : 
    2051              :      Set m_kind for this edge accordingly.  */
    2052           12 :   gcc_assert (cfg_edge->src->succs->length () == 2);
    2053           12 :   tree label_for_unexpected_exceptions = eh_reg->u.allowed.label;
    2054           12 :   tree label_for_dest_enode = dst_snode->get_label ();
    2055           12 :   if (label_for_dest_enode == label_for_unexpected_exceptions)
    2056            6 :     m_kind = eh_kind::unexpected;
    2057              :   else
    2058              :     {
    2059            6 :       gcc_assert (label_for_dest_enode == nullptr);
    2060            6 :       m_kind = eh_kind::expected;
    2061              :     }
    2062           12 : }
    2063              : 
    2064              : void
    2065            3 : eh_dispatch_allowed_edge_op::print_as_edge_label (pretty_printer *pp,
    2066              :                                                   bool user_facing) const
    2067              : {
    2068            3 :   if (!user_facing)
    2069              :     {
    2070            0 :       switch (m_kind)
    2071              :         {
    2072            0 :         default:
    2073            0 :           gcc_unreachable ();
    2074            0 :         case eh_kind::expected:
    2075            0 :           pp_string (pp, "expected: ");
    2076            0 :           break;
    2077            0 :         case eh_kind::unexpected:
    2078            0 :           pp_string (pp, "unexpected: ");
    2079            0 :           break;
    2080              :         }
    2081            0 :       pp_string (pp, "ERT_ALLOWED_EXCEPTIONS: ");
    2082            0 :       eh_region eh_reg = get_eh_region ();
    2083            0 :       bool first = true;
    2084            0 :       for (tree iter = eh_reg->u.allowed.type_list; iter;
    2085            0 :            iter = TREE_CHAIN (iter))
    2086              :         {
    2087            0 :           if (!first)
    2088            0 :             pp_string (pp, ", ");
    2089            0 :           pp_printf (pp, "%qT", TREE_VALUE (iter));
    2090            0 :           first = false;
    2091              :         }
    2092              :     }
    2093            3 : }
    2094              : 
    2095              : bool
    2096           13 : eh_dispatch_allowed_edge_op::
    2097              : apply_eh_constraints (const superedge *,
    2098              :                       region_model &model,
    2099              :                       region_model_context */*ctxt*/,
    2100              :                       tree exception_type,
    2101              :                       std::unique_ptr<rejected_constraint> *out) const
    2102              : {
    2103           13 :   auto curr_thrown_exception_node = model.get_current_thrown_exception ();
    2104            0 :   gcc_assert (curr_thrown_exception_node);
    2105           13 :   tree curr_exception_type = curr_thrown_exception_node->maybe_get_type ();
    2106           13 :   eh_region eh_reg = get_eh_region ();
    2107           13 :   tree type_list = eh_reg->u.allowed.type_list;
    2108              : 
    2109           13 :   switch (get_eh_kind ())
    2110              :     {
    2111            0 :     default:
    2112            0 :       gcc_unreachable ();
    2113            5 :     case eh_kind::expected:
    2114            5 :       if (!curr_exception_type)
    2115              :         {
    2116              :           /* We don't know the specific type;
    2117              :              assume we have one of an expected type.  */
    2118              :           return true;
    2119              :         }
    2120            8 :       for (tree iter = type_list; iter; iter = TREE_CHAIN (iter))
    2121           11 :         if (exception_matches_type_p (TREE_VALUE (iter),
    2122              :                                       exception_type))
    2123              :           return true;
    2124            3 :       if (out)
    2125            0 :         *out = std::make_unique<rejected_eh_dispatch> (model);
    2126              :       return false;
    2127              : 
    2128            8 :     case eh_kind::unexpected:
    2129            8 :       if (!curr_exception_type)
    2130              :         {
    2131              :           /* We don't know the specific type;
    2132              :              assume we don't have one of an expected type.  */
    2133            0 :           if (out)
    2134            0 :             *out = std::make_unique<rejected_eh_dispatch> (model);
    2135            0 :           return false;
    2136              :         }
    2137           14 :       for (tree iter = type_list; iter; iter = TREE_CHAIN (iter))
    2138            8 :         if (exception_matches_type_p (TREE_VALUE (iter),
    2139              :                                       exception_type))
    2140              :           {
    2141            2 :             if (out)
    2142            0 :               *out = std::make_unique<rejected_eh_dispatch> (model);
    2143            2 :             return false;
    2144              :           }
    2145              :       return true;
    2146              :     }
    2147              : }
    2148              : 
    2149              : // class phis_for_edge_op : public operation
    2150              : 
    2151              : std::unique_ptr<operation>
    2152        15548 : phis_for_edge_op::maybe_make (::edge cfg_in_edge)
    2153              : {
    2154        15548 :   std::vector<pair> pairs = get_pairs_for_phi_along_in_edge (cfg_in_edge);
    2155        15548 :   if (pairs.empty ())
    2156         6340 :     return nullptr;
    2157              : 
    2158         9208 :   return std::make_unique <phis_for_edge_op> (std::move (pairs));
    2159        15548 : }
    2160              : 
    2161         9208 : phis_for_edge_op::phis_for_edge_op (std::vector<pair> &&pairs)
    2162              : : operation (kind::phis),
    2163         9208 :   m_pairs (std::move (pairs))
    2164              : {
    2165         9208 : }
    2166              : 
    2167              : std::vector<phis_for_edge_op::pair>
    2168        15548 : phis_for_edge_op::get_pairs_for_phi_along_in_edge (::edge cfg_in_edge)
    2169              : {
    2170        15548 :   std::vector<pair> result;
    2171              : 
    2172        15548 :   const size_t phi_arg_idx = cfg_in_edge->dest_idx;
    2173        15548 :   for (gphi_iterator gpi = gsi_start_phis (cfg_in_edge->dest);
    2174        37887 :        !gsi_end_p (gpi); gsi_next (&gpi))
    2175              :     {
    2176        22339 :       gphi * const phi = gpi.phi ();
    2177        22339 :       tree dst = gimple_phi_result (phi);
    2178              : 
    2179              :       /* We don't bother tracking the .MEM SSA names.  */
    2180        22339 :       if (tree var = SSA_NAME_VAR (dst))
    2181        17508 :         if (TREE_CODE (var) == VAR_DECL)
    2182        16915 :           if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
    2183        11186 :             continue;
    2184              : 
    2185        11153 :       tree src = gimple_phi_arg_def (phi, phi_arg_idx);
    2186              : 
    2187        11153 :       result.push_back ({dst, src});
    2188              :     }
    2189              : 
    2190        15548 :   return result;
    2191              : }
    2192              : 
    2193              : void
    2194           87 : phis_for_edge_op::print_as_edge_label (pretty_printer *pp,
    2195              :                                        bool ) const
    2196              : {
    2197           87 :   pp_printf (pp, "PHI(");
    2198           87 :   bool first = true;
    2199          174 :   for (auto &p : m_pairs)
    2200              :     {
    2201           87 :       if (first)
    2202              :         first = false;
    2203              :       else
    2204            0 :         pp_string (pp, ", ");
    2205              : 
    2206           87 :       pp_printf (pp, "%E = %E", p.m_dst, p.m_src);
    2207              :     }
    2208           87 :   pp_printf (pp, ");");
    2209           87 : }
    2210              : 
    2211              : void
    2212         9208 : phis_for_edge_op::
    2213              : walk_load_store_addr_ops (void */*data*/ ,
    2214              :                           walk_stmt_load_store_addr_fn /*load_cb*/,
    2215              :                           walk_stmt_load_store_addr_fn /*store_cb*/,
    2216              :                           walk_stmt_load_store_addr_fn /*addr_cb*/) const
    2217              : {
    2218         9208 : }
    2219              : 
    2220              : bool
    2221        20651 : phis_for_edge_op::defines_ssa_name_p (const_tree ssa_name) const
    2222              : {
    2223        37872 :   for (auto &p : m_pairs)
    2224        28413 :     if (p.m_dst == ssa_name)
    2225        20651 :       return true;
    2226              :   return false;
    2227              : }
    2228              : 
    2229              : void
    2230        21353 : phis_for_edge_op::execute (operation_context &op_ctxt) const
    2231              : {
    2232        21353 :   auto logger = op_ctxt.get_logger ();
    2233        21353 :   LOG_SCOPE (logger);
    2234              : 
    2235        21353 :   auto dst_point (op_ctxt.get_next_intraprocedural_point ());
    2236              : 
    2237        21353 :   const program_state &src_state (op_ctxt.get_initial_state ());
    2238        21353 :   program_state dst_state (src_state);
    2239              : 
    2240        21353 :   impl_path_context path_ctxt (&dst_state, logger);
    2241        21353 :   uncertainty_t uncertainty;
    2242        21353 :   impl_region_model_context ctxt (op_ctxt.m_eg,
    2243        21353 :                                   &op_ctxt.m_src_enode,
    2244              : 
    2245              :                                   /* TODO: should we be getting the ECs from the
    2246              :                                      old state, rather than the new?  */
    2247        21353 :                                   &op_ctxt.get_initial_state (),
    2248              :                                   &dst_state,
    2249              :                                   &uncertainty,
    2250              :                                   &path_ctxt,
    2251              :                                   nullptr,
    2252        21353 :                                   nullptr);
    2253              : 
    2254        21353 :   update_state (src_state, dst_state, &ctxt);
    2255              : 
    2256        21353 :   op_ctxt.add_outcome (dst_point, dst_state, false, &uncertainty);
    2257        42706 : }
    2258              : 
    2259              : void
    2260        21767 : phis_for_edge_op::update_state (const program_state &src_state,
    2261              :                                 program_state &dst_state,
    2262              :                                 region_model_context *ctxt) const
    2263              : {
    2264        21767 :   const region_model &src_model = *src_state.m_region_model;
    2265        21767 :   region_model &dst_model = *dst_state.m_region_model;
    2266              : 
    2267        21767 :   hash_set<const svalue *> svals_changing_meaning;
    2268              : 
    2269              :   /* Get state from src_state so that all of the phi stmts for an edge
    2270              :      are effectively handled simultaneously.  */
    2271        51989 :   for (auto &p : m_pairs)
    2272              :     {
    2273        30222 :       const svalue *src_sval = src_model.get_rvalue (p.m_src, nullptr);
    2274        30222 :       const region *dst_reg = src_model.get_lvalue (p.m_dst, nullptr);
    2275              : 
    2276        30222 :       const svalue *old_sval = src_model.get_rvalue (p.m_dst, nullptr);
    2277        30222 :       if (old_sval->get_kind () == SK_WIDENING)
    2278           12 :         svals_changing_meaning.add (old_sval);
    2279              : 
    2280        30222 :       dst_model.set_value (dst_reg, src_sval, ctxt);
    2281              :     }
    2282              : 
    2283        43546 :  for (auto iter : svals_changing_meaning)
    2284           12 :    dst_model.get_constraints ()->purge_state_involving (iter);
    2285        21767 : }
    2286              : 
    2287              : bool
    2288        10929 : phis_for_edge_op::
    2289              : execute_for_feasibility (const exploded_edge &eedge,
    2290              :                          feasibility_state &fstate,
    2291              :                          region_model_context *ctxt,
    2292              :                          std::unique_ptr<rejected_constraint> */*out_rc*/) const
    2293              : {
    2294        10929 :   hash_set<const svalue *> svals_changing_meaning;
    2295              :   /* Get state from src_state so that all of the phi stmts for an edge
    2296              :      are effectively handled simultaneously.  */
    2297        10929 :   region_model &model = fstate.get_model ();
    2298        10929 :   region_model src_model (model);
    2299        24138 :   for (auto &p : m_pairs)
    2300              :     {
    2301        13209 :       const svalue *src_sval = src_model.get_rvalue (p.m_src, ctxt);
    2302        13209 :       const region *dst_reg = model.get_lvalue (p.m_dst, ctxt);
    2303              : 
    2304        13209 :       const svalue *sval = model.get_rvalue (p.m_dst, ctxt);
    2305        13209 :       if (sval->get_kind () == SK_WIDENING)
    2306           24 :         svals_changing_meaning.add (sval);
    2307              : 
    2308        13209 :       model.set_value (dst_reg, src_sval, ctxt);
    2309              :     }
    2310              : 
    2311        10953 :   for (auto iter : svals_changing_meaning)
    2312           24 :     model.get_constraints ()->purge_state_involving (iter);
    2313              : 
    2314        10929 :   {
    2315              :     /* If we've entering an snode that we've already visited on this
    2316              :        epath, then we need do fix things up for loops; see the
    2317              :        comment for store::loop_replay_fixup.
    2318              :        Perhaps we should probably also verify the callstring,
    2319              :        and track program_points,  but hopefully doing it by supernode
    2320              :        is good enough.  */
    2321        10929 :     const exploded_node &dst_enode = *eedge.m_dest;
    2322        10929 :     const unsigned dst_snode_idx = dst_enode.get_supernode ()->m_id;
    2323        10929 :     if (bitmap_bit_p (fstate.get_snodes_visited (), dst_snode_idx))
    2324         4661 :       model.loop_replay_fixup (dst_enode.get_state ().m_region_model);
    2325              :   }
    2326              :  
    2327        21858 :   return true;
    2328        10929 : }
    2329              : 
    2330              : void
    2331          414 : phis_for_edge_op::
    2332              : update_state_for_bulk_merger (const program_state &src_state,
    2333              :                               program_state &dst_state) const
    2334              : {
    2335          414 :   update_state (src_state, dst_state, nullptr);
    2336          414 : }
    2337              : 
    2338              : void
    2339         1258 : phis_for_edge_op::add_any_events_for_eedge (const exploded_edge &,
    2340              :                                             checker_path &) const
    2341              : {
    2342              :   // No-op
    2343         1258 : }
    2344              : 
    2345              : // class resx_op : public gimple_stmt_op
    2346              : 
    2347              : void
    2348          536 : resx_op::execute (operation_context &op_ctxt) const
    2349              : {
    2350          536 :   auto logger = op_ctxt.get_logger ();
    2351          536 :   LOG_SCOPE (logger);
    2352              : 
    2353          536 :   program_point dst_point (op_ctxt.get_next_intraprocedural_point ());
    2354          536 :   program_state dst_state (op_ctxt.get_initial_state ());
    2355          536 :   op_region_model_context ctxt (op_ctxt, dst_state);
    2356              : 
    2357         1072 :   if (exploded_node *dst_enode
    2358          536 :       = op_ctxt.m_eg.get_or_create_node (dst_point, dst_state,
    2359          536 :                                          &op_ctxt.m_src_enode,
    2360              :                                          // Don't add to worklist:
    2361              :                                          false))
    2362              :     {
    2363          536 :       op_ctxt.m_eg.add_edge (&op_ctxt.m_src_enode,
    2364              :                              dst_enode,
    2365          536 :                              &op_ctxt.m_sedge,
    2366              :                              false,
    2367          536 :                              nullptr);
    2368              :       /* Try to adding eedges and enodes that unwind to the next
    2369              :          eh_dispatch statement, if any.
    2370              :          Only the final enode is added to the worklist.  */
    2371          536 :       op_ctxt.m_eg.unwind_from_exception (*dst_enode,
    2372              :                                           nullptr,
    2373              :                                           &ctxt);
    2374              :     }
    2375          536 : }
    2376              : 
    2377              : void
    2378           18 : resx_op::add_any_events_for_eedge (const exploded_edge &,
    2379              :                                    checker_path &) const
    2380              : {
    2381           18 : }
    2382              : 
    2383              : } // namespace ana
    2384              : 
    2385              : #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.