LCOV - code coverage report
Current view: top level - gcc/analyzer - ops.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 85.8 % 1044 896
Test Date: 2026-03-28 14:25:54 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        20475 : event_loc_info::event_loc_info (const exploded_node *enode)
      47              : {
      48        20475 :   if (enode)
      49              :     {
      50        20475 :       m_loc = enode->get_location ();
      51        20475 :       m_fndecl = enode->get_point ().get_fndecl ();
      52        40905 :       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        20475 : }
      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       454983 : operation_context::get_logger () const
      85              : {
      86       454983 :   return m_eg.get_logger ();
      87              : }
      88              : 
      89              : const extrinsic_state &
      90       297897 : operation_context::get_ext_state () const
      91              : {
      92       297897 :   return m_eg.get_ext_state ();
      93              : }
      94              : 
      95              : const program_point &
      96        24726 : operation_context::get_initial_point () const
      97              : {
      98        24726 :   return m_src_enode.get_point ();
      99              : }
     100              : 
     101              : const program_state &
     102      1207683 : operation_context::get_initial_state () const
     103              : {
     104      1207683 :   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       346848 : operation_context::get_next_intraprocedural_point () const
     115              : {
     116              :   /* All edges are intraprocedural.  */
     117       346848 :   gcc_assert (m_sedge.m_src->get_function ()
     118              :               == m_sedge.m_dest->get_function ());
     119       346848 :   return program_point (m_sedge.m_dest,
     120       346848 :                         m_src_enode.get_point ().get_call_string ());
     121              : }
     122              : 
     123              : void
     124       295997 : 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       295997 :   const program_state &src_state = get_initial_state ();
     131       295997 :   impl_region_model_context ctxt (m_eg, &m_src_enode,
     132              :                                   &src_state, &dst_state,
     133       295997 :                                   uncertainty, nullptr);
     134       295997 :   program_state::detect_leaks (src_state, dst_state, nullptr,
     135              :                                get_ext_state (), &ctxt);
     136              : 
     137       591994 :   if (exploded_node *dst_enode
     138       295997 :       = m_eg.get_or_create_node (dst_point, dst_state, &m_src_enode))
     139              :     {
     140       294946 :       m_eg.add_edge (&m_src_enode, dst_enode, &m_sedge, could_do_work,
     141              :                      std::move (info));
     142       294946 :       m_eg.detect_infinite_recursion (dst_enode);
     143              :     }
     144       295997 : }
     145              : 
     146       220578 : class op_region_model_context : public impl_region_model_context
     147              : {
     148              : public:
     149       110289 :   op_region_model_context (operation_context &op_ctxt,
     150              :                            program_state &dst_state)
     151       110289 :   : impl_region_model_context (op_ctxt.m_eg,
     152       110289 :                                &op_ctxt.m_src_enode,
     153       110289 :                                &op_ctxt.get_initial_state (),
     154              :                                &dst_state,
     155              :                                nullptr,
     156       110289 :                                &m_path_context)
     157              :   {
     158       110289 :   }
     159              : 
     160        45025 :   bool terminate_path_p () const
     161              :   {
     162        45025 :     return m_path_context.terminate_path_p ();
     163              :   }
     164              : 
     165              : private:
     166        59952 :   class op_path_context : public path_context
     167              :   {
     168              :   public:
     169       110289 :     op_path_context ()
     170       110289 :     : 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        45025 :     bool terminate_path_p () const final override
     185              :     {
     186        45025 :       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       181718 : gimple_stmt_op::defines_ssa_name_p (const_tree ssa_name) const
     204              : {
     205       181718 :   return &m_stmt == SSA_NAME_DEF_STMT (ssa_name);
     206              : }
     207              : 
     208              : bool
     209        35266 : gimple_stmt_op::supports_bulk_merge_p () const
     210              : {
     211        35266 :   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       244256 :   impl_path_context (const program_state *cur_state,
     221              :                      logger *logger)
     222       244256 :   : m_cur_state (cur_state),
     223       244256 :     m_logger (logger),
     224       244256 :     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       427941 :   bool terminate_path_p () const final override
     267              :   {
     268       427941 :     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       250746 : 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       250746 :   const program_state &old_state = op_ctxt.get_initial_state ();
     305       250746 :   int sm_idx;
     306       250746 :   sm_state_map *smap;
     307      2005030 :   FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
     308              :     {
     309      1754284 :       const state_machine &sm = op_ctxt.m_eg.get_ext_state ().get_sm (sm_idx);
     310      1754284 :       const sm_state_map *old_smap
     311      1754284 :         = old_state.m_checker_states[sm_idx];
     312      1754284 :       sm_state_map *new_smap = dst_state.m_checker_states[sm_idx];
     313      1754284 :       impl_sm_context sm_ctxt (op_ctxt.m_eg, sm_idx, sm,
     314      1754284 :                                &op_ctxt.m_src_enode,
     315              :                                &old_state,
     316              :                                &dst_state,
     317              :                                old_smap, new_smap, path_ctxt,
     318      1754284 :                                unknown_side_effects);
     319              : 
     320              :       /* Allow the state_machine to handle the stmt.  */
     321      1754284 :       if (sm.on_stmt (sm_ctxt, &stmt))
     322        22122 :         unknown_side_effects = false;
     323      1754284 :     }
     324       250746 : }
     325              : 
     326              : void
     327       108865 : 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       108865 :   walk_stmt_load_store_addr_ops (const_cast<gimple *>(&m_stmt), data,
     334              :                                  load_cb, store_cb, addr_cb);
     335       108865 : }
     336              : 
     337              : void
     338       156028 : gimple_stmt_op::execute (operation_context &op_ctxt) const
     339              : {
     340       156028 :   auto logger = op_ctxt.get_logger ();
     341       156028 :   LOG_SCOPE (logger);
     342       156028 :   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       156028 :   execute_on_state (op_ctxt,
     350              :                     /* Pass in a copy.  */
     351              :                     op_ctxt.get_initial_state ());
     352       156028 : }
     353              : 
     354              : void
     355       205721 : gimple_stmt_op::execute_on_state (operation_context &op_ctxt,
     356              :                                   program_state dst_state) const
     357              : {
     358       205721 :   auto logger = op_ctxt.get_logger ();
     359       205721 :   LOG_SCOPE (logger);
     360              : 
     361       205721 :   auto dst_point (op_ctxt.get_next_intraprocedural_point ());
     362       205721 :   const program_state &old_state  = op_ctxt.get_initial_state ();
     363              : 
     364       205721 :   bool unknown_side_effects = false;
     365       205721 :   bool could_have_done_work = false;
     366              : 
     367       205721 :   impl_path_context path_ctxt (&dst_state, logger);
     368       205721 :   uncertainty_t uncertainty;
     369       205721 :   impl_region_model_context ctxt (op_ctxt.m_eg,
     370       205721 :                                   &op_ctxt.m_src_enode,
     371              :                                   &old_state,
     372              :                                   &dst_state,
     373              :                                   &uncertainty,
     374              :                                   &path_ctxt,
     375       205721 :                                   &m_stmt,
     376       205721 :                                   &could_have_done_work);
     377              : 
     378       205721 :   dst_state.m_region_model->on_stmt_pre (&get_stmt (),
     379              :                                          &unknown_side_effects,
     380              :                                          &ctxt);
     381              : 
     382       205721 :   handle_on_stmt_for_state_machines (op_ctxt,
     383              :                                      dst_state,
     384              :                                      &path_ctxt,
     385              :                                      unknown_side_effects,
     386              :                                      m_stmt);
     387              : 
     388       205721 :   if (path_ctxt.terminate_path_p ())
     389          678 :     return;
     390              : 
     391       205043 :   if (const gcall *call = dyn_cast <const gcall *> (&m_stmt))
     392        49448 :     dst_state.m_region_model->on_call_post (*call, unknown_side_effects, &ctxt);
     393              : 
     394       205043 :   if (!path_ctxt.terminate_path_p ())
     395       203875 :     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       226434 :   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       411442 : }
     445              : 
     446              : bool
     447       106180 : 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       106180 :   region_model &model = fstate.get_model ();
     454       106180 :   bool unknown_side_effects;
     455       106180 :   model.on_stmt_pre (&m_stmt, &unknown_side_effects, ctxt);
     456              : 
     457       106180 :   if (const gcall *call = dyn_cast <const gcall *> (&m_stmt))
     458        21053 :     model.on_call_post (*call, unknown_side_effects, ctxt);
     459              : 
     460       106180 :   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        94117 : struct null_assignment_sm_context : public sm_context
     471              : {
     472        94117 :   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        94117 :   : sm_context (sm_idx, sm), m_old_state (old_state), m_new_state (new_state),
     481        94117 :     m_stmt (stmt), m_point (point), m_emission_path (emission_path),
     482        94117 :     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        13436 :   state_machine::state_t get_global_state () const final override
     573              :   {
     574        13436 :     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        13483 :   tree is_zero_assignment (const gimple *stmt) final override
     592              :   {
     593        25694 :     const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
     594        13483 :     if (!assign_stmt)
     595              :      return NULL_TREE;
     596        26966 :     if (const svalue *sval
     597        13483 :         = m_new_state->m_region_model->get_gassign_result (assign_stmt, nullptr))
     598        13073 :       if (tree cst = sval->maybe_get_constant ())
     599         2401 :         if (::zerop(cst))
     600         1272 :           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        13623 : gimple_stmt_op::add_any_events_for_eedge (const exploded_edge &eedge,
     635              :                                           checker_path &out_path) const
     636              : {
     637        13623 :   out_path.add_event
     638        13623 :     (std::make_unique<statement_event> (&get_stmt (),
     639        13623 :                                         eedge.m_dest->get_function ()->decl,
     640        27246 :                                         eedge.m_dest->get_stack_depth (),
     641        13623 :                                         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        13623 :   if (const gassign *assign = dyn_cast<const gassign *> (&m_stmt))
     647              :     {
     648        13501 :       const program_point &src_point = eedge.m_src->get_point ();
     649        13501 :       const extrinsic_state &ext_state = out_path.get_ext_state ();
     650       107618 :       for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
     651              :         {
     652        94117 :           const state_machine &sm = ext_state.get_sm (i);
     653        94117 :           null_assignment_sm_context sm_ctxt (i, sm,
     654        94117 :                                               &eedge.m_src->get_state (),
     655        94117 :                                               &eedge.m_dest->get_state (),
     656              :                                               assign,
     657              :                                               &src_point,
     658              :                                               &out_path,
     659        94117 :                                               ext_state);
     660        94117 :           sm.on_stmt (sm_ctxt, assign);
     661              :           // TODO: what about phi nodes?
     662        94117 :         }
     663              :     }
     664        13623 : }
     665              : 
     666              : // class gassign_op : public gimple_stmt_op
     667              : 
     668              : // class greturn_op : public gimple_stmt_op
     669              : 
     670              : void
     671        17177 : greturn_op::execute (operation_context &op_ctxt) const
     672              : {
     673        17177 :   auto logger = op_ctxt.get_logger ();
     674              : 
     675        17177 :   auto dst_point (op_ctxt.get_next_intraprocedural_point ());
     676        17177 :   const program_state &old_state  = op_ctxt.get_initial_state ();
     677        17177 :   program_state dst_state (old_state);
     678              : 
     679        17177 :   impl_path_context path_ctxt (&dst_state, logger);
     680        17177 :   uncertainty_t uncertainty;
     681        17177 :   impl_region_model_context ctxt (op_ctxt.m_eg,
     682        17177 :                                   &op_ctxt.m_src_enode,
     683              : 
     684              :                                   /* TODO: should we be getting the ECs from the
     685              :                                      old state, rather than the new?  */
     686        17177 :                                   &op_ctxt.get_initial_state (),
     687              :                                   &dst_state,
     688              :                                   &uncertainty,
     689              :                                   &path_ctxt,
     690              :                                   nullptr,
     691        17177 :                                   nullptr);
     692              : 
     693        17177 :   tree callee = op_ctxt.get_initial_point ().get_function ()->decl;
     694        17177 :   tree lhs = DECL_RESULT (callee);
     695              : 
     696        34354 :   if (lhs && get_retval ())
     697              :     {
     698         8691 :       region_model *dst_region_model = dst_state.m_region_model;
     699         8691 :       const svalue *sval
     700         8691 :         = dst_region_model->get_rvalue (get_retval (), &ctxt);
     701         8691 :       const region *ret_reg = dst_region_model->get_lvalue (lhs, &ctxt);
     702         8691 :       dst_region_model->set_value (ret_reg, sval, &ctxt);
     703              :     }
     704              : 
     705        17177 :   if (!path_ctxt.terminate_path_p ())
     706        17162 :     op_ctxt.add_outcome (dst_point, dst_state, false, &uncertainty);
     707        34354 : }
     708              : 
     709              : bool
     710         3638 : 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         3638 :   tree callee = eedge.m_src->get_function ()->decl;
     717         3638 :   tree lhs = DECL_RESULT (callee);
     718              : 
     719         7276 :   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         3638 :   return true;
     728              : }
     729              : 
     730              : void
     731          970 : greturn_op::add_any_events_for_eedge (const exploded_edge &,
     732              :                                       checker_path &) const
     733              : {
     734              :   // No-op.
     735          970 : }
     736              : 
     737              : // class call_and_return_op : public gimple_stmt_op
     738              : 
     739              : std::unique_ptr<operation>
     740        41894 : call_and_return_op::make (const gcall &call_stmt)
     741              : {
     742        41894 :   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        41894 :   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        41894 :   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        41894 :   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        41585 :   else if (is_setjmp_call_p (call_stmt))
     751           29 :     return std::make_unique<setjmp_op> (call_stmt);
     752        41556 :   else if (is_longjmp_call_p (call_stmt))
     753           41 :     return std::make_unique<longjmp_op> (call_stmt);
     754        41515 :   else if (is_cxa_throw_p (call_stmt))
     755           73 :     return std::make_unique<cxa_throw_op> (call_stmt, false);
     756        41442 :   else if (is_cxa_rethrow_p (call_stmt))
     757           39 :     return std::make_unique<cxa_throw_op> (call_stmt, true);
     758              : 
     759        41403 :   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        57242 : 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        57242 :   const program_state &old_state  = op_ctxt.get_initial_state ();
     779        57242 :   program_state dst_state (old_state);
     780        57242 :   op_region_model_context ctxt (op_ctxt, dst_state);
     781        57242 :   ctxt.m_stmt = &get_gcall ();
     782        57242 :   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        57242 :   {
     787              :     /* Check for any preconditions if it's a known_function.  */
     788        57242 :     if (auto kf = maybe_get_known_function (cd))
     789        33431 :       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       457573 :       FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
     796              :         {
     797       400331 :           const state_machine &sm
     798       800662 :             = op_ctxt.m_eg.get_ext_state ().get_sm (sm_idx);
     799       400331 :           const sm_state_map *old_smap
     800       400331 :             = old_state.m_checker_states[sm_idx];
     801       400331 :           sm_state_map *new_smap = dst_state.m_checker_states[sm_idx];
     802       400331 :           impl_sm_context sm_ctxt (op_ctxt.m_eg, sm_idx, sm,
     803       400331 :                                    &op_ctxt.m_src_enode,
     804              :                                    &old_state, &dst_state,
     805       400331 :                                    old_smap, new_smap, nullptr);
     806       400331 :           sm.check_call_preconditions (sm_ctxt, cd);
     807       400331 :         }
     808              :     }
     809              :   }
     810              : 
     811        57242 :   if (tree callee_fndecl = cd.get_fndecl_for_call ())
     812              :     {
     813              :       // Consider using a call summary
     814        53442 :       if (function *called_fn = DECL_STRUCT_FUNCTION (callee_fndecl))
     815         7549 :         if (cgraph_edge *edge = get_any_cgraph_edge (op_ctxt))
     816         7549 :           if (op_ctxt.m_eg.get_analysis_plan ().use_summary_p (edge))
     817              :             {
     818          791 :               per_function_data *called_fn_data
     819          791 :                 = op_ctxt.m_eg.get_per_function_data (called_fn);
     820          791 :               if (called_fn_data)
     821              :                 {
     822          753 :                   replay_call_summaries (op_ctxt, *called_fn,
     823              :                                          *called_fn_data, &ctxt);
     824          753 :                   return;
     825              :                 }
     826              :             }
     827              : 
     828              :       // Do we have an entry snode for this fndecl?
     829        52689 :       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        49693 :   gimple_stmt_op::execute_on_state (op_ctxt, std::move (dst_state));
     854        57242 : }
     855              : 
     856              : cgraph_edge *
     857         7549 : call_and_return_op::get_any_cgraph_edge (operation_context &op_ctxt) const
     858              : {
     859         7549 :   tree caller_fndecl = op_ctxt.get_initial_point ().get_fndecl ();
     860         7549 :   gcc_assert (caller_fndecl);
     861              : 
     862         7549 :   auto caller_cgnode = cgraph_node::get (caller_fndecl);
     863         7549 :   gcc_assert (caller_cgnode);
     864         7549 :   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        57242 : call_and_return_op::maybe_get_known_function (const call_details &cd) const
     995              : {
     996        57242 :   region_model_manager *mgr = cd.get_manager ();
     997        57242 :   known_function_manager *known_fn_mgr = mgr->get_known_function_manager ();
     998              : 
     999        57242 :   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        53812 :   if (tree callee_fndecl = cd.get_fndecl_for_call ())
    1004        53442 :     return known_fn_mgr->get_match (callee_fndecl, cd);
    1005              : 
    1006              :   return nullptr;
    1007              : }
    1008              : 
    1009              : void
    1010          753 : 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          753 :   logger *logger = op_ctxt.get_logger ();
    1017          753 :   LOG_SCOPE (logger);
    1018              : 
    1019         3802 :   for (auto summary : called_fn_data.m_summaries)
    1020              :     {
    1021         1543 :       gcc_assert (summary);
    1022         1543 :       replay_call_summary (op_ctxt, called_fn, *summary, ctxt);
    1023              :     }
    1024          753 : }
    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         1418 :   call_summary_edge_info (const call_details &cd,
    1032              :                           const function &called_fn,
    1033              :                           call_summary &summary,
    1034              :                           const extrinsic_state &ext_state)
    1035         1418 :   : call_info (cd, called_fn),
    1036         1418 :     m_called_fn (called_fn),
    1037         1418 :     m_summary (summary),
    1038         1418 :     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         1543 : 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         1543 :   logger *logger = op_ctxt.get_logger ();
    1083         1543 :   LOG_SCOPE (logger);
    1084         1543 :   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         1543 :   const extrinsic_state &ext_state = op_ctxt.get_ext_state ();
    1090         1543 :   const program_state &old_state = op_ctxt.get_initial_state ();
    1091         1543 :   const program_state &summary_end_state = summary.get_state ();
    1092         1543 :   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         1543 :   program_state new_state (old_state);
    1108              : 
    1109         1543 :   call_details cd (get_gcall (), new_state.m_region_model, ctxt);
    1110         1543 :   call_summary_replay r (cd, called_fn, summary, ext_state);
    1111              : 
    1112         1543 :   if (new_state.replay_call_summary (r, summary_end_state))
    1113         1418 :     op_ctxt.add_outcome
    1114         1418 :       (op_ctxt.get_next_intraprocedural_point (),
    1115              :        new_state,
    1116              :        true,
    1117              :        nullptr,
    1118         2836 :        std::make_unique<call_summary_edge_info> (cd,
    1119              :                                                  called_fn,
    1120              :                                                  summary,
    1121              :                                                  ext_state));
    1122         1543 : }
    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        18114 : 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        18114 :   walk_stmt_load_store_addr_ops (const_cast <gimple *> (&m_ctrlflow_stmt),
    1224              :                                  data,
    1225              :                                  load_cb, store_cb, addr_cb);
    1226        18114 : }
    1227              : 
    1228              : void
    1229         2608 : control_flow_op::add_any_events_for_eedge (const exploded_edge &eedge,
    1230              :                                            checker_path &out_path) const
    1231              : {
    1232         2608 :   out_path.add_event
    1233         2608 :     (std::make_unique<start_cfg_edge_event> (eedge,
    1234         5216 :                                              event_loc_info (eedge.m_src),
    1235         2608 :                                              this));
    1236         2608 :   out_path.add_event
    1237         2608 :      (std::make_unique<end_cfg_edge_event> (eedge,
    1238         5216 :                                             event_loc_info (eedge.m_dest),
    1239         2608 :                                             this));
    1240         2608 : }
    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        51867 : control_flow_op::execute (operation_context &op_ctxt) const
    1277              : {
    1278        51867 :   auto logger = op_ctxt.get_logger ();
    1279        51867 :   LOG_SCOPE (logger);
    1280              : 
    1281        51867 :   program_state dst_state (op_ctxt.get_initial_state ());
    1282        51867 :   op_region_model_context ctxt (op_ctxt, dst_state);
    1283        51867 :   if (apply_constraints (&op_ctxt.m_sedge,
    1284        51867 :                          *dst_state.m_region_model,
    1285              :                          &ctxt,
    1286              :                          nullptr))
    1287              :     {
    1288        45025 :       bool unknown_side_effects;
    1289        45025 :       handle_on_stmt_for_state_machines (op_ctxt,
    1290              :                                          dst_state,
    1291              :                                          nullptr,
    1292              :                                          unknown_side_effects,
    1293              :                                          m_ctrlflow_stmt);
    1294              : 
    1295        45025 :       if (!ctxt.terminate_path_p ())
    1296              :         {
    1297        44997 :           auto dst_point (op_ctxt.get_next_intraprocedural_point ());
    1298        44997 :           op_ctxt.add_outcome (dst_point, dst_state, false, nullptr);
    1299              :         }
    1300              :     }
    1301        51867 : }
    1302              : 
    1303              : bool
    1304        29137 : 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        29137 :   gcc_assert (eedge.m_sedge);
    1311        29137 :   return apply_constraints (eedge.m_sedge,
    1312              :                             fstate.get_model (),
    1313              :                             ctxt,
    1314        29137 :                             out_rc);
    1315              : }
    1316              : 
    1317              : // class gcond_edge_op : public control_flow_op
    1318              : 
    1319        14920 : gcond_edge_op::gcond_edge_op (::edge cfg_edge,
    1320        14920 :                               const gcond &cond_stmt)
    1321              : : control_flow_op (kind::cond_edge, cfg_edge, cond_stmt),
    1322        14920 :   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        14920 :   gcc_assert (static_cast<bool> (get_flags () & EDGE_TRUE_VALUE)
    1327              :               ^ static_cast<bool> (get_flags () & EDGE_FALSE_VALUE));
    1328        14920 : }
    1329              : 
    1330              : void
    1331         6929 : gcond_edge_op::print_as_edge_label (pretty_printer *pp,
    1332              :                                     bool user_facing) const
    1333              : {
    1334         6929 :   if (!user_facing)
    1335          228 :     pp_gimple_stmt_1 (pp, &get_ctrlflow_stmt (), 0, (dump_flags_t)0);
    1336              : 
    1337         6929 :   if (m_true_value)
    1338         3738 :     pp_printf (pp, "true");
    1339              :   else
    1340         3191 :     pp_printf (pp, "false");
    1341         6929 : }
    1342              : 
    1343              : label_text
    1344         6701 : gcond_edge_op::maybe_describe_condition (bool can_colorize) const
    1345              : {
    1346         6701 :   const gcond &cond_stmt = get_gcond ();
    1347         6701 :   enum tree_code op = gimple_cond_code (&cond_stmt);
    1348         6701 :   tree lhs = gimple_cond_lhs (&cond_stmt);
    1349         6701 :   tree rhs = gimple_cond_rhs (&cond_stmt);
    1350         6701 :   if (!m_true_value)
    1351         3087 :     op = invert_tree_comparison (op, false /* honor_nans */);
    1352         6701 :   return maybe_describe_condition (can_colorize,
    1353         6701 :                                    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         6701 : 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         6701 :   if (TREE_CODE (lhs) == SSA_NAME
    1376         6701 :       && zerop (rhs))
    1377              :     {
    1378         5100 :       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         6641 :   if (!should_print_expr_p (lhs))
    1390         2654 :     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        10628 : gcond_edge_op::should_print_expr_p (tree expr)
    1418              : {
    1419        14889 :   if (TREE_CODE (expr) == SSA_NAME)
    1420              :     {
    1421         6962 :       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        72515 : 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        72515 :   const gcond &cond_stmt = get_gcond ();
    1444        72515 :   enum tree_code op = gimple_cond_code (&cond_stmt);
    1445        72515 :   tree lhs = gimple_cond_lhs (&cond_stmt);
    1446        72515 :   tree rhs = gimple_cond_rhs (&cond_stmt);
    1447        72515 :   if (!m_true_value)
    1448        32707 :     op = invert_tree_comparison (op, false /* honor_nans */);
    1449        72515 :   return model.add_constraint (lhs, op, rhs, ctxt, out);
    1450              : }
    1451              : 
    1452              : // class ggoto_edge_op : public control_flow_op
    1453              : 
    1454           36 : ggoto_edge_op::ggoto_edge_op (::edge cfg_edge,
    1455              :                               const ggoto &goto_stmt,
    1456           36 :                               tree dst_label)
    1457              : : control_flow_op (kind::goto_edge, cfg_edge, goto_stmt),
    1458           36 :   m_dst_label (dst_label)
    1459              : {
    1460           36 : }
    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           93 : 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           93 :   const ggoto &goto_stmt = get_ggoto ();
    1487           93 :   tree dest = gimple_goto_dest (&goto_stmt);
    1488           93 :   const svalue *dest_sval = model.get_rvalue (dest, ctxt);
    1489              : 
    1490              :   /* If we know we were jumping to a specific label.  */
    1491           93 :   if (m_dst_label)
    1492              :     {
    1493           93 :       auto mgr = model.get_manager ();
    1494           93 :       const label_region *dst_label_reg
    1495           93 :         = mgr->get_region_for_label (m_dst_label);
    1496           93 :       const svalue *dst_label_ptr
    1497           93 :         = mgr->get_ptr_svalue (ptr_type_node, dst_label_reg);
    1498              : 
    1499           93 :       if (!model.add_constraint (dest_sval, EQ_EXPR, dst_label_ptr, ctxt))
    1500              :         {
    1501           12 :           if (out_rc)
    1502            3 :             *out_rc
    1503            3 :               = std::make_unique <rejected_op_constraint> (model,
    1504              :                                                            dest_sval,
    1505            6 :                                                            EQ_EXPR,
    1506            3 :                                                            dst_label_ptr);
    1507           12 :           return false;
    1508              :         }
    1509              :     }
    1510              : 
    1511              :   return true;
    1512              : }
    1513              : 
    1514              : // class switch_case_op : public control_flow_op
    1515              : 
    1516         2983 : switch_case_op::switch_case_op (function &fun,
    1517              :                                 ::edge cfg_edge,
    1518              :                                 const gswitch &switch_stmt,
    1519         2983 :                                 bounded_ranges_manager &mgr)
    1520         2983 : : control_flow_op (kind::switch_edge, cfg_edge, switch_stmt)
    1521              : {
    1522              :   /* Populate m_case_labels with all cases which go to DST.  */
    1523       542488 :   for (unsigned i = 0; i < gimple_switch_num_labels (&switch_stmt); i++)
    1524              :     {
    1525       539505 :       tree case_ = gimple_switch_label (&switch_stmt, i);
    1526       539505 :       basic_block bb = label_to_block (&fun,
    1527       539505 :                                        CASE_LABEL (case_));
    1528       539505 :       if (bb == cfg_edge->dest)
    1529         3552 :         m_case_labels.push_back (case_);
    1530              :     }
    1531              : 
    1532         2983 :   auto_vec <const bounded_ranges *> case_ranges_vec
    1533         2983 :     (gimple_switch_num_labels (&switch_stmt));
    1534         6535 :   for (auto case_label : m_case_labels)
    1535              :     {
    1536              :       /* Get the ranges for this case label.  */
    1537         3552 :       const bounded_ranges *case_ranges
    1538         3552 :         = mgr.make_case_label_ranges (&switch_stmt, case_label);
    1539         3552 :       case_ranges_vec.quick_push (case_ranges);
    1540              :     }
    1541              : 
    1542         2983 :   m_all_cases_ranges = mgr.get_or_create_union (case_ranges_vec);
    1543         2983 : }
    1544              : 
    1545              : /* Print "case VAL:", "case LOWER ... UPPER:", or "default:" to PP.  */
    1546              : 
    1547              : void
    1548          448 : switch_case_op::print_as_edge_label (pretty_printer *pp,
    1549              :                                      bool user_facing) const
    1550              : {
    1551          448 :   if (user_facing)
    1552              :     {
    1553          888 :       for (unsigned i = 0; i < m_case_labels.size (); ++i)
    1554              :         {
    1555          447 :           if (i > 0)
    1556            6 :             pp_string (pp, ", ");
    1557          447 :           tree case_label = m_case_labels[i];
    1558          447 :           gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
    1559          447 :           tree lower_bound = CASE_LOW (case_label);
    1560          447 :           tree upper_bound = CASE_HIGH (case_label);
    1561          447 :           if (lower_bound)
    1562              :             {
    1563          162 :               pp_printf (pp, "case ");
    1564          162 :               dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0, false);
    1565          162 :               if (upper_bound)
    1566              :                 {
    1567           12 :                   pp_printf (pp, " ... ");
    1568           12 :                   dump_generic_node (pp, upper_bound, 0, (dump_flags_t)0,
    1569              :                                      false);
    1570              :                 }
    1571          162 :               pp_printf (pp, ":");
    1572              :             }
    1573              :           else
    1574          285 :             pp_printf (pp, "default:");
    1575              :         }
    1576              :     }
    1577              :   else
    1578              :     {
    1579            7 :       pp_character (pp, '{');
    1580           15 :       for (unsigned i = 0; i < m_case_labels.size (); ++i)
    1581              :         {
    1582            8 :           if (i > 0)
    1583            1 :             pp_string (pp, ", ");
    1584            8 :           tree case_label = m_case_labels[i];
    1585            8 :           gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
    1586            8 :           tree lower_bound = CASE_LOW (case_label);
    1587            8 :           tree upper_bound = CASE_HIGH (case_label);
    1588            8 :           if (lower_bound)
    1589              :             {
    1590            6 :               if (upper_bound)
    1591              :                 {
    1592            0 :                   pp_character (pp, '[');
    1593            0 :                   dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0,
    1594              :                                      false);
    1595            0 :                   pp_string (pp, ", ");
    1596            0 :                   dump_generic_node (pp, upper_bound, 0, (dump_flags_t)0,
    1597              :                                      false);
    1598            0 :                   pp_character (pp, ']');
    1599              :                 }
    1600              :               else
    1601            6 :                 dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0, false);
    1602              :             }
    1603              :           else
    1604            2 :             pp_printf (pp, "default");
    1605              :         }
    1606            7 :       pp_character (pp, '}');
    1607            7 :       if (implicitly_created_default_p ())
    1608              :         {
    1609            2 :           pp_string (pp, " IMPLICITLY CREATED");
    1610              :         }
    1611              :     }
    1612          448 : }
    1613              : 
    1614              : /* Return true iff SWITCH_STMT has a non-default label that contains
    1615              :    INT_CST.  */
    1616              : 
    1617              : static bool
    1618          142 : has_nondefault_case_for_value_p (const gswitch *switch_stmt, tree int_cst)
    1619              : {
    1620              :   /* We expect the initial label to be the default; skip it.  */
    1621          142 :   gcc_assert (CASE_LOW (gimple_switch_label (switch_stmt, 0)) == NULL_TREE);
    1622          142 :   unsigned min_idx = 1;
    1623          142 :   unsigned max_idx = gimple_switch_num_labels (switch_stmt) - 1;
    1624              : 
    1625              :   /* Binary search: try to find the label containing INT_CST.
    1626              :      This requires the cases to be sorted by CASE_LOW (done by the
    1627              :      gimplifier).  */
    1628          257 :   while (max_idx >= min_idx)
    1629              :     {
    1630          247 :       unsigned case_idx = (min_idx + max_idx) / 2;
    1631          247 :       tree label =  gimple_switch_label (switch_stmt, case_idx);
    1632          247 :       tree low = CASE_LOW (label);
    1633          247 :       gcc_assert (low);
    1634          247 :       tree high = CASE_HIGH (label);
    1635          247 :       if (!high)
    1636          195 :         high = low;
    1637          247 :       if (tree_int_cst_compare (int_cst, low) < 0)
    1638              :         {
    1639              :           /* INT_CST is below the range of this label.  */
    1640           27 :           gcc_assert (case_idx > 0);
    1641           27 :           max_idx = case_idx - 1;
    1642              :         }
    1643          220 :       else if (tree_int_cst_compare (int_cst, high) > 0)
    1644              :         {
    1645              :           /* INT_CST is above the range of this case.  */
    1646           88 :           min_idx = case_idx + 1;
    1647              :         }
    1648              :       else
    1649              :         /* This case contains INT_CST.  */
    1650              :         return true;
    1651              :     }
    1652              :   /* Not found.  */
    1653              :   return false;
    1654              : }
    1655              : 
    1656              : /* Return true iff SWITCH_STMT (which must be on an enum value)
    1657              :    has nondefault cases handling all values in the enum.  */
    1658              : 
    1659              : static bool
    1660           45 : has_nondefault_cases_for_all_enum_values_p (const gswitch *switch_stmt,
    1661              :                                             tree type)
    1662              : {
    1663           45 :   gcc_assert (switch_stmt);
    1664           45 :   gcc_assert (TREE_CODE (type) == ENUMERAL_TYPE);
    1665              : 
    1666           45 :   for (tree enum_val_iter = TYPE_VALUES (type);
    1667          177 :        enum_val_iter;
    1668          132 :        enum_val_iter = TREE_CHAIN (enum_val_iter))
    1669              :     {
    1670          142 :       tree enum_val = TREE_VALUE (enum_val_iter);
    1671          142 :       gcc_assert (TREE_CODE (enum_val) == CONST_DECL);
    1672          142 :       gcc_assert (TREE_CODE (DECL_INITIAL (enum_val)) == INTEGER_CST);
    1673          142 :       if (!has_nondefault_case_for_value_p (switch_stmt,
    1674          142 :                                             DECL_INITIAL (enum_val)))
    1675              :         return false;
    1676              :     }
    1677              :   return true;
    1678              : }
    1679              : 
    1680              : /* Given an EDGE guarded by SWITCH_STMT, determine appropriate constraints
    1681              :    for the edge to be taken.
    1682              : 
    1683              :    If they are feasible, add the constraints and return true.
    1684              : 
    1685              :    Return false if the constraints contradict existing knowledge
    1686              :    (and so the edge should not be taken).
    1687              :    When returning false, if OUT is non-NULL, write a new rejected_constraint
    1688              :    to it.  */
    1689              : 
    1690              : bool
    1691         8072 : switch_case_op::
    1692              : apply_constraints (const superedge *,
    1693              :                    region_model &model,
    1694              :                    region_model_context *ctxt,
    1695              :                    std::unique_ptr<rejected_constraint> *out) const
    1696              : {
    1697         8072 :   const gswitch *switch_stmt = &get_gswitch ();
    1698         8072 :   tree index  = gimple_switch_index (switch_stmt);
    1699         8072 :   const svalue *index_sval = model.get_rvalue (index, ctxt);
    1700         8072 :   bool check_index_type = true;
    1701              : 
    1702              :   /* With -fshort-enum, there may be a type cast.  */
    1703         6812 :   if (ctxt && index_sval->get_kind () == SK_UNARYOP
    1704         8519 :       && TREE_CODE (index_sval->get_type ()) == INTEGER_TYPE)
    1705              :     {
    1706          429 :       const unaryop_svalue *unaryop = as_a <const unaryop_svalue *> (index_sval);
    1707          429 :       if (unaryop->get_op () == NOP_EXPR
    1708          429 :           && is_a <const initial_svalue *> (unaryop->get_arg ()))
    1709          411 :         if (const initial_svalue *initvalop = (as_a <const initial_svalue *>
    1710          411 :                                                (unaryop->get_arg ())))
    1711          411 :           if (initvalop->get_type ()
    1712          411 :               && TREE_CODE (initvalop->get_type ()) == ENUMERAL_TYPE)
    1713              :             {
    1714              :               index_sval = initvalop;
    1715              :               check_index_type = false;
    1716              :             }
    1717              :     }
    1718              : 
    1719              :   /* If we're switching based on an enum type, assume that the user is only
    1720              :      working with values from the enum.  Hence if this is an
    1721              :      implicitly-created "default", assume it doesn't get followed.
    1722              :      This fixes numerous "uninitialized" false positives where we otherwise
    1723              :      consider jumping past the initialization cases.  */
    1724              : 
    1725         8072 :   if (/* Don't check during feasibility-checking (when ctxt is NULL).  */
    1726              :       ctxt
    1727              :       /* Must be an enum value.  */
    1728         6812 :       && index_sval->get_type ()
    1729         6812 :       && (!check_index_type
    1730         6497 :           || TREE_CODE (TREE_TYPE (index)) == ENUMERAL_TYPE)
    1731          663 :       && TREE_CODE (index_sval->get_type ()) == ENUMERAL_TYPE
    1732              :       /* If we have a constant, then we can check it directly.  */
    1733          663 :       && index_sval->get_kind () != SK_CONSTANT
    1734          634 :       && implicitly_created_default_p ()
    1735           45 :       && has_nondefault_cases_for_all_enum_values_p (switch_stmt,
    1736              :                                                      index_sval->get_type ())
    1737              :       /* Don't do this if there's a chance that the index is
    1738              :          attacker-controlled.  */
    1739         8107 :       && !ctxt->possibly_tainted_p (index_sval))
    1740              :     {
    1741           33 :       if (out)
    1742            0 :         *out = std::make_unique <rejected_default_case> (model);
    1743           33 :       return false;
    1744              :     }
    1745              : 
    1746         8039 :   bool sat
    1747        16078 :     = model.get_constraints ()->add_bounded_ranges (index_sval,
    1748         8039 :                                                     m_all_cases_ranges);
    1749         8039 :   if (!sat && out)
    1750           48 :     *out = std::make_unique <rejected_ranges_constraint>
    1751           48 :       (model, index, m_all_cases_ranges);
    1752         8039 :   if (sat && ctxt && !m_all_cases_ranges->empty_p ())
    1753         6202 :     ctxt->on_bounded_ranges (*index_sval, *m_all_cases_ranges);
    1754              :   return sat;
    1755              : }
    1756              : 
    1757              : /* Return true iff this op's edge is purely for an
    1758              :    implicitly-created "default".  */
    1759              : 
    1760              : bool
    1761          659 : switch_case_op::implicitly_created_default_p () const
    1762              : {
    1763          659 :   if (m_case_labels.size () != 1)
    1764              :     return false;
    1765              : 
    1766          592 :   tree case_label = m_case_labels[0];
    1767          592 :   gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
    1768          592 :   if (CASE_LOW (case_label))
    1769              :     return false;
    1770              : 
    1771              :   /* We have a single "default" case.
    1772              :      Assume that it was implicitly created if it has UNKNOWN_LOCATION.  */
    1773          172 :   return EXPR_LOCATION (case_label) == UNKNOWN_LOCATION;
    1774              : }
    1775              : 
    1776              : /* Given an ERT_TRY region, get the eh_catch corresponding to
    1777              :    the label of DST_SNODE, if any.  */
    1778              : 
    1779              : static eh_catch
    1780          179 : get_catch (eh_region eh_reg, supernode *dst_snode)
    1781              : {
    1782          179 :   gcc_assert (eh_reg->type == ERT_TRY);
    1783              : 
    1784          179 :   tree dst_snode_label = dst_snode->get_label ();
    1785          179 :   if (!dst_snode_label)
    1786              :     return nullptr;
    1787              : 
    1788          124 :   for (eh_catch iter = eh_reg->u.eh_try.first_catch;
    1789          184 :        iter;
    1790           60 :        iter = iter->next_catch)
    1791          184 :     if (iter->label == dst_snode_label)
    1792              :       return iter;
    1793              : 
    1794              :   return nullptr;
    1795              : }
    1796              : 
    1797              : class rejected_eh_dispatch : public rejected_constraint
    1798              : {
    1799              : public:
    1800            0 :   rejected_eh_dispatch (const region_model &model)
    1801            0 :   : rejected_constraint (model)
    1802              :   {}
    1803              : 
    1804            0 :   void dump_to_pp (pretty_printer *pp) const final override
    1805              :   {
    1806            0 :     pp_printf (pp, "rejected_eh_dispatch");
    1807            0 :   }
    1808              : };
    1809              : 
    1810              : static bool
    1811          273 : exception_matches_type_p (tree exception_type,
    1812              :                           tree catch_type)
    1813              : {
    1814            0 :   if (catch_type == exception_type)
    1815            0 :     return true;
    1816              : 
    1817              :   /* TODO (PR analyzer/119697): we should also handle subclasses etc;
    1818              :      see the rules in https://en.cppreference.com/w/cpp/language/catch
    1819              : 
    1820              :      It looks like we should be calling (or emulating)
    1821              :      can_convert_eh from the C++ FE, but that's specific to the C++ FE.  */
    1822              : 
    1823              :   return false;
    1824              : }
    1825              : 
    1826              : static bool
    1827          287 : matches_any_exception_type_p (eh_catch ehc, tree exception_type)
    1828              : {
    1829          287 :   if (ehc->type_list == NULL_TREE)
    1830              :     /* All exceptions are caught here.  */
    1831              :     return true;
    1832              : 
    1833          371 :   for (tree iter = ehc->type_list; iter; iter = TREE_CHAIN (iter))
    1834          287 :     if (exception_matches_type_p (TREE_VALUE (iter),
    1835              :                                   exception_type))
    1836              :       return true;
    1837              :   return false;
    1838              : }
    1839              : 
    1840              : // class eh_dispatch_edge_op : public control_flow_op
    1841              : 
    1842              : std::unique_ptr<eh_dispatch_edge_op>
    1843          191 : eh_dispatch_edge_op::make (supernode *src_snode,
    1844              :                            supernode *dst_snode,
    1845              :                            ::edge cfg_edge,
    1846              :                            const geh_dispatch &eh_dispatch_stmt)
    1847              : {
    1848          191 :   const eh_status *eh = src_snode->get_function ()->eh;
    1849          191 :   gcc_assert (eh);
    1850          191 :   int region_idx = gimple_eh_dispatch_region (&eh_dispatch_stmt);
    1851          191 :   gcc_assert (region_idx > 0);
    1852          191 :   gcc_assert ((*eh->region_array)[region_idx]);
    1853          191 :   eh_region eh_reg = (*eh->region_array)[region_idx];
    1854          191 :   gcc_assert (eh_reg);
    1855          191 :   switch (eh_reg->type)
    1856              :     {
    1857            0 :     default:
    1858            0 :       gcc_unreachable ();
    1859            0 :     case ERT_CLEANUP:
    1860              :       // TODO
    1861            0 :       gcc_unreachable ();
    1862          179 :       break;
    1863          179 :     case ERT_TRY:
    1864          179 :       {
    1865          179 :         eh_catch ehc = get_catch (eh_reg, dst_snode);
    1866          179 :         return std::make_unique<eh_dispatch_try_edge_op>
    1867          179 :           (src_snode,
    1868              :            cfg_edge, eh_dispatch_stmt,
    1869          179 :            eh_reg, ehc);
    1870              :       }
    1871           12 :       break;
    1872           12 :     case ERT_ALLOWED_EXCEPTIONS:
    1873           12 :       return std::make_unique<eh_dispatch_allowed_edge_op>
    1874           12 :         (src_snode, dst_snode,
    1875              :          cfg_edge, eh_dispatch_stmt,
    1876           12 :          eh_reg);
    1877            0 :       break;
    1878            0 :     case ERT_MUST_NOT_THROW:
    1879              :       // TODO
    1880            0 :       gcc_unreachable ();
    1881              :       break;
    1882              :     }
    1883              : }
    1884              : 
    1885          191 : eh_dispatch_edge_op::
    1886              : eh_dispatch_edge_op (supernode *src_snode,
    1887              :                      enum kind kind_,
    1888              :                      ::edge cfg_edge,
    1889              :                      const geh_dispatch &geh_dispatch_stmt,
    1890          191 :                      eh_region eh_reg)
    1891              : : control_flow_op (kind_, cfg_edge, geh_dispatch_stmt),
    1892          191 :   m_src_snode (src_snode),
    1893          191 :   m_eh_region (eh_reg)
    1894              : {
    1895          191 : }
    1896              : 
    1897              : bool
    1898          324 : eh_dispatch_edge_op::
    1899              : apply_constraints (const superedge *sedge,
    1900              :                    region_model &model,
    1901              :                    region_model_context *ctxt,
    1902              :                    std::unique_ptr<rejected_constraint> *out) const
    1903              : {
    1904          324 :   const exception_node *current_node = model.get_current_thrown_exception ();
    1905              : 
    1906          321 :   if (!current_node)
    1907              :     return false;
    1908              : 
    1909          321 :   gcc_assert (current_node);
    1910          321 :   tree curr_exception_type = current_node->maybe_get_type ();
    1911          321 :   if (!curr_exception_type)
    1912              :     /* We don't know the specific type.  */
    1913              :     return true;
    1914              : 
    1915          243 :   return apply_eh_constraints (sedge, model, ctxt, curr_exception_type, out);
    1916              : }
    1917              : 
    1918              : // class eh_dispatch_try_edge_op : public eh_dispatch_edge_op
    1919              : 
    1920          179 : eh_dispatch_try_edge_op::
    1921              : eh_dispatch_try_edge_op (supernode *src_snode,
    1922              :                          ::edge cfg_edge,
    1923              :                          const geh_dispatch &geh_dispatch_stmt,
    1924              :                          eh_region eh_reg,
    1925          179 :                          eh_catch ehc)
    1926              : : eh_dispatch_edge_op (src_snode,
    1927              :                        kind::eh_dispatch_try_edge,
    1928              :                        cfg_edge, geh_dispatch_stmt, eh_reg),
    1929          179 :   m_eh_catch (ehc)
    1930              : {
    1931          179 :   gcc_assert (eh_reg->type == ERT_TRY);
    1932          179 : }
    1933              : 
    1934              : void
    1935            0 : eh_dispatch_try_edge_op::print_as_edge_label (pretty_printer *pp,
    1936              :                                               bool user_facing) const
    1937              : {
    1938            0 :   if (!user_facing)
    1939            0 :     pp_string (pp, "ERT_TRY: ");
    1940            0 :   if (m_eh_catch)
    1941              :     {
    1942            0 :       bool first = true;
    1943            0 :       for (tree iter = m_eh_catch->type_list; iter; iter = TREE_CHAIN (iter))
    1944              :         {
    1945            0 :           if (!first)
    1946            0 :             pp_string (pp, ", ");
    1947            0 :           pp_printf (pp, "on catch %qT", TREE_VALUE (iter));
    1948            0 :           first = false;
    1949              :         }
    1950              :     }
    1951              :   else
    1952            0 :     pp_string (pp, "on uncaught exception");
    1953            0 : }
    1954              : 
    1955              : void
    1956           66 : eh_dispatch_try_edge_op::add_any_events_for_eedge (const exploded_edge &eedge,
    1957              :                                                    checker_path &out_path) const
    1958              : {
    1959           66 :   if (m_eh_catch)
    1960              :     {
    1961           63 :       const region_model *model = eedge.m_src->get_state ().m_region_model;
    1962           63 :       auto curr_thrown_exception_node
    1963           63 :         = model->get_current_thrown_exception ();
    1964            0 :       gcc_assert (curr_thrown_exception_node);
    1965           63 :       tree type = curr_thrown_exception_node->maybe_get_type ();
    1966           63 :       out_path.add_event
    1967           63 :         (std::make_unique<catch_cfg_edge_event>
    1968           63 :          (eedge,
    1969          126 :           event_loc_info (eedge.m_dest),
    1970              :           *this,
    1971              :           type));
    1972              :     }
    1973              :   else
    1974              :     {
    1975              :       /* We have the "uncaught exception" sedge, from eh_dispatch
    1976              :          to a block containing resx.
    1977              :          Don't add any events for this, so that we can consolidate
    1978              :          adjacent stack unwinding events.  */
    1979              :     }
    1980           66 : }
    1981              : 
    1982              : bool
    1983          230 : eh_dispatch_try_edge_op::
    1984              : apply_eh_constraints (const superedge *sedge,
    1985              :                       region_model &model,
    1986              :                       region_model_context */*ctxt*/,
    1987              :                       tree exception_type,
    1988              :                       std::unique_ptr<rejected_constraint> *out) const
    1989              : {
    1990              :   /* TODO: can we rely on this ordering?
    1991              :      or do we need to iterate through prev_catch ?  */
    1992              :   /* The exception must not match any of the previous edges.  */
    1993          768 :   for (auto sibling_sedge : get_src_snode ()->m_succs)
    1994              :     {
    1995          308 :       if (sibling_sedge == sedge)
    1996              :         break;
    1997              : 
    1998          139 :       const eh_dispatch_try_edge_op *sibling_edge_op
    1999          139 :         = (const eh_dispatch_try_edge_op *)sibling_sedge->get_op ();
    2000          139 :       if (eh_catch ehc = sibling_edge_op->m_eh_catch)
    2001          139 :         if (matches_any_exception_type_p (ehc, exception_type))
    2002              :           {
    2003              :             /* The earlier sibling matches, so the "unhandled" edge is
    2004              :                not taken.  */
    2005           61 :             if (out)
    2006            0 :               *out = std::make_unique<rejected_eh_dispatch> (model);
    2007           61 :             return false;
    2008              :           }
    2009              :     }
    2010              : 
    2011          169 :   if (eh_catch ehc = m_eh_catch)
    2012              :     {
    2013              :       /* We have an edge that tried to match one or more types.  */
    2014              : 
    2015              :       /* The exception must not match any of the previous edges.  */
    2016              : 
    2017              :       /* It must match this type.  */
    2018          148 :       if (matches_any_exception_type_p (ehc, exception_type))
    2019              :         return true;
    2020              :       else
    2021              :         {
    2022              :           /* Exception type doesn't match.  */
    2023           33 :           if (out)
    2024            0 :             *out = std::make_unique<rejected_eh_dispatch> (model);
    2025           33 :           return false;
    2026              :         }
    2027              :     }
    2028              :   else
    2029              :     {
    2030              :       /* This is the "unhandled exception" edge.
    2031              :          If we get here then no sibling edges matched;
    2032              :          we will follow this edge.  */
    2033              :       return true;
    2034              :     }
    2035              : }
    2036              : 
    2037              : // class eh_dispatch_allowed_edge_op : public eh_dispatch_edge_op
    2038              : 
    2039           12 : eh_dispatch_allowed_edge_op::
    2040              : eh_dispatch_allowed_edge_op (supernode *src_snode,
    2041              :                              supernode *dst_snode,
    2042              :                              ::edge cfg_edge,
    2043              :                              const geh_dispatch &geh_dispatch_stmt,
    2044           12 :                              eh_region eh_reg)
    2045              : : eh_dispatch_edge_op (src_snode,
    2046              :                        kind::eh_dispatch_try_edge,
    2047           12 :                        cfg_edge, geh_dispatch_stmt, eh_reg)
    2048              : {
    2049           12 :   gcc_assert (eh_reg->type == ERT_ALLOWED_EXCEPTIONS);
    2050              : 
    2051              :   /* We expect two sibling out-edges at an eh_dispatch from such a region:
    2052              : 
    2053              :      - one to a bb without a gimple label, with a resx,
    2054              :      for exceptions of expected types
    2055              : 
    2056              :      - one to a bb with a gimple label, with a call to __cxa_unexpected,
    2057              :      for exceptions of unexpected types.
    2058              : 
    2059              :      Set m_kind for this edge accordingly.  */
    2060           12 :   gcc_assert (cfg_edge->src->succs->length () == 2);
    2061           12 :   tree label_for_unexpected_exceptions = eh_reg->u.allowed.label;
    2062           12 :   tree label_for_dest_enode = dst_snode->get_label ();
    2063           12 :   if (label_for_dest_enode == label_for_unexpected_exceptions)
    2064            6 :     m_kind = eh_kind::unexpected;
    2065              :   else
    2066              :     {
    2067            6 :       gcc_assert (label_for_dest_enode == nullptr);
    2068            6 :       m_kind = eh_kind::expected;
    2069              :     }
    2070           12 : }
    2071              : 
    2072              : void
    2073            3 : eh_dispatch_allowed_edge_op::print_as_edge_label (pretty_printer *pp,
    2074              :                                                   bool user_facing) const
    2075              : {
    2076            3 :   if (!user_facing)
    2077              :     {
    2078            0 :       switch (m_kind)
    2079              :         {
    2080            0 :         default:
    2081            0 :           gcc_unreachable ();
    2082            0 :         case eh_kind::expected:
    2083            0 :           pp_string (pp, "expected: ");
    2084            0 :           break;
    2085            0 :         case eh_kind::unexpected:
    2086            0 :           pp_string (pp, "unexpected: ");
    2087            0 :           break;
    2088              :         }
    2089            0 :       pp_string (pp, "ERT_ALLOWED_EXCEPTIONS: ");
    2090            0 :       eh_region eh_reg = get_eh_region ();
    2091            0 :       bool first = true;
    2092            0 :       for (tree iter = eh_reg->u.allowed.type_list; iter;
    2093            0 :            iter = TREE_CHAIN (iter))
    2094              :         {
    2095            0 :           if (!first)
    2096            0 :             pp_string (pp, ", ");
    2097            0 :           pp_printf (pp, "%qT", TREE_VALUE (iter));
    2098            0 :           first = false;
    2099              :         }
    2100              :     }
    2101            3 : }
    2102              : 
    2103              : bool
    2104           13 : eh_dispatch_allowed_edge_op::
    2105              : apply_eh_constraints (const superedge *,
    2106              :                       region_model &model,
    2107              :                       region_model_context */*ctxt*/,
    2108              :                       tree exception_type,
    2109              :                       std::unique_ptr<rejected_constraint> *out) const
    2110              : {
    2111           13 :   auto curr_thrown_exception_node = model.get_current_thrown_exception ();
    2112            0 :   gcc_assert (curr_thrown_exception_node);
    2113           13 :   tree curr_exception_type = curr_thrown_exception_node->maybe_get_type ();
    2114           13 :   eh_region eh_reg = get_eh_region ();
    2115           13 :   tree type_list = eh_reg->u.allowed.type_list;
    2116              : 
    2117           13 :   switch (get_eh_kind ())
    2118              :     {
    2119            0 :     default:
    2120            0 :       gcc_unreachable ();
    2121            5 :     case eh_kind::expected:
    2122            5 :       if (!curr_exception_type)
    2123              :         {
    2124              :           /* We don't know the specific type;
    2125              :              assume we have one of an expected type.  */
    2126              :           return true;
    2127              :         }
    2128            8 :       for (tree iter = type_list; iter; iter = TREE_CHAIN (iter))
    2129           11 :         if (exception_matches_type_p (TREE_VALUE (iter),
    2130              :                                       exception_type))
    2131              :           return true;
    2132            3 :       if (out)
    2133            0 :         *out = std::make_unique<rejected_eh_dispatch> (model);
    2134              :       return false;
    2135              : 
    2136            8 :     case eh_kind::unexpected:
    2137            8 :       if (!curr_exception_type)
    2138              :         {
    2139              :           /* We don't know the specific type;
    2140              :              assume we don't have one of an expected type.  */
    2141            0 :           if (out)
    2142            0 :             *out = std::make_unique<rejected_eh_dispatch> (model);
    2143            0 :           return false;
    2144              :         }
    2145           14 :       for (tree iter = type_list; iter; iter = TREE_CHAIN (iter))
    2146            8 :         if (exception_matches_type_p (TREE_VALUE (iter),
    2147              :                                       exception_type))
    2148              :           {
    2149            2 :             if (out)
    2150            0 :               *out = std::make_unique<rejected_eh_dispatch> (model);
    2151            2 :             return false;
    2152              :           }
    2153              :       return true;
    2154              :     }
    2155              : }
    2156              : 
    2157              : // class phis_for_edge_op : public operation
    2158              : 
    2159              : std::unique_ptr<operation>
    2160        15572 : phis_for_edge_op::maybe_make (::edge cfg_in_edge)
    2161              : {
    2162        15572 :   std::vector<pair> pairs = get_pairs_for_phi_along_in_edge (cfg_in_edge);
    2163        15572 :   if (pairs.empty ())
    2164         6360 :     return nullptr;
    2165              : 
    2166         9212 :   return std::make_unique <phis_for_edge_op> (std::move (pairs));
    2167        15572 : }
    2168              : 
    2169         9212 : phis_for_edge_op::phis_for_edge_op (std::vector<pair> &&pairs)
    2170              : : operation (kind::phis),
    2171         9212 :   m_pairs (std::move (pairs))
    2172              : {
    2173         9212 : }
    2174              : 
    2175              : std::vector<phis_for_edge_op::pair>
    2176        15572 : phis_for_edge_op::get_pairs_for_phi_along_in_edge (::edge cfg_in_edge)
    2177              : {
    2178        15572 :   std::vector<pair> result;
    2179              : 
    2180        15572 :   const size_t phi_arg_idx = cfg_in_edge->dest_idx;
    2181        15572 :   for (gphi_iterator gpi = gsi_start_phis (cfg_in_edge->dest);
    2182        37935 :        !gsi_end_p (gpi); gsi_next (&gpi))
    2183              :     {
    2184        22363 :       gphi * const phi = gpi.phi ();
    2185        22363 :       tree dst = gimple_phi_result (phi);
    2186              : 
    2187              :       /* We don't bother tracking the .MEM SSA names.  */
    2188        22363 :       if (tree var = SSA_NAME_VAR (dst))
    2189        17528 :         if (TREE_CODE (var) == VAR_DECL)
    2190        16935 :           if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
    2191        11206 :             continue;
    2192              : 
    2193        11157 :       tree src = gimple_phi_arg_def (phi, phi_arg_idx);
    2194              : 
    2195        11157 :       result.push_back ({dst, src});
    2196              :     }
    2197              : 
    2198        15572 :   return result;
    2199              : }
    2200              : 
    2201              : void
    2202           87 : phis_for_edge_op::print_as_edge_label (pretty_printer *pp,
    2203              :                                        bool ) const
    2204              : {
    2205           87 :   pp_printf (pp, "PHI(");
    2206           87 :   bool first = true;
    2207          174 :   for (auto &p : m_pairs)
    2208              :     {
    2209           87 :       if (first)
    2210              :         first = false;
    2211              :       else
    2212            0 :         pp_string (pp, ", ");
    2213              : 
    2214           87 :       pp_printf (pp, "%E = %E", p.m_dst, p.m_src);
    2215              :     }
    2216           87 :   pp_printf (pp, ");");
    2217           87 : }
    2218              : 
    2219              : void
    2220         9212 : phis_for_edge_op::
    2221              : walk_load_store_addr_ops (void */*data*/ ,
    2222              :                           walk_stmt_load_store_addr_fn /*load_cb*/,
    2223              :                           walk_stmt_load_store_addr_fn /*store_cb*/,
    2224              :                           walk_stmt_load_store_addr_fn /*addr_cb*/) const
    2225              : {
    2226         9212 : }
    2227              : 
    2228              : bool
    2229        20655 : phis_for_edge_op::defines_ssa_name_p (const_tree ssa_name) const
    2230              : {
    2231        37876 :   for (auto &p : m_pairs)
    2232        28417 :     if (p.m_dst == ssa_name)
    2233        20655 :       return true;
    2234              :   return false;
    2235              : }
    2236              : 
    2237              : void
    2238        21358 : phis_for_edge_op::execute (operation_context &op_ctxt) const
    2239              : {
    2240        21358 :   auto logger = op_ctxt.get_logger ();
    2241        21358 :   LOG_SCOPE (logger);
    2242              : 
    2243        21358 :   auto dst_point (op_ctxt.get_next_intraprocedural_point ());
    2244              : 
    2245        21358 :   const program_state &src_state (op_ctxt.get_initial_state ());
    2246        21358 :   program_state dst_state (src_state);
    2247              : 
    2248        21358 :   impl_path_context path_ctxt (&dst_state, logger);
    2249        21358 :   uncertainty_t uncertainty;
    2250        21358 :   impl_region_model_context ctxt (op_ctxt.m_eg,
    2251        21358 :                                   &op_ctxt.m_src_enode,
    2252              : 
    2253              :                                   /* TODO: should we be getting the ECs from the
    2254              :                                      old state, rather than the new?  */
    2255        21358 :                                   &op_ctxt.get_initial_state (),
    2256              :                                   &dst_state,
    2257              :                                   &uncertainty,
    2258              :                                   &path_ctxt,
    2259              :                                   nullptr,
    2260        21358 :                                   nullptr);
    2261              : 
    2262        21358 :   update_state (src_state, dst_state, &ctxt);
    2263              : 
    2264        21358 :   op_ctxt.add_outcome (dst_point, dst_state, false, &uncertainty);
    2265        42716 : }
    2266              : 
    2267              : void
    2268        21772 : phis_for_edge_op::update_state (const program_state &src_state,
    2269              :                                 program_state &dst_state,
    2270              :                                 region_model_context *ctxt) const
    2271              : {
    2272        21772 :   const region_model &src_model = *src_state.m_region_model;
    2273        21772 :   region_model &dst_model = *dst_state.m_region_model;
    2274              : 
    2275        21772 :   hash_set<const svalue *> svals_changing_meaning;
    2276              : 
    2277              :   /* Get state from src_state so that all of the phi stmts for an edge
    2278              :      are effectively handled simultaneously.  */
    2279        51999 :   for (auto &p : m_pairs)
    2280              :     {
    2281        30227 :       const svalue *src_sval = src_model.get_rvalue (p.m_src, nullptr);
    2282        30227 :       const region *dst_reg = src_model.get_lvalue (p.m_dst, nullptr);
    2283              : 
    2284        30227 :       const svalue *old_sval = src_model.get_rvalue (p.m_dst, nullptr);
    2285        30227 :       if (old_sval->get_kind () == SK_WIDENING)
    2286           12 :         svals_changing_meaning.add (old_sval);
    2287              : 
    2288        30227 :       dst_model.set_value (dst_reg, src_sval, ctxt);
    2289              :     }
    2290              : 
    2291        43556 :  for (auto iter : svals_changing_meaning)
    2292           12 :    dst_model.get_constraints ()->purge_state_involving (iter);
    2293        21772 : }
    2294              : 
    2295              : bool
    2296        10936 : phis_for_edge_op::
    2297              : execute_for_feasibility (const exploded_edge &eedge,
    2298              :                          feasibility_state &fstate,
    2299              :                          region_model_context *ctxt,
    2300              :                          std::unique_ptr<rejected_constraint> */*out_rc*/) const
    2301              : {
    2302        10936 :   hash_set<const svalue *> svals_changing_meaning;
    2303              :   /* Get state from src_state so that all of the phi stmts for an edge
    2304              :      are effectively handled simultaneously.  */
    2305        10936 :   region_model &model = fstate.get_model ();
    2306        10936 :   region_model src_model (model);
    2307        24152 :   for (auto &p : m_pairs)
    2308              :     {
    2309        13216 :       const svalue *src_sval = src_model.get_rvalue (p.m_src, ctxt);
    2310        13216 :       const region *dst_reg = model.get_lvalue (p.m_dst, ctxt);
    2311              : 
    2312        13216 :       const svalue *sval = model.get_rvalue (p.m_dst, ctxt);
    2313        13216 :       if (sval->get_kind () == SK_WIDENING)
    2314           24 :         svals_changing_meaning.add (sval);
    2315              : 
    2316        13216 :       model.set_value (dst_reg, src_sval, ctxt);
    2317              :     }
    2318              : 
    2319        10960 :   for (auto iter : svals_changing_meaning)
    2320           24 :     model.get_constraints ()->purge_state_involving (iter);
    2321              : 
    2322        10936 :   {
    2323              :     /* If we've entering an snode that we've already visited on this
    2324              :        epath, then we need do fix things up for loops; see the
    2325              :        comment for store::loop_replay_fixup.
    2326              :        Perhaps we should probably also verify the callstring,
    2327              :        and track program_points,  but hopefully doing it by supernode
    2328              :        is good enough.  */
    2329        10936 :     const exploded_node &dst_enode = *eedge.m_dest;
    2330        10936 :     const unsigned dst_snode_idx = dst_enode.get_supernode ()->m_id;
    2331        10936 :     if (bitmap_bit_p (fstate.get_snodes_visited (), dst_snode_idx))
    2332         4661 :       model.loop_replay_fixup (dst_enode.get_state ().m_region_model);
    2333              :   }
    2334              :  
    2335        21872 :   return true;
    2336        10936 : }
    2337              : 
    2338              : void
    2339          414 : phis_for_edge_op::
    2340              : update_state_for_bulk_merger (const program_state &src_state,
    2341              :                               program_state &dst_state) const
    2342              : {
    2343          414 :   update_state (src_state, dst_state, nullptr);
    2344          414 : }
    2345              : 
    2346              : void
    2347         1259 : phis_for_edge_op::add_any_events_for_eedge (const exploded_edge &,
    2348              :                                             checker_path &) const
    2349              : {
    2350              :   // No-op
    2351         1259 : }
    2352              : 
    2353              : // class resx_op : public gimple_stmt_op
    2354              : 
    2355              : void
    2356          536 : resx_op::execute (operation_context &op_ctxt) const
    2357              : {
    2358          536 :   auto logger = op_ctxt.get_logger ();
    2359          536 :   LOG_SCOPE (logger);
    2360              : 
    2361          536 :   program_point dst_point (op_ctxt.get_next_intraprocedural_point ());
    2362          536 :   program_state dst_state (op_ctxt.get_initial_state ());
    2363          536 :   op_region_model_context ctxt (op_ctxt, dst_state);
    2364              : 
    2365         1072 :   if (exploded_node *dst_enode
    2366          536 :       = op_ctxt.m_eg.get_or_create_node (dst_point, dst_state,
    2367          536 :                                          &op_ctxt.m_src_enode,
    2368              :                                          // Don't add to worklist:
    2369              :                                          false))
    2370              :     {
    2371          536 :       op_ctxt.m_eg.add_edge (&op_ctxt.m_src_enode,
    2372              :                              dst_enode,
    2373          536 :                              &op_ctxt.m_sedge,
    2374              :                              false,
    2375          536 :                              nullptr);
    2376              :       /* Try to adding eedges and enodes that unwind to the next
    2377              :          eh_dispatch statement, if any.
    2378              :          Only the final enode is added to the worklist.  */
    2379          536 :       op_ctxt.m_eg.unwind_from_exception (*dst_enode,
    2380              :                                           nullptr,
    2381              :                                           &ctxt);
    2382              :     }
    2383          536 : }
    2384              : 
    2385              : void
    2386           18 : resx_op::add_any_events_for_eedge (const exploded_edge &,
    2387              :                                    checker_path &) const
    2388              : {
    2389           18 : }
    2390              : 
    2391              : } // namespace ana
    2392              : 
    2393              : #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.