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