LCOV - code coverage report
Current view: top level - gcc/analyzer - program-state.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 79.0 % 939 742
Test Date: 2026-02-28 14:20:25 Functions: 76.9 % 65 50
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Classes for representing the state of interest at a given path of analysis.
       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 "sbitmap.h"
      24              : #include "ordered-hash-map.h"
      25              : #include "selftest.h"
      26              : #include "cfg.h"
      27              : #include "gimple-iterator.h"
      28              : #include "cgraph.h"
      29              : #include "digraph.h"
      30              : #include "diagnostics/event-id.h"
      31              : #include "diagnostics/state-graphs.h"
      32              : #include "graphviz.h"
      33              : 
      34              : #include "text-art/tree-widget.h"
      35              : #include "text-art/dump.h"
      36              : 
      37              : #include "analyzer/analyzer-logging.h"
      38              : #include "analyzer/sm.h"
      39              : #include "analyzer/call-string.h"
      40              : #include "analyzer/program-point.h"
      41              : #include "analyzer/store.h"
      42              : #include "analyzer/region-model.h"
      43              : #include "analyzer/program-state.h"
      44              : #include "analyzer/constraint-manager.h"
      45              : #include "analyzer/pending-diagnostic.h"
      46              : #include "analyzer/diagnostic-manager.h"
      47              : #include "analyzer/supergraph.h"
      48              : #include "analyzer/program-state.h"
      49              : #include "analyzer/exploded-graph.h"
      50              : #include "analyzer/state-purge.h"
      51              : #include "analyzer/call-summary.h"
      52              : #include "analyzer/analyzer-selftests.h"
      53              : #include "analyzer/ana-state-to-diagnostic-state.h"
      54              : 
      55              : #if ENABLE_ANALYZER
      56              : 
      57              : namespace ana {
      58              : 
      59              : /* class extrinsic_state.  */
      60              : 
      61              : /* Dump a multiline representation of this state to PP.  */
      62              : 
      63              : void
      64            0 : extrinsic_state::dump_to_pp (pretty_printer *pp) const
      65              : {
      66            0 :   pp_printf (pp, "extrinsic_state: %i checker(s)\n", get_num_checkers ());
      67            0 :   unsigned i = 0;
      68            0 :   for (auto &checker : m_checkers)
      69              :     {
      70            0 :       pp_printf (pp, "m_checkers[%i]: %qs\n", ++i, checker->get_name ());
      71            0 :       checker->dump_to_pp (pp);
      72              :     }
      73            0 : }
      74              : 
      75              : /* Dump a multiline representation of this state to OUTF.  */
      76              : 
      77              : void
      78            0 : extrinsic_state::dump_to_file (FILE *outf) const
      79              : {
      80            0 :   tree_dump_pretty_printer pp (outf);
      81            0 :   dump_to_pp (&pp);
      82            0 : }
      83              : 
      84              : /* Dump a multiline representation of this state to stderr.  */
      85              : 
      86              : DEBUG_FUNCTION void
      87            0 : extrinsic_state::dump () const
      88              : {
      89            0 :   dump_to_file (stderr);
      90            0 : }
      91              : 
      92              : /* Return a new json::object of the form
      93              :    {"checkers"  : array of objects, one for each state_machine}.  */
      94              : 
      95              : std::unique_ptr<json::object>
      96            0 : extrinsic_state::to_json () const
      97              : {
      98            0 :   auto ext_state_obj = std::make_unique<json::object> ();
      99              : 
     100            0 :   {
     101            0 :     auto checkers_arr = std::make_unique<json::array> ();
     102            0 :     for (auto &sm : m_checkers)
     103            0 :       checkers_arr->append (sm->to_json ());
     104            0 :     ext_state_obj->set ("checkers", std::move (checkers_arr));
     105            0 :   }
     106              : 
     107            0 :   return ext_state_obj;
     108              : }
     109              : 
     110              : /* Get the region_model_manager for this extrinsic_state.  */
     111              : 
     112              : region_model_manager *
     113     16587253 : extrinsic_state::get_model_manager () const
     114              : {
     115     16587253 :   if (m_engine)
     116     16587253 :     return m_engine->get_model_manager ();
     117              :   else
     118              :     return nullptr; /* for selftests.  */
     119              : }
     120              : 
     121              : /* Try to find a state machine named NAME.
     122              :    If found, return true and write its index to *OUT.
     123              :    Otherwise return false.  */
     124              : 
     125              : bool
     126       722170 : extrinsic_state::get_sm_idx_by_name (const char *name, unsigned *out) const
     127              : {
     128      2885907 :   for (size_t i = 0; i < m_checkers.size (); ++i)
     129      2885436 :     if (0 == strcmp (name, m_checkers[i]->get_name ()))
     130              :       {
     131              :         /* Found NAME.  */
     132       721699 :         *out = i;
     133       721699 :         return true;
     134              :       }
     135              : 
     136              :   /* NAME not found.  */
     137              :   return false;
     138              : }
     139              : 
     140              : /* struct sm_state_map::entry_t.  */
     141              : 
     142              : int
     143       662196 : sm_state_map::entry_t::cmp (const entry_t &entry_a, const entry_t &entry_b)
     144              : {
     145       662196 :   gcc_assert (entry_a.m_state);
     146       662196 :   gcc_assert (entry_b.m_state);
     147       662196 :   if (int cmp_state = ((int)entry_a.m_state->get_id ()
     148       662196 :                        - (int)entry_b.m_state->get_id ()))
     149              :     return cmp_state;
     150       653825 :   if (entry_a.m_origin && entry_b.m_origin)
     151            0 :     return svalue::cmp_ptr (entry_a.m_origin, entry_b.m_origin);
     152       653825 :   if (entry_a.m_origin)
     153              :     return 1;
     154       653825 :   if (entry_b.m_origin)
     155            0 :     return -1;
     156              :   return 0;
     157              : }
     158              : 
     159              : /* class sm_state_map.  */
     160              : 
     161              : /* sm_state_map's ctor.  */
     162              : 
     163      2764166 : sm_state_map::sm_state_map (const state_machine &sm)
     164      2764166 : : m_sm (sm), m_map (), m_global_state (sm.get_start_state ())
     165              : {
     166      2764166 : }
     167              : 
     168              : /* Clone the sm_state_map.  */
     169              : 
     170              : sm_state_map *
     171     17340663 : sm_state_map::clone () const
     172              : {
     173     17340663 :   return new sm_state_map (*this);
     174              : }
     175              : 
     176              : /* Print this sm_state_map to PP.
     177              :    If MODEL is non-NULL, print representative tree values where
     178              :    available.  */
     179              : 
     180              : void
     181          413 : sm_state_map::print (const region_model *model,
     182              :                       bool simple, bool multiline,
     183              :                       pretty_printer *pp) const
     184              : {
     185          413 :   bool first = true;
     186          413 :   if (!multiline)
     187          101 :     pp_string (pp, "{");
     188          413 :   if (m_global_state != m_sm.get_start_state ())
     189              :     {
     190            0 :       if (multiline)
     191            0 :         pp_string (pp, "  ");
     192            0 :       pp_string (pp, "global: ");
     193            0 :       m_global_state->dump_to_pp (pp);
     194            0 :       if (multiline)
     195            0 :         pp_newline (pp);
     196              :       first = false;
     197              :     }
     198          413 :   auto_vec <const svalue *> keys (m_map.elements ());
     199          413 :   for (map_t::iterator iter = m_map.begin ();
     200         1092 :        iter != m_map.end ();
     201          679 :        ++iter)
     202          679 :     keys.quick_push ((*iter).first);
     203          413 :   keys.qsort (svalue::cmp_ptr_ptr);
     204              :   unsigned i;
     205              :   const svalue *sval;
     206         1092 :   FOR_EACH_VEC_ELT (keys, i, sval)
     207              :     {
     208          679 :       if (multiline)
     209          560 :         pp_string (pp, "  ");
     210          119 :       else if (!first)
     211           18 :         pp_string (pp, ", ");
     212          679 :       first = false;
     213          679 :       if (!flag_dump_noaddr)
     214              :         {
     215          679 :           pp_pointer (pp, sval);
     216          679 :           pp_string (pp, ": ");
     217              :         }
     218          679 :       sval->dump_to_pp (pp, simple);
     219              : 
     220          679 :       entry_t e = *const_cast <map_t &> (m_map).get (sval);
     221          679 :       pp_string (pp, ": ");
     222          679 :       e.m_state->dump_to_pp (pp);
     223          679 :       if (model)
     224          679 :         if (tree rep = model->get_representative_tree (sval))
     225              :           {
     226          653 :             pp_string (pp, " (");
     227          653 :             dump_quoted_tree (pp, rep);
     228          653 :             pp_character (pp, ')');
     229              :           }
     230          679 :       if (e.m_origin)
     231              :         {
     232            0 :           pp_string (pp, " (origin: ");
     233            0 :           if (!flag_dump_noaddr)
     234              :             {
     235            0 :               pp_pointer (pp, e.m_origin);
     236            0 :               pp_string (pp, ": ");
     237              :             }
     238            0 :           e.m_origin->dump_to_pp (pp, simple);
     239            0 :           if (model)
     240            0 :             if (tree rep = model->get_representative_tree (e.m_origin))
     241              :               {
     242            0 :                 pp_string (pp, " (");
     243            0 :                 dump_quoted_tree (pp, rep);
     244            0 :                 pp_character (pp, ')');
     245              :               }
     246            0 :           pp_string (pp, ")");
     247              :         }
     248          679 :       if (multiline)
     249          560 :         pp_newline (pp);
     250              :     }
     251          413 :   if (!multiline)
     252          101 :     pp_string (pp, "}");
     253          413 : }
     254              : 
     255              : /* Dump this object to stderr.  */
     256              : 
     257              : DEBUG_FUNCTION void
     258            0 : sm_state_map::dump (bool simple) const
     259              : {
     260            0 :   tree_dump_pretty_printer pp (stderr);
     261            0 :   print (nullptr, simple, true, &pp);
     262            0 :   pp_newline (&pp);
     263            0 : }
     264              : 
     265              : /* Return a new json::object of the form
     266              :    {"global"  : (optional) value for global state,
     267              :     SVAL_DESC : value for state}.  */
     268              : 
     269              : std::unique_ptr<json::object>
     270            0 : sm_state_map::to_json () const
     271              : {
     272            0 :   auto map_obj = std::make_unique<json::object> ();
     273              : 
     274            0 :   if (m_global_state != m_sm.get_start_state ())
     275            0 :     map_obj->set ("global", m_global_state->to_json ());
     276            0 :   for (map_t::iterator iter = m_map.begin ();
     277            0 :        iter != m_map.end ();
     278            0 :        ++iter)
     279              :     {
     280            0 :       const svalue *sval = (*iter).first;
     281            0 :       entry_t e = (*iter).second;
     282              : 
     283            0 :       label_text sval_desc = sval->get_desc ();
     284            0 :       map_obj->set (sval_desc.get (), e.m_state->to_json ());
     285              : 
     286              :       /* This doesn't yet JSONify e.m_origin.  */
     287            0 :     }
     288            0 :   return map_obj;
     289              : }
     290              : 
     291              : /* Make a text_art::tree_widget describing this sm_state_map,
     292              :    using MODEL if non-null to describe svalues.  */
     293              : 
     294              : std::unique_ptr<text_art::tree_widget>
     295            0 : sm_state_map::make_dump_widget (const text_art::dump_widget_info &dwi,
     296              :                                 const region_model *model) const
     297              : {
     298            0 :   using text_art::styled_string;
     299            0 :   using text_art::tree_widget;
     300            0 :   std::unique_ptr<tree_widget> state_widget
     301              :     (tree_widget::from_fmt (dwi, nullptr,
     302            0 :                             "%qs state machine", m_sm.get_name ()));
     303              : 
     304            0 :   if (m_global_state != m_sm.get_start_state ())
     305              :     {
     306            0 :       pretty_printer the_pp;
     307            0 :       pretty_printer * const pp = &the_pp;
     308            0 :       pp_format_decoder (pp) = default_tree_printer;
     309            0 :       pp_string (pp, "Global State: ");
     310            0 :       m_global_state->dump_to_pp (pp);
     311            0 :       state_widget->add_child (tree_widget::make (dwi, pp));
     312            0 :     }
     313              : 
     314            0 :   auto_vec <const svalue *> keys (m_map.elements ());
     315            0 :   for (map_t::iterator iter = m_map.begin ();
     316            0 :        iter != m_map.end ();
     317            0 :        ++iter)
     318            0 :     keys.quick_push ((*iter).first);
     319            0 :   keys.qsort (svalue::cmp_ptr_ptr);
     320              :   unsigned i;
     321              :   const svalue *sval;
     322            0 :   FOR_EACH_VEC_ELT (keys, i, sval)
     323              :     {
     324            0 :       pretty_printer the_pp;
     325            0 :       pretty_printer * const pp = &the_pp;
     326            0 :       const bool simple = true;
     327            0 :       pp_format_decoder (pp) = default_tree_printer;
     328            0 :       if (!flag_dump_noaddr)
     329              :         {
     330            0 :           pp_pointer (pp, sval);
     331            0 :           pp_string (pp, ": ");
     332              :         }
     333            0 :       sval->dump_to_pp (pp, simple);
     334              : 
     335            0 :       entry_t e = *const_cast <map_t &> (m_map).get (sval);
     336            0 :       pp_string (pp, ": ");
     337            0 :       e.m_state->dump_to_pp (pp);
     338            0 :       if (model)
     339            0 :         if (tree rep = model->get_representative_tree (sval))
     340              :           {
     341            0 :             pp_string (pp, " (");
     342            0 :             dump_quoted_tree (pp, rep);
     343            0 :             pp_character (pp, ')');
     344              :           }
     345            0 :       if (e.m_origin)
     346              :         {
     347            0 :           pp_string (pp, " (origin: ");
     348            0 :           if (!flag_dump_noaddr)
     349              :             {
     350            0 :               pp_pointer (pp, e.m_origin);
     351            0 :               pp_string (pp, ": ");
     352              :             }
     353            0 :           e.m_origin->dump_to_pp (pp, simple);
     354            0 :           if (model)
     355            0 :             if (tree rep = model->get_representative_tree (e.m_origin))
     356              :               {
     357            0 :                 pp_string (pp, " (");
     358            0 :                 dump_quoted_tree (pp, rep);
     359            0 :                 pp_character (pp, ')');
     360              :               }
     361            0 :           pp_string (pp, ")");
     362              :         }
     363              : 
     364            0 :       state_widget->add_child (tree_widget::make (dwi, pp));
     365            0 :     }
     366              : 
     367            0 :   return state_widget;
     368            0 : }
     369              : 
     370              : /* Return true if no states have been set within this map
     371              :    (all expressions are for the start state).  */
     372              : 
     373              : bool
     374        12252 : sm_state_map::is_empty_p () const
     375              : {
     376        12252 :   return m_map.elements () == 0 && m_global_state == m_sm.get_start_state ();
     377              : }
     378              : 
     379              : /* Generate a hash value for this sm_state_map.  */
     380              : 
     381              : hashval_t
     382      5953877 : sm_state_map::hash () const
     383              : {
     384      5953877 :   hashval_t result = 0;
     385              : 
     386              :   /* Accumulate the result by xoring a hash for each slot, so that the
     387              :      result doesn't depend on the ordering of the slots in the map.  */
     388              : 
     389      5953877 :   for (map_t::iterator iter = m_map.begin ();
     390      8255912 :        iter != m_map.end ();
     391      2302035 :        ++iter)
     392              :     {
     393      2302035 :       inchash::hash hstate;
     394      2302035 :       hstate.add_ptr ((*iter).first);
     395      2302035 :       entry_t e = (*iter).second;
     396      2302035 :       hstate.add_int (e.m_state->get_id ());
     397      2302035 :       hstate.add_ptr (e.m_origin);
     398      2302035 :       result ^= hstate.end ();
     399              :     }
     400      5953877 :   result ^= m_global_state->get_id ();
     401              : 
     402      5953877 :   return result;
     403              : }
     404              : 
     405              : /* Equality operator for sm_state_map.  */
     406              : 
     407              : bool
     408      1681429 : sm_state_map::operator== (const sm_state_map &other) const
     409              : {
     410      1681429 :   if (m_global_state != other.m_global_state)
     411              :     return false;
     412              : 
     413      1680398 :   if (m_map.elements () != other.m_map.elements ())
     414              :     return false;
     415              : 
     416      1456835 :   for (map_t::iterator iter = m_map.begin ();
     417      2281139 :        iter != m_map.end ();
     418       824304 :        ++iter)
     419              :     {
     420       850197 :       const svalue *sval = (*iter).first;
     421       850197 :       entry_t e = (*iter).second;
     422       850197 :       entry_t *other_slot = const_cast <map_t &> (other.m_map).get (sval);
     423       850197 :       if (other_slot == nullptr)
     424        25893 :         return false;
     425      1674501 :       if (e != *other_slot)
     426              :         return false;
     427              :     }
     428              : 
     429      1430942 :   gcc_checking_assert (hash () == other.hash ());
     430              : 
     431              :   return true;
     432              : }
     433              : 
     434              : /* Get the state of SVAL within this object.
     435              :    States default to the start state.  */
     436              : 
     437              : state_machine::state_t
     438     12311716 : sm_state_map::get_state (const svalue *sval,
     439              :                           const extrinsic_state &ext_state) const
     440              : {
     441     12311716 :   gcc_assert (sval);
     442              : 
     443     12311716 :   sval = canonicalize_svalue (sval, ext_state);
     444              : 
     445     24623432 :   if (entry_t *slot
     446     12311716 :       = const_cast <map_t &> (m_map).get (sval))
     447       982822 :     return slot->m_state;
     448              : 
     449              :   /* SVAL has no explicit sm-state.
     450              :      If this sm allows for state inheritance, then SVAL might have implicit
     451              :      sm-state inherited via a parent.
     452              :      For example INIT_VAL(foo.field) might inherit taintedness state from
     453              :      INIT_VAL(foo).  */
     454     11328894 :   if (m_sm.inherited_state_p ())
     455      3890900 :     if (region_model_manager *mgr = ext_state.get_model_manager ())
     456              :       {
     457      3890900 :         if (const initial_svalue *init_sval = sval->dyn_cast_initial_svalue ())
     458              :           {
     459       243913 :             const region *reg = init_sval->get_region ();
     460              :             /* Try recursing upwards (up to the base region for the
     461              :                cluster).  */
     462       243913 :             if (!reg->base_region_p ())
     463        58439 :               if (const region *parent_reg = reg->get_parent_region ())
     464              :                 {
     465        58439 :                   const svalue *parent_init_sval
     466        58439 :                     = mgr->get_or_create_initial_value (parent_reg);
     467        58439 :                   state_machine::state_t parent_state
     468        58439 :                     = get_state (parent_init_sval, ext_state);
     469        58439 :                   if (parent_state)
     470              :                     return parent_state;
     471              :                 }
     472              :           }
     473      3646987 :         else if (const sub_svalue *sub_sval = sval->dyn_cast_sub_svalue ())
     474              :           {
     475        17993 :             const svalue *parent_sval = sub_sval->get_parent ();
     476        35986 :             if (state_machine::state_t parent_state
     477        17993 :                   = get_state (parent_sval, ext_state))
     478              :               return parent_state;
     479              :           }
     480              :       }
     481              : 
     482     22504924 :   if (state_machine::state_t state
     483     11252462 :       = m_sm.alt_get_inherited_state (*this, sval, ext_state))
     484              :     return state;
     485              : 
     486     11035477 :   return m_sm.get_default_state (sval);
     487              : }
     488              : 
     489              : /* Get the "origin" svalue for any state of SVAL.  */
     490              : 
     491              : const svalue *
     492           12 : sm_state_map::get_origin (const svalue *sval,
     493              :                            const extrinsic_state &ext_state) const
     494              : {
     495           12 :   gcc_assert (sval);
     496              : 
     497           12 :   sval = canonicalize_svalue (sval, ext_state);
     498              : 
     499           12 :   entry_t *slot
     500           12 :     = const_cast <map_t &> (m_map).get (sval);
     501           12 :   if (slot)
     502           12 :     return slot->m_origin;
     503              :   else
     504              :     return nullptr;
     505              : }
     506              : 
     507              : /* Set the state of SID within MODEL to STATE, recording that
     508              :    the state came from ORIGIN.  */
     509              : 
     510              : void
     511        37236 : sm_state_map::set_state (region_model *model,
     512              :                          const svalue *sval,
     513              :                          state_machine::state_t state,
     514              :                          const svalue *origin,
     515              :                          const extrinsic_state &ext_state)
     516              : {
     517        37236 :   if (model == nullptr)
     518              :     return;
     519              : 
     520              :   /* Reject attempts to set state on UNKNOWN/POISONED.  */
     521        37236 :   if (!sval->can_have_associated_state_p ())
     522              :     return;
     523              : 
     524        32663 :   equiv_class &ec = model->get_constraints ()->get_equiv_class (sval);
     525        32663 :   if (!set_state (ec, state, origin, ext_state))
     526              :     return;
     527              : }
     528              : 
     529              : /* Set the state of EC to STATE, recording that the state came from
     530              :    ORIGIN.
     531              :    Return true if any states of svalue_ids within EC changed.  */
     532              : 
     533              : bool
     534        32663 : sm_state_map::set_state (const equiv_class &ec,
     535              :                          state_machine::state_t state,
     536              :                          const svalue *origin,
     537              :                          const extrinsic_state &ext_state)
     538              : {
     539        32663 :   bool any_changed = false;
     540       132418 :   for (const svalue *sval : ec.m_vars)
     541        34429 :     any_changed |= impl_set_state (sval, state, origin, ext_state);
     542        32663 :   return any_changed;
     543              : }
     544              : 
     545              : /* Set state of SVAL to STATE, bypassing equivalence classes.
     546              :    Return true if the state changed.  */
     547              : 
     548              : bool
     549       370993 : sm_state_map::impl_set_state (const svalue *sval,
     550              :                               state_machine::state_t state,
     551              :                               const svalue *origin,
     552              :                               const extrinsic_state &ext_state)
     553              : {
     554       370993 :   sval = canonicalize_svalue (sval, ext_state);
     555              : 
     556       370993 :   if (get_state (sval, ext_state) == state)
     557              :     return false;
     558              : 
     559       302838 :   gcc_assert (sval->can_have_associated_state_p ());
     560              : 
     561       302838 :   if (m_sm.inherited_state_p ())
     562              :     {
     563       427586 :       if (const compound_svalue *compound_sval
     564       213793 :             = sval->dyn_cast_compound_svalue ())
     565            0 :         for (auto iter = compound_sval->begin ();
     566            0 :              iter != compound_sval->end (); ++iter)
     567              :           {
     568            0 :             const svalue *inner_sval = iter.get_svalue ();
     569            0 :             if (inner_sval->can_have_associated_state_p ())
     570            0 :               impl_set_state (inner_sval, state, origin, ext_state);
     571              :           }
     572              :     }
     573              : 
     574              :   /* Special-case state 0 as the default value.  */
     575       302838 :   if (state == 0)
     576              :     {
     577          984 :       if (m_map.get (sval))
     578          980 :         m_map.remove (sval);
     579          984 :       return true;
     580              :     }
     581       301854 :   gcc_assert (sval);
     582       301854 :   m_map.put (sval, entry_t (state, origin));
     583       301854 :   return true;
     584              : }
     585              : 
     586              : /* Clear any state for SVAL from this state map.  */
     587              : 
     588              : void
     589         2910 : sm_state_map::clear_any_state (const svalue *sval)
     590              : {
     591         2910 :   m_map.remove (sval);
     592         2910 : }
     593              : 
     594              : /* Clear all per-svalue state within this state map.  */
     595              : 
     596              : void
     597         9681 : sm_state_map::clear_all_per_svalue_state ()
     598              : {
     599         9681 :   m_map.empty ();
     600         9681 : }
     601              : 
     602              : /* Set the "global" state within this state map to STATE.  */
     603              : 
     604              : void
     605       294009 : sm_state_map::set_global_state (state_machine::state_t state)
     606              : {
     607       294009 :   m_global_state = state;
     608       294009 : }
     609              : 
     610              : /* Get the "global" state within this state map.  */
     611              : 
     612              : state_machine::state_t
     613      1344074 : sm_state_map::get_global_state () const
     614              : {
     615      1344074 :   return m_global_state;
     616              : }
     617              : 
     618              : /* Purge any state for SVAL.
     619              :    If !SM::can_purge_p, then report the state as leaking,
     620              :    using CTXT.  */
     621              : 
     622              : void
     623       605120 : sm_state_map::on_svalue_leak (const svalue *sval,
     624              :                               impl_region_model_context *ctxt)
     625              : {
     626       605120 :   if (state_machine::state_t state = get_state (sval, ctxt->m_ext_state))
     627              :     {
     628       605120 :       if (m_sm.can_purge_p (state))
     629       604486 :         m_map.remove (sval);
     630              :       else
     631          634 :         ctxt->on_state_leak (m_sm, sval, state);
     632              :     }
     633       605120 : }
     634              : 
     635              : /* Purge any state for svalues that aren't live with respect to LIVE_SVALUES
     636              :    and MODEL.  */
     637              : 
     638              : void
     639      3386574 : sm_state_map::on_liveness_change (const svalue_set &live_svalues,
     640              :                                   const region_model *model,
     641              :                                   const extrinsic_state &ext_state,
     642              :                                   impl_region_model_context *ctxt)
     643              : {
     644      3386574 :   svalue_set svals_to_unset;
     645      3386574 :   uncertainty_t *uncertainty = ctxt->get_uncertainty ();
     646              : 
     647      3386574 :   auto_vec<const svalue *> leaked_svals (m_map.elements ());
     648      4294736 :   for (map_t::iterator iter = m_map.begin ();
     649      4294736 :        iter != m_map.end ();
     650       908162 :        ++iter)
     651              :     {
     652       908162 :       const svalue *iter_sval = (*iter).first;
     653       908162 :       if (!iter_sval->live_p (&live_svalues, model))
     654              :         {
     655       133677 :           svals_to_unset.add (iter_sval);
     656       133677 :           entry_t e = (*iter).second;
     657       133677 :           if (!m_sm.can_purge_p (e.m_state))
     658          937 :             leaked_svals.quick_push (iter_sval);
     659              :         }
     660       908162 :       if (uncertainty)
     661       830824 :         if (uncertainty->unknown_sm_state_p (iter_sval))
     662          308 :           svals_to_unset.add (iter_sval);
     663              :     }
     664              : 
     665      3386574 :   leaked_svals.qsort (svalue::cmp_ptr_ptr);
     666              : 
     667              :   unsigned i;
     668              :   const svalue *sval;
     669      3387511 :   FOR_EACH_VEC_ELT (leaked_svals, i, sval)
     670              :     {
     671          937 :       entry_t e = *m_map.get (sval);
     672          937 :       ctxt->on_state_leak (m_sm, sval, e.m_state);
     673              :     }
     674              : 
     675      3386574 :   sm_state_map old_sm_map = *this;
     676              : 
     677      3386574 :   for (svalue_set::iterator iter = svals_to_unset.begin ();
     678      3654544 :        iter != svals_to_unset.end (); ++iter)
     679       133985 :     m_map.remove (*iter);
     680              : 
     681              :   /* For state machines like "taint" where states can be
     682              :      alt-inherited from other svalues, ensure that state purging doesn't
     683              :      make us lose sm-state.
     684              : 
     685              :      Consider e.g.:
     686              : 
     687              :      make_tainted(foo);
     688              :      if (foo.field > 128)
     689              :        return;
     690              :      arr[foo.field].f1 = v1;
     691              : 
     692              :      where the last line is:
     693              : 
     694              :      (A): _t1 = foo.field;
     695              :      (B): _t2 = _t1 * sizeof(arr[0]);
     696              :      (C): [arr + _t2].f1 = val;
     697              : 
     698              :      At (A), foo is 'tainted' and foo.field is 'has_ub'.
     699              :      After (B), foo.field's value (in _t1) is no longer directly
     700              :      within LIVE_SVALUES, so with state purging enabled, we would
     701              :      erroneously purge the "has_ub" state from the svalue.
     702              : 
     703              :      Given that _t2's value's state comes from _t1's value's state,
     704              :      we need to preserve that information.
     705              : 
     706              :      Hence for all svalues that have had their explicit sm-state unset,
     707              :      having their sm-state being unset, determine if doing so has changed
     708              :      their effective state, and if so, explicitly set their state.
     709              : 
     710              :      For example, in the above, unsetting the "has_ub" for _t1's value means
     711              :      that _t2's effective value changes from "has_ub" (from alt-inherited
     712              :      from _t1's value) to "tainted" (inherited from "foo"'s value).
     713              : 
     714              :      For such cases, preserve the effective state by explicitly setting the
     715              :      new state.  In the above example, this means explicitly setting _t2's
     716              :      value to the value ("has_ub") it was previously alt-inheriting from _t1's
     717              :      value.  */
     718      3386574 :   if (m_sm.has_alt_get_inherited_state_p ())
     719              :     {
     720       483724 :       auto_vec<const svalue *> svalues_needing_state;
     721       747258 :       for (auto unset_sval : svals_to_unset)
     722              :         {
     723       131767 :           const state_machine::state_t old_state
     724       131767 :             = old_sm_map.get_state (unset_sval, ext_state);
     725       131767 :           const state_machine::state_t new_state
     726       131767 :             = get_state (unset_sval, ext_state);
     727       131767 :           if (new_state != old_state)
     728       131767 :             svalues_needing_state.safe_push (unset_sval);
     729              :         }
     730       733413 :       for (auto sval : svalues_needing_state)
     731              :         {
     732       131767 :           const state_machine::state_t old_state
     733       131767 :             = old_sm_map.get_state (sval, ext_state);
     734       131767 :           impl_set_state (sval, old_state, nullptr, ext_state);
     735              :         }
     736       483724 :     }
     737      3386574 : }
     738              : 
     739              : /* Purge state from SVAL (in response to a call to an unknown function).  */
     740              : 
     741              : void
     742       295637 : sm_state_map::on_unknown_change (const svalue *sval,
     743              :                                  bool is_mutable,
     744              :                                  const extrinsic_state &ext_state)
     745              : {
     746       295637 :   svalue_set svals_to_unset;
     747              : 
     748       318408 :   for (map_t::iterator iter = m_map.begin ();
     749       318408 :        iter != m_map.end ();
     750        22771 :        ++iter)
     751              :     {
     752        22771 :       const svalue *key = (*iter).first;
     753        22771 :       entry_t e = (*iter).second;
     754              :       /* We only want to purge state for some states when things
     755              :          are mutable.  For example, in sm-malloc.cc, an on-stack ptr
     756              :          doesn't stop being stack-allocated when passed to an unknown fn.  */
     757        22771 :       if (!m_sm.reset_when_passed_to_unknown_fn_p (e.m_state, is_mutable))
     758        10378 :         continue;
     759        12393 :       if (key == sval)
     760          854 :         svals_to_unset.add (key);
     761              :       /* If we have INIT_VAL(BASE_REG), then unset any INIT_VAL(REG)
     762              :          for REG within BASE_REG.  */
     763        12393 :       if (const initial_svalue *init_sval = sval->dyn_cast_initial_svalue ())
     764         2517 :         if (const initial_svalue *init_key = key->dyn_cast_initial_svalue ())
     765              :           {
     766         1174 :             const region *changed_reg = init_sval->get_region ();
     767         1174 :             const region *changed_key = init_key->get_region ();
     768         1174 :             if (changed_key->get_base_region () == changed_reg)
     769          182 :               svals_to_unset.add (key);
     770              :           }
     771              :     }
     772              : 
     773       296492 :   for (svalue_set::iterator iter = svals_to_unset.begin ();
     774       592984 :        iter != svals_to_unset.end (); ++iter)
     775          855 :     impl_set_state (*iter, (state_machine::state_t)0, nullptr, ext_state);
     776       295637 : }
     777              : 
     778              : /* Purge state for things involving SVAL.
     779              :    For use when SVAL changes meaning, at the def_stmt on an SSA_NAME.   */
     780              : 
     781              : void
     782       110124 : sm_state_map::purge_state_involving (const svalue *sval,
     783              :                                      const extrinsic_state &ext_state)
     784              : {
     785              :   /* Currently svalue::involves_p requires this.  */
     786       220248 :   if (!(sval->get_kind () == SK_INITIAL
     787       110124 :         || sval->get_kind () == SK_CONJURED))
     788            0 :     return;
     789              : 
     790       110124 :   svalue_set svals_to_unset;
     791              : 
     792       133933 :   for (map_t::iterator iter = m_map.begin ();
     793       133933 :        iter != m_map.end ();
     794        23809 :        ++iter)
     795              :     {
     796        23809 :       const svalue *key = (*iter).first;
     797        23809 :       entry_t e = (*iter).second;
     798        23809 :       if (!m_sm.can_purge_p (e.m_state))
     799         9538 :         continue;
     800        14271 :       if (key->involves_p (sval))
     801          121 :         svals_to_unset.add (key);
     802              :     }
     803              : 
     804       110245 :   for (svalue_set::iterator iter = svals_to_unset.begin ();
     805       220490 :        iter != svals_to_unset.end (); ++iter)
     806          121 :     impl_set_state (*iter, (state_machine::state_t)0, nullptr, ext_state);
     807       110124 : }
     808              : 
     809              : /* Comparator for imposing an order on sm_state_map instances.  */
     810              : 
     811              : int
     812      1206040 : sm_state_map::cmp (const sm_state_map &smap_a, const sm_state_map &smap_b)
     813              : {
     814      1206040 :   if (int cmp_count = smap_a.elements () - smap_b.elements ())
     815              :     return cmp_count;
     816              : 
     817      1043298 :   auto_vec <const svalue *> keys_a (smap_a.elements ());
     818      1043298 :   for (map_t::iterator iter = smap_a.begin ();
     819      1748159 :        iter != smap_a.end ();
     820       704861 :        ++iter)
     821       704861 :     keys_a.quick_push ((*iter).first);
     822      1043298 :   keys_a.qsort (svalue::cmp_ptr_ptr);
     823              : 
     824      1043298 :   auto_vec <const svalue *> keys_b (smap_b.elements ());
     825      1043298 :   for (map_t::iterator iter = smap_b.begin ();
     826      1748159 :        iter != smap_b.end ();
     827       704861 :        ++iter)
     828       704861 :     keys_b.quick_push ((*iter).first);
     829      1043298 :   keys_b.qsort (svalue::cmp_ptr_ptr);
     830              : 
     831              :   unsigned i;
     832              :   const svalue *sval_a;
     833      2013108 :   FOR_EACH_VEC_ELT (keys_a, i, sval_a)
     834              :     {
     835       679001 :       const svalue *sval_b = keys_b[i];
     836       679001 :       if (int cmp_sval = svalue::cmp_ptr (sval_a, sval_b))
     837        25176 :         return cmp_sval;
     838       662196 :       const entry_t *e_a = const_cast <map_t &> (smap_a.m_map).get (sval_a);
     839       662196 :       const entry_t *e_b = const_cast <map_t &> (smap_b.m_map).get (sval_b);
     840       662196 :       if (int cmp_entry = entry_t::cmp (*e_a, *e_b))
     841              :         return cmp_entry;
     842              :     }
     843              : 
     844              :   return 0;
     845      1043298 : }
     846              : 
     847              : /* Canonicalize SVAL before getting/setting it within the map.
     848              :    Convert all NULL pointers to (void *) to avoid state explosions
     849              :    involving all of the various (foo *)NULL vs (bar *)NULL.  */
     850              : 
     851              : const svalue *
     852     12682721 : sm_state_map::canonicalize_svalue (const svalue *sval,
     853              :                                    const extrinsic_state &ext_state)
     854              : {
     855     12682721 :   region_model_manager *mgr = ext_state.get_model_manager ();
     856     12682721 :   if (mgr && sval->get_type () && POINTER_TYPE_P (sval->get_type ()))
     857      3435775 :     if (tree cst = sval->maybe_get_constant ())
     858        58954 :       if (zerop (cst))
     859        56268 :         return mgr->get_or_create_constant_svalue (null_pointer_node);
     860              : 
     861              :   return sval;
     862              : }
     863              : 
     864              : /* Attempt to merge this state map with OTHER, writing the result
     865              :    into *OUT.
     866              :    Return true if the merger was possible, false otherwise.
     867              : 
     868              :    Normally, only identical state maps can be merged, so that
     869              :    differences between state maps lead to different enodes
     870              : 
     871              :    However some state machines may support merging states to
     872              :    allow for discarding of less important states, and thus avoid
     873              :    blow-up of the exploded graph.  */
     874              : 
     875              : bool
     876      1618167 : sm_state_map::can_merge_with_p (const sm_state_map &other,
     877              :                                 const state_machine &sm,
     878              :                                 const extrinsic_state &ext_state,
     879              :                                 sm_state_map **out) const
     880              : {
     881              :   /* If identical, then they merge trivially, with a copy.  */
     882      1618167 :   if (*this == other)
     883              :     {
     884      2737344 :       delete *out;
     885      1368672 :       *out = clone ();
     886      1368672 :       return true;
     887              :     }
     888              : 
     889       498990 :   delete *out;
     890       249495 :   *out = new sm_state_map (sm);
     891              : 
     892              :   /* Otherwise, attempt to merge element by element. */
     893              : 
     894              :   /* Try to merge global state.  */
     895       498990 :   if (state_machine::state_t merged_global_state
     896       250355 :       = sm.maybe_get_merged_state (get_global_state (),
     897              :                                    other.get_global_state ()))
     898       248635 :     (*out)->set_global_state (merged_global_state);
     899              :   else
     900              :     return false;
     901              : 
     902              :   /* Try to merge state each svalue's state (for the union
     903              :      of svalues represented by each smap).
     904              :      Ignore the origin information.  */
     905       248635 :   hash_set<const svalue *> svals;
     906       907229 :   for (auto kv : *this)
     907       658594 :     svals.add (kv.first);
     908       843089 :   for (auto kv : other)
     909       594454 :     svals.add (kv.first);
     910       656173 :   for (auto sval : svals)
     911              :     {
     912       400987 :       state_machine::state_t this_state = get_state (sval, ext_state);
     913       400987 :       state_machine::state_t other_state = other.get_state (sval, ext_state);
     914       400987 :       if (state_machine::state_t merged_state
     915       400987 :             = sm.maybe_get_merged_state (this_state, other_state))
     916       203769 :         (*out)->impl_set_state (sval, merged_state, nullptr, ext_state);
     917              :       else
     918       197218 :         return false;
     919              :     }
     920              : 
     921              :   /* Successfully merged all elements.  */
     922        51417 :   return true;
     923       248635 : }
     924              : 
     925              : /* class program_state.  */
     926              : 
     927              : /* program_state's ctor.  */
     928              : 
     929       359306 : program_state::program_state (const extrinsic_state &ext_state)
     930       359306 : : m_region_model (nullptr),
     931       359306 :   m_checker_states (ext_state.get_num_checkers ()),
     932       359306 :   m_valid (true)
     933              : {
     934       359306 :   engine *eng = ext_state.get_engine ();
     935       359306 :   region_model_manager *mgr = eng->get_model_manager ();
     936       359306 :   m_region_model = new region_model (mgr);
     937       359306 :   const int num_states = ext_state.get_num_checkers ();
     938      2873945 :   for (int i = 0; i < num_states; i++)
     939              :     {
     940      2514639 :       sm_state_map *sm = new sm_state_map (ext_state.get_sm (i));
     941      2514639 :       m_checker_states.quick_push (sm);
     942              :     }
     943       359306 : }
     944              : 
     945              : /* Attempt to use R to replay SUMMARY into this object.
     946              :    Return true if it is possible.  */
     947              : 
     948              : bool
     949         9919 : sm_state_map::replay_call_summary (call_summary_replay &r,
     950              :                                    const sm_state_map &summary)
     951              : {
     952        14991 :   for (auto kv : summary.m_map)
     953              :     {
     954         2536 :       const svalue *summary_sval = kv.first;
     955         2536 :       const svalue *caller_sval = r.convert_svalue_from_summary (summary_sval);
     956         2536 :       if (!caller_sval)
     957          768 :         continue;
     958         2536 :       if (!caller_sval->can_have_associated_state_p ())
     959          768 :         continue;
     960         1768 :       const svalue *summary_origin = kv.second.m_origin;
     961         1768 :       const svalue *caller_origin
     962              :         = (summary_origin
     963         1768 :            ? r.convert_svalue_from_summary (summary_origin)
     964              :            : nullptr);
     965              :       // caller_origin can be nullptr.
     966         1768 :       m_map.put (caller_sval, entry_t (kv.second.m_state, caller_origin));
     967              :     }
     968         9919 :   m_global_state = summary.m_global_state;
     969         9919 :   return true;
     970              : }
     971              : 
     972              : /* program_state's copy ctor.  */
     973              : 
     974      2246392 : program_state::program_state (const program_state &other)
     975      2246392 : : m_region_model (new region_model (*other.m_region_model)),
     976      4492784 :   m_checker_states (other.m_checker_states.length ()),
     977      2246392 :   m_valid (true)
     978              : {
     979      2246392 :   int i;
     980      2246392 :   sm_state_map *smap;
     981     17957044 :   FOR_EACH_VEC_ELT (other.m_checker_states, i, smap)
     982     15710652 :     m_checker_states.quick_push (smap->clone ());
     983      2246392 : }
     984              : 
     985              : /* program_state's assignment operator.  */
     986              : 
     987              : program_state&
     988        37347 : program_state::operator= (const program_state &other)
     989              : {
     990        37347 :   delete m_region_model;
     991        37347 :   m_region_model = new region_model (*other.m_region_model);
     992              : 
     993        37347 :   int i;
     994        37347 :   sm_state_map *smap;
     995       298686 :   FOR_EACH_VEC_ELT (m_checker_states, i, smap)
     996       522678 :     delete smap;
     997        37347 :   m_checker_states.truncate (0);
     998       112041 :   gcc_assert (m_checker_states.space (other.m_checker_states.length ()));
     999              : 
    1000       298686 :   FOR_EACH_VEC_ELT (other.m_checker_states, i, smap)
    1001       261339 :     m_checker_states.quick_push (smap->clone ());
    1002              : 
    1003        37347 :   m_valid = other.m_valid;
    1004              : 
    1005        37347 :   return *this;
    1006              : }
    1007              : 
    1008              : /* Move constructor for program_state (when building with C++11).  */
    1009       443447 : program_state::program_state (program_state &&other)
    1010       443447 : : m_region_model (other.m_region_model),
    1011       886894 :   m_checker_states (other.m_checker_states.length ())
    1012              : {
    1013       443447 :   other.m_region_model = nullptr;
    1014              : 
    1015       443447 :   int i;
    1016       443447 :   sm_state_map *smap;
    1017      3544769 :   FOR_EACH_VEC_ELT (other.m_checker_states, i, smap)
    1018      3101322 :     m_checker_states.quick_push (smap);
    1019       443447 :   other.m_checker_states.truncate (0);
    1020              : 
    1021       443447 :   m_valid = other.m_valid;
    1022       443447 : }
    1023              : 
    1024              : /* program_state's dtor.  */
    1025              : 
    1026      3049145 : program_state::~program_state ()
    1027              : {
    1028      3049145 :   delete m_region_model;
    1029      3049145 : }
    1030              : 
    1031              : /* Generate a hash value for this program_state.  */
    1032              : 
    1033              : hashval_t
    1034       442100 : program_state::hash () const
    1035              : {
    1036       442100 :   hashval_t result = m_region_model->hash ();
    1037              : 
    1038       442100 :   int i;
    1039       442100 :   sm_state_map *smap;
    1040      3976153 :   FOR_EACH_VEC_ELT (m_checker_states, i, smap)
    1041      3091953 :     result ^= smap->hash ();
    1042       442100 :   return result;
    1043              : }
    1044              : 
    1045              : /* Equality operator for program_state.
    1046              :    All parts of the program_state (region model, checker states) must
    1047              :    equal their counterparts in OTHER for the two program_states to be
    1048              :    considered equal.  */
    1049              : 
    1050              : bool
    1051       112392 : program_state::operator== (const program_state &other) const
    1052              : {
    1053       112392 :   if (!(*m_region_model == *other.m_region_model))
    1054              :     return false;
    1055              : 
    1056              :   int i;
    1057              :   sm_state_map *smap;
    1058        71956 :   FOR_EACH_VEC_ELT (m_checker_states, i, smap)
    1059        63242 :     if (!(*smap == *other.m_checker_states[i]))
    1060              :       return false;
    1061              : 
    1062         8714 :   gcc_checking_assert (hash () == other.hash ());
    1063              : 
    1064              :   return true;
    1065              : }
    1066              : 
    1067              : /* Print a compact representation of this state to PP.  */
    1068              : 
    1069              : void
    1070            0 : program_state::print (const extrinsic_state &ext_state,
    1071              :                       pretty_printer *pp) const
    1072              : {
    1073            0 :   pp_printf (pp, "rmodel: ");
    1074            0 :   m_region_model->dump_to_pp (pp, true, false);
    1075            0 :   pp_newline (pp);
    1076              : 
    1077            0 :   int i;
    1078            0 :   sm_state_map *smap;
    1079            0 :   FOR_EACH_VEC_ELT (m_checker_states, i, smap)
    1080              :     {
    1081            0 :       if (!smap->is_empty_p ())
    1082              :         {
    1083            0 :           pp_printf (pp, "%s: ", ext_state.get_name (i));
    1084            0 :           smap->print (m_region_model, true, false, pp);
    1085            0 :           pp_newline (pp);
    1086              :         }
    1087              :     }
    1088            0 :   if (!m_valid)
    1089              :     {
    1090            0 :       pp_printf (pp, "invalid state");
    1091            0 :       pp_newline (pp);
    1092              :     }
    1093            0 : }
    1094              : 
    1095              : /* Dump a representation of this state to PP.  */
    1096              : 
    1097              : void
    1098         1748 : program_state::dump_to_pp (const extrinsic_state &ext_state,
    1099              :                            bool /*summarize*/, bool multiline,
    1100              :                            pretty_printer *pp) const
    1101              : {
    1102         1748 :   if (!multiline)
    1103         1355 :     pp_string (pp, "{");
    1104         1748 :   {
    1105         1748 :     pp_printf (pp, "rmodel:");
    1106         1748 :     if (multiline)
    1107          393 :       pp_newline (pp);
    1108              :     else
    1109         1355 :       pp_string (pp, " {");
    1110         1748 :     m_region_model->dump_to_pp (pp, true, multiline);
    1111         1748 :     if (!multiline)
    1112         1355 :       pp_string (pp, "}");
    1113              :   }
    1114              : 
    1115              :   int i;
    1116              :   sm_state_map *smap;
    1117        13984 :   FOR_EACH_VEC_ELT (m_checker_states, i, smap)
    1118              :     {
    1119        12236 :       if (!smap->is_empty_p ())
    1120              :         {
    1121          413 :           if (!multiline)
    1122          101 :             pp_string (pp, " {");
    1123          413 :           pp_printf (pp, "%s: ", ext_state.get_name (i));
    1124          413 :           if (multiline)
    1125          312 :             pp_newline (pp);
    1126          413 :           smap->print (m_region_model, true, multiline, pp);
    1127          413 :           if (!multiline)
    1128          101 :             pp_string (pp, "}");
    1129              :         }
    1130              :     }
    1131              : 
    1132         1748 :   if (!m_valid)
    1133              :     {
    1134            0 :       if (!multiline)
    1135            0 :         pp_space (pp);
    1136            0 :       pp_printf (pp, "invalid state");
    1137            0 :       if (multiline)
    1138            0 :         pp_newline (pp);
    1139              :     }
    1140         1748 :   if (!multiline)
    1141         1355 :     pp_string (pp, "}");
    1142         1748 : }
    1143              : 
    1144              : /* Dump a representation of this state to OUTF.  */
    1145              : 
    1146              : void
    1147            0 : program_state::dump_to_file (const extrinsic_state &ext_state,
    1148              :                              bool summarize, bool multiline,
    1149              :                              FILE *outf) const
    1150              : {
    1151            0 :   tree_dump_pretty_printer pp (outf);
    1152            0 :   dump_to_pp (ext_state, summarize, multiline, &pp);
    1153            0 : }
    1154              : 
    1155              : /* Dump a multiline representation of this state to stderr.  */
    1156              : 
    1157              : DEBUG_FUNCTION void
    1158            0 : program_state::dump (const extrinsic_state &ext_state,
    1159              :                      bool summarize) const
    1160              : {
    1161            0 :   dump_to_file (ext_state, summarize, true, stderr);
    1162            0 : }
    1163              : 
    1164              : /* Dump a tree-like representation of this state to stderr.  */
    1165              : 
    1166              : DEBUG_FUNCTION void
    1167            0 : program_state::dump () const
    1168              : {
    1169            0 :   text_art::dump (*this);
    1170            0 : }
    1171              : 
    1172              : /* Return a new json::object of the form
    1173              :    {"store"  : object for store,
    1174              :     "constraints" : object for constraint_manager,
    1175              :     "curr_frame" : (optional) str for current frame,
    1176              :     "checkers" : { STATE_NAME : object per sm_state_map },
    1177              :     "valid" : true/false}.  */
    1178              : 
    1179              : std::unique_ptr<json::object>
    1180            0 : program_state::to_json (const extrinsic_state &ext_state) const
    1181              : {
    1182            0 :   auto state_obj = std::make_unique<json::object> ();
    1183              : 
    1184            0 :   state_obj->set ("store", m_region_model->get_store ()->to_json ());
    1185            0 :   state_obj->set ("constraints",
    1186            0 :                   m_region_model->get_constraints ()->to_json ());
    1187            0 :   if (m_region_model->get_current_frame ())
    1188            0 :     state_obj->set ("curr_frame",
    1189            0 :                     m_region_model->get_current_frame ()->to_json ());
    1190              : 
    1191              :   /* Provide m_checker_states as an object, using names as keys.  */
    1192            0 :   {
    1193            0 :     auto checkers_obj = std::make_unique<json::object> ();
    1194              : 
    1195            0 :     int i;
    1196            0 :     sm_state_map *smap;
    1197            0 :     FOR_EACH_VEC_ELT (m_checker_states, i, smap)
    1198            0 :       if (!smap->is_empty_p ())
    1199            0 :         checkers_obj->set (ext_state.get_name (i), smap->to_json ());
    1200              : 
    1201            0 :     state_obj->set ("checkers", std::move (checkers_obj));
    1202            0 :   }
    1203              : 
    1204            0 :   state_obj->set_bool ("valid", m_valid);
    1205              : 
    1206            0 :   return state_obj;
    1207              : }
    1208              : 
    1209              : 
    1210              : std::unique_ptr<text_art::tree_widget>
    1211            0 : program_state::make_dump_widget (const text_art::dump_widget_info &dwi) const
    1212              : {
    1213            0 :   using text_art::tree_widget;
    1214            0 :   std::unique_ptr<tree_widget> state_widget
    1215            0 :     (tree_widget::from_fmt (dwi, nullptr, "State"));
    1216              : 
    1217            0 :   state_widget->add_child (m_region_model->make_dump_widget (dwi));
    1218              : 
    1219              :   /* Add nodes for any sm_state_maps with state.  */
    1220            0 :   {
    1221            0 :     int i;
    1222            0 :     sm_state_map *smap;
    1223            0 :     FOR_EACH_VEC_ELT (m_checker_states, i, smap)
    1224            0 :       if (!smap->is_empty_p ())
    1225            0 :         state_widget->add_child (smap->make_dump_widget (dwi, m_region_model));
    1226              :   }
    1227              : 
    1228            0 :   return state_widget;
    1229              : }
    1230              : 
    1231              : void
    1232            0 : program_state::dump_dot (const extrinsic_state &ext_state) const
    1233              : {
    1234            0 :   auto state_graph = make_diagnostic_state_graph (ext_state);
    1235              : 
    1236            0 :   gcc_assert (global_dc);
    1237            0 :   auto logical_loc_mgr = global_dc->get_logical_location_manager ();
    1238            0 :   gcc_assert (logical_loc_mgr);
    1239              : 
    1240            0 :   auto graph = diagnostics::state_graphs::make_dot_graph (*state_graph,
    1241            0 :                                                           *logical_loc_mgr);
    1242              : 
    1243            0 :   pretty_printer pp;
    1244            0 :   dot::writer w (pp);
    1245            0 :   graph->print (w);
    1246            0 :   pp_flush (&pp);
    1247            0 : }
    1248              : 
    1249              : /* Update this program_state to reflect a top-level call to FUN.
    1250              :    The params will have initial_svalues.  */
    1251              : 
    1252              : void
    1253        10061 : program_state::push_frame (const extrinsic_state &ext_state ATTRIBUTE_UNUSED,
    1254              :                            const function &fun)
    1255              : {
    1256        10061 :   m_region_model->push_frame (fun, nullptr, nullptr, nullptr);
    1257        10061 : }
    1258              : 
    1259              : /* Get the current function of this state.  */
    1260              : 
    1261              : const function *
    1262           22 : program_state::get_current_function () const
    1263              : {
    1264           22 :   return m_region_model->get_current_function ();
    1265              : }
    1266              : 
    1267              : /* Generate a simpler version of THIS, discarding state that's no longer
    1268              :    relevant at POINT.
    1269              :    The idea is that we're more likely to be able to consolidate
    1270              :    multiple (point, state) into single exploded_nodes if we discard
    1271              :    irrelevant state (e.g. at the end of functions).  */
    1272              : 
    1273              : program_state
    1274       397148 : program_state::prune_for_point (exploded_graph &eg,
    1275              :                                 const program_point &point,
    1276              :                                 exploded_node *enode_for_diag,
    1277              :                                 uncertainty_t *uncertainty) const
    1278              : {
    1279       397148 :   logger * const logger = eg.get_logger ();
    1280       397148 :   LOG_SCOPE (logger);
    1281              : 
    1282       397148 :   function *fun = point.get_function ();
    1283       393771 :   if (!fun)
    1284         3377 :     return *this;
    1285              : 
    1286       393771 :   program_state new_state (*this);
    1287              : 
    1288       393771 :   const state_purge_map *pm = eg.get_purge_map ();
    1289       393771 :   if (pm)
    1290              :     {
    1291       393393 :       unsigned num_ssas_purged = 0;
    1292       393393 :       unsigned num_decls_purged = 0;
    1293       393393 :       auto_vec<const decl_region *> regs;
    1294       393393 :       new_state.m_region_model->get_regions_for_current_frame (&regs);
    1295       393393 :       regs.qsort (region::cmp_ptr_ptr);
    1296              :       unsigned i;
    1297              :       const decl_region *reg;
    1298      2134788 :       FOR_EACH_VEC_ELT (regs, i, reg)
    1299              :         {
    1300      1741395 :           const tree node = reg->get_decl ();
    1301      1741395 :           if (TREE_CODE (node) == SSA_NAME)
    1302              :             {
    1303      1456987 :               const tree ssa_name = node;
    1304      1456987 :               const state_purge_per_ssa_name &per_ssa
    1305      1456987 :                 = pm->get_data_for_ssa_name (node);
    1306      1456987 :               if (!per_ssa.needed_at_supernode_p (point.get_supernode ()))
    1307              :                 {
    1308              :                   /* Don't purge bindings of SSA names to svalues
    1309              :                      that have unpurgable sm-state, so that leaks are
    1310              :                      reported at the end of the function, rather than
    1311              :                      at the last place that such an SSA name is referred to.
    1312              : 
    1313              :                      But do purge them for temporaries (when SSA_NAME_VAR is
    1314              :                      NULL), so that we report for cases where a leak happens when
    1315              :                      a variable is overwritten with another value, so that the leak
    1316              :                      is reported at the point of overwrite, rather than having
    1317              :                      temporaries keep the value reachable until the frame is
    1318              :                      popped.  */
    1319       232531 :                   const svalue *sval
    1320       232531 :                     = new_state.m_region_model->get_store_value (reg, nullptr);
    1321       232531 :                   if (!new_state.can_purge_p (eg.get_ext_state (), sval)
    1322       257014 :                       && SSA_NAME_VAR (ssa_name))
    1323              :                     {
    1324              :                       /* (currently only state maps can keep things
    1325              :                          alive).  */
    1326        18699 :                       if (logger)
    1327            0 :                         logger->log ("not purging binding for %qE"
    1328              :                                      " (used by state map)", ssa_name);
    1329        18699 :                       continue;
    1330              :                     }
    1331              : 
    1332       213832 :                   new_state.m_region_model->purge_region (reg);
    1333       213832 :                   num_ssas_purged++;
    1334              :                 }
    1335              :             }
    1336              :           else
    1337              :             {
    1338       284408 :               const tree decl = node;
    1339       284408 :               gcc_assert (TREE_CODE (node) == VAR_DECL
    1340              :                           || TREE_CODE (node) == PARM_DECL
    1341              :                           || TREE_CODE (node) == RESULT_DECL);
    1342       568816 :               if (const state_purge_per_decl *per_decl
    1343       284408 :                   = pm->get_any_data_for_decl (decl))
    1344       262901 :                 if (!per_decl->needed_at_supernode_p (point.get_supernode ()))
    1345              :                   {
    1346              :                     /* Don't purge bindings of decls if there are svalues
    1347              :                        that have unpurgable sm-state within the decl's cluster,
    1348              :                        so that leaks are reported at the end of the function,
    1349              :                        rather than at the last place that such a decl is
    1350              :                        referred to.  */
    1351         3530 :                     if (!new_state.can_purge_base_region_p (eg.get_ext_state (),
    1352              :                                                             reg))
    1353              :                       {
    1354              :                         /* (currently only state maps can keep things
    1355              :                            alive).  */
    1356          783 :                         if (logger)
    1357            0 :                           logger->log ("not purging binding for %qE"
    1358              :                                        " (value in binding used by state map)",
    1359              :                                        decl);
    1360          783 :                         continue;
    1361              :                       }
    1362              : 
    1363         2747 :                     new_state.m_region_model->purge_region (reg);
    1364         2747 :                     num_decls_purged++;
    1365              :                   }
    1366              :             }
    1367              :         }
    1368              : 
    1369       393393 :       if (num_ssas_purged > 0 || num_decls_purged > 0)
    1370              :         {
    1371       164770 :           if (logger)
    1372              :             {
    1373          108 :               logger->log ("num_ssas_purged: %i", num_ssas_purged);
    1374          108 :               logger->log ("num_decl_purged: %i", num_decls_purged);
    1375              :             }
    1376       164770 :           impl_region_model_context ctxt (eg, enode_for_diag,
    1377              :                                           this,
    1378              :                                           &new_state,
    1379              :                                           uncertainty,
    1380       164770 :                                           nullptr);
    1381       164770 :           detect_leaks (*this, new_state, nullptr, eg.get_ext_state (), &ctxt);
    1382       164770 :         }
    1383       393393 :     }
    1384              : 
    1385       393771 :   new_state.m_region_model->canonicalize ();
    1386              : 
    1387       393771 :   return new_state;
    1388       397148 : }
    1389              : 
    1390              : /* Return true if there are no unpurgeable bindings within BASE_REG. */
    1391              : 
    1392              : bool
    1393         3530 : program_state::can_purge_base_region_p (const extrinsic_state &ext_state,
    1394              :                                         const region *base_reg) const
    1395              : {
    1396         3530 :   binding_cluster *cluster
    1397         3530 :     = m_region_model->get_store ()->get_cluster (base_reg);
    1398         3530 :   if (!cluster)
    1399              :     return true;
    1400              : 
    1401         9115 :   for (auto iter : *cluster)
    1402              :     {
    1403         6368 :       const svalue *sval = iter.m_sval;
    1404         6368 :       if (!can_purge_p (ext_state, sval))
    1405          783 :         return false;
    1406              :     }
    1407              : 
    1408         2747 :   return true;
    1409              : }
    1410              : 
    1411              : /* Get a representative tree to use for describing SVAL.  */
    1412              : 
    1413              : tree
    1414            0 : program_state::get_representative_tree (const svalue *sval) const
    1415              : {
    1416            0 :   gcc_assert (m_region_model);
    1417            0 :   return m_region_model->get_representative_tree (sval);
    1418              : }
    1419              : 
    1420              : /* Attempt to merge this state with OTHER, both at POINT.
    1421              :    Write the result to *OUT.
    1422              :    If the states were merged successfully, return true.  */
    1423              : 
    1424              : bool
    1425       345838 : program_state::can_merge_with_p (const program_state &other,
    1426              :                                  const extrinsic_state &ext_state,
    1427              :                                  const program_point &point,
    1428              :                                  program_state *out) const
    1429              : {
    1430       345838 :   gcc_assert (out);
    1431       345838 :   gcc_assert (m_region_model);
    1432              : 
    1433              :   /* Attempt to merge the sm-states.  */
    1434              :   int i;
    1435              :   sm_state_map *smap;
    1436      1765927 :   FOR_EACH_VEC_ELT (out->m_checker_states, i, smap)
    1437      3236334 :     if (!m_checker_states[i]->can_merge_with_p (*other.m_checker_states[i],
    1438              :                                                 ext_state.get_sm (i),
    1439              :                                                 ext_state,
    1440      1618167 :                                                 &out->m_checker_states[i]))
    1441              :       return false;
    1442              : 
    1443              :   /* Attempt to merge the region_models.  */
    1444       147760 :   if (!m_region_model->can_merge_with_p (*other.m_region_model,
    1445              :                                           point,
    1446              :                                          out->m_region_model,
    1447              :                                          &ext_state,
    1448              :                                          this, &other))
    1449              :     return false;
    1450              : 
    1451        39966 :   out->m_region_model->canonicalize ();
    1452              : 
    1453        39966 :   return true;
    1454              : }
    1455              : 
    1456              : /* Assert that this object is valid.  */
    1457              : 
    1458              : void
    1459      1718070 : program_state::validate (const extrinsic_state &ext_state) const
    1460              : {
    1461              :   /* Skip this in a release build.  */
    1462              : #if !CHECKING_P
    1463              :   return;
    1464              : #endif
    1465              : 
    1466      3436140 :   gcc_assert (m_checker_states.length () == ext_state.get_num_checkers ());
    1467      1718070 :   m_region_model->validate ();
    1468      1718070 : }
    1469              : 
    1470              : static void
    1471          538 : log_set_of_svalues (logger *logger, const char *name,
    1472              :                     const svalue_set &set)
    1473              : {
    1474          538 :   logger->log ("%s", name);
    1475          538 :   logger->inc_indent ();
    1476          538 :   auto_vec<const svalue *> sval_vecs (set.elements ());
    1477          538 :   for (svalue_set::iterator iter = set.begin ();
    1478         4772 :        iter != set.end (); ++iter)
    1479         2117 :     sval_vecs.quick_push (*iter);
    1480          538 :   sval_vecs.qsort (svalue::cmp_ptr_ptr);
    1481              :   unsigned i;
    1482              :   const svalue *sval;
    1483         2655 :   FOR_EACH_VEC_ELT (sval_vecs, i, sval)
    1484              :     {
    1485         2117 :       logger->start_log_line ();
    1486         2117 :       pretty_printer *pp = logger->get_printer ();
    1487         2117 :       if (!flag_dump_noaddr)
    1488              :         {
    1489         2117 :           pp_pointer (pp, sval);
    1490         2117 :           pp_string (pp, ": ");
    1491              :         }
    1492         2117 :       sval->dump_to_pp (pp, false);
    1493         2117 :       logger->end_log_line ();
    1494              :     }
    1495          538 :   logger->dec_indent ();
    1496          538 : }
    1497              : 
    1498              : /* Compare the sets of svalues reachable from each of SRC_STATE and DEST_STATE.
    1499              :    For all svalues that are reachable in SRC_STATE and are not live in
    1500              :    DEST_STATE (whether explicitly reachable in DEST_STATE, or implicitly live
    1501              :    based on the former set), call CTXT->on_svalue_leak for them.
    1502              : 
    1503              :    Call on_liveness_change on both the CTXT and on the DEST_STATE's
    1504              :    constraint_manager, purging dead svalues from sm-state and from
    1505              :    constraints, respectively.
    1506              : 
    1507              :    This function should be called at each fine-grained state change, not
    1508              :    just at exploded edges.  */
    1509              : 
    1510              : void
    1511       484105 : program_state::detect_leaks (const program_state &src_state,
    1512              :                              const program_state &dest_state,
    1513              :                              const svalue *extra_sval,
    1514              :                              const extrinsic_state &ext_state,
    1515              :                              region_model_context *ctxt)
    1516              : {
    1517       484105 :   logger *logger = ext_state.get_logger ();
    1518       484105 :   LOG_SCOPE (logger);
    1519       484105 :   const uncertainty_t *uncertainty = ctxt->get_uncertainty ();
    1520       484105 :   if (logger)
    1521              :     {
    1522          269 :       pretty_printer *pp = logger->get_printer ();
    1523          269 :       logger->start_log_line ();
    1524          269 :       pp_string (pp, "src_state: ");
    1525          269 :       src_state.dump_to_pp (ext_state, true, false, pp);
    1526          269 :       logger->end_log_line ();
    1527          269 :       logger->start_log_line ();
    1528          269 :       pp_string (pp, "dest_state: ");
    1529          269 :       dest_state.dump_to_pp (ext_state, true, false, pp);
    1530          269 :       logger->end_log_line ();
    1531          269 :       if (extra_sval)
    1532              :         {
    1533            1 :           logger->start_log_line ();
    1534            1 :           pp_string (pp, "extra_sval: ");
    1535            1 :           extra_sval->dump_to_pp (pp, true);
    1536            1 :           logger->end_log_line ();
    1537              :         }
    1538          269 :       if (uncertainty)
    1539              :         {
    1540          241 :           logger->start_log_line ();
    1541          241 :           pp_string (pp, "uncertainty: ");
    1542          241 :           uncertainty->dump_to_pp (pp, true);
    1543          241 :           logger->end_log_line ();
    1544              :         }
    1545              :     }
    1546              : 
    1547              :   /* Get svalues reachable from each of src_state and dest_state.
    1548              :      Get svalues *known* to be reachable in src_state.
    1549              :      Pass in uncertainty for dest_state so that we additionally get svalues that
    1550              :      *might* still be reachable in dst_state.  */
    1551       484105 :   svalue_set known_src_svalues;
    1552       484105 :   src_state.m_region_model->get_reachable_svalues (&known_src_svalues,
    1553              :                                                    nullptr, nullptr);
    1554       484105 :   svalue_set maybe_dest_svalues;
    1555       484105 :   dest_state.m_region_model->get_reachable_svalues (&maybe_dest_svalues,
    1556              :                                                     extra_sval, uncertainty);
    1557              : 
    1558       484105 :   if (logger)
    1559              :     {
    1560          269 :       log_set_of_svalues (logger, "src_state known reachable svalues:",
    1561              :                           known_src_svalues);
    1562          269 :       log_set_of_svalues (logger, "dest_state maybe reachable svalues:",
    1563              :                           maybe_dest_svalues);
    1564              :     }
    1565              : 
    1566       484105 :   auto_vec <const svalue *> dead_svals (known_src_svalues.elements ());
    1567      4887252 :   for (svalue_set::iterator iter = known_src_svalues.begin ();
    1568      9290399 :        iter != known_src_svalues.end (); ++iter)
    1569              :     {
    1570      4403147 :       const svalue *sval = (*iter);
    1571              :       /* For each sval reachable from SRC_STATE, determine if it is
    1572              :          live in DEST_STATE: either explicitly reachable, implicitly
    1573              :          live based on the set of explicitly reachable svalues,
    1574              :          or possibly reachable as recorded in uncertainty.
    1575              :          Record those that have ceased to be live i.e. were known
    1576              :          to be live, and are now not known to be even possibly-live.  */
    1577      4403147 :       if (!sval->live_p (&maybe_dest_svalues, dest_state.m_region_model))
    1578        86493 :         dead_svals.quick_push (sval);
    1579              :     }
    1580              : 
    1581              :   /* Call CTXT->on_svalue_leak on all svals in SRC_STATE  that have ceased
    1582              :      to be live, sorting them first to ensure deterministic behavior.  */
    1583       484105 :   dead_svals.qsort (svalue::cmp_ptr_ptr);
    1584              :   unsigned i;
    1585              :   const svalue *sval;
    1586       570598 :   FOR_EACH_VEC_ELT (dead_svals, i, sval)
    1587        86493 :     ctxt->on_svalue_leak (sval);
    1588              : 
    1589              :   /* Purge dead svals from sm-state.  */
    1590       484105 :   ctxt->on_liveness_change (maybe_dest_svalues,
    1591       484105 :                             dest_state.m_region_model);
    1592              : 
    1593              :   /* Purge dead svals from constraints.  */
    1594       484105 :   dest_state.m_region_model->get_constraints ()->on_liveness_change
    1595       484105 :     (maybe_dest_svalues, dest_state.m_region_model);
    1596              : 
    1597              :   /* Purge dead heap-allocated regions from dynamic extents.  */
    1598      1450598 :   for (const svalue *sval : dead_svals)
    1599        86493 :     if (const region *reg = sval->maybe_get_region ())
    1600        19286 :       if (reg->get_kind () == RK_HEAP_ALLOCATED)
    1601         6838 :         dest_state.m_region_model->unset_dynamic_extents (reg);
    1602       484105 : }
    1603              : 
    1604              : /* Attempt to use R to replay SUMMARY into this object.
    1605              :    Return true if it is possible.  */
    1606              : 
    1607              : bool
    1608         1541 : program_state::replay_call_summary (call_summary_replay &r,
    1609              :                                     const program_state &summary)
    1610              : {
    1611         1541 :   if (!m_region_model->replay_call_summary (r, *summary.m_region_model))
    1612              :     return false;
    1613              : 
    1614        11336 :   for (unsigned sm_idx = 0; sm_idx < m_checker_states.length (); sm_idx++)
    1615              :     {
    1616         9919 :       const sm_state_map *summary_sm_map = summary.m_checker_states[sm_idx];
    1617         9919 :       m_checker_states[sm_idx]->replay_call_summary (r, *summary_sm_map);
    1618              :     }
    1619              : 
    1620         1417 :   if (!summary.m_valid)
    1621            0 :     m_valid = false;
    1622              : 
    1623              :   return true;
    1624              : }
    1625              : 
    1626              : /* Handle calls to "__analyzer_dump_state".  */
    1627              : 
    1628              : void
    1629          357 : program_state::impl_call_analyzer_dump_state (const gcall &call,
    1630              :                                               const extrinsic_state &ext_state,
    1631              :                                               region_model_context *ctxt)
    1632              : {
    1633          357 :   call_details cd (call, m_region_model, ctxt);
    1634          357 :   const char *sm_name = cd.get_arg_string_literal (0);
    1635          357 :   if (!sm_name)
    1636              :     {
    1637            4 :       error_at (call.location, "cannot determine state machine");
    1638           12 :       return;
    1639              :     }
    1640          353 :   unsigned sm_idx;
    1641          353 :   if (!ext_state.get_sm_idx_by_name (sm_name, &sm_idx))
    1642              :     {
    1643            4 :       error_at (call.location, "unrecognized state machine %qs", sm_name);
    1644            4 :       return;
    1645              :     }
    1646          349 :   const sm_state_map *smap = m_checker_states[sm_idx];
    1647              : 
    1648          349 :   const svalue *sval = cd.get_arg_svalue (1);
    1649              : 
    1650              :   /* Strip off cast to int (due to variadic args).  */
    1651          349 :   if (const svalue *cast = sval->maybe_undo_cast ())
    1652            5 :     sval = cast;
    1653              : 
    1654          349 :   state_machine::state_t state = smap->get_state (sval, ext_state);
    1655          349 :   warning_at (call.location, 0, "state: %qs", state->get_name ());
    1656              : }
    1657              : 
    1658              : #if CHECKING_P
    1659              : 
    1660              : namespace selftest {
    1661              : 
    1662              : /* Tests for sm_state_map.  */
    1663              : 
    1664              : static void
    1665            4 : test_sm_state_map ()
    1666              : {
    1667            4 :   tree x = build_global_decl ("x", integer_type_node);
    1668            4 :   tree y = build_global_decl ("y", integer_type_node);
    1669            4 :   tree z = build_global_decl ("z", integer_type_node);
    1670              : 
    1671            4 :   std::unique_ptr<state_machine> sm = make_malloc_state_machine (nullptr);
    1672            4 :   state_machine::state_t start = sm->get_start_state ();
    1673            4 :   std::vector<std::unique_ptr<state_machine>> checkers;
    1674            4 :   const state_machine &borrowed_sm = *sm.get ();
    1675            4 :   checkers.push_back (std::move (sm));
    1676            4 :   region_model_manager mgr;
    1677            4 :   engine eng (mgr);
    1678            4 :   extrinsic_state ext_state (std::move (checkers), &eng);
    1679              : 
    1680              :   /* Test setting states on svalue_id instances directly.  */
    1681            4 :   {
    1682            4 :     const state_machine::state test_state_42 ("test state 42", 42);
    1683            4 :     const state_machine::state_t TEST_STATE_42 = &test_state_42;
    1684            4 :     region_model model (&mgr);
    1685            4 :     const svalue *x_sval = model.get_rvalue (x, nullptr);
    1686            4 :     const svalue *y_sval = model.get_rvalue (y, nullptr);
    1687            4 :     const svalue *z_sval = model.get_rvalue (z, nullptr);
    1688              : 
    1689            4 :     sm_state_map map (borrowed_sm);
    1690            4 :     ASSERT_TRUE (map.is_empty_p ());
    1691            4 :     ASSERT_EQ (map.get_state (x_sval, ext_state), start);
    1692              : 
    1693            4 :     map.impl_set_state (x_sval, TEST_STATE_42, z_sval, ext_state);
    1694            4 :     ASSERT_EQ (map.get_state (x_sval, ext_state), TEST_STATE_42);
    1695            4 :     ASSERT_EQ (map.get_origin (x_sval, ext_state), z_sval);
    1696            4 :     ASSERT_EQ (map.get_state (y_sval, ext_state), start);
    1697            4 :     ASSERT_FALSE (map.is_empty_p ());
    1698              : 
    1699            4 :     map.impl_set_state (y_sval, 0, z_sval, ext_state);
    1700            4 :     ASSERT_EQ (map.get_state (y_sval, ext_state), start);
    1701              : 
    1702            4 :     map.impl_set_state (x_sval, 0, z_sval, ext_state);
    1703            4 :     ASSERT_EQ (map.get_state (x_sval, ext_state), start);
    1704            4 :     ASSERT_TRUE (map.is_empty_p ());
    1705            4 :   }
    1706              : 
    1707            4 :   const state_machine::state test_state_5 ("test state 5", 5);
    1708            4 :   const state_machine::state_t TEST_STATE_5 = &test_state_5;
    1709              : 
    1710              :   /* Test setting states via equivalence classes.  */
    1711            4 :   {
    1712            4 :     region_model model (&mgr);
    1713            4 :     const svalue *x_sval = model.get_rvalue (x, nullptr);
    1714            4 :     const svalue *y_sval = model.get_rvalue (y, nullptr);
    1715            4 :     const svalue *z_sval = model.get_rvalue (z, nullptr);
    1716              : 
    1717            4 :     sm_state_map map (borrowed_sm);
    1718            4 :     ASSERT_TRUE (map.is_empty_p ());
    1719            4 :     ASSERT_EQ (map.get_state (x_sval, ext_state), start);
    1720            4 :     ASSERT_EQ (map.get_state (y_sval, ext_state), start);
    1721              : 
    1722            4 :     model.add_constraint (x, EQ_EXPR, y, nullptr);
    1723              : 
    1724              :     /* Setting x to a state should also update y, as they
    1725              :        are in the same equivalence class.  */
    1726            4 :     map.set_state (&model, x_sval, TEST_STATE_5, z_sval, ext_state);
    1727            4 :     ASSERT_EQ (map.get_state (x_sval, ext_state), TEST_STATE_5);
    1728            4 :     ASSERT_EQ (map.get_state (y_sval, ext_state), TEST_STATE_5);
    1729            4 :     ASSERT_EQ (map.get_origin (x_sval, ext_state), z_sval);
    1730            4 :     ASSERT_EQ (map.get_origin (y_sval, ext_state), z_sval);
    1731            4 :   }
    1732              : 
    1733              :   /* Test equality and hashing.  */
    1734            4 :   {
    1735            4 :     region_model model (&mgr);
    1736            4 :     const svalue *y_sval = model.get_rvalue (y, nullptr);
    1737            4 :     const svalue *z_sval = model.get_rvalue (z, nullptr);
    1738              : 
    1739            4 :     sm_state_map map0 (borrowed_sm);
    1740            4 :     sm_state_map map1 (borrowed_sm);
    1741            4 :     sm_state_map map2 (borrowed_sm);
    1742              : 
    1743            4 :     ASSERT_EQ (map0.hash (), map1.hash ());
    1744            4 :     ASSERT_EQ (map0, map1);
    1745              : 
    1746            4 :     map1.impl_set_state (y_sval, TEST_STATE_5, z_sval, ext_state);
    1747            4 :     ASSERT_NE (map0.hash (), map1.hash ());
    1748            4 :     ASSERT_NE (map0, map1);
    1749              : 
    1750              :     /* Make the same change to map2.  */
    1751            4 :     map2.impl_set_state (y_sval, TEST_STATE_5, z_sval, ext_state);
    1752            4 :     ASSERT_EQ (map1.hash (), map2.hash ());
    1753            4 :     ASSERT_EQ (map1, map2);
    1754            4 :   }
    1755              : 
    1756              :   /* Equality and hashing shouldn't depend on ordering.  */
    1757            4 :   {
    1758            4 :     const state_machine::state test_state_2 ("test state 2", 2);
    1759            4 :     const state_machine::state_t TEST_STATE_2 = &test_state_2;
    1760            4 :     const state_machine::state test_state_3 ("test state 3", 3);
    1761            4 :     const state_machine::state_t TEST_STATE_3 = &test_state_3;
    1762            4 :     sm_state_map map0 (borrowed_sm);
    1763            4 :     sm_state_map map1 (borrowed_sm);
    1764            4 :     sm_state_map map2 (borrowed_sm);
    1765              : 
    1766            4 :     ASSERT_EQ (map0.hash (), map1.hash ());
    1767            4 :     ASSERT_EQ (map0, map1);
    1768              : 
    1769            4 :     region_model model (&mgr);
    1770            4 :     const svalue *x_sval = model.get_rvalue (x, nullptr);
    1771            4 :     const svalue *y_sval = model.get_rvalue (y, nullptr);
    1772            4 :     const svalue *z_sval = model.get_rvalue (z, nullptr);
    1773              : 
    1774            4 :     map1.impl_set_state (x_sval, TEST_STATE_2, nullptr, ext_state);
    1775            4 :     map1.impl_set_state (y_sval, TEST_STATE_3, nullptr, ext_state);
    1776            4 :     map1.impl_set_state (z_sval, TEST_STATE_2, nullptr, ext_state);
    1777              : 
    1778            4 :     map2.impl_set_state (z_sval, TEST_STATE_2, nullptr, ext_state);
    1779            4 :     map2.impl_set_state (y_sval, TEST_STATE_3, nullptr, ext_state);
    1780            4 :     map2.impl_set_state (x_sval, TEST_STATE_2, nullptr, ext_state);
    1781              : 
    1782            4 :     ASSERT_EQ (map1.hash (), map2.hash ());
    1783            4 :     ASSERT_EQ (map1, map2);
    1784            4 :   }
    1785              : 
    1786              :   // TODO: coverage for purging
    1787            4 : }
    1788              : 
    1789              : /* Check program_state works as expected.  */
    1790              : 
    1791              : static void
    1792            4 : test_program_state_1 ()
    1793              : {
    1794              :   /* Create a program_state for a global ptr "p" that has
    1795              :      malloc sm-state, pointing to a region on the heap.  */
    1796            4 :   tree p = build_global_decl ("p", ptr_type_node);
    1797              : 
    1798            4 :   std::unique_ptr<state_machine> sm = make_malloc_state_machine (nullptr);
    1799            4 :   const state_machine::state_t UNCHECKED_STATE
    1800            4 :     = sm->get_state_by_name ("unchecked");
    1801              : 
    1802            4 :   region_model_manager mgr;
    1803            4 :   engine eng (mgr);
    1804            4 :   extrinsic_state ext_state (std::move (sm), &eng);
    1805            4 :   program_state s (ext_state);
    1806            4 :   region_model *model = s.m_region_model;
    1807            4 :   const svalue *size_in_bytes
    1808            4 :     = mgr.get_or_create_unknown_svalue (size_type_node);
    1809            4 :   const region *new_reg
    1810            4 :     = model->get_or_create_region_for_heap_alloc (size_in_bytes, nullptr);
    1811            4 :   const svalue *ptr_sval = mgr.get_ptr_svalue (ptr_type_node, new_reg);
    1812            4 :   model->set_value (model->get_lvalue (p, nullptr),
    1813              :                     ptr_sval, nullptr);
    1814            4 :   sm_state_map *smap = s.m_checker_states[0];
    1815              : 
    1816            4 :   smap->impl_set_state (ptr_sval, UNCHECKED_STATE, nullptr, ext_state);
    1817            4 :   ASSERT_EQ (smap->get_state (ptr_sval, ext_state), UNCHECKED_STATE);
    1818            4 : }
    1819              : 
    1820              : /* Check that program_state works for string literals.  */
    1821              : 
    1822              : static void
    1823            4 : test_program_state_2 ()
    1824              : {
    1825              :   /* Create a program_state for a global ptr "p" that points to
    1826              :      a string constant.  */
    1827            4 :   tree p = build_global_decl ("p", ptr_type_node);
    1828              : 
    1829            4 :   tree string_cst_ptr = build_string_literal (4, "foo");
    1830              : 
    1831            4 :   std::vector<std::unique_ptr<state_machine>> checkers;
    1832            4 :   region_model_manager mgr;
    1833            4 :   engine eng (mgr);
    1834            4 :   extrinsic_state ext_state (std::move (checkers), &eng);
    1835              : 
    1836            4 :   program_state s (ext_state);
    1837            4 :   region_model *model = s.m_region_model;
    1838            4 :   const region *p_reg = model->get_lvalue (p, nullptr);
    1839            4 :   const svalue *str_sval = model->get_rvalue (string_cst_ptr, nullptr);
    1840            4 :   model->set_value (p_reg, str_sval, nullptr);
    1841            4 : }
    1842              : 
    1843              : /* Verify that program_states with identical sm-state can be merged,
    1844              :    and that the merged program_state preserves the sm-state.  */
    1845              : 
    1846              : static void
    1847            4 : test_program_state_merging ()
    1848              : {
    1849              :   /* Create a program_state for a global ptr "p" that has
    1850              :      malloc sm-state, pointing to a region on the heap.  */
    1851            4 :   tree p = build_global_decl ("p", ptr_type_node);
    1852              : 
    1853            4 :   region_model_manager mgr;
    1854            4 :   engine eng (mgr);
    1855            4 :   program_point point (program_point::origin (mgr));
    1856            4 :   extrinsic_state ext_state (make_malloc_state_machine (nullptr),
    1857            4 :                              &eng);
    1858              : 
    1859            4 :   program_state s0 (ext_state);
    1860            4 :   uncertainty_t uncertainty;
    1861            4 :   impl_region_model_context ctxt (&s0, ext_state, &uncertainty);
    1862              : 
    1863            4 :   region_model *model0 = s0.m_region_model;
    1864            4 :   const svalue *size_in_bytes
    1865            4 :     = mgr.get_or_create_unknown_svalue (size_type_node);
    1866            4 :   const region *new_reg
    1867            4 :     = model0->get_or_create_region_for_heap_alloc (size_in_bytes, nullptr);
    1868            4 :   const svalue *ptr_sval = mgr.get_ptr_svalue (ptr_type_node, new_reg);
    1869            4 :   model0->set_value (model0->get_lvalue (p, &ctxt),
    1870              :                      ptr_sval, &ctxt);
    1871            4 :   sm_state_map *smap = s0.m_checker_states[0];
    1872            4 :   const state_machine::state test_state ("test state", 0);
    1873            4 :   const state_machine::state_t TEST_STATE = &test_state;
    1874            4 :   smap->impl_set_state (ptr_sval, TEST_STATE, nullptr, ext_state);
    1875            4 :   ASSERT_EQ (smap->get_state (ptr_sval, ext_state), TEST_STATE);
    1876              : 
    1877            4 :   model0->canonicalize ();
    1878              : 
    1879              :   /* Verify that canonicalization preserves sm-state.  */
    1880            4 :   ASSERT_EQ (smap->get_state (model0->get_rvalue (p, nullptr), ext_state),
    1881              :              TEST_STATE);
    1882              : 
    1883              :   /* Make a copy of the program_state.  */
    1884            4 :   program_state s1 (s0);
    1885            4 :   ASSERT_EQ (s0, s1);
    1886              : 
    1887              :   /* We have two identical states with "p" pointing to a heap region
    1888              :      with the given sm-state.
    1889              :      They ought to be mergeable, preserving the sm-state.  */
    1890            4 :   program_state merged (ext_state);
    1891            4 :   ASSERT_TRUE (s0.can_merge_with_p (s1, ext_state, point, &merged));
    1892            4 :   merged.validate (ext_state);
    1893              : 
    1894              :   /* Verify that the merged state has the sm-state for "p".  */
    1895            4 :   region_model *merged_model = merged.m_region_model;
    1896            4 :   sm_state_map *merged_smap = merged.m_checker_states[0];
    1897            4 :   ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, nullptr),
    1898              :                                      ext_state),
    1899              :              TEST_STATE);
    1900              : 
    1901              :   /* Try canonicalizing.  */
    1902            4 :   merged.m_region_model->canonicalize ();
    1903            4 :   merged.validate (ext_state);
    1904              : 
    1905              :   /* Verify that the merged state still has the sm-state for "p".  */
    1906            4 :   ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, nullptr),
    1907              :                                      ext_state),
    1908              :              TEST_STATE);
    1909              : 
    1910              :   /* After canonicalization, we ought to have equality with the inputs.  */
    1911            4 :   ASSERT_EQ (s0, merged);
    1912            8 : }
    1913              : 
    1914              : /* Verify that program_states with different global-state in an sm-state
    1915              :    can't be merged.  */
    1916              : 
    1917              : static void
    1918            4 : test_program_state_merging_2 ()
    1919              : {
    1920            4 :   region_model_manager mgr;
    1921            4 :   engine eng (mgr);
    1922            4 :   program_point point (program_point::origin (mgr));
    1923            4 :   extrinsic_state ext_state (make_signal_state_machine (nullptr), &eng);
    1924              : 
    1925            4 :   const state_machine::state test_state_0 ("test state 0", 0);
    1926            4 :   const state_machine::state test_state_1 ("test state 1", 1);
    1927            4 :   const state_machine::state_t TEST_STATE_0 = &test_state_0;
    1928            4 :   const state_machine::state_t TEST_STATE_1 = &test_state_1;
    1929              : 
    1930            4 :   program_state s0 (ext_state);
    1931            4 :   {
    1932            4 :     sm_state_map *smap0 = s0.m_checker_states[0];
    1933            4 :     smap0->set_global_state (TEST_STATE_0);
    1934            4 :     ASSERT_EQ (smap0->get_global_state (), TEST_STATE_0);
    1935              :   }
    1936              : 
    1937            4 :   program_state s1 (ext_state);
    1938            4 :   {
    1939            4 :     sm_state_map *smap1 = s1.m_checker_states[0];
    1940            4 :     smap1->set_global_state (TEST_STATE_1);
    1941            4 :     ASSERT_EQ (smap1->get_global_state (), TEST_STATE_1);
    1942              :   }
    1943              : 
    1944            4 :   ASSERT_NE (s0, s1);
    1945              : 
    1946              :   /* They ought to not be mergeable.  */
    1947            4 :   program_state merged (ext_state);
    1948            4 :   ASSERT_FALSE (s0.can_merge_with_p (s1, ext_state, point, &merged));
    1949            4 : }
    1950              : 
    1951              : /* Run all of the selftests within this file.  */
    1952              : 
    1953              : void
    1954            4 : analyzer_program_state_cc_tests ()
    1955              : {
    1956            4 :   test_sm_state_map ();
    1957            4 :   test_program_state_1 ();
    1958            4 :   test_program_state_2 ();
    1959            4 :   test_program_state_merging ();
    1960            4 :   test_program_state_merging_2 ();
    1961            4 : }
    1962              : 
    1963              : } // namespace selftest
    1964              : 
    1965              : #endif /* CHECKING_P */
    1966              : 
    1967              : } // namespace ana
    1968              : 
    1969              : #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.