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