LCOV - code coverage report
Current view: top level - gcc/analyzer - region-model.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.0 % 4424 4072
Test Date: 2026-10-24 16:24:59 Functions: 92.6 % 312 289
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Classes for modeling the state of memory.
       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              : #define INCLUDE_ALGORITHM
      22              : #include "analyzer/common.h"
      23              : 
      24              : #include "ordered-hash-map.h"
      25              : #include "options.h"
      26              : #include "cgraph.h"
      27              : #include "cfg.h"
      28              : #include "sbitmap.h"
      29              : #include "diagnostics/event-id.h"
      30              : #include "stor-layout.h"
      31              : #include "stringpool.h"
      32              : #include "attribs.h"
      33              : #include "tree-object-size.h"
      34              : #include "gimple-ssa.h"
      35              : #include "tree-phinodes.h"
      36              : #include "tree-ssa-operands.h"
      37              : #include "ssa-iterators.h"
      38              : #include "target.h"
      39              : #include "calls.h"
      40              : #include "is-a.h"
      41              : #include "gcc-rich-location.h"
      42              : #include "gcc-urlifier.h"
      43              : #include "diagnostics/sarif-sink.h"
      44              : #include "tree-pretty-print.h"
      45              : #include "fold-const.h"
      46              : #include "selftest-tree.h"
      47              : #include "context.h"
      48              : #include "channels.h"
      49              : #include "value-relation.h"
      50              : #include "range-op.h"
      51              : #include "ipa-utils.h"
      52              : #include "gimple-iterator.h"
      53              : #include "gimple-fold.h"
      54              : 
      55              : #include "text-art/tree-widget.h"
      56              : 
      57              : #include "analyzer/analyzer-logging.h"
      58              : #include "analyzer/supergraph.h"
      59              : #include "analyzer/call-string.h"
      60              : #include "analyzer/program-point.h"
      61              : #include "analyzer/store.h"
      62              : #include "analyzer/region-model.h"
      63              : #include "analyzer/constraint-manager.h"
      64              : #include "analyzer/sm.h"
      65              : #include "analyzer/pending-diagnostic.h"
      66              : #include "analyzer/region-model-reachability.h"
      67              : #include "analyzer/analyzer-selftests.h"
      68              : #include "analyzer/program-state.h"
      69              : #include "analyzer/call-summary.h"
      70              : #include "analyzer/checker-event.h"
      71              : #include "analyzer/checker-path.h"
      72              : #include "analyzer/feasible-graph.h"
      73              : #include "analyzer/record-layout.h"
      74              : #include "analyzer/function-set.h"
      75              : #include "analyzer/state-transition.h"
      76              : 
      77              : #if ENABLE_ANALYZER
      78              : 
      79              : namespace ana {
      80              : 
      81              : /* Dump T to PP in language-independent form, for debugging/logging/dumping
      82              :    purposes.  */
      83              : 
      84              : void
      85        41739 : dump_tree (pretty_printer *pp, tree t)
      86              : {
      87        41739 :   dump_generic_node (pp, t, 0, TDF_SLIM, 0);
      88        41739 : }
      89              : 
      90              : /* Dump T to PP in language-independent form in quotes, for
      91              :    debugging/logging/dumping purposes.  */
      92              : 
      93              : void
      94         1366 : dump_quoted_tree (pretty_printer *pp, tree t)
      95              : {
      96         1366 :   pp_begin_quote (pp, pp_show_color (pp));
      97         1366 :   dump_tree (pp, t);
      98         1366 :   pp_end_quote (pp, pp_show_color (pp));
      99         1366 : }
     100              : 
     101              : /* Equivalent to pp_printf (pp, "%qT", t), to avoid nesting pp_printf
     102              :    calls within other pp_printf calls.
     103              : 
     104              :    default_tree_printer handles 'T' and some other codes by calling
     105              :      dump_generic_node (pp, t, 0, TDF_SLIM, 0);
     106              :    dump_generic_node calls pp_printf in various places, leading to
     107              :    garbled output.
     108              : 
     109              :    Ideally pp_printf could be made to be reentrant, but in the meantime
     110              :    this function provides a workaround.  */
     111              : 
     112              : void
     113         4448 : print_quoted_type (pretty_printer *pp, tree t)
     114              : {
     115         4448 :   if (!t)
     116              :     return;
     117         4355 :   pp_begin_quote (pp, pp_show_color (pp));
     118         4355 :   dump_generic_node (pp, t, 0, TDF_SLIM, 0);
     119         4355 :   pp_end_quote (pp, pp_show_color (pp));
     120              : }
     121              : 
     122              : /* Print EXPR to PP, without quotes.
     123              :    For use within svalue::maybe_print_for_user
     124              :    and region::maybe_print_for_user. */
     125              : 
     126              : void
     127           38 : print_expr_for_user (pretty_printer *pp, tree expr)
     128              : {
     129              :   /* Workaround for C++'s lang_hooks.decl_printable_name,
     130              :      which unhelpfully (for us) prefixes the decl with its
     131              :      type.  */
     132           38 :   if (DECL_P (expr))
     133           38 :     dump_generic_node (pp, expr, 0, TDF_SLIM, 0);
     134              :   else
     135            0 :     pp_printf (pp, "%E", expr);
     136           38 : }
     137              : 
     138              : /* class region_to_value_map.  */
     139              : 
     140              : /* Assignment operator for region_to_value_map.  */
     141              : 
     142              : region_to_value_map &
     143        99055 : region_to_value_map::operator= (const region_to_value_map &other)
     144              : {
     145        99055 :   m_hash_map.empty ();
     146       128886 :   for (auto iter : other.m_hash_map)
     147              :     {
     148        29831 :       const region *reg = iter.first;
     149        29831 :       const svalue *sval = iter.second;
     150        29831 :       m_hash_map.put (reg, sval);
     151              :     }
     152        99055 :   return *this;
     153              : }
     154              : 
     155              : /* Equality operator for region_to_value_map.  */
     156              : 
     157              : bool
     158       485247 : region_to_value_map::operator== (const region_to_value_map &other) const
     159              : {
     160       485247 :   if (m_hash_map.elements () != other.m_hash_map.elements ())
     161              :     return false;
     162              : 
     163       621374 :   for (auto iter : *this)
     164              :     {
     165       138794 :       const region *reg = iter.first;
     166       138794 :       const svalue *sval = iter.second;
     167       138794 :       const svalue * const *other_slot = other.get (reg);
     168       138794 :       if (other_slot == nullptr)
     169           58 :         return false;
     170       138764 :       if (sval != *other_slot)
     171              :         return false;
     172              :     }
     173              : 
     174       482580 :   return true;
     175              : }
     176              : 
     177              : /* Dump this object to PP.  */
     178              : 
     179              : void
     180          416 : region_to_value_map::dump_to_pp (pretty_printer *pp, bool simple,
     181              :                                  bool multiline) const
     182              : {
     183          416 :   auto_vec<const region *> regs;
     184          832 :   for (iterator iter = begin (); iter != end (); ++iter)
     185          416 :     regs.safe_push ((*iter).first);
     186          416 :   regs.qsort (region::cmp_ptr_ptr);
     187          416 :   if (multiline)
     188          416 :     pp_newline (pp);
     189              :   else
     190            0 :     pp_string (pp, " {");
     191          416 :   unsigned i;
     192          416 :   const region *reg;
     193          832 :   FOR_EACH_VEC_ELT (regs, i, reg)
     194              :     {
     195          416 :       if (multiline)
     196          416 :         pp_string (pp, "  ");
     197            0 :       else if (i > 0)
     198            0 :         pp_string (pp, ", ");
     199          416 :       reg->dump_to_pp (pp, simple);
     200          416 :       pp_string (pp, ": ");
     201          416 :       const svalue *sval = *get (reg);
     202          416 :       sval->dump_to_pp (pp, true);
     203          416 :       if (multiline)
     204          416 :         pp_newline (pp);
     205              :     }
     206          416 :   if (!multiline)
     207            0 :     pp_string (pp, "}");
     208          416 : }
     209              : 
     210              : /* Dump this object to stderr.  */
     211              : 
     212              : DEBUG_FUNCTION void
     213            0 : region_to_value_map::dump (bool simple) const
     214              : {
     215            0 :   tree_dump_pretty_printer pp (stderr);
     216            0 :   dump_to_pp (&pp, simple, true);
     217            0 :   pp_newline (&pp);
     218            0 : }
     219              : 
     220              : /* Generate a JSON value for this region_to_value_map.
     221              :    This is intended for debugging the analyzer rather than
     222              :    serialization.  */
     223              : 
     224              : std::unique_ptr<json::object>
     225            4 : region_to_value_map::to_json () const
     226              : {
     227            4 :   auto map_obj = std::make_unique<json::object> ();
     228              : 
     229            4 :   auto_vec<const region *> regs;
     230            4 :   for (iterator iter = begin (); iter != end (); ++iter)
     231            0 :     regs.safe_push ((*iter).first);
     232            4 :   regs.qsort (region::cmp_ptr_ptr);
     233              : 
     234            4 :   unsigned i;
     235            4 :   const region *reg;
     236            4 :   FOR_EACH_VEC_ELT (regs, i, reg)
     237              :     {
     238            0 :       label_text reg_desc = reg->get_desc ();
     239            0 :       const svalue *sval = *get (reg);
     240            0 :       map_obj->set (reg_desc.get (), sval->to_json ());
     241            0 :     }
     242              : 
     243            4 :   return map_obj;
     244            4 : }
     245              : 
     246              : std::unique_ptr<text_art::tree_widget>
     247            4 : region_to_value_map::
     248              : make_dump_widget (const text_art::dump_widget_info &dwi) const
     249              : {
     250            4 :   if (is_empty ())
     251            4 :     return nullptr;
     252              : 
     253            0 :   std::unique_ptr<text_art::tree_widget> w
     254            0 :     (text_art::tree_widget::make (dwi, "Dynamic Extents"));
     255              : 
     256            0 :   auto_vec<const region *> regs;
     257            0 :   for (iterator iter = begin (); iter != end (); ++iter)
     258            0 :     regs.safe_push ((*iter).first);
     259            0 :   regs.qsort (region::cmp_ptr_ptr);
     260              : 
     261            0 :   unsigned i;
     262            0 :   const region *reg;
     263            0 :   FOR_EACH_VEC_ELT (regs, i, reg)
     264              :     {
     265            0 :       pretty_printer the_pp;
     266            0 :       pretty_printer * const pp = &the_pp;
     267            0 :       pp_format_decoder (pp) = default_tree_printer;
     268            0 :       const bool simple = true;
     269              : 
     270            0 :       reg->dump_to_pp (pp, simple);
     271            0 :       pp_string (pp, ": ");
     272            0 :       const svalue *sval = *get (reg);
     273            0 :       sval->dump_to_pp (pp, true);
     274            0 :       w->add_child (text_art::tree_widget::make (dwi, pp));
     275            0 :     }
     276            0 :   return w;
     277            0 : }
     278              : 
     279              : /* Attempt to merge THIS with OTHER, writing the result
     280              :    to OUT.
     281              : 
     282              :    For now, write (region, value) mappings that are in common between THIS
     283              :    and OTHER to OUT, effectively taking the intersection.
     284              : 
     285              :    Reject merger of different values.  */
     286              : 
     287              : bool
     288        42550 : region_to_value_map::can_merge_with_p (const region_to_value_map &other,
     289              :                                        region_to_value_map *out) const
     290              : {
     291        50078 :   for (auto iter : *this)
     292              :     {
     293         9396 :       const region *iter_reg = iter.first;
     294         9396 :       const svalue *iter_sval = iter.second;
     295         9396 :       const svalue * const * other_slot = other.get (iter_reg);
     296         9396 :       if (other_slot)
     297              :         {
     298         9119 :           if (iter_sval == *other_slot)
     299         7251 :             out->put (iter_reg, iter_sval);
     300              :           else
     301         1868 :             return false;
     302              :         }
     303              :     }
     304        40682 :   return true;
     305              : }
     306              : 
     307              : /* Purge any state involving SVAL.  */
     308              : 
     309              : void
     310        30285 : region_to_value_map::purge_state_involving (const svalue *sval)
     311              : {
     312        30285 :   auto_vec<const region *> to_purge;
     313        53616 :   for (auto iter : *this)
     314              :     {
     315        23331 :       const region *iter_reg = iter.first;
     316        23331 :       const svalue *iter_sval = iter.second;
     317        23331 :       if (iter_reg->involves_p (sval) || iter_sval->involves_p (sval))
     318           26 :         to_purge.safe_push (iter_reg);
     319              :     }
     320        30363 :   for (auto iter : to_purge)
     321           26 :     m_hash_map.remove (iter);
     322        30285 : }
     323              : 
     324              : // struct exception_node
     325              : 
     326              : bool
     327        11319 : exception_node::operator== (const exception_node &other) const
     328              : {
     329        11319 :   return (m_exception_sval == other.m_exception_sval
     330        11319 :           && m_typeinfo_sval == other.m_typeinfo_sval
     331        22638 :           && m_destructor_sval == other.m_destructor_sval);
     332              : }
     333              : 
     334              : void
     335            6 : exception_node::dump_to_pp (pretty_printer *pp,
     336              :                             bool simple) const
     337              : {
     338            6 :   pp_printf (pp, "{exception: ");
     339            6 :   m_exception_sval->dump_to_pp (pp, simple);
     340            6 :   pp_string (pp, ", typeinfo: ");
     341            6 :   m_typeinfo_sval->dump_to_pp (pp, simple);
     342            6 :   pp_string (pp, ", destructor: ");
     343            6 :   m_destructor_sval->dump_to_pp (pp, simple);
     344            6 :   pp_string (pp, "}");
     345            6 : }
     346              : 
     347              : void
     348            0 : exception_node::dump (FILE *fp, bool simple) const
     349              : {
     350            0 :   tree_dump_pretty_printer pp (fp);
     351            0 :   dump_to_pp (&pp, simple);
     352            0 :   pp_newline (&pp);
     353            0 : }
     354              : 
     355              : /* Dump a multiline representation of this model to stderr.  */
     356              : 
     357              : DEBUG_FUNCTION void
     358            0 : exception_node::dump (bool simple) const
     359              : {
     360            0 :   dump (stderr, simple);
     361            0 : }
     362              : 
     363              : DEBUG_FUNCTION void
     364            0 : exception_node::dump () const
     365              : {
     366            0 :   text_art::dump (*this);
     367            0 : }
     368              : 
     369              : std::unique_ptr<json::object>
     370            0 : exception_node::to_json () const
     371              : {
     372            0 :   auto obj = std::make_unique<json::object> ();
     373            0 :   obj->set ("exception", m_exception_sval->to_json ());
     374            0 :   obj->set ("typeinfo", m_typeinfo_sval->to_json ());
     375            0 :   obj->set ("destructor", m_destructor_sval->to_json ());
     376            0 :   return obj;
     377              : }
     378              : 
     379              : std::unique_ptr<text_art::tree_widget>
     380            0 : exception_node::make_dump_widget (const text_art::dump_widget_info &dwi) const
     381              : {
     382            0 :   using text_art::tree_widget;
     383            0 :   std::unique_ptr<tree_widget> w
     384            0 :     (tree_widget::from_fmt (dwi, nullptr, "Exception Node"));
     385              : 
     386            0 :   w->add_child (m_exception_sval->make_dump_widget (dwi, "exception"));
     387            0 :   w->add_child (m_typeinfo_sval->make_dump_widget (dwi, "typeinfo"));
     388            0 :   w->add_child (m_destructor_sval->make_dump_widget (dwi, "destructor"));
     389              : 
     390            0 :   return w;
     391              : }
     392              : 
     393              : tree
     394          697 : exception_node::maybe_get_type () const
     395              : {
     396          697 :   return m_typeinfo_sval->maybe_get_type_from_typeinfo ();
     397              : }
     398              : 
     399              : void
     400           64 : exception_node::add_to_reachable_regions (reachable_regions &regs) const
     401              : {
     402           64 :   regs.handle_sval (m_exception_sval);
     403           64 :   regs.handle_sval (m_typeinfo_sval);
     404           64 :   regs.handle_sval (m_destructor_sval);
     405           64 : }
     406              : 
     407              : /* class region_model.  */
     408              : 
     409              : /* Ctor for region_model: construct an "empty" model.  */
     410              : 
     411       421442 : region_model::region_model (region_model_manager *mgr)
     412       421442 : : m_mgr (mgr), m_store (), m_current_frame (nullptr),
     413       421442 :   m_thrown_exceptions_stack (),
     414       421442 :   m_caught_exceptions_stack (),
     415       421442 :   m_dynamic_extents ()
     416              : {
     417       421442 :   m_constraints = new constraint_manager (mgr);
     418       421442 : }
     419              : 
     420              : /* region_model's copy ctor.  */
     421              : 
     422      3268755 : region_model::region_model (const region_model &other)
     423      3268755 : : m_mgr (other.m_mgr), m_store (other.m_store),
     424      3268755 :   m_constraints (new constraint_manager (*other.m_constraints)),
     425      3268755 :   m_current_frame (other.m_current_frame),
     426      3268755 :   m_thrown_exceptions_stack (other.m_thrown_exceptions_stack),
     427      3268755 :   m_caught_exceptions_stack (other.m_caught_exceptions_stack),
     428      3268755 :   m_dynamic_extents (other.m_dynamic_extents)
     429              : {
     430      3268755 : }
     431              : 
     432              : /* region_model's dtor.  */
     433              : 
     434      3690197 : region_model::~region_model ()
     435              : {
     436      3690197 :   delete m_constraints;
     437      3690197 : }
     438              : 
     439              : /* region_model's assignment operator.  */
     440              : 
     441              : region_model &
     442        99055 : region_model::operator= (const region_model &other)
     443              : {
     444              :   /* m_mgr is const.  */
     445        99055 :   gcc_assert (m_mgr == other.m_mgr);
     446              : 
     447        99055 :   m_store = other.m_store;
     448              : 
     449        99055 :   delete m_constraints;
     450        99055 :   m_constraints = new constraint_manager (*other.m_constraints);
     451              : 
     452        99055 :   m_current_frame = other.m_current_frame;
     453              : 
     454        99055 :   m_thrown_exceptions_stack = other.m_thrown_exceptions_stack;
     455        99055 :   m_caught_exceptions_stack = other.m_caught_exceptions_stack;
     456              : 
     457        99055 :   m_dynamic_extents = other.m_dynamic_extents;
     458              : 
     459        99055 :   return *this;
     460              : }
     461              : 
     462              : /* Equality operator for region_model.
     463              : 
     464              :    Amongst other things this directly compares the stores and the constraint
     465              :    managers, so for this to be meaningful both this and OTHER should
     466              :    have been canonicalized.  */
     467              : 
     468              : bool
     469       543072 : region_model::operator== (const region_model &other) const
     470              : {
     471              :   /* We can only compare instances that use the same manager.  */
     472       543072 :   gcc_assert (m_mgr == other.m_mgr);
     473              : 
     474       543072 :   if (m_store != other.m_store)
     475              :     return false;
     476              : 
     477       444039 :   if (*m_constraints != *other.m_constraints)
     478              :     return false;
     479              : 
     480       439067 :   if (m_current_frame != other.m_current_frame)
     481              :     return false;
     482              : 
     483       439059 :   if (m_thrown_exceptions_stack != other.m_thrown_exceptions_stack)
     484              :     return false;
     485       439059 :   if (m_caught_exceptions_stack != other.m_caught_exceptions_stack)
     486              :     return false;
     487              : 
     488       439059 :   if (m_dynamic_extents != other.m_dynamic_extents)
     489              :     return false;
     490              : 
     491       438790 :   gcc_checking_assert (hash () == other.hash ());
     492              : 
     493              :   return true;
     494              : }
     495              : 
     496              : /* Generate a hash value for this region_model.  */
     497              : 
     498              : hashval_t
     499      1358981 : region_model::hash () const
     500              : {
     501      1358981 :   hashval_t result = m_store.hash ();
     502      1358981 :   result ^= m_constraints->hash ();
     503      1358981 :   return result;
     504              : }
     505              : 
     506              : /* Dump a representation of this model to PP, showing the
     507              :    stack, the store, and any constraints.
     508              :    Use SIMPLE to control how svalues and regions are printed.  */
     509              : 
     510              : void
     511         2126 : region_model::dump_to_pp (pretty_printer *pp, bool simple,
     512              :                           bool multiline) const
     513              : {
     514              :   /* Dump frame stack.  */
     515         2126 :   pp_printf (pp, "stack depth: %i", get_stack_depth ());
     516         2126 :   if (multiline)
     517          545 :     pp_newline (pp);
     518              :   else
     519         1581 :     pp_string (pp, " {");
     520         4228 :   for (const frame_region *iter_frame = m_current_frame; iter_frame;
     521         2102 :        iter_frame = iter_frame->get_calling_frame ())
     522              :     {
     523         2102 :       if (multiline)
     524          549 :         pp_string (pp, "  ");
     525         1553 :       else if (iter_frame != m_current_frame)
     526            0 :         pp_string (pp, ", ");
     527         2102 :       pp_printf (pp, "frame (index %i): ", iter_frame->get_index ());
     528         2102 :       iter_frame->dump_to_pp (pp, simple);
     529         2102 :       if (multiline)
     530          549 :         pp_newline (pp);
     531              :     }
     532         2126 :   if (!multiline)
     533         1581 :     pp_string (pp, "}");
     534              : 
     535              :   /* Dump exception stacks.  */
     536         2126 :   if (m_thrown_exceptions_stack.size () > 0)
     537              :     {
     538            6 :       pp_printf (pp, "thrown exceptions: %i", (int)m_thrown_exceptions_stack.size ());
     539            6 :       if (multiline)
     540            6 :         pp_newline (pp);
     541              :       else
     542            0 :         pp_string (pp, " {");
     543           12 :       for (size_t idx = 0; idx < m_thrown_exceptions_stack.size (); ++idx)
     544              :         {
     545            6 :           if (multiline)
     546            6 :             pp_string (pp, "  ");
     547            0 :           else if (idx > 0)
     548            0 :             pp_string (pp, ", ");
     549            6 :           pp_printf (pp, "exception (index %i): ", (int)idx);
     550            6 :           m_thrown_exceptions_stack[idx].dump_to_pp (pp, simple);
     551            6 :           if (multiline)
     552            6 :             pp_newline (pp);
     553              :         }
     554            6 :       if (!multiline)
     555            0 :         pp_string (pp, "}");
     556              :     }
     557         2126 :   if (m_caught_exceptions_stack.size () > 0)
     558              :     {
     559            0 :       pp_printf (pp, "caught exceptions: %i", (int)m_caught_exceptions_stack.size ());
     560            0 :       if (multiline)
     561            0 :         pp_newline (pp);
     562              :       else
     563            0 :         pp_string (pp, " {");
     564            0 :       for (size_t idx = 0; idx < m_caught_exceptions_stack.size (); ++idx)
     565              :         {
     566            0 :           if (multiline)
     567            0 :             pp_string (pp, "  ");
     568            0 :           else if (idx > 0)
     569            0 :             pp_string (pp, ", ");
     570            0 :           pp_printf (pp, "exception (index %i): ", (int)idx);
     571            0 :           m_caught_exceptions_stack[idx].dump_to_pp (pp, simple);
     572            0 :           if (multiline)
     573            0 :             pp_newline (pp);
     574              :         }
     575            0 :       if (!multiline)
     576            0 :         pp_string (pp, "}");
     577              :     }
     578              : 
     579              :   /* Dump store.  */
     580         2126 :   if (!multiline)
     581         1581 :     pp_string (pp, ", {");
     582         2126 :   m_store.dump_to_pp (pp, simple, multiline,
     583         2126 :                       m_mgr->get_store_manager ());
     584         2126 :   if (!multiline)
     585         1581 :     pp_string (pp, "}");
     586              : 
     587              :   /* Dump constraints.  */
     588         2126 :   pp_string (pp, "constraint_manager:");
     589         2126 :   if (multiline)
     590          545 :     pp_newline (pp);
     591              :   else
     592         1581 :     pp_string (pp, " {");
     593         2126 :   m_constraints->dump_to_pp (pp, multiline);
     594         2126 :   if (!multiline)
     595         1581 :     pp_string (pp, "}");
     596              : 
     597              :   /* Dump sizes of dynamic regions, if any are known.  */
     598         2126 :   if (!m_dynamic_extents.is_empty ())
     599              :     {
     600          416 :       pp_string (pp, "dynamic_extents:");
     601          416 :       m_dynamic_extents.dump_to_pp (pp, simple, multiline);
     602              :     }
     603         2126 : }
     604              : 
     605              : /* Dump a representation of this model to FILE.  */
     606              : 
     607              : void
     608            0 : region_model::dump (FILE *fp, bool simple, bool multiline) const
     609              : {
     610            0 :   tree_dump_pretty_printer pp (fp);
     611            0 :   dump_to_pp (&pp, simple, multiline);
     612            0 :   pp_newline (&pp);
     613            0 : }
     614              : 
     615              : /* Dump a multiline representation of this model to stderr.  */
     616              : 
     617              : DEBUG_FUNCTION void
     618            0 : region_model::dump (bool simple) const
     619              : {
     620            0 :   dump (stderr, simple, true);
     621            0 : }
     622              : 
     623              : /* Dump a tree-like representation of this state to stderr.  */
     624              : 
     625              : DEBUG_FUNCTION void
     626            0 : region_model::dump () const
     627              : {
     628            0 :   text_art::dump (*this);
     629            0 : }
     630              : 
     631              : /* Dump a multiline representation of this model to stderr.  */
     632              : 
     633              : DEBUG_FUNCTION void
     634            0 : region_model::debug () const
     635              : {
     636            0 :   dump (true);
     637            0 : }
     638              : 
     639              : /* Generate a JSON value for this region_model.
     640              :    This is intended for debugging the analyzer rather than
     641              :    serialization.  */
     642              : 
     643              : std::unique_ptr<json::object>
     644            4 : region_model::to_json () const
     645              : {
     646            4 :   auto model_obj = std::make_unique<json::object> ();
     647            4 :   model_obj->set ("store", m_store.to_json ());
     648            4 :   model_obj->set ("constraints", m_constraints->to_json ());
     649            4 :   if (m_current_frame)
     650            4 :     model_obj->set ("current_frame", m_current_frame->to_json ());
     651              : 
     652            4 :   auto thrown_exceptions_arr = std::make_unique<json::array> ();
     653            4 :   for (auto &node : m_thrown_exceptions_stack)
     654            0 :     thrown_exceptions_arr->append (node.to_json ());
     655            4 :   model_obj->set ("thrown_exception_stack", std::move (thrown_exceptions_arr));
     656              : 
     657            4 :   auto caught_exceptions_arr = std::make_unique<json::array> ();
     658            4 :   for (auto &node : m_caught_exceptions_stack)
     659            0 :     caught_exceptions_arr->append (node.to_json ());
     660            4 :   model_obj->set ("caught_exception_stack", std::move (caught_exceptions_arr));
     661              : 
     662            4 :   model_obj->set ("dynamic_extents", m_dynamic_extents.to_json ());
     663            8 :   return model_obj;
     664            4 : }
     665              : 
     666              : std::unique_ptr<text_art::tree_widget>
     667            4 : region_model::make_dump_widget (const text_art::dump_widget_info &dwi) const
     668              : {
     669            4 :   using text_art::tree_widget;
     670            4 :   std::unique_ptr<tree_widget> model_widget
     671            4 :     (tree_widget::from_fmt (dwi, nullptr, "Region Model"));
     672              : 
     673            4 :   if (m_current_frame)
     674              :     {
     675            0 :       pretty_printer the_pp;
     676            0 :       pretty_printer * const pp = &the_pp;
     677            0 :       pp_format_decoder (pp) = default_tree_printer;
     678            0 :       pp_show_color (pp) = true;
     679            0 :       const bool simple = true;
     680              : 
     681            0 :       pp_string (pp, "Current Frame: ");
     682            0 :       m_current_frame->dump_to_pp (pp, simple);
     683            0 :       model_widget->add_child (tree_widget::make (dwi, pp));
     684            0 :     }
     685              : 
     686            4 :   if (m_thrown_exceptions_stack.size () > 0)
     687              :     {
     688            0 :       auto thrown_exceptions_widget
     689            0 :         = tree_widget::make (dwi, "Thrown Exceptions");
     690            0 :       for (auto &thrown_exception : m_thrown_exceptions_stack)
     691            0 :         thrown_exceptions_widget->add_child
     692            0 :           (thrown_exception.make_dump_widget (dwi));
     693            0 :       model_widget->add_child (std::move (thrown_exceptions_widget));
     694            0 :     }
     695            4 :   if (m_caught_exceptions_stack.size () > 0)
     696              :     {
     697            0 :       auto caught_exceptions_widget
     698            0 :         = tree_widget::make (dwi, "Caught Exceptions");
     699            0 :       for (auto &caught_exception : m_caught_exceptions_stack)
     700            0 :         caught_exceptions_widget->add_child
     701            0 :           (caught_exception.make_dump_widget (dwi));
     702            0 :       model_widget->add_child (std::move (caught_exceptions_widget));
     703            0 :     }
     704              : 
     705            4 :   model_widget->add_child
     706            8 :     (m_store.make_dump_widget (dwi,
     707            4 :                                m_mgr->get_store_manager ()));
     708            4 :   model_widget->add_child (m_constraints->make_dump_widget (dwi));
     709            4 :   model_widget->add_child (m_dynamic_extents.make_dump_widget (dwi));
     710            4 :   return model_widget;
     711              : }
     712              : 
     713              : /* Assert that this object is valid.  */
     714              : 
     715              : void
     716      1876326 : region_model::validate () const
     717              : {
     718      1876326 :   m_store.validate ();
     719      1876326 : }
     720              : 
     721              : /* Canonicalize the store and constraints, to maximize the chance of
     722              :    equality between region_model instances.  */
     723              : 
     724              : void
     725       902109 : region_model::canonicalize ()
     726              : {
     727       902109 :   m_store.canonicalize (m_mgr->get_store_manager ());
     728       902109 :   m_constraints->canonicalize ();
     729       902109 : }
     730              : 
     731              : /* Return true if this region_model is in canonical form.  */
     732              : 
     733              : bool
     734       428720 : region_model::canonicalized_p () const
     735              : {
     736       428720 :   region_model copy (*this);
     737       428720 :   copy.canonicalize ();
     738       428720 :   return *this == copy;
     739       428720 : }
     740              : 
     741              : /* See the comment for store::loop_replay_fixup.  */
     742              : 
     743              : void
     744         4656 : region_model::loop_replay_fixup (const region_model *dst_state)
     745              : {
     746         4656 :   m_store.loop_replay_fixup (dst_state->get_store (), m_mgr);
     747         4656 : }
     748              : 
     749              : /* A subclass of pending_diagnostic for complaining about pointer
     750              :    subtractions involving unrelated buffers.  */
     751              : 
     752              : class undefined_ptrdiff_diagnostic
     753              : : public pending_diagnostic_subclass<undefined_ptrdiff_diagnostic>
     754              : {
     755              : public:
     756              :   /* Region_creation_event subclass to give a custom wording when
     757              :      talking about creation of buffers for LHS and RHS of the
     758              :      subtraction.  */
     759              :   class ptrdiff_region_creation_event : public region_creation_event
     760              :   {
     761              :   public:
     762           56 :     ptrdiff_region_creation_event (const event_loc_info &loc_info,
     763              :                                    bool is_lhs)
     764              :     : region_creation_event (loc_info),
     765           56 :       m_is_lhs (is_lhs)
     766              :     {
     767              :     }
     768              : 
     769          112 :     void print_desc (pretty_printer &pp) const final override
     770              :     {
     771          112 :       if (m_is_lhs)
     772           56 :         pp_string (&pp,
     773              :                    "underlying object for left-hand side"
     774              :                    " of subtraction created here");
     775              :       else
     776           56 :         pp_string (&pp,
     777              :                    "underlying object for right-hand side"
     778              :                    " of subtraction created here");
     779          112 :     }
     780              : 
     781              :   private:
     782              :     bool m_is_lhs;
     783              :   };
     784              : 
     785           64 :   undefined_ptrdiff_diagnostic (const gassign *assign,
     786              :                                 const svalue *sval_a,
     787              :                                 const svalue *sval_b,
     788              :                                 const region *base_reg_a,
     789              :                                 const region *base_reg_b)
     790           64 :   : m_assign (assign),
     791           64 :     m_sval_a (sval_a),
     792           64 :     m_sval_b (sval_b),
     793           64 :     m_base_reg_a (base_reg_a),
     794           64 :     m_base_reg_b (base_reg_b)
     795              :   {
     796           64 :     gcc_assert (m_base_reg_a != m_base_reg_b);
     797              :   }
     798              : 
     799          380 :   const char *get_kind () const final override
     800              :   {
     801          380 :     return "undefined_ptrdiff_diagnostic";
     802              :   }
     803              : 
     804           56 :   bool operator== (const undefined_ptrdiff_diagnostic &other) const
     805              :   {
     806           56 :     return (m_assign == other.m_assign
     807           56 :             && m_sval_a == other.m_sval_a
     808           56 :             && m_sval_b == other.m_sval_b
     809           56 :             && m_base_reg_a == other.m_base_reg_a
     810          112 :             && m_base_reg_b == other.m_base_reg_b);
     811              :   }
     812              : 
     813           84 :   int get_controlling_option () const final override
     814              :   {
     815           84 :     return OPT_Wanalyzer_undefined_behavior_ptrdiff;
     816              :   }
     817              : 
     818           28 :   bool emit (diagnostic_emission_context &ctxt) final override
     819              :   {
     820              :     /* CWE-469: Use of Pointer Subtraction to Determine Size.  */
     821           28 :     ctxt.add_cwe (469);
     822           28 :     return ctxt.warn ("undefined behavior when subtracting pointers");
     823              :   }
     824              : 
     825           56 :   void add_region_creation_events (const region *reg,
     826              :                                    tree /*capacity*/,
     827              :                                    const event_loc_info &loc_info,
     828              :                                    checker_path &emission_path) final override
     829              :   {
     830           56 :     if (reg == m_base_reg_a)
     831           28 :       emission_path.add_event
     832           28 :         (std::make_unique<ptrdiff_region_creation_event> (loc_info, true));
     833           28 :     else if (reg == m_base_reg_b)
     834           28 :       emission_path.add_event
     835           28 :         (std::make_unique<ptrdiff_region_creation_event> (loc_info, false));
     836           56 :   }
     837              : 
     838              :   bool
     839           56 :   describe_final_event (pretty_printer &pp,
     840              :                         const evdesc::final_event &) final override
     841              :   {
     842           56 :     pp_string (&pp,
     843              :                "subtraction of pointers has undefined behavior if"
     844              :                " they do not point into the same array object");
     845           56 :     return true;
     846              :   }
     847              : 
     848           56 :   void mark_interesting_stuff (interesting_t *interesting) final override
     849              :   {
     850           56 :     interesting->add_region_creation (m_base_reg_a);
     851           56 :     interesting->add_region_creation (m_base_reg_b);
     852           56 :   }
     853              : 
     854              : private:
     855              :   const gassign *m_assign;
     856              :   const svalue *m_sval_a;
     857              :   const svalue *m_sval_b;
     858              :   const region *m_base_reg_a;
     859              :   const region *m_base_reg_b;
     860              : };
     861              : 
     862              : /* Locate the parameter with the given index within FNDECL.
     863              :    ARGNUM is zero based, -1 indicates the `this' argument of a method.
     864              :    Return the location of the FNDECL itself if there are problems.  */
     865              : 
     866              : bool
     867           23 : callsite_expr::maybe_get_param_location (tree fndecl,
     868              :                                          location_t *out_loc) const
     869              : {
     870           23 :   gcc_assert (fndecl);
     871              : 
     872           23 :   if (DECL_ARTIFICIAL (fndecl))
     873              :     return false;
     874              : 
     875           23 :   tree param = get_param_tree (fndecl);
     876           23 :   if (!param)
     877              :     return false;
     878              : 
     879           22 :   *out_loc = DECL_SOURCE_LOCATION (param);
     880           22 :   return true;
     881              : }
     882              : 
     883              : /* If this callsite_expr refers to a parameter, get the PARM_DECL from
     884              :    FNDECL.
     885              :    Return NULL_TREE on any problems.  */
     886              : 
     887              : tree
     888           69 : callsite_expr::get_param_tree (tree fndecl) const
     889              : {
     890           69 :   if (!param_p ())
     891              :     return NULL_TREE;
     892              : 
     893           66 :   int i;
     894           66 :   tree param;
     895              : 
     896              :   /* Locate param by index within DECL_ARGUMENTS (fndecl).  */
     897           66 :   for (i = 1, param = DECL_ARGUMENTS (fndecl);
     898          126 :        i < param_num () && param;
     899           60 :        i++, param = TREE_CHAIN (param))
     900              :     ;
     901              : 
     902              :   return param;
     903              : }
     904              : 
     905              : class div_by_zero_diagnostic
     906              : : public pending_diagnostic_subclass<div_by_zero_diagnostic>
     907              : {
     908              : public:
     909           74 :   div_by_zero_diagnostic (const gassign *assign,
     910              :                           const region *divisor_reg)
     911           74 :   : m_assign (assign),
     912           74 :     m_divisor_reg (divisor_reg)
     913              :   {}
     914              : 
     915          409 :   const char *get_kind () const final override
     916              :   {
     917          409 :     return "div_by_zero_diagnostic";
     918              :   }
     919              : 
     920           74 :   bool operator== (const div_by_zero_diagnostic &other) const
     921              :   {
     922           74 :     return m_assign == other.m_assign;
     923              :   }
     924              : 
     925          107 :   int get_controlling_option () const final override
     926              :   {
     927          107 :     return OPT_Wanalyzer_div_by_zero;
     928              :   }
     929              : 
     930           33 :   bool emit (diagnostic_emission_context &ctxt) final override
     931              :   {
     932           33 :     return ctxt.warn ("division by zero");
     933              :   }
     934              : 
     935              :   bool
     936           66 :   describe_final_event (pretty_printer &pp,
     937              :                         const evdesc::final_event &) final override
     938              :   {
     939           66 :     pp_printf (&pp, "division by zero");
     940           66 :     return true;
     941              :   }
     942              : 
     943              :   void
     944           66 :   mark_interesting_stuff (interesting_t *interest) override
     945              :   {
     946           66 :     interest->add_read_region (m_divisor_reg, "divisor zero value");
     947           66 :   }
     948              : 
     949              :   void
     950           57 :   add_function_entry_event (const exploded_edge &eedge,
     951              :                             checker_path *emission_path,
     952              :                             const state_transition_at_call *state_trans)
     953              :                             override
     954              :   {
     955            0 :     class custom_function_entry_event : public function_entry_event
     956              :     {
     957              :     public:
     958           57 :       custom_function_entry_event (const event_loc_info &loc_info,
     959              :                                    const program_state &state,
     960              :                                    const state_transition_at_call *state_trans)
     961              :       : function_entry_event (loc_info,
     962              :                               state,
     963           57 :                               state_trans)
     964              :       {
     965              :       }
     966              : 
     967           72 :       void print_desc (pretty_printer &pp) const override
     968              :       {
     969           72 :         if (auto state_trans = get_state_transition_at_call ())
     970              :           {
     971            4 :             auto expr = state_trans->get_callsite_expr ();
     972            4 :             if (tree parm = expr.get_param_tree (m_effective_fndecl))
     973              :               {
     974            4 :                 auto src_event_id = state_trans->get_src_event_id ();
     975            4 :                 if (src_event_id.known_p ())
     976            4 :                   pp_printf (&pp, "entry to %qE with zero from %@ for %qE",
     977            4 :                              m_effective_fndecl,
     978              :                              &src_event_id,
     979              :                              parm);
     980              :                 else
     981            0 :                   pp_printf (&pp, "entry to %qE with zero for %qE",
     982            0 :                              m_effective_fndecl, parm);
     983            4 :                 return;
     984              :               }
     985              :           }
     986           68 :         return function_entry_event::print_desc (pp);
     987              :       }
     988              :     };
     989              : 
     990           57 :     const exploded_node *dst_node = eedge.m_dest;
     991           57 :     const program_point &dst_point = dst_node->get_point ();
     992           57 :     const program_state &dst_state = dst_node->get_state ();
     993           57 :     auto loc_info {event_loc_info_for_function_entry (dst_point, state_trans)};
     994           57 :     emission_path->add_event
     995           57 :       (std::make_unique<custom_function_entry_event> (loc_info,
     996              :                                                       dst_state,
     997              :                                                       state_trans));
     998           57 :   }
     999              : 
    1000              :   bool
    1001           44 :   describe_origin_of_state (pretty_printer &pp,
    1002              :                             const evdesc::origin_of_state &) final override
    1003              :   {
    1004           44 :     pp_printf (&pp, "zero value originates here");
    1005           44 :     return true;
    1006              :   }
    1007              : 
    1008              :   bool
    1009            4 :   describe_call_with_state (pretty_printer &pp,
    1010              :                             const evdesc::call_with_state &evd) final override
    1011              :   {
    1012            4 :     if (evd.m_state_trans)
    1013              :       {
    1014            4 :         callsite_expr expr = evd.m_state_trans->get_callsite_expr ();
    1015            4 :         if (expr.param_p ())
    1016              :           {
    1017            4 :             if (evd.m_src_event_id.known_p ())
    1018            4 :               pp_printf (&pp, "passing zero from %@ from %qE to %qE via parameter %i",
    1019              :                          &evd.m_src_event_id,
    1020            4 :                          evd.m_caller_fndecl,
    1021            4 :                          evd.m_callee_fndecl,
    1022              :                          expr.param_num ());
    1023              :             else
    1024            0 :               pp_printf (&pp, "passing zero from %qE to %qE via parameter %i",
    1025            0 :                          evd.m_caller_fndecl,
    1026            0 :                          evd.m_callee_fndecl,
    1027              :                          expr.param_num ());
    1028            4 :             return true;
    1029              :           }
    1030              :       }
    1031              : 
    1032              :     return false;
    1033              :   }
    1034              : 
    1035              :   bool
    1036           24 :   describe_return_of_state (pretty_printer &pp,
    1037              :                             const evdesc::return_of_state &evd) final override
    1038              :   {
    1039           24 :     if (evd.m_src_event_id.known_p ())
    1040           24 :       pp_printf (&pp, "returning zero from %@ from %qE here",
    1041              :                  &evd.m_src_event_id,
    1042           24 :                  evd.m_callee_fndecl);
    1043              :     else
    1044            0 :       pp_printf (&pp, "returning zero from %qE here",
    1045            0 :                evd.m_callee_fndecl);
    1046           24 :     return true;
    1047              :   }
    1048              : 
    1049              :   bool
    1050           12 :   describe_copy_of_state (pretty_printer &pp,
    1051              :                           const evdesc::copy_of_state &evd) final override
    1052              :   {
    1053           12 :     if (evd.m_src_event_id.known_p ())
    1054           12 :       pp_printf (&pp, "copying zero value from %@ from %qE to %qE",
    1055              :                  &evd.m_src_event_id,
    1056           12 :                  evd.m_src_reg_expr, evd.m_dst_reg_expr);
    1057              :     else
    1058            0 :       pp_printf (&pp, "copying zero value from %qE to %qE",
    1059            0 :                  evd.m_src_reg_expr, evd.m_dst_reg_expr);
    1060           12 :     return true;
    1061              :   }
    1062              : 
    1063              :   bool
    1064           16 :   describe_use_of_state (pretty_printer &pp,
    1065              :                          const evdesc::use_of_state &evd) final override
    1066              :   {
    1067           16 :     if (evd.m_src_event_id.known_p ())
    1068            8 :       pp_printf (&pp, "using zero value from %@ from %qE",
    1069              :                  &evd.m_src_event_id,
    1070            8 :                  evd.m_src_reg_expr);
    1071              :     else
    1072            8 :       pp_printf (&pp, "using zero value from %qE",
    1073            8 :                  evd.m_src_reg_expr);
    1074           16 :     return true;
    1075              :   }
    1076              : 
    1077              : private:
    1078              :   const gassign *m_assign;
    1079              :   const region *m_divisor_reg;
    1080              : };
    1081              : 
    1082              : /* Check the pointer subtraction SVAL_A - SVAL_B at ASSIGN and add
    1083              :    a warning to CTXT if they're not within the same base region.  */
    1084              : 
    1085              : static void
    1086          774 : check_for_invalid_ptrdiff (const gassign *assign,
    1087              :                            region_model_context &ctxt,
    1088              :                            const svalue *sval_a, const svalue *sval_b)
    1089              : {
    1090          774 :   const region *base_reg_a = sval_a->maybe_get_deref_base_region ();
    1091          774 :   if (!base_reg_a)
    1092          710 :     return;
    1093          158 :   const region *base_reg_b = sval_b->maybe_get_deref_base_region ();
    1094          158 :   if (!base_reg_b)
    1095              :     return;
    1096              : 
    1097          134 :   if (base_reg_a == base_reg_b)
    1098              :     return;
    1099              : 
    1100           64 :   if (base_reg_a->get_kind () == RK_SYMBOLIC)
    1101              :     return;
    1102           64 :   if (base_reg_b->get_kind () == RK_SYMBOLIC)
    1103              :     return;
    1104              : 
    1105           64 :   ctxt.warn
    1106           64 :     (std::make_unique<undefined_ptrdiff_diagnostic> (assign,
    1107              :                                                      sval_a,
    1108              :                                                      sval_b,
    1109              :                                                      base_reg_a,
    1110              :                                                      base_reg_b));
    1111              : }
    1112              : 
    1113              : /* If ASSIGN is a stmt that can be modelled via
    1114              :      set_value (lhs_reg, SVALUE, CTXT)
    1115              :    for some SVALUE, get the SVALUE.
    1116              :    Otherwise return nullptr.  */
    1117              : 
    1118              : const svalue *
    1119       446562 : region_model::get_gassign_result (const gassign *assign,
    1120              :                                    region_model_context *ctxt)
    1121              : {
    1122       446562 :   tree lhs = gimple_assign_lhs (assign);
    1123              : 
    1124       446562 :   if (gimple_has_volatile_ops (assign)
    1125       446562 :       && !gimple_clobber_p (assign))
    1126              :     {
    1127          116 :       conjured_purge p (this, ctxt);
    1128          116 :       return m_mgr->get_or_create_conjured_svalue (TREE_TYPE (lhs),
    1129              :                                                    assign,
    1130              :                                                    get_lvalue (lhs, ctxt),
    1131              :                                                    p);
    1132              :     }
    1133              : 
    1134       446446 :   tree rhs1 = gimple_assign_rhs1 (assign);
    1135       446446 :   enum tree_code op = gimple_assign_rhs_code (assign);
    1136       446446 :   switch (op)
    1137              :     {
    1138              :     default:
    1139              :       return nullptr;
    1140              : 
    1141        44006 :     case POINTER_PLUS_EXPR:
    1142        44006 :       {
    1143              :         /* e.g. "_1 = a_10(D) + 12;" */
    1144        44006 :         tree ptr = rhs1;
    1145        44006 :         tree offset = gimple_assign_rhs2 (assign);
    1146              : 
    1147        44006 :         const svalue *ptr_sval = get_rvalue (ptr, ctxt);
    1148        44006 :         const svalue *offset_sval = get_rvalue (offset, ctxt);
    1149              :         /* Quoting tree.def, "the second operand [of a POINTER_PLUS_EXPR]
    1150              :            is an integer of type sizetype".  */
    1151        44006 :         offset_sval = m_mgr->get_or_create_cast (size_type_node, offset_sval);
    1152              : 
    1153        44006 :         const svalue *sval_binop
    1154        44006 :           = m_mgr->get_or_create_binop (TREE_TYPE (lhs), op,
    1155              :                                         ptr_sval, offset_sval);
    1156        44006 :         return sval_binop;
    1157              :       }
    1158          944 :       break;
    1159              : 
    1160          944 :     case POINTER_DIFF_EXPR:
    1161          944 :       {
    1162              :         /* e.g. "_1 = p_2(D) - q_3(D);".  */
    1163          944 :         tree rhs2 = gimple_assign_rhs2 (assign);
    1164          944 :         const svalue *rhs1_sval = get_rvalue (rhs1, ctxt);
    1165          944 :         const svalue *rhs2_sval = get_rvalue (rhs2, ctxt);
    1166              : 
    1167              :         // TODO: perhaps fold to zero if they're known to be equal?
    1168              : 
    1169          944 :         if (ctxt)
    1170          774 :           check_for_invalid_ptrdiff (assign, *ctxt, rhs1_sval, rhs2_sval);
    1171              : 
    1172          944 :         const svalue *sval_binop
    1173          944 :           = m_mgr->get_or_create_binop (TREE_TYPE (lhs), op,
    1174              :                                         rhs1_sval, rhs2_sval);
    1175          944 :         return sval_binop;
    1176              :       }
    1177       222379 :       break;
    1178              : 
    1179              :     /* Assignments of the form
    1180              :         set_value (lvalue (LHS), rvalue (EXPR))
    1181              :        for various EXPR.
    1182              :        We already have the lvalue for the LHS above, as "lhs_reg".  */
    1183       222379 :     case ADDR_EXPR: /* LHS = &RHS;  */
    1184       222379 :     case BIT_FIELD_REF:
    1185       222379 :     case COMPONENT_REF: /* LHS = op0.op1;  */
    1186       222379 :     case MEM_REF:
    1187       222379 :     case REAL_CST:
    1188       222379 :     case COMPLEX_CST:
    1189       222379 :     case VECTOR_CST:
    1190       222379 :     case INTEGER_CST:
    1191       222379 :     case ARRAY_REF:
    1192       222379 :     case SSA_NAME: /* LHS = VAR; */
    1193       222379 :     case VAR_DECL: /* LHS = VAR; */
    1194       222379 :     case PARM_DECL:/* LHS = VAR; */
    1195       222379 :     case REALPART_EXPR:
    1196       222379 :     case IMAGPART_EXPR:
    1197       222379 :       return get_rvalue (rhs1, ctxt);
    1198              : 
    1199        67690 :     case ABS_EXPR:
    1200        67690 :     case ABSU_EXPR:
    1201        67690 :     case CONJ_EXPR:
    1202        67690 :     case BIT_NOT_EXPR:
    1203        67690 :     case FIX_TRUNC_EXPR:
    1204        67690 :     case FLOAT_EXPR:
    1205        67690 :     case NEGATE_EXPR:
    1206        67690 :     case NOP_EXPR:
    1207        67690 :     case VIEW_CONVERT_EXPR:
    1208        67690 :       {
    1209              :         /* Unary ops.  */
    1210        67690 :         const svalue *rhs_sval = get_rvalue (rhs1, ctxt);
    1211        67690 :         const svalue *sval_unaryop
    1212        67690 :           = m_mgr->get_or_create_unaryop (TREE_TYPE (lhs), op, rhs_sval);
    1213        67690 :         return sval_unaryop;
    1214              :       }
    1215              : 
    1216        16520 :     case EQ_EXPR:
    1217        16520 :     case GE_EXPR:
    1218        16520 :     case LE_EXPR:
    1219        16520 :     case NE_EXPR:
    1220        16520 :     case GT_EXPR:
    1221        16520 :     case LT_EXPR:
    1222        16520 :     case UNORDERED_EXPR:
    1223        16520 :     case ORDERED_EXPR:
    1224        16520 :       {
    1225        16520 :         tree rhs2 = gimple_assign_rhs2 (assign);
    1226              : 
    1227        16520 :         const svalue *rhs1_sval = get_rvalue (rhs1, ctxt);
    1228        16520 :         const svalue *rhs2_sval = get_rvalue (rhs2, ctxt);
    1229              : 
    1230        16520 :         if (TREE_TYPE (lhs) == boolean_type_node)
    1231              :           {
    1232              :             /* Consider constraints between svalues.  */
    1233        16373 :             tristate t = eval_condition (rhs1_sval, op, rhs2_sval);
    1234        16373 :             if (t.is_known ())
    1235         9246 :               return m_mgr->get_or_create_constant_svalue
    1236         9246 :                 (t.is_true () ? boolean_true_node : boolean_false_node);
    1237              :           }
    1238              : 
    1239              :         /* Otherwise, generate a symbolic binary op.  */
    1240         7274 :         const svalue *sval_binop
    1241         7274 :           = m_mgr->get_or_create_binop (TREE_TYPE (lhs), op,
    1242              :                                         rhs1_sval, rhs2_sval);
    1243         7274 :         return sval_binop;
    1244              :       }
    1245        78995 :       break;
    1246              : 
    1247        78995 :     case PLUS_EXPR:
    1248        78995 :     case MINUS_EXPR:
    1249        78995 :     case MULT_EXPR:
    1250        78995 :     case MULT_HIGHPART_EXPR:
    1251        78995 :     case TRUNC_DIV_EXPR:
    1252        78995 :     case CEIL_DIV_EXPR:
    1253        78995 :     case FLOOR_DIV_EXPR:
    1254        78995 :     case ROUND_DIV_EXPR:
    1255        78995 :     case TRUNC_MOD_EXPR:
    1256        78995 :     case CEIL_MOD_EXPR:
    1257        78995 :     case FLOOR_MOD_EXPR:
    1258        78995 :     case ROUND_MOD_EXPR:
    1259        78995 :     case RDIV_EXPR:
    1260        78995 :     case EXACT_DIV_EXPR:
    1261        78995 :     case LSHIFT_EXPR:
    1262        78995 :     case RSHIFT_EXPR:
    1263        78995 :     case LROTATE_EXPR:
    1264        78995 :     case RROTATE_EXPR:
    1265        78995 :     case BIT_IOR_EXPR:
    1266        78995 :     case BIT_XOR_EXPR:
    1267        78995 :     case BIT_AND_EXPR:
    1268        78995 :     case MIN_EXPR:
    1269        78995 :     case MAX_EXPR:
    1270        78995 :     case COMPLEX_EXPR:
    1271        78995 :       {
    1272              :         /* Binary ops.  */
    1273        78995 :         tree rhs2 = gimple_assign_rhs2 (assign);
    1274              : 
    1275        78995 :         const svalue *rhs1_sval = get_rvalue (rhs1, ctxt);
    1276        78995 :         const svalue *rhs2_sval = get_rvalue (rhs2, ctxt);
    1277              : 
    1278        78995 :         if (ctxt && (op == LSHIFT_EXPR || op == RSHIFT_EXPR))
    1279              :           {
    1280              :             /* "INT34-C. Do not shift an expression by a negative number of bits
    1281              :                or by greater than or equal to the number of bits that exist in
    1282              :                the operand."  */
    1283        13755 :             if (const tree rhs2_cst = rhs2_sval->maybe_get_constant ())
    1284        13459 :               if (TREE_CODE (rhs2_cst) == INTEGER_CST
    1285        13459 :                   && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
    1286              :                 {
    1287        13457 :                   if (tree_int_cst_sgn (rhs2_cst) < 0)
    1288              :                     {
    1289           24 :                       const region *rhs2_reg
    1290           48 :                         = get_lvalue (gimple_assign_rhs2 (assign), nullptr);
    1291           24 :                       ctxt->warn
    1292           24 :                         (make_shift_count_negative_diagnostic (assign,
    1293              :                                                                rhs2_cst,
    1294              :                                                                rhs2_reg));
    1295              :                     }
    1296        13433 :                   else if (compare_tree_int (rhs2_cst,
    1297        13433 :                                              TYPE_PRECISION (TREE_TYPE (rhs1)))
    1298              :                            >= 0)
    1299              :                     {
    1300           24 :                       const region *rhs2_reg
    1301           48 :                         = get_lvalue (gimple_assign_rhs2 (assign), nullptr);
    1302           48 :                       ctxt->warn (make_shift_count_overflow_diagnostic
    1303           24 :                                   (assign,
    1304           24 :                                    int (TYPE_PRECISION (TREE_TYPE (rhs1))),
    1305              :                                    rhs2_cst,
    1306              :                                    rhs2_reg));
    1307              :                     }
    1308              :                 }
    1309              :           }
    1310              : 
    1311        78995 :         if (op == TRUNC_DIV_EXPR
    1312              :             || op == CEIL_DIV_EXPR
    1313              :             || op == FLOOR_DIV_EXPR
    1314              :             || op == ROUND_DIV_EXPR
    1315              :             || op == TRUNC_MOD_EXPR
    1316              :             || op == CEIL_MOD_EXPR
    1317              :             || op == FLOOR_MOD_EXPR
    1318              :             || op == ROUND_MOD_EXPR
    1319              :             || op == RDIV_EXPR
    1320        78995 :             || op == EXACT_DIV_EXPR)
    1321              :           {
    1322         1256 :             value_range rhs_vr;
    1323         1256 :             if (rhs2_sval->maybe_get_value_range (rhs_vr))
    1324         1156 :               if (rhs_vr.zero_p ())
    1325              :                 {
    1326           74 :                   if (ctxt)
    1327              :                     {
    1328           74 :                       const region *rhs2_reg
    1329          148 :                         = get_lvalue (gimple_assign_rhs2 (assign), nullptr);
    1330           74 :                       ctxt->warn
    1331           74 :                         (std::make_unique<div_by_zero_diagnostic> (assign,
    1332              :                                                                    rhs2_reg));
    1333           74 :                       ctxt->terminate_path ();
    1334              :                     }
    1335           74 :                   return nullptr;
    1336              :                 }
    1337         1256 :           }
    1338              : 
    1339        78921 :         const svalue *sval_binop
    1340        78921 :           = m_mgr->get_or_create_binop (TREE_TYPE (lhs), op,
    1341              :                                         rhs1_sval, rhs2_sval);
    1342        78921 :         return sval_binop;
    1343              :       }
    1344              : 
    1345              :     /* Vector expressions.  In theory we could implement these elementwise,
    1346              :        but for now, simply return unknown values.  */
    1347            0 :     case VEC_DUPLICATE_EXPR:
    1348            0 :     case VEC_SERIES_EXPR:
    1349            0 :     case VEC_COND_EXPR:
    1350            0 :     case VEC_PERM_EXPR:
    1351            0 :     case VEC_WIDEN_MULT_HI_EXPR:
    1352            0 :     case VEC_WIDEN_MULT_LO_EXPR:
    1353            0 :     case VEC_WIDEN_MULT_EVEN_EXPR:
    1354            0 :     case VEC_WIDEN_MULT_ODD_EXPR:
    1355            0 :     case VEC_UNPACK_HI_EXPR:
    1356            0 :     case VEC_UNPACK_LO_EXPR:
    1357            0 :     case VEC_UNPACK_FLOAT_HI_EXPR:
    1358            0 :     case VEC_UNPACK_FLOAT_LO_EXPR:
    1359            0 :     case VEC_UNPACK_FIX_TRUNC_HI_EXPR:
    1360            0 :     case VEC_UNPACK_FIX_TRUNC_LO_EXPR:
    1361            0 :     case VEC_PACK_TRUNC_EXPR:
    1362            0 :     case VEC_PACK_SAT_EXPR:
    1363            0 :     case VEC_PACK_FIX_TRUNC_EXPR:
    1364            0 :     case VEC_PACK_FLOAT_EXPR:
    1365            0 :     case VEC_WIDEN_LSHIFT_HI_EXPR:
    1366            0 :     case VEC_WIDEN_LSHIFT_LO_EXPR:
    1367            0 :       return m_mgr->get_or_create_unknown_svalue (TREE_TYPE (lhs));
    1368              :     }
    1369              : }
    1370              : 
    1371              : /* Workaround for discarding certain false positives from
    1372              :    -Wanalyzer-use-of-uninitialized-value
    1373              :    of the form:
    1374              :      ((A OR-IF B) OR-IF C)
    1375              :    and:
    1376              :      ((A AND-IF B) AND-IF C)
    1377              :    where evaluating B is redundant, but could involve simple accesses of
    1378              :    uninitialized locals.
    1379              : 
    1380              :    When optimization is turned on the FE can immediately fold compound
    1381              :    conditionals.  Specifically, c_parser_condition parses this condition:
    1382              :      ((A OR-IF B) OR-IF C)
    1383              :    and calls c_fully_fold on the condition.
    1384              :    Within c_fully_fold, fold_truth_andor is called, which bails when
    1385              :    optimization is off, but if any optimization is turned on can convert the
    1386              :      ((A OR-IF B) OR-IF C)
    1387              :    into:
    1388              :      ((A OR B) OR_IF C)
    1389              :    for sufficiently simple B
    1390              :    i.e. the inner OR-IF becomes an OR.
    1391              :    At gimplification time the inner OR becomes BIT_IOR_EXPR (in gimplify_expr),
    1392              :    giving this for the inner condition:
    1393              :       tmp = A | B;
    1394              :       if (tmp)
    1395              :    thus effectively synthesizing a redundant access of B when optimization
    1396              :    is turned on, when compared to:
    1397              :       if (A) goto L1; else goto L4;
    1398              :   L1: if (B) goto L2; else goto L4;
    1399              :   L2: if (C) goto L3; else goto L4;
    1400              :    for the unoptimized case.
    1401              : 
    1402              :    Return true if CTXT appears to be  handling such a short-circuitable stmt,
    1403              :    such as the def-stmt for B for the:
    1404              :       tmp = A | B;
    1405              :    case above, for the case where A is true and thus B would have been
    1406              :    short-circuited without optimization, using MODEL for the value of A.  */
    1407              : 
    1408              : static bool
    1409         1212 : within_short_circuited_stmt_p (const region_model *model,
    1410              :                                const gassign *assign_stmt)
    1411              : {
    1412              :   /* We must have an assignment to a temporary of _Bool type.  */
    1413         1212 :   tree lhs = gimple_assign_lhs (assign_stmt);
    1414         1212 :   if (TREE_TYPE (lhs) != boolean_type_node)
    1415              :     return false;
    1416           40 :   if (TREE_CODE (lhs) != SSA_NAME)
    1417              :     return false;
    1418           40 :   if (SSA_NAME_VAR (lhs) != NULL_TREE)
    1419              :     return false;
    1420              : 
    1421              :   /* The temporary bool must be used exactly once: as the second arg of
    1422              :      a BIT_IOR_EXPR or BIT_AND_EXPR.  */
    1423           40 :   use_operand_p use_op;
    1424           40 :   gimple *use_stmt;
    1425           40 :   if (!single_imm_use (lhs, &use_op, &use_stmt))
    1426              :     return false;
    1427           40 :   const gassign *use_assign = dyn_cast <const gassign *> (use_stmt);
    1428           40 :   if (!use_assign)
    1429              :     return false;
    1430           40 :   enum tree_code op = gimple_assign_rhs_code (use_assign);
    1431           40 :   if (!(op == BIT_IOR_EXPR ||op == BIT_AND_EXPR))
    1432              :     return false;
    1433           28 :   if (!(gimple_assign_rhs1 (use_assign) != lhs
    1434           28 :         && gimple_assign_rhs2 (use_assign) == lhs))
    1435              :     return false;
    1436              : 
    1437              :   /* The first arg of the bitwise stmt must have a known value in MODEL
    1438              :      that implies that the value of the second arg doesn't matter, i.e.
    1439              :      1 for bitwise or, 0 for bitwise and.  */
    1440           28 :   tree other_arg = gimple_assign_rhs1 (use_assign);
    1441              :   /* Use a nullptr ctxt here to avoid generating warnings.  */
    1442           28 :   const svalue *other_arg_sval = model->get_rvalue (other_arg, nullptr);
    1443           28 :   tree other_arg_cst = other_arg_sval->maybe_get_constant ();
    1444           28 :   if (!other_arg_cst)
    1445              :     return false;
    1446           12 :   switch (op)
    1447              :     {
    1448              :     default:
    1449              :       gcc_unreachable ();
    1450           12 :     case BIT_IOR_EXPR:
    1451           12 :       if (zerop (other_arg_cst))
    1452            0 :         return false;
    1453              :       break;
    1454            0 :     case BIT_AND_EXPR:
    1455            0 :       if (!zerop (other_arg_cst))
    1456              :         return false;
    1457              :       break;
    1458              :     }
    1459              : 
    1460              :   /* All tests passed.  We appear to be in a stmt that generates a boolean
    1461              :      temporary with a value that won't matter.  */
    1462              :   return true;
    1463              : }
    1464              : 
    1465              : /* Workaround for discarding certain false positives from
    1466              :    -Wanalyzer-use-of-uninitialized-value
    1467              :    seen with -ftrivial-auto-var-init=.
    1468              : 
    1469              :    -ftrivial-auto-var-init= will generate calls to IFN_DEFERRED_INIT.
    1470              : 
    1471              :    If the address of the var is taken, gimplification will give us
    1472              :    something like:
    1473              : 
    1474              :      _1 = .DEFERRED_INIT (4, 2, &"len"[0]);
    1475              :      len = _1;
    1476              : 
    1477              :    The result of DEFERRED_INIT will be an uninit value; we don't
    1478              :    want to emit a false positive for "len = _1;"
    1479              : 
    1480              :    Return true if ASSIGN_STMT is such a stmt.  */
    1481              : 
    1482              : static bool
    1483         1200 : due_to_ifn_deferred_init_p (const gassign *assign_stmt)
    1484              : 
    1485              : {
    1486              :   /* We must have an assignment to a decl from an SSA name that's the
    1487              :      result of a IFN_DEFERRED_INIT call.  */
    1488         2230 :   if (gimple_assign_rhs_code (assign_stmt) != SSA_NAME)
    1489              :     return false;
    1490          323 :   tree lhs = gimple_assign_lhs (assign_stmt);
    1491          323 :   if (TREE_CODE (lhs) != VAR_DECL)
    1492              :     return false;
    1493          258 :   tree rhs = gimple_assign_rhs1 (assign_stmt);
    1494          258 :   if (TREE_CODE (rhs) != SSA_NAME)
    1495              :     return false;
    1496          258 :   const gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
    1497          258 :   const gcall *call = dyn_cast <const gcall *> (def_stmt);
    1498          258 :   if (!call)
    1499              :     return false;
    1500          258 :   if (gimple_call_internal_p (call)
    1501          258 :       && gimple_call_internal_fn (call) == IFN_DEFERRED_INIT)
    1502          246 :     return true;
    1503              :   return false;
    1504              : }
    1505              : 
    1506              : /* Check for SVAL being poisoned, adding a warning to CTXT.
    1507              :    Return SVAL, or, if a warning is added, another value, to avoid
    1508              :    repeatedly complaining about the same poisoned value in followup code.
    1509              :    SRC_REGION is a hint about where SVAL came from, and can be nullptr.  */
    1510              : 
    1511              : const svalue *
    1512      3555651 : region_model::check_for_poison (const svalue *sval,
    1513              :                                 tree expr,
    1514              :                                 const region *src_region,
    1515              :                                 region_model_context *ctxt) const
    1516              : {
    1517      3555651 :   if (!ctxt)
    1518              :     return sval;
    1519              : 
    1520      1814272 :   if (const poisoned_svalue *poisoned_sval = sval->dyn_cast_poisoned_svalue ())
    1521              :     {
    1522         2811 :       enum poison_kind pkind = poisoned_sval->get_poison_kind ();
    1523              : 
    1524              :       /* Ignore uninitialized uses of empty types; there's nothing
    1525              :          to initialize.  */
    1526         2811 :       if (pkind == poison_kind::uninit
    1527         2770 :           && sval->get_type ()
    1528         5472 :           && is_empty_type (sval->get_type ()))
    1529              :         return sval;
    1530              : 
    1531         2529 :       if (pkind == poison_kind::uninit)
    1532         2488 :         if (const gimple *curr_stmt = ctxt->get_stmt ())
    1533         1556 :           if (const gassign *assign_stmt
    1534         3483 :                 = dyn_cast <const gassign *> (curr_stmt))
    1535              :             {
    1536              :               /* Special case to avoid certain false positives.  */
    1537         1212 :               if (within_short_circuited_stmt_p (this, assign_stmt))
    1538              :                 return sval;
    1539              : 
    1540              :               /* Special case to avoid false positive on
    1541              :                  -ftrivial-auto-var-init=.  */
    1542         1200 :               if (due_to_ifn_deferred_init_p (assign_stmt))
    1543              :                 return sval;
    1544              :           }
    1545              : 
    1546              :       /* If we have an SSA name for a temporary, we don't want to print
    1547              :          '<unknown>'.
    1548              :          Poisoned values are shared by type, and so we can't reconstruct
    1549              :          the tree other than via the def stmts, using
    1550              :          fixup_tree_for_diagnostic.  */
    1551         2271 :       tree diag_arg = fixup_tree_for_diagnostic (expr);
    1552         2271 :       if (src_region == nullptr && pkind == poison_kind::uninit)
    1553         2181 :         src_region = get_region_for_poisoned_expr (expr);
    1554              : 
    1555              :       /* Can we reliably get the poisoned value from "expr"?
    1556              :          This is for use by poisoned_value_diagnostic::check_valid_fpath_p.
    1557              :          Unfortunately, we might not have a reliable value for EXPR.
    1558              :          Hence we only query its value now, and only use it if we get the
    1559              :          poisoned value back again.  */
    1560         2271 :       tree check_expr = expr;
    1561         2271 :       const svalue *foo_sval = get_rvalue (expr, nullptr);
    1562         2271 :       if (foo_sval == sval)
    1563              :         check_expr = expr;
    1564              :       else
    1565          109 :         check_expr = nullptr;
    1566         2271 :       if (ctxt->warn (make_poisoned_value_diagnostic (diag_arg,
    1567              :                                                       pkind,
    1568              :                                                       src_region,
    1569              :                                                       check_expr)))
    1570              :         {
    1571              :           /* We only want to report use of a poisoned value at the first
    1572              :              place it gets used; return an unknown value to avoid generating
    1573              :              a chain of followup warnings.  */
    1574         1382 :           sval = m_mgr->get_or_create_unknown_svalue (sval->get_type ());
    1575              :         }
    1576              : 
    1577              :       return sval;
    1578              :     }
    1579              : 
    1580              :   return sval;
    1581              : }
    1582              : 
    1583              : /* Attempt to get a region for describing EXPR, the source of region of
    1584              :    a poisoned_svalue for use in a poisoned_value_diagnostic.
    1585              :    Return nullptr if there is no good region to use.  */
    1586              : 
    1587              : const region *
    1588         2181 : region_model::get_region_for_poisoned_expr (tree expr) const
    1589              : {
    1590         2181 :   if (TREE_CODE (expr) == SSA_NAME)
    1591              :     {
    1592         1402 :       tree decl = SSA_NAME_VAR (expr);
    1593         1362 :       if (decl && DECL_P (decl))
    1594              :         expr = decl;
    1595              :       else
    1596              :         return nullptr;
    1597              :     }
    1598         2141 :   return get_lvalue (expr, nullptr);
    1599              : }
    1600              : 
    1601              : /* Update this model for the ASSIGN stmt, using CTXT to report any
    1602              :    diagnostics.  */
    1603              : 
    1604              : void
    1605       266146 : region_model::on_assignment (const gassign *assign, region_model_context *ctxt)
    1606              : {
    1607       266146 :   tree lhs = gimple_assign_lhs (assign);
    1608       266146 :   tree rhs1 = gimple_assign_rhs1 (assign);
    1609              : 
    1610       266146 :   const region *lhs_reg = get_lvalue (lhs, ctxt);
    1611              : 
    1612              :   /* Any writes other than to the stack are treated
    1613              :      as externally visible.  */
    1614       266146 :   if (ctxt)
    1615              :     {
    1616       204632 :       enum memory_space memspace = lhs_reg->get_memory_space ();
    1617       204632 :       if (memspace != MEMSPACE_STACK)
    1618        13318 :         ctxt->maybe_did_work ();
    1619              :     }
    1620              : 
    1621              :   /* Most assignments are handled by:
    1622              :        set_value (lhs_reg, SVALUE, CTXT)
    1623              :      for some SVALUE.  */
    1624       266146 :   if (const svalue *sval = get_gassign_result (assign, ctxt))
    1625              :     {
    1626       257320 :       tree expr = get_diagnostic_tree_for_gassign (assign);
    1627       257320 :       check_for_poison (sval, expr, nullptr, ctxt);
    1628       257320 :       set_value (lhs_reg, sval, ctxt);
    1629       257320 :       return;
    1630              :     }
    1631              : 
    1632         8826 :   enum tree_code op = gimple_assign_rhs_code (assign);
    1633         8826 :   switch (op)
    1634              :     {
    1635           37 :     default:
    1636           37 :       {
    1637           37 :         if (0)
    1638              :           sorry_at (assign->location, "unhandled assignment op: %qs",
    1639              :                     get_tree_code_name (op));
    1640           37 :         const svalue *unknown_sval
    1641           37 :           = m_mgr->get_or_create_unknown_svalue (TREE_TYPE (lhs));
    1642           37 :         set_value (lhs_reg, unknown_sval, ctxt);
    1643              :       }
    1644           37 :       break;
    1645              : 
    1646         8231 :     case CONSTRUCTOR:
    1647         8231 :       {
    1648         8231 :         if (TREE_CLOBBER_P (rhs1))
    1649              :           {
    1650              :             /* e.g. "x ={v} {CLOBBER};"  */
    1651         8067 :             clobber_region (lhs_reg);
    1652              :           }
    1653              :         else
    1654              :           {
    1655              :             /* Any CONSTRUCTOR that survives to this point is either
    1656              :                just a zero-init of everything, or a vector.  */
    1657          164 :             if (!CONSTRUCTOR_NO_CLEARING (rhs1))
    1658          164 :               zero_fill_region (lhs_reg, ctxt);
    1659          164 :             unsigned ix;
    1660          164 :             tree index;
    1661          164 :             tree val;
    1662          326 :             FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (rhs1), ix, index, val)
    1663              :               {
    1664          162 :                 gcc_assert (TREE_CODE (TREE_TYPE (rhs1)) == VECTOR_TYPE);
    1665          162 :                 if (!index)
    1666           22 :                   index = build_int_cst (integer_type_node, ix);
    1667          162 :                 gcc_assert (TREE_CODE (index) == INTEGER_CST);
    1668          162 :                 const svalue *index_sval
    1669          162 :                   = m_mgr->get_or_create_constant_svalue (index);
    1670          162 :                 gcc_assert (index_sval);
    1671          162 :                 const region *sub_reg
    1672          162 :                   = m_mgr->get_element_region (lhs_reg,
    1673          162 :                                                TREE_TYPE (val),
    1674              :                                                index_sval);
    1675          162 :                 const svalue *val_sval = get_rvalue (val, ctxt);
    1676          162 :                 set_value (sub_reg, val_sval, ctxt);
    1677              :               }
    1678              :           }
    1679              :       }
    1680              :       break;
    1681              : 
    1682          558 :     case STRING_CST:
    1683          558 :       {
    1684              :         /* e.g. "struct s2 x = {{'A', 'B', 'C', 'D'}};".  */
    1685          558 :         const svalue *rhs_sval = get_rvalue (rhs1, ctxt);
    1686          762 :         m_store.set_value (m_mgr->get_store_manager(), lhs_reg, rhs_sval,
    1687          204 :                            ctxt ? ctxt->get_uncertainty () : nullptr,
    1688              :                            *this);
    1689              :       }
    1690          558 :       break;
    1691              :     }
    1692              : }
    1693              : 
    1694              : /* Handle the pre-sm-state part of STMT, modifying this object in-place.
    1695              :    Write true to *OUT_UNKNOWN_SIDE_EFFECTS if the stmt has unknown
    1696              :    side effects.  */
    1697              : 
    1698              : void
    1699       348849 : region_model::on_stmt_pre (const gimple *stmt,
    1700              :                            bool *out_unknown_side_effects,
    1701              :                            region_model_context *ctxt)
    1702              : {
    1703       348849 :   switch (gimple_code (stmt))
    1704              :     {
    1705              :     case GIMPLE_COND:
    1706              :     case GIMPLE_EH_DISPATCH:
    1707              :     case GIMPLE_GOTO:
    1708              :     case GIMPLE_LABEL:
    1709              :     case GIMPLE_NOP:
    1710              :     case GIMPLE_PREDICT:
    1711              :     case GIMPLE_RESX:
    1712              :     case GIMPLE_SWITCH:
    1713              :       /* No-ops here.  */
    1714              :       break;
    1715              : 
    1716       266146 :     case GIMPLE_ASSIGN:
    1717       266146 :       {
    1718       266146 :         const gassign *assign = as_a <const gassign *> (stmt);
    1719       266146 :         on_assignment (assign, ctxt);
    1720              :       }
    1721       266146 :       break;
    1722              : 
    1723          384 :     case GIMPLE_ASM:
    1724          384 :       {
    1725          384 :         const gasm *asm_stmt = as_a <const gasm *> (stmt);
    1726          384 :         on_asm_stmt (asm_stmt, ctxt);
    1727          384 :         if (ctxt)
    1728          342 :           ctxt->maybe_did_work ();
    1729              :       }
    1730              :       break;
    1731              : 
    1732        78781 :     case GIMPLE_CALL:
    1733        78781 :       {
    1734              :         /* Track whether we have a gcall to a function that's not recognized by
    1735              :            anything, for which we don't have a function body, or for which we
    1736              :            don't know the fndecl.  */
    1737        78781 :         const gcall *call = as_a <const gcall *> (stmt);
    1738        78781 :         *out_unknown_side_effects = on_call_pre (*call, ctxt);
    1739              :       }
    1740        78781 :       break;
    1741              : 
    1742            0 :     case GIMPLE_RETURN:
    1743            0 :       {
    1744            0 :         const greturn *return_ = as_a <const greturn *> (stmt);
    1745            0 :         on_return (return_, ctxt);
    1746              :       }
    1747            0 :       break;
    1748              : 
    1749              :     /* We don't expect to see any other statement kinds in the analyzer.  */
    1750            0 :     case GIMPLE_DEBUG: // should have stripped these out when building the supergraph
    1751            0 :     default:
    1752            0 :       internal_error ("unexpected gimple stmt code: %qs",
    1753            0 :                       gimple_code_name[gimple_code (stmt)]);
    1754       348849 :       break;
    1755              :     }
    1756       348849 : }
    1757              : 
    1758              : /* Given a call CD with function attribute FORMAT_ATTR, check that the
    1759              :    format arg to the call is a valid null-terminated string.  */
    1760              : 
    1761              : void
    1762         1055 : region_model::check_call_format_attr (const call_details &cd,
    1763              :                                       tree format_attr) const
    1764              : {
    1765              :   /* We assume that FORMAT_ATTR has already been validated.  */
    1766              : 
    1767              :   /* arg0 of the attribute should be kind of format strings
    1768              :      that this function expects (e.g. "printf").  */
    1769         1055 :   const tree arg0_tree_list = TREE_VALUE (format_attr);
    1770         1055 :   if (!arg0_tree_list)
    1771            0 :     return;
    1772              : 
    1773              :   /* arg1 of the attribute should be the 1-based parameter index
    1774              :      to treat as the format string.  */
    1775         1055 :   const tree arg1_tree_list = TREE_CHAIN (arg0_tree_list);
    1776         1055 :   if (!arg1_tree_list)
    1777              :     return;
    1778         1055 :   const tree arg1_value = TREE_VALUE (arg1_tree_list);
    1779         1055 :   if (!arg1_value)
    1780              :     return;
    1781              : 
    1782         1055 :   unsigned format_arg_idx = TREE_INT_CST_LOW (arg1_value) - 1;
    1783         1055 :   if (cd.num_args () <= format_arg_idx)
    1784              :     return;
    1785              : 
    1786              :   /* Subclass of annotating_context that
    1787              :      adds a note about the format attr to any saved diagnostics.  */
    1788         1055 :   class annotating_ctxt : public annotating_context
    1789              :   {
    1790              :   public:
    1791         1055 :     annotating_ctxt (const call_details &cd,
    1792              :                      unsigned fmt_param_idx)
    1793              :     : annotating_context (cd.get_ctxt ()),
    1794         1055 :       m_cd (cd),
    1795         1055 :       m_fmt_param_idx (fmt_param_idx)
    1796              :     {
    1797              :     }
    1798           13 :     void add_annotations () final override
    1799              :     {
    1800            0 :       class reason_format_attr
    1801              :         : public pending_note_subclass<reason_format_attr>
    1802              :       {
    1803              :       public:
    1804           13 :         reason_format_attr (const call_arg_details &arg_details)
    1805           13 :           : m_arg_details (arg_details)
    1806              :         {
    1807              :         }
    1808              : 
    1809           74 :         const char *get_kind () const final override
    1810              :         {
    1811           74 :           return "reason_format_attr";
    1812              :         }
    1813              : 
    1814           13 :         void emit () const final override
    1815              :         {
    1816           13 :           inform (DECL_SOURCE_LOCATION (m_arg_details.m_called_fndecl),
    1817              :                   "parameter %i of %qD marked as a format string"
    1818              :                   " via %qs attribute",
    1819           13 :                   m_arg_details.m_arg_idx + 1, m_arg_details.m_called_fndecl,
    1820              :                   "format");
    1821           13 :         }
    1822              : 
    1823           37 :         bool operator== (const reason_format_attr &other) const
    1824              :         {
    1825           37 :           return m_arg_details == other.m_arg_details;
    1826              :         }
    1827              : 
    1828              :       private:
    1829              :         call_arg_details m_arg_details;
    1830              :       };
    1831              : 
    1832           13 :       call_arg_details arg_details (m_cd, m_fmt_param_idx);
    1833           13 :       add_note (std::make_unique<reason_format_attr> (arg_details));
    1834           13 :     }
    1835              :   private:
    1836              :     const call_details &m_cd;
    1837              :     unsigned m_fmt_param_idx;
    1838              :   };
    1839              : 
    1840         1055 :   annotating_ctxt my_ctxt (cd, format_arg_idx);
    1841         1055 :   call_details my_cd (cd, &my_ctxt);
    1842         1055 :   my_cd.check_for_null_terminated_string_arg (format_arg_idx);
    1843              : }
    1844              : 
    1845              : /* Ensure that all arguments at the call described by CD are checked
    1846              :    for poisoned values, by calling get_rvalue on each argument.
    1847              : 
    1848              :    Check that calls to functions with "format" attribute have valid
    1849              :    null-terminated strings for their format argument.  */
    1850              : 
    1851              : void
    1852        50816 : region_model::check_call_args (const call_details &cd) const
    1853              : {
    1854       118347 :   for (unsigned arg_idx = 0; arg_idx < cd.num_args (); arg_idx++)
    1855        67531 :     cd.get_arg_svalue (arg_idx);
    1856              : 
    1857              :   /* Handle attribute "format".  */
    1858        50816 :   if (tree format_attr = cd.lookup_function_attribute ("format"))
    1859         1055 :     check_call_format_attr (cd, format_attr);
    1860        50816 : }
    1861              : 
    1862              : /* Update this model for an outcome of a call that returns a specific
    1863              :    integer constant.
    1864              :    If UNMERGEABLE, then make the result unmergeable, e.g. to prevent
    1865              :    the state-merger code from merging success and failure outcomes.  */
    1866              : 
    1867              : void
    1868          936 : region_model::update_for_int_cst_return (const call_details &cd,
    1869              :                                          int retval,
    1870              :                                          bool unmergeable)
    1871              : {
    1872          936 :   if (!cd.get_lhs_type ())
    1873              :     return;
    1874          615 :   if (TREE_CODE (cd.get_lhs_type ()) != INTEGER_TYPE)
    1875              :     return;
    1876          609 :   const svalue *result
    1877          609 :     = m_mgr->get_or_create_int_cst (cd.get_lhs_type (), retval);
    1878          609 :   if (unmergeable)
    1879          609 :     result = m_mgr->get_or_create_unmergeable (result);
    1880          609 :   set_value (cd.get_lhs_region (), result, cd.get_ctxt ());
    1881              : }
    1882              : 
    1883              : /* Update this model for an outcome of a call that returns zero.
    1884              :    If UNMERGEABLE, then make the result unmergeable, e.g. to prevent
    1885              :    the state-merger code from merging success and failure outcomes.  */
    1886              : 
    1887              : void
    1888          290 : region_model::update_for_zero_return (const call_details &cd,
    1889              :                                       bool unmergeable)
    1890              : {
    1891          290 :   update_for_int_cst_return (cd, 0, unmergeable);
    1892          290 : }
    1893              : 
    1894              : /* Update this model for an outcome of a call that returns a NULL
    1895              :    pointer.
    1896              :    If UNMERGEABLE, then make the result unmergeable, e.g. to prevent
    1897              :    the state-merger code from merging success and failure outcomes.  */
    1898              : 
    1899              : void
    1900           14 : region_model::update_for_null_return (const call_details &cd, bool unmergeable)
    1901              : {
    1902           14 :   if (!cd.get_lhs_type ())
    1903              :     return;
    1904            2 :   if (!POINTER_TYPE_P (cd.get_lhs_type ()))
    1905              :     return;
    1906            2 :   const svalue *result = m_mgr->get_or_create_null_ptr (cd.get_lhs_type ());
    1907            2 :   if (unmergeable)
    1908            2 :     result = m_mgr->get_or_create_unmergeable (result);
    1909            2 :   set_value (cd.get_lhs_region (), result, cd.get_ctxt ());
    1910              : }
    1911              : 
    1912              : /* Update this model for an outcome of a call that returns non-zero.
    1913              :    Specifically, assign an svalue to the LHS, and add a constraint that
    1914              :    that svalue is non-zero.  */
    1915              : 
    1916              : void
    1917          136 : region_model::update_for_nonzero_return (const call_details &cd)
    1918              : {
    1919          136 :   if (!cd.get_lhs_type ())
    1920              :     return;
    1921          100 :   if (TREE_CODE (cd.get_lhs_type ()) != INTEGER_TYPE)
    1922              :     return;
    1923          100 :   cd.set_any_lhs_with_defaults ();
    1924          100 :   const svalue *zero
    1925          100 :     = m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
    1926          100 :   const svalue *result
    1927          100 :     = get_store_value (cd.get_lhs_region (), cd.get_ctxt ());
    1928          100 :   add_constraint (result, NE_EXPR, zero, cd.get_ctxt ());
    1929              : }
    1930              : 
    1931              : /* Subroutine of region_model::maybe_get_copy_bounds.
    1932              :    The Linux kernel commonly uses
    1933              :      min_t([unsigned] long, VAR, sizeof(T));
    1934              :    to set an upper bound on the size of a copy_to_user.
    1935              :    Attempt to simplify such sizes by trying to get the upper bound as a
    1936              :    constant.
    1937              :    Return the simplified svalue if possible, or nullptr otherwise.  */
    1938              : 
    1939              : static const svalue *
    1940           53 : maybe_simplify_upper_bound (const svalue *num_bytes_sval,
    1941              :                             region_model_manager *mgr)
    1942              : {
    1943           53 :   tree type = num_bytes_sval->get_type ();
    1944           70 :   while (const svalue *raw = num_bytes_sval->maybe_undo_cast ())
    1945              :     num_bytes_sval = raw;
    1946           53 :   if (const binop_svalue *binop_sval = num_bytes_sval->dyn_cast_binop_svalue ())
    1947           38 :     if (binop_sval->get_op () == MIN_EXPR)
    1948            8 :       if (binop_sval->get_arg1 ()->get_kind () == SK_CONSTANT)
    1949              :         {
    1950            8 :           return mgr->get_or_create_cast (type, binop_sval->get_arg1 ());
    1951              :           /* TODO: we might want to also capture the constraint
    1952              :              when recording the diagnostic, or note that we're using
    1953              :              the upper bound.  */
    1954              :         }
    1955              :   return nullptr;
    1956              : }
    1957              : 
    1958              : /* Attempt to get an upper bound for the size of a copy when simulating a
    1959              :    copy function.
    1960              : 
    1961              :    NUM_BYTES_SVAL is the symbolic value for the size of the copy.
    1962              :    Use it if it's constant, otherwise try to simplify it.  Failing
    1963              :    that, use the size of SRC_REG if constant.
    1964              : 
    1965              :    Return a symbolic value for an upper limit on the number of bytes
    1966              :    copied, or nullptr if no such value could be determined.  */
    1967              : 
    1968              : const svalue *
    1969          157 : region_model::maybe_get_copy_bounds (const region *src_reg,
    1970              :                                      const svalue *num_bytes_sval)
    1971              : {
    1972          157 :   if (num_bytes_sval->maybe_get_constant ())
    1973              :     return num_bytes_sval;
    1974              : 
    1975          106 :   if (const svalue *simplified
    1976           53 :       = maybe_simplify_upper_bound (num_bytes_sval, m_mgr))
    1977            8 :     num_bytes_sval = simplified;
    1978              : 
    1979           53 :   if (num_bytes_sval->maybe_get_constant ())
    1980              :     return num_bytes_sval;
    1981              : 
    1982              :   /* For now, try just guessing the size as the capacity of the
    1983              :      base region of the src.
    1984              :      This is a hack; we might get too large a value.  */
    1985           45 :   const region *src_base_reg = src_reg->get_base_region ();
    1986           45 :   num_bytes_sval = get_capacity (src_base_reg);
    1987              : 
    1988           45 :   if (num_bytes_sval->maybe_get_constant ())
    1989           11 :     return num_bytes_sval;
    1990              : 
    1991              :   /* Non-constant: give up. */
    1992              :   return nullptr;
    1993              : }
    1994              : 
    1995              : /* Get any known_function for FNDECL for call CD.
    1996              : 
    1997              :    The call must match all assumptions made by the known_function (such as
    1998              :    e.g. "argument 1's type must be a pointer type").
    1999              : 
    2000              :    Return nullptr if no known_function is found, or it does not match the
    2001              :    assumption(s).  */
    2002              : 
    2003              : const known_function *
    2004       313110 : region_model::get_known_function (tree fndecl, const call_details &cd) const
    2005              : {
    2006       313110 :   known_function_manager *known_fn_mgr = m_mgr->get_known_function_manager ();
    2007       313110 :   return known_fn_mgr->get_match (fndecl, cd);
    2008              : }
    2009              : 
    2010              : /* Get any known_function for IFN, or nullptr.  */
    2011              : 
    2012              : const known_function *
    2013         1442 : region_model::get_known_function (enum internal_fn ifn) const
    2014              : {
    2015         1442 :   known_function_manager *known_fn_mgr = m_mgr->get_known_function_manager ();
    2016         1442 :   return known_fn_mgr->get_internal_fn (ifn);
    2017              : }
    2018              : 
    2019              : /* Get any builtin_known_function for CALL and emit any warning to CTXT
    2020              :    if not nullptr.
    2021              : 
    2022              :    The call must match all assumptions made by the known_function (such as
    2023              :    e.g. "argument 1's type must be a pointer type").
    2024              : 
    2025              :    Return nullptr if no builtin_known_function is found, or it does
    2026              :    not match the assumption(s).
    2027              : 
    2028              :    Internally calls get_known_function to find a known_function and cast it
    2029              :    to a builtin_known_function.
    2030              : 
    2031              :    For instance, calloc is a C builtin, defined in gcc/builtins.def
    2032              :    by the DEF_LIB_BUILTIN macro. Such builtins are recognized by the
    2033              :    analyzer by their name, so that even in C++ or if the user redeclares
    2034              :    them but mismatch their signature, they are still recognized as builtins.
    2035              : 
    2036              :    Cases when a supposed builtin is not flagged as one by the FE:
    2037              : 
    2038              :     The C++ FE does not recognize calloc as a builtin if it has not been
    2039              :     included from a standard header, but the C FE does. Hence in C++ if
    2040              :     CALL comes from a calloc and stdlib is not included,
    2041              :     gcc/tree.h:fndecl_built_in_p (CALL) would be false.
    2042              : 
    2043              :     In C code, a __SIZE_TYPE__ calloc (__SIZE_TYPE__, __SIZE_TYPE__) user
    2044              :     declaration has obviously a mismatching signature from the standard, and
    2045              :     its function_decl tree won't be unified by
    2046              :     gcc/c-decl.cc:match_builtin_function_types.
    2047              : 
    2048              :    Yet in both cases the analyzer should treat the calls as a builtin calloc
    2049              :    so that extra attributes unspecified by the standard but added by GCC
    2050              :    (e.g. sprintf attributes in gcc/builtins.def), useful for the detection of
    2051              :    dangerous behavior, are indeed processed.
    2052              : 
    2053              :    Therefore for those cases when a "builtin flag" is not added by the FE,
    2054              :    builtins' kf are derived from builtin_known_function, whose method
    2055              :    builtin_known_function::builtin_decl returns the builtin's
    2056              :    function_decl tree as defined in gcc/builtins.def, with all the extra
    2057              :    attributes.  */
    2058              : 
    2059              : const builtin_known_function *
    2060       169778 : region_model::get_builtin_kf (const gcall &call,
    2061              :                                region_model_context *ctxt /* = nullptr */) const
    2062              : {
    2063       169778 :   region_model *mut_this = const_cast <region_model *> (this);
    2064       169778 :   tree callee_fndecl = mut_this->get_fndecl_for_call (call, ctxt);
    2065       169778 :   if (! callee_fndecl)
    2066              :     return nullptr;
    2067              : 
    2068       169778 :   call_details cd (call, mut_this, ctxt);
    2069       169778 :   if (const known_function *kf = get_known_function (callee_fndecl, cd))
    2070       117372 :     return kf->dyn_cast_builtin_kf ();
    2071              : 
    2072              :   return nullptr;
    2073              : }
    2074              : 
    2075              : /* Subclass of custom_edge_info for use by exploded_edges that represent
    2076              :    an exception being thrown from a call we don't have the code for.  */
    2077              : 
    2078              : class exception_thrown_from_unrecognized_call : public custom_edge_info
    2079              : {
    2080              : public:
    2081         5605 :   exception_thrown_from_unrecognized_call (const gcall &call,
    2082              :                                            tree fndecl)
    2083         5605 :   : m_call (call),
    2084         5605 :     m_fndecl (fndecl)
    2085              :   {
    2086              :   }
    2087              : 
    2088           12 :   void print (pretty_printer *pp) const final override
    2089              :   {
    2090           12 :     if (m_fndecl)
    2091           12 :       pp_printf (pp, "if %qD throws an exception...", m_fndecl);
    2092              :     else
    2093            0 :       pp_printf (pp, "if the called function throws an exception...");
    2094           12 :   };
    2095              : 
    2096              :   bool
    2097         5642 :   update_model (region_model *model,
    2098              :                 const exploded_edge *,
    2099              :                 region_model_context *ctxt) const final override
    2100              :   {
    2101              :     /* Allocate an exception and set it as the current exception.  */
    2102         5642 :     const region *exception_reg
    2103              :       = model->get_or_create_region_for_heap_alloc
    2104         5642 :           (nullptr, /* We don't know the size of the region.  */
    2105              :            ctxt);
    2106              : 
    2107         5642 :     region_model_manager *mgr = model->get_manager ();
    2108         5642 :     conjured_purge p (model, ctxt);
    2109              : 
    2110              :     /* The contents of the region are some conjured svalue.  */
    2111         5642 :     const svalue *exception_sval
    2112        11284 :       = mgr->get_or_create_conjured_svalue (NULL_TREE,
    2113         5642 :                                             &m_call,
    2114              :                                             exception_reg, p, 0);
    2115         5642 :     model->set_value (exception_reg, exception_sval, ctxt);
    2116         5642 :     const svalue *exception_ptr_sval
    2117         5642 :       = mgr->get_ptr_svalue (ptr_type_node, exception_reg);
    2118         5642 :     const svalue *tinfo_sval
    2119        11284 :       = mgr->get_or_create_conjured_svalue (ptr_type_node,
    2120         5642 :                                             &m_call,
    2121              :                                             exception_reg, p, 1);
    2122         5642 :     const svalue *destructor_sval
    2123        11284 :       = mgr->get_or_create_conjured_svalue (ptr_type_node,
    2124         5642 :                                             &m_call,
    2125              :                                             exception_reg, p, 2);
    2126              : 
    2127              :     /* Push a new exception_node on the model's thrown exception stack.  */
    2128         5642 :     exception_node eh_node (exception_ptr_sval, tinfo_sval, destructor_sval);
    2129         5642 :     model->push_thrown_exception (eh_node);
    2130              : 
    2131         5642 :     return true;
    2132              :   }
    2133              : 
    2134              :   void
    2135           29 :   add_events_to_path (checker_path *emission_path,
    2136              :                       const exploded_edge &eedge,
    2137              :                       pending_diagnostic &,
    2138              :                       const state_transition *) const final override
    2139              :   {
    2140           29 :     const exploded_node *dst_node = eedge.m_dest;
    2141           29 :     const program_point &dst_point = dst_node->get_point ();
    2142           29 :     const int dst_stack_depth = dst_point.get_stack_depth ();
    2143              : 
    2144           29 :     emission_path->add_event
    2145           29 :       (std::make_unique<throw_from_call_to_external_fn_event>
    2146           29 :          (event_loc_info (m_call.location,
    2147              :                           dst_point.get_fndecl (),
    2148           29 :                           dst_stack_depth),
    2149              :           dst_node,
    2150              :           m_call,
    2151           29 :           m_fndecl));
    2152           29 :   }
    2153              : 
    2154              :   exploded_node *
    2155         5492 :   create_enode (exploded_graph &eg,
    2156              :                 const program_point &point,
    2157              :                 program_state &&state,
    2158              :                 exploded_node *enode_for_diag,
    2159              :                 region_model_context *ctxt) const final override
    2160              :   {
    2161         5492 :     exploded_node *thrown_enode
    2162         5492 :       = eg.get_or_create_node (point, state, enode_for_diag,
    2163              :                                /* Don't add to worklist.  */
    2164              :                                false);
    2165         5492 :     if (!thrown_enode)
    2166              :       return nullptr;
    2167              : 
    2168              :     /* Add successor edges for thrown_enode "by hand" for the exception.  */
    2169         5416 :     eg.unwind_from_exception (*thrown_enode,
    2170         5416 :                               &m_call,
    2171              :                               ctxt);
    2172         5416 :     return thrown_enode;
    2173              :   }
    2174              : 
    2175              : private:
    2176              :   const gcall &m_call;
    2177              :   tree m_fndecl; // could be null
    2178              : };
    2179              : 
    2180              : /* Get a set of functions that are assumed to not throw exceptions.  */
    2181              : 
    2182              : static function_set
    2183         5469 : get_fns_assumed_not_to_throw ()
    2184              : {
    2185              :   // TODO: populate this list more fully
    2186         5469 :   static const char * const fn_names[] = {
    2187              :     /* This array must be kept sorted.  */
    2188              : 
    2189              :     "fclose"
    2190              :   };
    2191         5469 :   const size_t count = ARRAY_SIZE (fn_names);
    2192         5469 :   function_set fs (fn_names, count);
    2193         5469 :   return fs;
    2194              : }
    2195              : 
    2196              : /* Return true if CALL could throw an exception.
    2197              :    FNDECL could be NULL_TREE.  */
    2198              : 
    2199              : static bool
    2200        12946 : can_throw_p (const gcall &call, tree fndecl)
    2201              : {
    2202        12946 :   if (!flag_exceptions)
    2203              :     return false;
    2204              : 
    2205              :   /* Compatibility flag to allow the user to assume external functions
    2206              :      never throw exceptions.  This may be useful when using the analyzer
    2207              :      on C code that is compiled with -fexceptions, but for which the headers
    2208              :      haven't yet had "nothrow" attributes systematically added.  */
    2209         6156 :   if (flag_analyzer_assume_nothrow)
    2210              :     return false;
    2211              : 
    2212         6154 :   if (gimple_call_nothrow_p (&call))
    2213              :     return false;
    2214              : 
    2215         5615 :   if (fndecl)
    2216              :     {
    2217              :       /* If we are checking a thunk, we want to verify whether or not the
    2218              :          underlying function is nothrow.  */
    2219         5472 :       if (cgraph_node *n = cgraph_node::get (fndecl))
    2220         5472 :         fndecl = n->function_symbol ()->decl;
    2221              : 
    2222         5472 :       if (TREE_NOTHROW (fndecl))
    2223           10 :         return false;
    2224              : 
    2225         5469 :       const function_set fs = get_fns_assumed_not_to_throw ();
    2226         5469 :       if (fs.contains_decl_p (fndecl))
    2227              :         return false;
    2228              :     }
    2229              : 
    2230              :   return true;
    2231              : }
    2232              : 
    2233              : /* Given CALL where we don't know what code is being called
    2234              :    (by not having the body of FNDECL, or having NULL_TREE for FNDECL),
    2235              :   potentially bifurcate control flow to simulate the call throwing
    2236              :   an exception.  */
    2237              : 
    2238              : void
    2239        18966 : region_model::check_for_throw_inside_call (const gcall &call,
    2240              :                                            tree fndecl,
    2241              :                                            region_model_context *ctxt)
    2242              : {
    2243        18966 :   if (!ctxt)
    2244        13361 :     return;
    2245              : 
    2246              :   /* Could this function throw an exception?
    2247              :      If so, add an extra e-edge for that.  */
    2248        12946 :   if (!can_throw_p (call, fndecl))
    2249              :     return;
    2250              : 
    2251         5605 :   auto throws_exception
    2252         5605 :     = std::make_unique<exception_thrown_from_unrecognized_call> (call, fndecl);
    2253         5605 :   ctxt->bifurcate (std::move (throws_exception));
    2254         5605 : }
    2255              : 
    2256              : /* A subclass of pending_diagnostic for complaining about jumps through NULL
    2257              :    function pointers.  */
    2258              : 
    2259              : class jump_through_null : public pending_diagnostic_subclass<jump_through_null>
    2260              : {
    2261              : public:
    2262           16 :   jump_through_null (const gcall &call)
    2263           16 :   : m_call (call)
    2264              :   {}
    2265              : 
    2266          152 :   const char *get_kind () const final override
    2267              :   {
    2268          152 :     return "jump_through_null";
    2269              :   }
    2270              : 
    2271           16 :   bool operator== (const jump_through_null &other) const
    2272              :   {
    2273           16 :     return &m_call == &other.m_call;
    2274              :   }
    2275              : 
    2276           32 :   int get_controlling_option () const final override
    2277              :   {
    2278           32 :     return OPT_Wanalyzer_jump_through_null;
    2279              :   }
    2280              : 
    2281           16 :   bool emit (diagnostic_emission_context &ctxt) final override
    2282              :   {
    2283           16 :     return ctxt.warn ("jump through null pointer");
    2284              :   }
    2285              : 
    2286           32 :   bool describe_final_event (pretty_printer &pp,
    2287              :                              const evdesc::final_event &) final override
    2288              :   {
    2289           32 :     pp_string (&pp, "jump through null pointer here");
    2290           32 :     return true;
    2291              :   }
    2292              : 
    2293              : private:
    2294              :   const gcall &m_call;
    2295              : };
    2296              : /* Update this model for the CALL stmt, using CTXT to report any
    2297              :    diagnostics - the first half.
    2298              : 
    2299              :    Updates to the region_model that should be made *before* sm-states
    2300              :    are updated are done here; other updates to the region_model are done
    2301              :    in region_model::on_call_post.
    2302              : 
    2303              :    Return true if the function call has unknown side effects (it wasn't
    2304              :    recognized and we don't have a body for it, or are unable to tell which
    2305              :    fndecl it is).  */
    2306              : 
    2307              : bool
    2308        78781 : region_model::on_call_pre (const gcall &call, region_model_context *ctxt)
    2309              : {
    2310        78781 :   call_details cd (call, this, ctxt);
    2311              : 
    2312              :   /* Special-case for IFN_DEFERRED_INIT.
    2313              :      We want to report uninitialized variables with -fanalyzer (treating
    2314              :      -ftrivial-auto-var-init= as purely a mitigation feature).
    2315              :      Handle IFN_DEFERRED_INIT by treating it as no-op: don't touch the
    2316              :      lhs of the call, so that it is still uninitialized from the point of
    2317              :      view of the analyzer.  */
    2318        78781 :   if (gimple_call_internal_p (&call)
    2319        78781 :       && gimple_call_internal_fn (&call) == IFN_DEFERRED_INIT)
    2320              :     return false; /* No side effects.  */
    2321              : 
    2322              :   /* Get svalues for all of the arguments at the callsite, to ensure that we
    2323              :      complain about any uninitialized arguments.  This might lead to
    2324              :      duplicates if any of the handling below also looks up the svalues,
    2325              :      but the deduplication code should deal with that.  */
    2326        73705 :   if (ctxt)
    2327        50816 :     check_call_args (cd);
    2328              : 
    2329        73705 :   tree callee_fndecl = get_fndecl_for_call (call, ctxt);
    2330              : 
    2331        73705 :   if (gimple_call_internal_p (&call))
    2332         2884 :     if (const known_function *kf
    2333         1442 :           = get_known_function (gimple_call_internal_fn (&call)))
    2334              :       {
    2335         1408 :         kf->impl_call_pre (cd);
    2336         1408 :         return false; /* No further side effects.  */
    2337              :       }
    2338              : 
    2339        72297 :   if (!callee_fndecl)
    2340              :     {
    2341              :       /* Check for jump through nullptr.  */
    2342          523 :       if (ctxt)
    2343          407 :         if (tree fn_ptr = gimple_call_fn (&call))
    2344              :           {
    2345          381 :             const svalue *fn_ptr_sval = get_rvalue (fn_ptr, ctxt);
    2346          381 :             if (fn_ptr_sval->all_zeroes_p ())
    2347              :               {
    2348           16 :                 ctxt->warn
    2349           16 :                   (std::make_unique<jump_through_null> (call));
    2350           16 :                 ctxt->terminate_path ();
    2351           16 :                 return true;
    2352              :               }
    2353              :           }
    2354              : 
    2355          507 :       check_for_throw_inside_call (call, NULL_TREE, ctxt);
    2356          507 :       cd.set_any_lhs_with_defaults ();
    2357          507 :       return true; /* Unknown side effects.  */
    2358              :     }
    2359              : 
    2360        71774 :   if (const known_function *kf = get_known_function (callee_fndecl, cd))
    2361              :     {
    2362        50979 :       kf->impl_call_pre (cd);
    2363        50979 :       return false; /* No further side effects.  */
    2364              :     }
    2365              : 
    2366        20795 :   cd.set_any_lhs_with_defaults ();
    2367              : 
    2368        20795 :   const int callee_fndecl_flags = flags_from_decl_or_type (callee_fndecl);
    2369        20795 :   if (callee_fndecl_flags & (ECF_CONST | ECF_PURE))
    2370              :     return false; /* No side effects.  */
    2371              : 
    2372        19251 :   if (fndecl_built_in_p (callee_fndecl))
    2373              :     return true; /* Unknown side effects.  */
    2374              : 
    2375        18459 :   if (!fndecl_has_gimple_body_p (callee_fndecl))
    2376              :     {
    2377        18459 :       check_for_throw_inside_call (call, callee_fndecl, ctxt);
    2378        18459 :       return true; /* Unknown side effects.  */
    2379              :     }
    2380              : 
    2381              :   return false; /* No side effects.  */
    2382              : }
    2383              : 
    2384              : /* Update this model for the CALL stmt, using CTXT to report any
    2385              :    diagnostics - the second half.
    2386              : 
    2387              :    Updates to the region_model that should be made *after* sm-states
    2388              :    are updated are done here; other updates to the region_model are done
    2389              :    in region_model::on_call_pre.
    2390              : 
    2391              :    If UNKNOWN_SIDE_EFFECTS is true, also call handle_unrecognized_call
    2392              :    to purge state.  */
    2393              : 
    2394              : void
    2395        78518 : region_model::on_call_post (const gcall &call,
    2396              :                             bool unknown_side_effects,
    2397              :                             region_model_context *ctxt)
    2398              : {
    2399        78518 :   if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
    2400              :     {
    2401        71558 :       call_details cd (call, this, ctxt);
    2402        71558 :       if (const known_function *kf = get_known_function (callee_fndecl, cd))
    2403              :         {
    2404        50821 :           kf->impl_call_post (cd);
    2405       102129 :           return;
    2406              :         }
    2407              :       /* Was this fndecl referenced by
    2408              :          __attribute__((malloc(FOO)))?  */
    2409        20737 :       if (lookup_attribute ("*dealloc", DECL_ATTRIBUTES (callee_fndecl)))
    2410              :         {
    2411          487 :           impl_deallocation_call (cd);
    2412          487 :           return;
    2413              :         }
    2414              :     }
    2415              : 
    2416        27210 :   if (unknown_side_effects)
    2417              :     {
    2418        18123 :       handle_unrecognized_call (call, ctxt);
    2419        18123 :       if (ctxt)
    2420        12356 :         ctxt->maybe_did_work ();
    2421              :     }
    2422              : }
    2423              : 
    2424              : /* Purge state involving SVAL from this region_model, using CTXT
    2425              :    (if non-NULL) to purge other state in a program_state.
    2426              : 
    2427              :    For example, if we're at the def-stmt of an SSA name, then we need to
    2428              :    purge any state for svalues that involve that SSA name.  This avoids
    2429              :    false positives in loops, since a symbolic value referring to the
    2430              :    SSA name will be referring to the previous value of that SSA name.
    2431              : 
    2432              :    For example, in:
    2433              :      while ((e = hashmap_iter_next(&iter))) {
    2434              :        struct oid2strbuf *e_strbuf = (struct oid2strbuf *)e;
    2435              :        free (e_strbuf->value);
    2436              :      }
    2437              :    at the def-stmt of e_8:
    2438              :      e_8 = hashmap_iter_next (&iter);
    2439              :    we should purge the "freed" state of:
    2440              :      INIT_VAL(CAST_REG(‘struct oid2strbuf’, (*INIT_VAL(e_8))).value)
    2441              :    which is the "e_strbuf->value" value from the previous iteration,
    2442              :    or we will erroneously report a double-free - the "e_8" within it
    2443              :    refers to the previous value.  */
    2444              : 
    2445              : void
    2446        30285 : region_model::purge_state_involving (const svalue *sval,
    2447              :                                      region_model_context *ctxt)
    2448              : {
    2449        30285 :   if (!sval->can_have_associated_state_p ())
    2450              :     return;
    2451        30285 :   m_store.purge_state_involving (sval, m_mgr);
    2452        30285 :   m_constraints->purge_state_involving (sval);
    2453        30285 :   m_dynamic_extents.purge_state_involving (sval);
    2454        30285 :   if (ctxt)
    2455        17985 :     ctxt->purge_state_involving (sval);
    2456              : }
    2457              : 
    2458              : /* A pending_note subclass for adding a note about an
    2459              :    __attribute__((access, ...)) to a diagnostic.  */
    2460              : 
    2461              : class reason_attr_access : public pending_note_subclass<reason_attr_access>
    2462              : {
    2463              : public:
    2464           22 :   reason_attr_access (tree callee_fndecl, const attr_access &access)
    2465           22 :   : m_callee_fndecl (callee_fndecl),
    2466           22 :     m_ptr_argno (access.ptrarg),
    2467           22 :     m_access_str (TREE_STRING_POINTER (access.to_external_string ()))
    2468              :   {
    2469           22 :   }
    2470              : 
    2471          116 :   const char *get_kind () const final override { return "reason_attr_access"; }
    2472              : 
    2473           18 :   void emit () const final override
    2474              :   {
    2475           18 :     auto_urlify_attributes sentinel;
    2476           18 :     inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
    2477              :             "parameter %i of %qD marked with attribute %qs",
    2478           18 :             m_ptr_argno + 1, m_callee_fndecl, m_access_str);
    2479           18 :   }
    2480              : 
    2481           58 :   bool operator== (const reason_attr_access &other) const
    2482              :   {
    2483           58 :     return (m_callee_fndecl == other.m_callee_fndecl
    2484           22 :             && m_ptr_argno == other.m_ptr_argno
    2485           80 :             && !strcmp (m_access_str, other.m_access_str));
    2486              :   }
    2487              : 
    2488              : private:
    2489              :   tree m_callee_fndecl;
    2490              :   unsigned m_ptr_argno;
    2491              :   const char *m_access_str;
    2492              : };
    2493              : 
    2494              : /* Check CALL a call to external function CALLEE_FNDECL based on
    2495              :    any __attribute__ ((access, ....) on the latter, complaining to
    2496              :    CTXT about any issues.
    2497              : 
    2498              :    Currently we merely call check_region_for_write on any regions
    2499              :    pointed to by arguments marked with a "write_only" or "read_write"
    2500              :    attribute.  */
    2501              : 
    2502              : void
    2503         1257 : region_model::check_function_attr_access (const gcall &call,
    2504              :                                           tree callee_fndecl,
    2505              :                                           region_model_context *ctxt,
    2506              :                                           rdwr_map &rdwr_idx) const
    2507              : {
    2508         1257 :   gcc_assert (callee_fndecl);
    2509         1257 :   gcc_assert (ctxt);
    2510              : 
    2511         1257 :   tree fntype = TREE_TYPE (callee_fndecl);
    2512         1257 :   gcc_assert (fntype);
    2513              : 
    2514         1257 :   unsigned argno = 0;
    2515              : 
    2516         4776 :   for (tree iter = TYPE_ARG_TYPES (fntype); iter;
    2517         3519 :        iter = TREE_CHAIN (iter), ++argno)
    2518              :     {
    2519         3519 :       const attr_access* access = rdwr_idx.get (argno);
    2520         3519 :       if (!access)
    2521         3241 :         continue;
    2522              : 
    2523              :       /* Ignore any duplicate entry in the map for the size argument.  */
    2524          278 :       if (access->ptrarg != argno)
    2525          114 :         continue;
    2526              : 
    2527          164 :       if (access->mode == access_write_only
    2528          164 :           || access->mode == access_read_write)
    2529              :         {
    2530              :           /* Subclass of annotating_context that
    2531              :              adds a note about the attr access to any saved diagnostics.  */
    2532           40 :           class annotating_ctxt : public annotating_context
    2533              :           {
    2534              :           public:
    2535           40 :             annotating_ctxt (tree callee_fndecl,
    2536              :                              const attr_access &access,
    2537              :                              region_model_context *ctxt)
    2538              :             : annotating_context (ctxt),
    2539           40 :               m_callee_fndecl (callee_fndecl),
    2540           40 :               m_access (access)
    2541              :             {
    2542              :             }
    2543           22 :             void add_annotations () final override
    2544              :             {
    2545           22 :               add_note (std::make_unique<reason_attr_access>
    2546           22 :                           (m_callee_fndecl, m_access));
    2547           22 :             }
    2548              :           private:
    2549              :             tree m_callee_fndecl;
    2550              :             const attr_access &m_access;
    2551              :           };
    2552              : 
    2553              :           /* Use this ctxt below so that any diagnostics get the
    2554              :              note added to them.  */
    2555           40 :           annotating_ctxt my_ctxt (callee_fndecl, *access, ctxt);
    2556              : 
    2557           40 :           tree ptr_tree = gimple_call_arg (&call, access->ptrarg);
    2558           40 :           const svalue *ptr_sval = get_rvalue (ptr_tree, &my_ctxt);
    2559           40 :           const region *reg = deref_rvalue (ptr_sval, ptr_tree, &my_ctxt);
    2560           40 :           check_region_for_write (reg, nullptr, &my_ctxt);
    2561              :           /* We don't use the size arg for now.  */
    2562              :         }
    2563              :     }
    2564         1257 : }
    2565              : 
    2566              : /* Subroutine of region_model::check_function_attr_null_terminated_string_arg,
    2567              :    checking one instance of __attribute__((null_terminated_string_arg)).  */
    2568              : 
    2569              : void
    2570          200 : region_model::
    2571              : check_one_function_attr_null_terminated_string_arg (const gcall &call,
    2572              :                                                     tree callee_fndecl,
    2573              :                                                     region_model_context *ctxt,
    2574              :                                                     rdwr_map &rdwr_idx,
    2575              :                                                     tree attr)
    2576              : {
    2577          200 :   gcc_assert (callee_fndecl);
    2578          200 :   gcc_assert (ctxt);
    2579          200 :   gcc_assert (attr);
    2580              : 
    2581          200 :   tree arg = TREE_VALUE (attr);
    2582          200 :   if (!arg)
    2583           76 :     return;
    2584              : 
    2585              :   /* Convert from 1-based to 0-based index.  */
    2586          200 :   unsigned int arg_idx = TREE_INT_CST_LOW (TREE_VALUE (arg)) - 1;
    2587              : 
    2588              :   /* If there's also an "access" attribute on the ptr param
    2589              :      for reading with a size param specified, then that size
    2590              :      limits the size of the possible read from the pointer.  */
    2591          200 :   if (const attr_access* access = rdwr_idx.get (arg_idx))
    2592          104 :     if ((access->mode == access_read_only
    2593          104 :          || access->mode == access_read_write)
    2594          104 :         && access->sizarg != UINT_MAX)
    2595              :       {
    2596           76 :         call_details cd_checked (call, this, ctxt);
    2597           76 :         const svalue *limit_sval
    2598           76 :           = cd_checked.get_arg_svalue (access->sizarg);
    2599           76 :         const svalue *ptr_sval
    2600           76 :           = cd_checked.get_arg_svalue (arg_idx);
    2601              :         /* Try reading all of the bytes expressed by the size param,
    2602              :            but without emitting warnings (via a null context).  */
    2603           76 :         const svalue *limited_sval
    2604           76 :           = read_bytes (deref_rvalue (ptr_sval, NULL_TREE, nullptr),
    2605              :                         NULL_TREE,
    2606              :                         limit_sval,
    2607              :                         nullptr);
    2608           76 :         if (limited_sval->get_kind () == SK_POISONED)
    2609              :           {
    2610              :             /* Reading up to the truncation limit caused issues.
    2611              :                Assume that the string is meant to be terminated
    2612              :                before then, so perform a *checked* check for the
    2613              :                terminator.  */
    2614           24 :             check_for_null_terminated_string_arg (cd_checked,
    2615              :                                                   arg_idx);
    2616              :           }
    2617              :         else
    2618              :           {
    2619              :             /* Reading up to the truncation limit seems OK; repeat
    2620              :                the read, but with checking enabled.  */
    2621           52 :             read_bytes (deref_rvalue (ptr_sval, NULL_TREE, ctxt),
    2622              :                         NULL_TREE,
    2623              :                         limit_sval,
    2624              :                         ctxt);
    2625              :           }
    2626           76 :         return;
    2627              :       }
    2628              : 
    2629              :   /* Otherwise, we don't have an access-attribute limiting the read.
    2630              :      Simulate a read up to the null terminator (if any).  */
    2631              : 
    2632          124 :   call_details cd (call, this, ctxt);
    2633          124 :   check_for_null_terminated_string_arg (cd, arg_idx);
    2634              : }
    2635              : 
    2636              : /* Check CALL a call to external function CALLEE_FNDECL for any uses
    2637              :    of __attribute__ ((null_terminated_string_arg)), complaining
    2638              :    to CTXT about any issues.
    2639              : 
    2640              :    Use RDWR_IDX for tracking uses of __attribute__ ((access, ....).  */
    2641              : 
    2642              : void
    2643         1257 : region_model::
    2644              : check_function_attr_null_terminated_string_arg (const gcall &call,
    2645              :                                                 tree callee_fndecl,
    2646              :                                                 region_model_context *ctxt,
    2647              :                                                 rdwr_map &rdwr_idx)
    2648              : {
    2649         1257 :   gcc_assert (callee_fndecl);
    2650         1257 :   gcc_assert (ctxt);
    2651              : 
    2652         1257 :   tree fntype = TREE_TYPE (callee_fndecl);
    2653         1257 :   gcc_assert (fntype);
    2654              : 
    2655              :   /* A function declaration can specify multiple attribute
    2656              :      null_terminated_string_arg, each with one argument.  */
    2657         1457 :   for (tree attr = TYPE_ATTRIBUTES (fntype); attr; attr = TREE_CHAIN (attr))
    2658              :     {
    2659         1281 :       attr = lookup_attribute ("null_terminated_string_arg", attr);
    2660         1281 :       if (!attr)
    2661              :         return;
    2662              : 
    2663          200 :       check_one_function_attr_null_terminated_string_arg (call, callee_fndecl,
    2664              :                                                           ctxt, rdwr_idx,
    2665              :                                                           attr);
    2666              :     }
    2667              : }
    2668              : 
    2669              : /* Check CALL a call to external function CALLEE_FNDECL for any
    2670              :    function attributes, complaining to CTXT about any issues.  */
    2671              : 
    2672              : void
    2673        11970 : region_model::check_function_attrs (const gcall &call,
    2674              :                                     tree callee_fndecl,
    2675              :                                     region_model_context *ctxt)
    2676              : {
    2677        11970 :   gcc_assert (callee_fndecl);
    2678        11970 :   gcc_assert (ctxt);
    2679              : 
    2680        11970 :   tree fntype = TREE_TYPE (callee_fndecl);
    2681        11970 :   if (!fntype)
    2682        10713 :     return;
    2683              : 
    2684        11970 :   if (!TYPE_ATTRIBUTES (fntype))
    2685              :     return;
    2686              : 
    2687              :   /* Initialize a map of attribute access specifications for arguments
    2688              :      to the function call.  */
    2689         1257 :   rdwr_map rdwr_idx;
    2690         1257 :   init_attr_rdwr_indices (&rdwr_idx, TYPE_ATTRIBUTES (fntype));
    2691              : 
    2692         1257 :   check_function_attr_access (call, callee_fndecl, ctxt, rdwr_idx);
    2693         1257 :   check_function_attr_null_terminated_string_arg (call, callee_fndecl,
    2694              :                                                   ctxt, rdwr_idx);
    2695         1257 : }
    2696              : 
    2697              : /* Handle a call CALL to a function with unknown behavior.
    2698              : 
    2699              :    Traverse the regions in this model, determining what regions are
    2700              :    reachable from pointer arguments to CALL and from global variables,
    2701              :    recursively.
    2702              : 
    2703              :    Set all reachable regions to new unknown values and purge sm-state
    2704              :    from their values, and from values that point to them.  */
    2705              : 
    2706              : void
    2707        18123 : region_model::handle_unrecognized_call (const gcall &call,
    2708              :                                         region_model_context *ctxt)
    2709              : {
    2710        18123 :   tree fndecl = get_fndecl_for_call (call, ctxt);
    2711              : 
    2712        18123 :   if (fndecl && ctxt)
    2713        11970 :     check_function_attrs (call, fndecl, ctxt);
    2714              : 
    2715        18123 :   reachable_regions reachable_regs (this);
    2716              : 
    2717              :   /* Determine the reachable regions and their mutability.  */
    2718        18123 :   {
    2719              :     /* Add globals and regions that already escaped in previous
    2720              :        unknown calls.  */
    2721        18123 :     m_store.for_each_cluster (reachable_regions::init_cluster_cb,
    2722              :                               &reachable_regs);
    2723              : 
    2724              :     /* Params that are pointers.  */
    2725        18123 :     tree iter_param_types = NULL_TREE;
    2726        18123 :     if (fndecl)
    2727        17621 :       iter_param_types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
    2728        37883 :     for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (&call);
    2729              :          arg_idx++)
    2730              :       {
    2731              :         /* Track expected param type, where available.  */
    2732        19760 :         tree param_type = NULL_TREE;
    2733        19760 :         if (iter_param_types)
    2734              :           {
    2735        18221 :             param_type = TREE_VALUE (iter_param_types);
    2736        18221 :             gcc_assert (param_type);
    2737        18221 :             iter_param_types = TREE_CHAIN (iter_param_types);
    2738              :           }
    2739              : 
    2740        19760 :         tree parm = gimple_call_arg (&call, arg_idx);
    2741        19760 :         const svalue *parm_sval = get_rvalue (parm, ctxt);
    2742        19760 :         reachable_regs.handle_parm (parm_sval, param_type);
    2743              :       }
    2744              :   }
    2745              : 
    2746        18123 :   uncertainty_t *uncertainty = ctxt ? ctxt->get_uncertainty () : nullptr;
    2747              : 
    2748              :   /* Purge sm-state for the svalues that were reachable,
    2749              :      both in non-mutable and mutable form.  */
    2750        46697 :   for (svalue_set::iterator iter
    2751        18123 :          = reachable_regs.begin_reachable_svals ();
    2752        46697 :        iter != reachable_regs.end_reachable_svals (); ++iter)
    2753              :     {
    2754        28574 :       const svalue *sval = (*iter);
    2755        28574 :       if (ctxt)
    2756        22225 :         ctxt->on_unknown_change (sval, false);
    2757              :     }
    2758        59628 :   for (svalue_set::iterator iter
    2759        18123 :          = reachable_regs.begin_mutable_svals ();
    2760        59628 :        iter != reachable_regs.end_mutable_svals (); ++iter)
    2761              :     {
    2762        41505 :       const svalue *sval = (*iter);
    2763        41505 :       if (ctxt)
    2764        32493 :         ctxt->on_unknown_change (sval, true);
    2765        41505 :       if (uncertainty)
    2766        31282 :         uncertainty->on_mutable_sval_at_unknown_call (sval);
    2767              :     }
    2768              : 
    2769              :   /* Mark any clusters that have escaped.  */
    2770        18123 :   reachable_regs.mark_escaped_clusters (ctxt);
    2771              : 
    2772              :   /* Update bindings for all clusters that have escaped, whether above,
    2773              :      or previously.  */
    2774        18123 :   m_store.on_unknown_fncall (call, m_mgr->get_store_manager (),
    2775        18123 :                              conjured_purge (this, ctxt));
    2776              : 
    2777              :   /* Purge dynamic extents from any regions that have escaped mutably:
    2778              :      realloc could have been called on them.  */
    2779        26225 :   for (hash_set<const region *>::iterator
    2780        18123 :          iter = reachable_regs.begin_mutable_base_regs ();
    2781        44348 :        iter != reachable_regs.end_mutable_base_regs ();
    2782        26225 :        ++iter)
    2783              :     {
    2784        26225 :       const region *base_reg = (*iter);
    2785        26225 :       unset_dynamic_extents (base_reg);
    2786              :     }
    2787        18123 : }
    2788              : 
    2789              : /* Traverse the regions in this model, determining what regions are
    2790              :    reachable from the store and populating *OUT.
    2791              : 
    2792              :    If EXTRA_SVAL is non-NULL, treat it as an additional "root"
    2793              :    for reachability (for handling return values from functions when
    2794              :    analyzing return of the only function on the stack).
    2795              : 
    2796              :    If UNCERTAINTY is non-NULL, treat any svalues that were recorded
    2797              :    within it as being maybe-bound as additional "roots" for reachability.
    2798              : 
    2799              :    Find svalues that haven't leaked.    */
    2800              : 
    2801              : void
    2802      1048792 : region_model::get_reachable_svalues (svalue_set *out,
    2803              :                                      const svalue *extra_sval,
    2804              :                                      const uncertainty_t *uncertainty)
    2805              : {
    2806      1048792 :   reachable_regions reachable_regs (this);
    2807              : 
    2808              :   /* Add globals and regions that already escaped in previous
    2809              :      unknown calls.  */
    2810      1048792 :   m_store.for_each_cluster (reachable_regions::init_cluster_cb,
    2811              :                             &reachable_regs);
    2812              : 
    2813      1048792 :   if (extra_sval)
    2814         5425 :     reachable_regs.handle_sval (extra_sval);
    2815              : 
    2816      1048792 :   if (uncertainty)
    2817       482018 :     for (uncertainty_t::iterator iter
    2818       466813 :            = uncertainty->begin_maybe_bound_svals ();
    2819       948831 :          iter != uncertainty->end_maybe_bound_svals (); ++iter)
    2820        15205 :       reachable_regs.handle_sval (*iter);
    2821              : 
    2822              :   /* Get regions for locals that have explicitly bound values.  */
    2823      9913423 :   for (store::cluster_map_t::iterator iter = m_store.begin ();
    2824      9913423 :        iter != m_store.end (); ++iter)
    2825              :     {
    2826      8864631 :       const region *base_reg = (*iter).first;
    2827      8864631 :       if (const region *parent = base_reg->get_parent_region ())
    2828      8864631 :         if (parent->get_kind () == RK_FRAME)
    2829      5863285 :           reachable_regs.add (base_reg, false);
    2830              :     }
    2831              : 
    2832              :   /* Populate *OUT based on the values that were reachable.  */
    2833      1048792 :   for (svalue_set::iterator iter
    2834      1048792 :          = reachable_regs.begin_reachable_svals ();
    2835     10572528 :        iter != reachable_regs.end_reachable_svals (); ++iter)
    2836      9523736 :     out->add (*iter);
    2837      1048792 : }
    2838              : 
    2839              : /* Update this model for the RETURN_STMT, using CTXT to report any
    2840              :    diagnostics.  */
    2841              : 
    2842              : void
    2843            0 : region_model::on_return (const greturn *return_stmt, region_model_context *ctxt)
    2844              : {
    2845            0 :   tree callee = get_current_function ()->decl;
    2846            0 :   tree lhs = DECL_RESULT (callee);
    2847            0 :   tree rhs = gimple_return_retval (return_stmt);
    2848              : 
    2849            0 :   if (lhs && rhs)
    2850              :     {
    2851            0 :       const svalue *sval = get_rvalue (rhs, ctxt);
    2852            0 :       const region *ret_reg = get_lvalue (lhs, ctxt);
    2853            0 :       set_value (ret_reg, sval, ctxt);
    2854              :     }
    2855            0 : }
    2856              : 
    2857              : /* Implementation of region_model::get_lvalue; the latter adds type-checking.
    2858              : 
    2859              :    Get the id of the region for PV within this region_model,
    2860              :    emitting any diagnostics to CTXT.  */
    2861              : 
    2862              : const region *
    2863      2708761 : region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt) const
    2864              : {
    2865      2708761 :   tree expr = pv.m_tree;
    2866              : 
    2867      2708761 :   gcc_assert (expr);
    2868              : 
    2869      2708761 :   switch (TREE_CODE (expr))
    2870              :     {
    2871           84 :     default:
    2872           84 :       return m_mgr->get_region_for_unexpected_tree_code (ctxt, expr,
    2873           84 :                                                          dump_location_t ());
    2874              : 
    2875        28310 :     case ARRAY_REF:
    2876        28310 :       {
    2877        28310 :         tree array = TREE_OPERAND (expr, 0);
    2878        28310 :         tree index = TREE_OPERAND (expr, 1);
    2879              : 
    2880        28310 :         const region *array_reg = get_lvalue (array, ctxt);
    2881        28310 :         const svalue *index_sval = get_rvalue (index, ctxt);
    2882        28310 :         return m_mgr->get_element_region (array_reg,
    2883        28310 :                                           TREE_TYPE (TREE_TYPE (array)),
    2884        28310 :                                           index_sval);
    2885              :       }
    2886          189 :       break;
    2887              : 
    2888          189 :     case BIT_FIELD_REF:
    2889          189 :       {
    2890          189 :         tree inner_expr = TREE_OPERAND (expr, 0);
    2891          189 :         const region *inner_reg = get_lvalue (inner_expr, ctxt);
    2892          189 :         tree num_bits = TREE_OPERAND (expr, 1);
    2893          189 :         tree first_bit_offset = TREE_OPERAND (expr, 2);
    2894          189 :         gcc_assert (TREE_CODE (num_bits) == INTEGER_CST);
    2895          189 :         gcc_assert (TREE_CODE (first_bit_offset) == INTEGER_CST);
    2896          189 :         bit_range bits (TREE_INT_CST_LOW (first_bit_offset),
    2897          189 :                         TREE_INT_CST_LOW (num_bits));
    2898          189 :         return m_mgr->get_bit_range (inner_reg, TREE_TYPE (expr), bits);
    2899              :       }
    2900        82398 :       break;
    2901              : 
    2902        82398 :     case MEM_REF:
    2903        82398 :       {
    2904        82398 :         tree ptr = TREE_OPERAND (expr, 0);
    2905        82398 :         tree offset = TREE_OPERAND (expr, 1);
    2906        82398 :         const svalue *ptr_sval = get_rvalue (ptr, ctxt);
    2907        82398 :         const svalue *offset_sval = get_rvalue (offset, ctxt);
    2908        82398 :         const region *star_ptr = deref_rvalue (ptr_sval, ptr, ctxt);
    2909        82398 :         return m_mgr->get_offset_region (star_ptr,
    2910        82398 :                                          TREE_TYPE (expr),
    2911        82398 :                                          offset_sval);
    2912              :       }
    2913       930912 :       break;
    2914              : 
    2915       930912 :     case FUNCTION_DECL:
    2916       930912 :       return m_mgr->get_region_for_fndecl (expr);
    2917              : 
    2918          343 :     case LABEL_DECL:
    2919          343 :       return m_mgr->get_region_for_label (expr);
    2920              : 
    2921       169030 :     case VAR_DECL:
    2922              :       /* Handle globals.  */
    2923       169030 :       if (is_global_var (expr))
    2924        55834 :         return m_mgr->get_region_for_global (expr);
    2925              : 
    2926              :       /* Fall through.  */
    2927              : 
    2928      1536443 :     case SSA_NAME:
    2929      1536443 :     case PARM_DECL:
    2930      1536443 :     case RESULT_DECL:
    2931      1536443 :       {
    2932      1536443 :         gcc_assert (TREE_CODE (expr) == SSA_NAME
    2933              :                     || TREE_CODE (expr) == PARM_DECL
    2934              :                     || VAR_P (expr)
    2935              :                     || TREE_CODE (expr) == RESULT_DECL);
    2936              : 
    2937      1536443 :         int stack_index = pv.m_stack_depth;
    2938      1536443 :         const frame_region *frame = get_frame_at_index (stack_index);
    2939      1536443 :         gcc_assert (frame);
    2940      1536443 :         return frame->get_region_for_local (m_mgr, expr, ctxt);
    2941              :       }
    2942              : 
    2943        58493 :     case COMPONENT_REF:
    2944        58493 :       {
    2945              :         /* obj.field  */
    2946        58493 :         tree obj = TREE_OPERAND (expr, 0);
    2947        58493 :         tree field = TREE_OPERAND (expr, 1);
    2948        58493 :         const region *obj_reg = get_lvalue (obj, ctxt);
    2949        58493 :         return m_mgr->get_field_region (obj_reg, field);
    2950              :       }
    2951        15755 :       break;
    2952              : 
    2953        15755 :     case STRING_CST:
    2954        15755 :       return m_mgr->get_region_for_string (expr);
    2955              :     }
    2956              : }
    2957              : 
    2958              : /* Assert that SRC_TYPE can be converted to DST_TYPE as a no-op.  */
    2959              : 
    2960              : static void
    2961      6015193 : assert_compat_types (tree src_type, tree dst_type)
    2962              : {
    2963      6015193 :   if (src_type && dst_type && !VOID_TYPE_P (dst_type))
    2964              :     {
    2965              : #if CHECKING_P
    2966      6014808 :       if (!(useless_type_conversion_p (src_type, dst_type)))
    2967            0 :         internal_error ("incompatible types: %qT and %qT", src_type, dst_type);
    2968              : #endif
    2969              :     }
    2970      6015193 : }
    2971              : 
    2972              : /* Return true if SRC_TYPE can be converted to DST_TYPE as a no-op.  */
    2973              : 
    2974              : bool
    2975        14943 : compat_types_p (tree src_type, tree dst_type)
    2976              : {
    2977        14943 :   if (src_type && dst_type && !VOID_TYPE_P (dst_type))
    2978        14943 :     if (!(useless_type_conversion_p (src_type, dst_type)))
    2979              :       return false;
    2980              :   return true;
    2981              : }
    2982              : 
    2983              : /* Get the region for PV within this region_model,
    2984              :    emitting any diagnostics to CTXT.  */
    2985              : 
    2986              : const region *
    2987      2708761 : region_model::get_lvalue (path_var pv, region_model_context *ctxt) const
    2988              : {
    2989      2708761 :   if (pv.m_tree == NULL_TREE)
    2990              :     return nullptr;
    2991              : 
    2992      2708761 :   const region *result_reg = get_lvalue_1 (pv, ctxt);
    2993      2708761 :   assert_compat_types (result_reg->get_type (), TREE_TYPE (pv.m_tree));
    2994      2708761 :   return result_reg;
    2995              : }
    2996              : 
    2997              : /* Get the region for EXPR within this region_model (assuming the most
    2998              :    recent stack frame if it's a local).  */
    2999              : 
    3000              : const region *
    3001      1678925 : region_model::get_lvalue (tree expr, region_model_context *ctxt) const
    3002              : {
    3003      1678925 :   return get_lvalue (path_var (expr, get_stack_depth () - 1), ctxt);
    3004              : }
    3005              : 
    3006              : /* Implementation of region_model::get_rvalue; the latter adds type-checking.
    3007              : 
    3008              :    Get the value of PV within this region_model,
    3009              :    emitting any diagnostics to CTXT.  */
    3010              : 
    3011              : const svalue *
    3012      3291878 : region_model::get_rvalue_1 (path_var pv, region_model_context *ctxt) const
    3013              : {
    3014      3291878 :   gcc_assert (pv.m_tree);
    3015              : 
    3016      3291878 :   switch (TREE_CODE (pv.m_tree))
    3017              :     {
    3018          281 :     default:
    3019          281 :       return m_mgr->get_or_create_unknown_svalue (TREE_TYPE (pv.m_tree));
    3020              : 
    3021      1005758 :     case ADDR_EXPR:
    3022      1005758 :       {
    3023              :         /* "&EXPR".  */
    3024      1005758 :         tree expr = pv.m_tree;
    3025      1005758 :         tree op0 = TREE_OPERAND (expr, 0);
    3026      1005758 :         const region *expr_reg = get_lvalue (op0, ctxt);
    3027      1005758 :         return m_mgr->get_ptr_svalue (TREE_TYPE (expr), expr_reg);
    3028              :       }
    3029          130 :       break;
    3030              : 
    3031          130 :     case BIT_FIELD_REF:
    3032          130 :       {
    3033          130 :         tree expr = pv.m_tree;
    3034          130 :         tree op0 = TREE_OPERAND (expr, 0);
    3035          130 :         const region *reg = get_lvalue (op0, ctxt);
    3036          130 :         tree num_bits = TREE_OPERAND (expr, 1);
    3037          130 :         tree first_bit_offset = TREE_OPERAND (expr, 2);
    3038          130 :         gcc_assert (TREE_CODE (num_bits) == INTEGER_CST);
    3039          130 :         gcc_assert (TREE_CODE (first_bit_offset) == INTEGER_CST);
    3040          130 :         bit_range bits (TREE_INT_CST_LOW (first_bit_offset),
    3041          130 :                         TREE_INT_CST_LOW (num_bits));
    3042          130 :         return get_rvalue_for_bits (TREE_TYPE (expr), reg, bits, ctxt);
    3043              :       }
    3044              : 
    3045        36433 :     case VAR_DECL:
    3046        36433 :       if (DECL_HARD_REGISTER (pv.m_tree))
    3047              :         {
    3048              :           /* If it has a hard register, it doesn't have a memory region
    3049              :              and can't be referred to as an lvalue.  */
    3050           43 :           return m_mgr->get_or_create_unknown_svalue (TREE_TYPE (pv.m_tree));
    3051              :         }
    3052              :       /* Fall through. */
    3053       975769 :     case PARM_DECL:
    3054       975769 :     case SSA_NAME:
    3055       975769 :     case RESULT_DECL:
    3056       975769 :     case ARRAY_REF:
    3057       975769 :       {
    3058       975769 :         const region *reg = get_lvalue (pv, ctxt);
    3059       975769 :         return get_store_value (reg, ctxt);
    3060              :       }
    3061              : 
    3062          174 :     case REALPART_EXPR:
    3063          174 :     case IMAGPART_EXPR:
    3064          174 :     case VIEW_CONVERT_EXPR:
    3065          174 :       {
    3066          174 :         tree expr = pv.m_tree;
    3067          174 :         tree arg = TREE_OPERAND (expr, 0);
    3068          174 :         const svalue *arg_sval = get_rvalue (arg, ctxt);
    3069          174 :         const svalue *sval_unaryop
    3070          174 :           = m_mgr->get_or_create_unaryop (TREE_TYPE (expr), TREE_CODE (expr),
    3071              :                                           arg_sval);
    3072          174 :         return sval_unaryop;
    3073      1255441 :       };
    3074              : 
    3075      1255441 :     case INTEGER_CST:
    3076      1255441 :     case REAL_CST:
    3077      1255441 :     case COMPLEX_CST:
    3078      1255441 :     case VECTOR_CST:
    3079      1255441 :     case STRING_CST:
    3080      1255441 :     case RAW_DATA_CST:
    3081      1255441 :       return m_mgr->get_or_create_constant_svalue (pv.m_tree);
    3082              : 
    3083           41 :     case POINTER_PLUS_EXPR:
    3084           41 :         {
    3085           41 :           tree expr = pv.m_tree;
    3086           41 :           tree ptr = TREE_OPERAND (expr, 0);
    3087           41 :           tree offset = TREE_OPERAND (expr, 1);
    3088           41 :           const svalue *ptr_sval = get_rvalue (ptr, ctxt);
    3089           41 :           const svalue *offset_sval = get_rvalue (offset, ctxt);
    3090           41 :           const svalue *sval_binop
    3091           41 :             = m_mgr->get_or_create_binop (TREE_TYPE (expr), POINTER_PLUS_EXPR,
    3092              :                                           ptr_sval, offset_sval);
    3093           41 :           return sval_binop;
    3094              :         }
    3095              : 
    3096              :     /* Binary ops.  */
    3097           94 :     case PLUS_EXPR:
    3098           94 :     case MULT_EXPR:
    3099           94 :     case BIT_AND_EXPR:
    3100           94 :     case BIT_IOR_EXPR:
    3101           94 :     case BIT_XOR_EXPR:
    3102           94 :         {
    3103           94 :           tree expr = pv.m_tree;
    3104           94 :           tree arg0 = TREE_OPERAND (expr, 0);
    3105           94 :           tree arg1 = TREE_OPERAND (expr, 1);
    3106           94 :           const svalue *arg0_sval = get_rvalue (arg0, ctxt);
    3107           94 :           const svalue *arg1_sval = get_rvalue (arg1, ctxt);
    3108           94 :           const svalue *sval_binop
    3109           94 :             = m_mgr->get_or_create_binop (TREE_TYPE (expr), TREE_CODE (expr),
    3110              :                                           arg0_sval, arg1_sval);
    3111           94 :           return sval_binop;
    3112              :         }
    3113              : 
    3114        54027 :     case COMPONENT_REF:
    3115        54027 :     case MEM_REF:
    3116        54027 :       {
    3117        54027 :         const region *ref_reg = get_lvalue (pv, ctxt);
    3118        54027 :         return get_store_value (ref_reg, ctxt);
    3119              :       }
    3120          120 :     case OBJ_TYPE_REF:
    3121          120 :       {
    3122          120 :         tree expr = OBJ_TYPE_REF_EXPR (pv.m_tree);
    3123          120 :         return get_rvalue (expr, ctxt);
    3124              :       }
    3125              :     }
    3126              : }
    3127              : 
    3128              : /* Get the value of PV within this region_model,
    3129              :    emitting any diagnostics to CTXT.  */
    3130              : 
    3131              : const svalue *
    3132      3329053 : region_model::get_rvalue (path_var pv, region_model_context *ctxt) const
    3133              : {
    3134      3329053 :   if (pv.m_tree == NULL_TREE)
    3135              :     return nullptr;
    3136              : 
    3137      3291878 :   const svalue *result_sval = get_rvalue_1 (pv, ctxt);
    3138              : 
    3139      3291878 :   assert_compat_types (result_sval->get_type (), TREE_TYPE (pv.m_tree));
    3140              : 
    3141      3291878 :   result_sval = check_for_poison (result_sval, pv.m_tree, nullptr, ctxt);
    3142              : 
    3143      3291878 :   return result_sval;
    3144              : }
    3145              : 
    3146              : /* Get the value of EXPR within this region_model (assuming the most
    3147              :    recent stack frame if it's a local).  */
    3148              : 
    3149              : const svalue *
    3150      3327326 : region_model::get_rvalue (tree expr, region_model_context *ctxt) const
    3151              : {
    3152      3327326 :   return get_rvalue (path_var (expr, get_stack_depth () - 1), ctxt);
    3153              : }
    3154              : 
    3155              : /* Return true if this model is on a path with "main" as the entrypoint
    3156              :    (as opposed to one in which we're merely analyzing a subset of the
    3157              :    path through the code).  */
    3158              : 
    3159              : bool
    3160       281552 : region_model::called_from_main_p () const
    3161              : {
    3162       281552 :   if (!m_current_frame)
    3163              :     return false;
    3164              :   /* Determine if the oldest stack frame in this model is for "main".  */
    3165       275100 :   const frame_region *frame0 = get_frame_at_index (0);
    3166       275100 :   gcc_assert (frame0);
    3167       275100 :   return id_equal (DECL_NAME (frame0->get_function ().decl), "main");
    3168              : }
    3169              : 
    3170              : /* Subroutine of region_model::get_store_value for when REG is (or is within)
    3171              :    a global variable that hasn't been touched since the start of this path
    3172              :    (or was implicitly touched due to a call to an unknown function).  */
    3173              : 
    3174              : const svalue *
    3175       290821 : region_model::get_initial_value_for_global (const region *reg) const
    3176              : {
    3177              :   /* Get the decl that REG is for (or is within).  */
    3178       290821 :   const decl_region *base_reg
    3179       290821 :     = reg->get_base_region ()->dyn_cast_decl_region ();
    3180       290821 :   gcc_assert (base_reg);
    3181       290821 :   tree decl = base_reg->get_decl ();
    3182              : 
    3183              :   /* Special-case: to avoid having to explicitly update all previously
    3184              :      untracked globals when calling an unknown fn, they implicitly have
    3185              :      an unknown value if an unknown call has occurred, unless this is
    3186              :      static to-this-TU and hasn't escaped.  Globals that have escaped
    3187              :      are explicitly tracked, so we shouldn't hit this case for them.  */
    3188       290821 :   if (m_store.called_unknown_fn_p ()
    3189        71041 :       && TREE_PUBLIC (decl)
    3190       308461 :       && !TREE_READONLY (decl))
    3191         9325 :     return m_mgr->get_or_create_unknown_svalue (reg->get_type ());
    3192              : 
    3193              :   /* If we are on a path from the entrypoint from "main" and we have a
    3194              :      global decl defined in this TU that hasn't been touched yet, then
    3195              :      the initial value of REG can be taken from the initialization value
    3196              :      of the decl.  */
    3197       281496 :   if (called_from_main_p () || TREE_READONLY (decl))
    3198        72017 :     return reg->get_initial_value_at_main (m_mgr);
    3199              : 
    3200              :   /* Otherwise, return INIT_VAL(REG).  */
    3201       209479 :   return m_mgr->get_or_create_initial_value (reg);
    3202              : }
    3203              : 
    3204              : /* Get a value for REG, looking it up in the store, or otherwise falling
    3205              :    back to "initial" or "unknown" values.
    3206              :    Use CTXT to report any warnings associated with reading from REG. */
    3207              : 
    3208              : const svalue *
    3209      4467198 : region_model::get_store_value (const region *reg,
    3210              :                                region_model_context *ctxt) const
    3211              : {
    3212              :   /* Getting the value of an empty region gives an unknown_svalue.  */
    3213      4467198 :   if (reg->empty_p ())
    3214           52 :     return m_mgr->get_or_create_unknown_svalue (reg->get_type ());
    3215              : 
    3216      4467146 :   bool check_poisoned = true;
    3217      4467146 :   if (check_region_for_read (reg, ctxt))
    3218          436 :     check_poisoned = false;
    3219              : 
    3220              :   /* Special-case: handle var_decls in the constant pool.  */
    3221      4467146 :   if (const decl_region *decl_reg = reg->dyn_cast_decl_region ())
    3222      3663968 :     if (const svalue *sval = decl_reg->maybe_get_constant_value (m_mgr))
    3223              :       return sval;
    3224              : 
    3225      4467130 :   const svalue *sval
    3226      4467130 :     = m_store.get_any_binding (m_mgr->get_store_manager (), reg);
    3227      4467130 :   if (sval)
    3228              :     {
    3229      1232630 :       if (reg->get_type ())
    3230      1230358 :         sval = m_mgr->get_or_create_cast (reg->get_type (), sval);
    3231              :       return sval;
    3232              :     }
    3233              : 
    3234              :   /* Special-case: read at a constant index within a STRING_CST.  */
    3235      3234500 :   if (const offset_region *offset_reg = reg->dyn_cast_offset_region ())
    3236       157647 :     if (tree byte_offset_cst
    3237       157647 :           = offset_reg->get_byte_offset ()->maybe_get_constant ())
    3238        32663 :       if (const string_region *str_reg
    3239        32663 :           = reg->get_parent_region ()->dyn_cast_string_region ())
    3240              :         {
    3241          205 :           tree string_cst = str_reg->get_string_cst ();
    3242          410 :           if (const svalue *char_sval
    3243          205 :                 = m_mgr->maybe_get_char_from_string_cst (string_cst,
    3244              :                                                          byte_offset_cst))
    3245          201 :             return m_mgr->get_or_create_cast (reg->get_type (), char_sval);
    3246              :         }
    3247              : 
    3248              :   /* Special-case: read the initial char of a STRING_CST.  */
    3249      3234299 :   if (const cast_region *cast_reg = reg->dyn_cast_cast_region ())
    3250         6180 :     if (const string_region *str_reg
    3251         3090 :         = cast_reg->get_parent_region ()->dyn_cast_string_region ())
    3252              :       {
    3253          197 :         tree string_cst = str_reg->get_string_cst ();
    3254          197 :         tree byte_offset_cst = integer_zero_node;
    3255          394 :         if (const svalue *char_sval
    3256          197 :             = m_mgr->maybe_get_char_from_string_cst (string_cst,
    3257              :                                                      byte_offset_cst))
    3258          197 :           return m_mgr->get_or_create_cast (reg->get_type (), char_sval);
    3259              :       }
    3260              : 
    3261              :   /* Otherwise we implicitly have the initial value of the region
    3262              :      (if the cluster had been touched, binding_cluster::get_any_binding,
    3263              :      would have returned UNKNOWN, and we would already have returned
    3264              :      that above).  */
    3265              : 
    3266              :   /* Handle globals.  */
    3267      3234102 :   if (reg->get_base_region ()->get_parent_region ()->get_kind ()
    3268              :       == RK_GLOBALS)
    3269       290821 :     return get_initial_value_for_global (reg);
    3270              : 
    3271      2943281 :   return m_mgr->get_or_create_initial_value (reg, check_poisoned);
    3272              : }
    3273              : 
    3274              : /* Return false if REG does not exist, true if it may do.
    3275              :    This is for detecting regions within the stack that don't exist anymore
    3276              :    after frames are popped.  */
    3277              : 
    3278              : bool
    3279      2754289 : region_model::region_exists_p (const region *reg) const
    3280              : {
    3281              :   /* If within a stack frame, check that the stack frame is live.  */
    3282      2754289 :   if (const frame_region *enclosing_frame = reg->maybe_get_frame_region ())
    3283              :     {
    3284              :       /* Check that the current frame is the enclosing frame, or is called
    3285              :          by it.  */
    3286      2827709 :       for (const frame_region *iter_frame = get_current_frame (); iter_frame;
    3287       672805 :            iter_frame = iter_frame->get_calling_frame ())
    3288      2808802 :         if (iter_frame == enclosing_frame)
    3289              :           return true;
    3290              :       return false;
    3291              :     }
    3292              : 
    3293              :   return true;
    3294              : }
    3295              : 
    3296              : /* Get a region for referencing PTR_SVAL, creating a region if need be, and
    3297              :    potentially generating warnings via CTXT.
    3298              :    PTR_SVAL must be of pointer type.
    3299              :    PTR_TREE if non-NULL can be used when emitting diagnostics.  */
    3300              : 
    3301              : const region *
    3302       144812 : region_model::deref_rvalue (const svalue *ptr_sval, tree ptr_tree,
    3303              :                             region_model_context *ctxt,
    3304              :                             bool add_nonnull_constraint) const
    3305              : {
    3306       144812 :   gcc_assert (ptr_sval);
    3307       144812 :   gcc_assert (POINTER_TYPE_P (ptr_sval->get_type ()));
    3308              : 
    3309              :   /* If we're dereferencing PTR_SVAL, assume that it is non-NULL; add this
    3310              :      as a constraint.  This suppresses false positives from
    3311              :      -Wanalyzer-null-dereference for the case where we later have an
    3312              :      if (PTR_SVAL) that would occur if we considered the false branch
    3313              :      and transitioned the malloc state machine from start->null.  */
    3314       144812 :   if (add_nonnull_constraint)
    3315              :     {
    3316       136599 :       tree null_ptr_cst = build_int_cst (ptr_sval->get_type (), 0);
    3317       136599 :       const svalue *null_ptr
    3318       136599 :         = m_mgr->get_or_create_constant_svalue (null_ptr_cst);
    3319       136599 :       m_constraints->add_constraint (ptr_sval, NE_EXPR, null_ptr);
    3320              :     }
    3321              : 
    3322       144812 :   switch (ptr_sval->get_kind ())
    3323              :     {
    3324              :     default:
    3325              :       break;
    3326              : 
    3327        59715 :     case SK_REGION:
    3328        59715 :       {
    3329        59715 :         const region_svalue *region_sval
    3330        59715 :           = as_a <const region_svalue *> (ptr_sval);
    3331        59715 :         return region_sval->get_pointee ();
    3332              :       }
    3333              : 
    3334        25286 :     case SK_BINOP:
    3335        25286 :       {
    3336        25286 :         const binop_svalue *binop_sval
    3337        25286 :           = as_a <const binop_svalue *> (ptr_sval);
    3338        25286 :         switch (binop_sval->get_op ())
    3339              :           {
    3340        25286 :           case POINTER_PLUS_EXPR:
    3341        25286 :             {
    3342              :               /* If we have a symbolic value expressing pointer arithmetic,
    3343              :                  try to convert it to a suitable region.  */
    3344        25286 :               const region *parent_region
    3345        25286 :                 = deref_rvalue (binop_sval->get_arg0 (), NULL_TREE, ctxt);
    3346        25286 :               const svalue *offset = binop_sval->get_arg1 ();
    3347        25286 :               tree type= TREE_TYPE (ptr_sval->get_type ());
    3348        25286 :               return m_mgr->get_offset_region (parent_region, type, offset);
    3349              :             }
    3350              :           default:
    3351              :             break;
    3352              :           }
    3353              :       }
    3354              :       break;
    3355              : 
    3356         2678 :     case SK_POISONED:
    3357         2678 :       {
    3358         2678 :         if (ctxt)
    3359              :           {
    3360          624 :             tree ptr = get_representative_tree (ptr_sval);
    3361              :             /* If we can't get a representative tree for PTR_SVAL
    3362              :                (e.g. if it hasn't been bound into the store), then
    3363              :                fall back on PTR_TREE, if non-NULL.  */
    3364          624 :             if (!ptr)
    3365          624 :               ptr = ptr_tree;
    3366          624 :             if (ptr)
    3367              :               {
    3368            0 :                 const poisoned_svalue *poisoned_sval
    3369            0 :                   = as_a <const poisoned_svalue *> (ptr_sval);
    3370            0 :                 enum poison_kind pkind = poisoned_sval->get_poison_kind ();
    3371            0 :                 ctxt->warn (make_poisoned_value_diagnostic
    3372            0 :                               (ptr, pkind, nullptr, nullptr));
    3373              :               }
    3374              :           }
    3375              :       }
    3376              :       break;
    3377              :     }
    3378              : 
    3379        59811 :   return m_mgr->get_symbolic_region (ptr_sval);
    3380              : }
    3381              : 
    3382              : /* Attempt to get BITS within any value of REG, as TYPE.
    3383              :    In particular, extract values from compound_svalues for the case
    3384              :    where there's a concrete binding at BITS.
    3385              :    Return an unknown svalue if we can't handle the given case.
    3386              :    Use CTXT to report any warnings associated with reading from REG.  */
    3387              : 
    3388              : const svalue *
    3389          130 : region_model::get_rvalue_for_bits (tree type,
    3390              :                                    const region *reg,
    3391              :                                    const bit_range &bits,
    3392              :                                    region_model_context *ctxt) const
    3393              : {
    3394          130 :   const svalue *sval = get_store_value (reg, ctxt);
    3395          130 :   return m_mgr->get_or_create_bits_within (type, bits, sval);
    3396              : }
    3397              : 
    3398              : /* Use CTXT to warn If DEST_REG is a region that shouldn't be written to.  */
    3399              : 
    3400              : void
    3401       290868 : region_model::check_for_writable_region (const region* dest_reg,
    3402              :                                          region_model_context *ctxt) const
    3403              : {
    3404              :   /* Fail gracefully if CTXT is nullptr.  */
    3405       290868 :   if (!ctxt)
    3406              :     return;
    3407              : 
    3408       290868 :   const region *base_reg = dest_reg->get_base_region ();
    3409       290868 :   switch (base_reg->get_kind ())
    3410              :     {
    3411              :     default:
    3412              :       break;
    3413            9 :     case RK_FUNCTION:
    3414            9 :       {
    3415            9 :         const function_region *func_reg = as_a <const function_region *> (base_reg);
    3416            9 :         tree fndecl = func_reg->get_fndecl ();
    3417            9 :         ctxt->warn (make_write_to_const_diagnostic (func_reg, fndecl));
    3418              :       }
    3419            9 :       break;
    3420            4 :     case RK_LABEL:
    3421            4 :       {
    3422            4 :         const label_region *label_reg = as_a <const label_region *> (base_reg);
    3423            4 :         tree label = label_reg->get_label ();
    3424            4 :         ctxt->warn (make_write_to_const_diagnostic (label_reg, label));
    3425              :       }
    3426            4 :       break;
    3427       272093 :     case RK_DECL:
    3428       272093 :       {
    3429       272093 :         const decl_region *decl_reg = as_a <const decl_region *> (base_reg);
    3430       272093 :         tree decl = decl_reg->get_decl ();
    3431              :         /* Warn about writes to const globals.
    3432              :            Don't warn for writes to const locals, and params in particular,
    3433              :            since we would warn in push_frame when setting them up (e.g the
    3434              :            "this" param is "T* const").  */
    3435       272093 :         if (TREE_READONLY (decl)
    3436       272093 :             && is_global_var (decl))
    3437           20 :           ctxt->warn (make_write_to_const_diagnostic (dest_reg, decl));
    3438              :       }
    3439              :       break;
    3440           51 :     case RK_STRING:
    3441           51 :       ctxt->warn (make_write_to_string_literal_diagnostic (dest_reg));
    3442           51 :       break;
    3443              :     }
    3444              : }
    3445              : 
    3446              : /* Get the capacity of REG in bytes.  */
    3447              : 
    3448              : const svalue *
    3449       909678 : region_model::get_capacity (const region *reg) const
    3450              : {
    3451       909693 :   switch (reg->get_kind ())
    3452              :     {
    3453              :     default:
    3454              :       break;
    3455       840048 :     case RK_DECL:
    3456       840048 :       {
    3457       840048 :         const decl_region *decl_reg = as_a <const decl_region *> (reg);
    3458       840048 :         tree decl = decl_reg->get_decl ();
    3459       840048 :         if (TREE_CODE (decl) == SSA_NAME)
    3460              :           {
    3461       740742 :             tree type = TREE_TYPE (decl);
    3462       740742 :             tree size = TYPE_SIZE (type);
    3463       740742 :             return get_rvalue (size, nullptr);
    3464              :           }
    3465              :         else
    3466              :           {
    3467        99306 :             tree size = decl_init_size (decl, false);
    3468        99306 :             if (size)
    3469        99139 :               return get_rvalue (size, nullptr);
    3470              :           }
    3471              :       }
    3472              :       break;
    3473           15 :     case RK_SIZED:
    3474              :       /* Look through sized regions to get at the capacity
    3475              :          of the underlying regions.  */
    3476           15 :       return get_capacity (reg->get_parent_region ());
    3477          535 :     case RK_STRING:
    3478          535 :       {
    3479              :         /* "Capacity" here means "size".  */
    3480          535 :         const string_region *string_reg = as_a <const string_region *> (reg);
    3481          535 :         tree string_cst = string_reg->get_string_cst ();
    3482          535 :         return m_mgr->get_or_create_int_cst (size_type_node,
    3483          535 :                                              TREE_STRING_LENGTH (string_cst));
    3484              :       }
    3485        69262 :       break;
    3486              :     }
    3487              : 
    3488        69262 :   if (const svalue *recorded = get_dynamic_extents (reg))
    3489              :     return recorded;
    3490              : 
    3491        56644 :   return m_mgr->get_or_create_unknown_svalue (sizetype);
    3492              : }
    3493              : 
    3494              : /* If CTXT is non-NULL, use it to warn about any problems accessing REG,
    3495              :    using DIR to determine if this access is a read or write.
    3496              :    Return TRUE if an OOB access was detected.
    3497              :    If SVAL_HINT is non-NULL, use it as a hint in diagnostics
    3498              :    about the value that would be written to REG.  */
    3499              : 
    3500              : bool
    3501      4858364 : region_model::check_region_access (const region *reg,
    3502              :                                    enum access_direction dir,
    3503              :                                    const svalue *sval_hint,
    3504              :                                    region_model_context *ctxt) const
    3505              : {
    3506              :   /* Fail gracefully if CTXT is NULL.  */
    3507      4858364 :   if (!ctxt)
    3508              :     return false;
    3509              : 
    3510       897624 :   bool oob_access_detected = false;
    3511       897624 :   check_region_for_taint (reg, dir, ctxt);
    3512       897624 :   if (!check_region_bounds (reg, dir, sval_hint, ctxt))
    3513          779 :     oob_access_detected = true;
    3514              : 
    3515       897624 :   switch (dir)
    3516              :     {
    3517            0 :     default:
    3518            0 :       gcc_unreachable ();
    3519              :     case access_direction::read:
    3520              :       /* Currently a no-op.  */
    3521              :       break;
    3522       290868 :     case access_direction::write:
    3523       290868 :       check_for_writable_region (reg, ctxt);
    3524       290868 :       break;
    3525              :     }
    3526              :   return oob_access_detected;
    3527              : }
    3528              : 
    3529              : /* If CTXT is non-NULL, use it to warn about any problems writing to REG.  */
    3530              : 
    3531              : void
    3532       391218 : region_model::check_region_for_write (const region *dest_reg,
    3533              :                                       const svalue *sval_hint,
    3534              :                                       region_model_context *ctxt) const
    3535              : {
    3536       391218 :   check_region_access (dest_reg, access_direction::write, sval_hint, ctxt);
    3537       391218 : }
    3538              : 
    3539              : /* If CTXT is non-NULL, use it to warn about any problems reading from REG.
    3540              :   Returns TRUE if an OOB read was detected.  */
    3541              : 
    3542              : bool
    3543      4467146 : region_model::check_region_for_read (const region *src_reg,
    3544              :                                      region_model_context *ctxt) const
    3545              : {
    3546      4467146 :   return check_region_access (src_reg, access_direction::read, nullptr, ctxt);
    3547              : }
    3548              : 
    3549              : /* Concrete subclass for casts of pointers that lead to trailing bytes.  */
    3550              : 
    3551              : class dubious_allocation_size
    3552              : : public pending_diagnostic_subclass<dubious_allocation_size>
    3553              : {
    3554              : public:
    3555          111 :   dubious_allocation_size (const region *lhs, const region *rhs,
    3556              :                            const svalue *capacity_sval, tree expr,
    3557              :                            const gimple *stmt)
    3558          111 :   : m_lhs (lhs), m_rhs (rhs),
    3559          111 :     m_capacity_sval (capacity_sval), m_expr (expr),
    3560          111 :     m_stmt (stmt),
    3561          111 :     m_has_allocation_event (false)
    3562              :   {
    3563          111 :     gcc_assert (m_capacity_sval);
    3564              :   }
    3565              : 
    3566         1186 :   const char *get_kind () const final override
    3567              :   {
    3568         1186 :     return "dubious_allocation_size";
    3569              :   }
    3570              : 
    3571          111 :   bool operator== (const dubious_allocation_size &other) const
    3572              :   {
    3573          111 :     return (m_stmt == other.m_stmt
    3574          111 :             && pending_diagnostic::same_tree_p (m_expr, other.m_expr));
    3575              :   }
    3576              : 
    3577          222 :   int get_controlling_option () const final override
    3578              :   {
    3579          222 :     return OPT_Wanalyzer_allocation_size;
    3580              :   }
    3581              : 
    3582          111 :   bool emit (diagnostic_emission_context &ctxt) final override
    3583              :   {
    3584          111 :     ctxt.add_cwe (131);
    3585              : 
    3586          111 :     return ctxt.warn ("allocated buffer size is not a multiple"
    3587          111 :                       " of the pointee's size");
    3588              :   }
    3589              : 
    3590              :   bool
    3591          222 :   describe_final_event (pretty_printer &pp,
    3592              :                         const evdesc::final_event &) final override
    3593              :   {
    3594          222 :     tree pointee_type = TREE_TYPE (m_lhs->get_type ());
    3595          222 :     if (m_has_allocation_event)
    3596              :       {
    3597          214 :         pp_printf (&pp,
    3598              :                    "assigned to %qT here;"
    3599              :                    " %<sizeof (%T)%> is %qE",
    3600          214 :                    m_lhs->get_type (), pointee_type,
    3601              :                    size_in_bytes (pointee_type));
    3602          214 :         return true;
    3603              :       }
    3604              :     /* Fallback: Typically, we should always see an allocation_event
    3605              :        before.  */
    3606            8 :     if (m_expr)
    3607              :       {
    3608            8 :         if (TREE_CODE (m_expr) == INTEGER_CST)
    3609              :           {
    3610            8 :             pp_printf (&pp,
    3611              :                        "allocated %E bytes and assigned to"
    3612              :                        " %qT here; %<sizeof (%T)%> is %qE",
    3613            8 :                        m_expr, m_lhs->get_type (), pointee_type,
    3614              :                        size_in_bytes (pointee_type));
    3615            8 :             return true;
    3616              :           }
    3617              :         else
    3618              :           {
    3619            0 :             pp_printf (&pp,
    3620              :                        "allocated %qE bytes and assigned to"
    3621              :                        " %qT here; %<sizeof (%T)%> is %qE",
    3622            0 :                        m_expr, m_lhs->get_type (), pointee_type,
    3623              :                        size_in_bytes (pointee_type));
    3624            0 :             return true;
    3625              :           }
    3626              :       }
    3627              : 
    3628            0 :     pp_printf (&pp,
    3629              :                "allocated and assigned to %qT here;"
    3630              :                " %<sizeof (%T)%> is %qE",
    3631            0 :                m_lhs->get_type (), pointee_type,
    3632              :                size_in_bytes (pointee_type));
    3633            0 :     return true;
    3634              :   }
    3635              : 
    3636              :   void
    3637          107 :   add_region_creation_events (const region *,
    3638              :                               tree capacity,
    3639              :                               const event_loc_info &loc_info,
    3640              :                               checker_path &emission_path) final override
    3641              :   {
    3642          107 :     emission_path.add_event
    3643          107 :       (std::make_unique<region_creation_event_allocation_size>
    3644          107 :          (capacity, loc_info));
    3645              : 
    3646          107 :     m_has_allocation_event = true;
    3647          107 :   }
    3648              : 
    3649          222 :   void mark_interesting_stuff (interesting_t *interest) final override
    3650              :   {
    3651          222 :     interest->add_region_creation (m_rhs);
    3652          222 :   }
    3653              : 
    3654              :   void
    3655            0 :   maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
    3656              :     const final override
    3657              :   {
    3658            0 :     auto &props = result_obj.get_or_create_properties ();
    3659              : #define PROPERTY_PREFIX "gcc/analyzer/dubious_allocation_size/"
    3660            0 :     props.set (PROPERTY_PREFIX "lhs", m_lhs->to_json ());
    3661            0 :     props.set (PROPERTY_PREFIX "rhs", m_rhs->to_json ());
    3662            0 :     props.set (PROPERTY_PREFIX "capacity_sval", m_capacity_sval->to_json ());
    3663              : #undef PROPERTY_PREFIX
    3664            0 :   }
    3665              : 
    3666              : private:
    3667              :   const region *m_lhs;
    3668              :   const region *m_rhs;
    3669              :   const svalue *m_capacity_sval;
    3670              :   const tree m_expr;
    3671              :   const gimple *m_stmt;
    3672              :   bool m_has_allocation_event;
    3673              : };
    3674              : 
    3675              : /* Return true on dubious allocation sizes for constant sizes.  */
    3676              : 
    3677              : static bool
    3678         2037 : capacity_compatible_with_type (tree cst, tree pointee_size_tree,
    3679              :                                bool is_struct)
    3680              : {
    3681         2037 :   gcc_assert (TREE_CODE (cst) == INTEGER_CST);
    3682         2037 :   gcc_assert (TREE_CODE (pointee_size_tree) == INTEGER_CST);
    3683              : 
    3684         2037 :   unsigned HOST_WIDE_INT pointee_size = TREE_INT_CST_LOW (pointee_size_tree);
    3685         2037 :   unsigned HOST_WIDE_INT alloc_size = TREE_INT_CST_LOW (cst);
    3686              : 
    3687         2037 :   if (is_struct)
    3688          722 :     return alloc_size == 0 || alloc_size >= pointee_size;
    3689         1315 :   return alloc_size % pointee_size == 0;
    3690              : }
    3691              : 
    3692              : static bool
    3693          394 : capacity_compatible_with_type (tree cst, tree pointee_size_tree)
    3694              : {
    3695            0 :   return capacity_compatible_with_type (cst, pointee_size_tree, false);
    3696              : }
    3697              : 
    3698              : /* Checks whether SVAL could be a multiple of SIZE_CST.
    3699              : 
    3700              :    It works by visiting all svalues inside SVAL until it reaches
    3701              :    atomic nodes.  From those, it goes back up again and adds each
    3702              :    node that is not a multiple of SIZE_CST to the RESULT_SET.  */
    3703              : 
    3704         6780 : class size_visitor : public visitor
    3705              : {
    3706              : public:
    3707         3390 :   size_visitor (tree size_cst, const svalue *root_sval, constraint_manager *cm)
    3708         3390 :   : m_size_cst (size_cst), m_root_sval (root_sval), m_cm (cm)
    3709              :   {
    3710         3390 :     m_root_sval->accept (this);
    3711         3390 :   }
    3712              : 
    3713         3390 :   bool is_dubious_capacity ()
    3714              :   {
    3715         3390 :     return result_set.contains (m_root_sval);
    3716              :   }
    3717              : 
    3718          410 :   void visit_constant_svalue (const constant_svalue *sval) final override
    3719              :   {
    3720          410 :     check_constant (sval->get_constant (), sval);
    3721          410 :   }
    3722              : 
    3723          250 :   void visit_unaryop_svalue (const unaryop_svalue *sval) final override
    3724              :   {
    3725          250 :     if (CONVERT_EXPR_CODE_P (sval->get_op ())
    3726          291 :           && result_set.contains (sval->get_arg ()))
    3727          105 :       result_set.add (sval);
    3728          250 :   }
    3729              : 
    3730          406 :   void visit_binop_svalue (const binop_svalue *sval) final override
    3731              :   {
    3732          406 :     const svalue *arg0 = sval->get_arg0 ();
    3733          406 :     const svalue *arg1 = sval->get_arg1 ();
    3734              : 
    3735          406 :     switch (sval->get_op ())
    3736              :       {
    3737          288 :         case MULT_EXPR:
    3738          288 :           if (result_set.contains (arg0) && result_set.contains (arg1))
    3739           24 :             result_set.add (sval);
    3740              :           break;
    3741           90 :         case PLUS_EXPR:
    3742           90 :         case MINUS_EXPR:
    3743           90 :           if (result_set.contains (arg0) || result_set.contains (arg1))
    3744           28 :             result_set.add (sval);
    3745              :           break;
    3746              :         default:
    3747              :           break;
    3748              :       }
    3749          406 :   }
    3750              : 
    3751            0 :   void visit_unmergeable_svalue (const unmergeable_svalue *sval) final override
    3752              :   {
    3753            0 :     if (result_set.contains (sval->get_arg ()))
    3754            0 :       result_set.add (sval);
    3755            0 :   }
    3756              : 
    3757           12 :   void visit_widening_svalue (const widening_svalue *sval) final override
    3758              :   {
    3759           12 :     const svalue *base = sval->get_base_svalue ();
    3760           12 :     const svalue *iter = sval->get_iter_svalue ();
    3761              : 
    3762           12 :     if (result_set.contains (base) || result_set.contains (iter))
    3763            8 :       result_set.add (sval);
    3764           12 :   }
    3765              : 
    3766          303 :   void visit_initial_svalue (const initial_svalue *sval) final override
    3767              :   {
    3768          303 :     equiv_class_id id = equiv_class_id::null ();
    3769          303 :     if (m_cm->get_equiv_class_by_svalue (sval, &id))
    3770              :       {
    3771           75 :         if (tree cst = id.get_obj (*m_cm).get_any_constant ())
    3772            0 :           check_constant (cst, sval);
    3773              :       }
    3774          228 :     else if (!m_cm->sval_constrained_p (sval))
    3775              :       {
    3776          174 :         result_set.add (sval);
    3777              :       }
    3778          303 :   }
    3779              : 
    3780           30 :   void visit_conjured_svalue (const conjured_svalue *sval) final override
    3781              :   {
    3782           30 :     equiv_class_id id = equiv_class_id::null ();
    3783           30 :     if (m_cm->get_equiv_class_by_svalue (sval, &id))
    3784           13 :       if (tree cst = id.get_obj (*m_cm).get_any_constant ())
    3785            8 :         check_constant (cst, sval);
    3786           30 :   }
    3787              : 
    3788              : private:
    3789          418 :   void check_constant (tree cst, const svalue *sval)
    3790              :   {
    3791          418 :     switch (TREE_CODE (cst))
    3792              :       {
    3793              :       default:
    3794              :         /* Assume all unhandled operands are compatible.  */
    3795              :         break;
    3796          394 :       case INTEGER_CST:
    3797          394 :         if (!capacity_compatible_with_type (cst, m_size_cst))
    3798           68 :           result_set.add (sval);
    3799              :         break;
    3800              :       }
    3801          418 :   }
    3802              : 
    3803              :   tree m_size_cst;
    3804              :   const svalue *m_root_sval;
    3805              :   constraint_manager *m_cm;
    3806              :   svalue_set result_set; /* Used as a mapping of svalue*->bool.  */
    3807              : };
    3808              : 
    3809              : /* Return true if SIZE_CST is a power of 2, and we have
    3810              :    CAPACITY_SVAL == ((X | (Y - 1) ) + 1), since it is then a multiple
    3811              :    of SIZE_CST, as used by Linux kernel's round_up macro.  */
    3812              : 
    3813              : static bool
    3814         3394 : is_round_up (tree size_cst,
    3815              :              const svalue *capacity_sval)
    3816              : {
    3817         3394 :   if (!integer_pow2p (size_cst))
    3818              :     return false;
    3819         3394 :   const binop_svalue *binop_sval = capacity_sval->dyn_cast_binop_svalue ();
    3820         3394 :   if (!binop_sval)
    3821              :     return false;
    3822          272 :   if (binop_sval->get_op () != PLUS_EXPR)
    3823              :     return false;
    3824           70 :   tree rhs_cst = binop_sval->get_arg1 ()->maybe_get_constant ();
    3825           70 :   if (!rhs_cst)
    3826              :     return false;
    3827           70 :   if (!integer_onep (rhs_cst))
    3828              :     return false;
    3829              : 
    3830              :   /* We have CAPACITY_SVAL == (LHS + 1) for some LHS expression.  */
    3831              : 
    3832            4 :   const binop_svalue *lhs_binop_sval
    3833            4 :     = binop_sval->get_arg0 ()->dyn_cast_binop_svalue ();
    3834            4 :   if (!lhs_binop_sval)
    3835              :     return false;
    3836            4 :   if (lhs_binop_sval->get_op () != BIT_IOR_EXPR)
    3837              :     return false;
    3838              : 
    3839            4 :   tree inner_rhs_cst = lhs_binop_sval->get_arg1 ()->maybe_get_constant ();
    3840            4 :   if (!inner_rhs_cst)
    3841              :     return false;
    3842              : 
    3843            4 :   if (wi::to_widest (inner_rhs_cst) + 1 != wi::to_widest (size_cst))
    3844              :     return false;
    3845              :   return true;
    3846              : }
    3847              : 
    3848              : /* Return true if CAPACITY_SVAL is known to be a multiple of SIZE_CST.  */
    3849              : 
    3850              : static bool
    3851         3394 : is_multiple_p (tree size_cst,
    3852              :                const svalue *capacity_sval)
    3853              : {
    3854         3450 :   if (const svalue *sval = capacity_sval->maybe_undo_cast ())
    3855              :     return is_multiple_p (size_cst, sval);
    3856              : 
    3857         3394 :   if (is_round_up (size_cst, capacity_sval))
    3858              :     return true;
    3859              : 
    3860              :   return false;
    3861              : }
    3862              : 
    3863              : /* Return true if we should emit a dubious_allocation_size warning
    3864              :    on assigning a region of capacity CAPACITY_SVAL bytes to a pointer
    3865              :    of type with size SIZE_CST, where CM expresses known constraints.  */
    3866              : 
    3867              : static bool
    3868         3394 : is_dubious_capacity (tree size_cst,
    3869              :                      const svalue *capacity_sval,
    3870              :                      constraint_manager *cm)
    3871              : {
    3872         3394 :   if (is_multiple_p (size_cst, capacity_sval))
    3873              :     return false;
    3874         3390 :   size_visitor v (size_cst, capacity_sval, cm);
    3875         3390 :   return v.is_dubious_capacity ();
    3876         3390 : }
    3877              : 
    3878              : 
    3879              : /* Return true if a struct or union either uses the inheritance pattern,
    3880              :    where the first field is a base struct, or the flexible array member
    3881              :    pattern, where the last field is an array without a specified size.  */
    3882              : 
    3883              : static bool
    3884         4581 : struct_or_union_with_inheritance_p (tree struc)
    3885              : {
    3886         4581 :   tree iter = TYPE_FIELDS (struc);
    3887         4581 :   if (iter == NULL_TREE)
    3888              :           return false;
    3889         4573 :   if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (iter)))
    3890              :           return true;
    3891              : 
    3892              :   tree last_field;
    3893       101564 :   while (iter != NULL_TREE)
    3894              :     {
    3895        97395 :       last_field = iter;
    3896        97395 :       iter = DECL_CHAIN (iter);
    3897              :     }
    3898              : 
    3899         4169 :   if (last_field != NULL_TREE
    3900         4169 :       && TREE_CODE (TREE_TYPE (last_field)) == ARRAY_TYPE)
    3901           35 :           return true;
    3902              : 
    3903              :   return false;
    3904              : }
    3905              : 
    3906              : /* Return true if the lhs and rhs of an assignment have different types.  */
    3907              : 
    3908              : static bool
    3909       205598 : is_any_cast_p (const gimple *stmt)
    3910              : {
    3911       205598 :   if (const gassign *assign = dyn_cast <const gassign *> (stmt))
    3912       159910 :     return gimple_assign_cast_p (assign)
    3913       293803 :            || !pending_diagnostic::same_tree_p (
    3914       133893 :                   TREE_TYPE (gimple_assign_lhs (assign)),
    3915       133893 :                   TREE_TYPE (gimple_assign_rhs1 (assign)));
    3916        45688 :   else if (const gcall *call = dyn_cast <const gcall *> (stmt))
    3917              :     {
    3918        45280 :       tree lhs = gimple_call_lhs (call);
    3919        78281 :       return lhs != NULL_TREE && !pending_diagnostic::same_tree_p (
    3920        33001 :                                     TREE_TYPE (gimple_call_lhs (call)),
    3921              :                                     gimple_call_return_type (call));
    3922              :     }
    3923              : 
    3924              :   return false;
    3925              : }
    3926              : 
    3927              : /* On pointer assignments, check whether the buffer size of
    3928              :    RHS_SVAL is compatible with the type of the LHS_REG.
    3929              :    Use a non-null CTXT to report allocation size warnings.  */
    3930              : 
    3931              : void
    3932       389514 : region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval,
    3933              :                                  region_model_context *ctxt) const
    3934              : {
    3935       389514 :   if (!ctxt || ctxt->get_stmt () == nullptr)
    3936       381470 :     return;
    3937              :   /* Only report warnings on assignments that actually change the type.  */
    3938       205598 :   if (!is_any_cast_p (ctxt->get_stmt ()))
    3939              :     return;
    3940              : 
    3941        66564 :   tree pointer_type = lhs_reg->get_type ();
    3942        66564 :   if (pointer_type == NULL_TREE || !POINTER_TYPE_P (pointer_type))
    3943              :     return;
    3944              : 
    3945        20372 :   tree pointee_type = TREE_TYPE (pointer_type);
    3946              :   /* Make sure that the type on the left-hand size actually has a size.  */
    3947        20372 :   if (pointee_type == NULL_TREE || VOID_TYPE_P (pointee_type)
    3948        39943 :       || TYPE_SIZE_UNIT (pointee_type) == NULL_TREE)
    3949              :     return;
    3950              : 
    3951              :   /* Bail out early on function pointers.  */
    3952        19471 :   if (TREE_CODE (pointee_type) == FUNCTION_TYPE)
    3953              :     return;
    3954              : 
    3955              :   /* Bail out early on pointers to structs where we can
    3956              :      not deduce whether the buffer size is compatible.  */
    3957        19183 :   bool is_struct = RECORD_OR_UNION_TYPE_P (pointee_type);
    3958        19183 :   if (is_struct && struct_or_union_with_inheritance_p (pointee_type))
    3959              :     return;
    3960              : 
    3961        18744 :   tree pointee_size_tree = size_in_bytes (pointee_type);
    3962              :   /* We give up if the type size is not known at compile-time or the
    3963              :      type size is always compatible regardless of the buffer size.  */
    3964        18744 :   if (TREE_CODE (pointee_size_tree) != INTEGER_CST
    3965        18657 :       || integer_zerop (pointee_size_tree)
    3966        37388 :       || integer_onep (pointee_size_tree))
    3967              :     return;
    3968              : 
    3969         8044 :   const region *rhs_reg = deref_rvalue (rhs_sval, NULL_TREE, ctxt, false);
    3970         8044 :   const svalue *capacity = get_capacity (rhs_reg);
    3971         8044 :   switch (capacity->get_kind ())
    3972              :     {
    3973         1643 :     case svalue_kind::SK_CONSTANT:
    3974         1643 :       {
    3975         1643 :         const constant_svalue *cst_cap_sval
    3976         1643 :           = as_a <const constant_svalue *> (capacity);
    3977         1643 :         tree cst_cap = cst_cap_sval->get_constant ();
    3978         1643 :         if (TREE_CODE (cst_cap) == INTEGER_CST
    3979         1643 :             && !capacity_compatible_with_type (cst_cap, pointee_size_tree,
    3980              :                                                is_struct))
    3981           63 :           ctxt->warn
    3982          126 :             (std::make_unique <dubious_allocation_size> (lhs_reg, rhs_reg,
    3983              :                                                          capacity, cst_cap,
    3984          126 :                                                          ctxt->get_stmt ()));
    3985              :       }
    3986         1643 :       break;
    3987         6401 :     default:
    3988         6401 :       {
    3989         6401 :         if (!is_struct)
    3990              :           {
    3991         3394 :             if (is_dubious_capacity (pointee_size_tree,
    3992              :                                      capacity,
    3993         3394 :                                      m_constraints))
    3994              :               {
    3995           48 :                 tree expr = get_representative_tree (capacity);
    3996           48 :                 ctxt->warn
    3997           96 :                   (std::make_unique <dubious_allocation_size> (lhs_reg,
    3998              :                                                                rhs_reg,
    3999              :                                                                capacity, expr,
    4000           96 :                                                                ctxt->get_stmt ()));
    4001              :               }
    4002              :           }
    4003              :       break;
    4004              :       }
    4005              :     }
    4006              : }
    4007              : 
    4008              : /* Set the value of the region given by LHS_REG to the value given
    4009              :    by RHS_SVAL.
    4010              :    Use CTXT to report any warnings associated with writing to LHS_REG.  */
    4011              : 
    4012              : void
    4013       389534 : region_model::set_value (const region *lhs_reg, const svalue *rhs_sval,
    4014              :                          region_model_context *ctxt)
    4015              : {
    4016       389534 :   gcc_assert (lhs_reg);
    4017       389534 :   gcc_assert (rhs_sval);
    4018              : 
    4019              :   /* Setting the value of an empty region is a no-op.  */
    4020       389534 :   if (lhs_reg->empty_p ())
    4021              :     return;
    4022              : 
    4023       389514 :   check_region_size (lhs_reg, rhs_sval, ctxt);
    4024              : 
    4025       389514 :   check_region_for_write (lhs_reg, rhs_sval, ctxt);
    4026              : 
    4027       679420 :   m_store.set_value (m_mgr->get_store_manager(), lhs_reg, rhs_sval,
    4028       289906 :                      ctxt ? ctxt->get_uncertainty () : nullptr,
    4029              :                      *this);
    4030              : }
    4031              : 
    4032              : /* Set the value of the region given by LHS to the value given by RHS.  */
    4033              : 
    4034              : void
    4035           84 : region_model::set_value (tree lhs, tree rhs, region_model_context *ctxt)
    4036              : {
    4037           84 :   const region *lhs_reg = get_lvalue (lhs, ctxt);
    4038           84 :   const svalue *rhs_sval = get_rvalue (rhs, ctxt);
    4039           84 :   gcc_assert (lhs_reg);
    4040           84 :   gcc_assert (rhs_sval);
    4041           84 :   set_value (lhs_reg, rhs_sval, ctxt);
    4042           84 : }
    4043              : 
    4044              : /* Issue a note specifying that a particular function parameter is expected
    4045              :    to be a valid null-terminated string.  */
    4046              : 
    4047              : static void
    4048          152 : inform_about_expected_null_terminated_string_arg (const call_arg_details &ad)
    4049              : {
    4050              :   // TODO: ideally we'd underline the param here
    4051          152 :   inform (DECL_SOURCE_LOCATION (ad.m_called_fndecl),
    4052              :           "argument %d of %qD must be a pointer to a null-terminated string",
    4053          152 :           ad.m_arg_idx + 1, ad.m_called_fndecl);
    4054          152 : }
    4055              : 
    4056              : /* A binding of a specific svalue at a concrete byte range.  */
    4057              : 
    4058              : struct fragment
    4059              : {
    4060         3851 :   fragment ()
    4061         3851 :   : m_byte_range (0, 0), m_sval (nullptr)
    4062              :   {
    4063         3851 :   }
    4064              : 
    4065         1033 :   fragment (const byte_range &bytes, const svalue *sval)
    4066         1033 :     : m_byte_range (bytes), m_sval (sval)
    4067              :   {
    4068              :   }
    4069              : 
    4070         1977 :   static int cmp_ptrs (const void *p1, const void *p2)
    4071              :   {
    4072         1977 :     const fragment *f1 = (const fragment *)p1;
    4073         1977 :     const fragment *f2 = (const fragment *)p2;
    4074         1977 :     return byte_range::cmp (f1->m_byte_range, f2->m_byte_range);
    4075              :   }
    4076              : 
    4077              :   void
    4078            2 :   dump_to_pp (pretty_printer *pp) const
    4079              :   {
    4080            2 :     pp_string (pp, "fragment(");
    4081            2 :     m_byte_range.dump_to_pp (pp);
    4082            2 :     pp_string (pp, ", sval: ");
    4083            2 :     if (m_sval)
    4084            2 :       m_sval->dump_to_pp (pp, true);
    4085              :     else
    4086            0 :       pp_string (pp, "nullptr");
    4087            2 :     pp_string (pp, ")");
    4088            2 :   }
    4089              : 
    4090              :   byte_range m_byte_range;
    4091              :   const svalue *m_sval;
    4092              : };
    4093              : 
    4094              : /* Determine if there is a zero terminator somewhere in the
    4095              :    part of STRING_CST covered by BYTES (where BYTES is relative to the
    4096              :    start of the constant).
    4097              : 
    4098              :    Return a tristate:
    4099              :    - true if there definitely is a zero byte, writing to *OUT_BYTES_READ
    4100              :    the number of bytes from that would be read, including the zero byte.
    4101              :    - false if there definitely isn't a zero byte
    4102              :    - unknown if we don't know.  */
    4103              : 
    4104              : static tristate
    4105          463 : string_cst_has_null_terminator (tree string_cst,
    4106              :                                 const byte_range &bytes,
    4107              :                                 byte_offset_t *out_bytes_read)
    4108              : {
    4109          463 :   gcc_assert (bytes.m_start_byte_offset >= 0);
    4110              : 
    4111              :   /* If we're beyond the string_cst, reads are unsuccessful.  */
    4112          463 :   if (tree cst_size = get_string_cst_size (string_cst))
    4113          463 :     if (TREE_CODE (cst_size) == INTEGER_CST)
    4114          463 :       if (bytes.m_start_byte_offset >= TREE_INT_CST_LOW (cst_size))
    4115            0 :         return tristate::unknown ();
    4116              : 
    4117              :   /* Assume all bytes after TREE_STRING_LENGTH are zero.  This handles
    4118              :      the case where an array is initialized with a string_cst that isn't
    4119              :      as long as the array, where the remaining elements are
    4120              :      empty-initialized and thus zeroed.  */
    4121          463 :   if (bytes.m_start_byte_offset >= TREE_STRING_LENGTH (string_cst))
    4122              :     {
    4123            2 :       *out_bytes_read = 1;
    4124            2 :       return tristate (true);
    4125              :     }
    4126              : 
    4127              :   /* Look for the first 0 byte within STRING_CST
    4128              :      from START_READ_OFFSET onwards.  */
    4129          461 :   const byte_offset_t num_bytes_to_search
    4130          922 :     = std::min<byte_offset_t> ((TREE_STRING_LENGTH (string_cst)
    4131          461 :                                 - bytes.m_start_byte_offset),
    4132          461 :                                bytes.m_size_in_bytes);
    4133          461 :   const char *start = (TREE_STRING_POINTER (string_cst)
    4134          461 :                        + bytes.m_start_byte_offset.slow ());
    4135          461 :   if (num_bytes_to_search >= 0)
    4136          461 :     if (const void *p = memchr (start, 0, bytes.m_size_in_bytes.slow ()))
    4137              :       {
    4138          332 :         *out_bytes_read = (const char *)p - start + 1;
    4139          332 :         return tristate (true);
    4140              :       }
    4141              : 
    4142          129 :   *out_bytes_read = bytes.m_size_in_bytes;
    4143          129 :   return tristate (false);
    4144              : }
    4145              : 
    4146              : static tristate
    4147              : svalue_byte_range_has_null_terminator (const svalue *sval,
    4148              :                                        const byte_range &bytes,
    4149              :                                        byte_offset_t *out_bytes_read,
    4150              :                                        logger *logger);
    4151              : 
    4152              : /* Determine if there is a zero terminator somewhere in the
    4153              :    part of SVAL covered by BYTES (where BYTES is relative to the svalue).
    4154              : 
    4155              :    Return a tristate:
    4156              :    - true if there definitely is a zero byte, writing to *OUT_BYTES_READ
    4157              :    the number of bytes from that would be read, including the zero byte.
    4158              :    - false if there definitely isn't a zero byte
    4159              :    - unknown if we don't know.
    4160              : 
    4161              :    Use LOGGER (if non-null) for any logging.  */
    4162              : 
    4163              : static tristate
    4164          849 : svalue_byte_range_has_null_terminator_1 (const svalue *sval,
    4165              :                                          const byte_range &bytes,
    4166              :                                          byte_offset_t *out_bytes_read,
    4167              :                                          logger *logger)
    4168              : {
    4169          849 :   if (bytes.m_start_byte_offset == 0
    4170          849 :       && sval->all_zeroes_p ())
    4171              :     {
    4172              :       /* The initial byte of an all-zeroes SVAL is a zero byte.  */
    4173           21 :       *out_bytes_read = 1;
    4174           21 :       return tristate (true);
    4175              :     }
    4176              : 
    4177          828 :   switch (sval->get_kind ())
    4178              :     {
    4179          341 :     case SK_CONSTANT:
    4180          341 :       {
    4181          341 :         tree cst
    4182          341 :           = as_a <const constant_svalue *> (sval)->get_constant ();
    4183          341 :         switch (TREE_CODE (cst))
    4184              :           {
    4185          326 :           case STRING_CST:
    4186          326 :             return string_cst_has_null_terminator (cst, bytes, out_bytes_read);
    4187           15 :           case INTEGER_CST:
    4188           15 :             if (bytes.m_start_byte_offset == 0
    4189           15 :                 && integer_onep (TYPE_SIZE_UNIT (TREE_TYPE (cst))))
    4190              :               {
    4191              :                 /* Model accesses to the initial byte of a 1-byte
    4192              :                    INTEGER_CST.  */
    4193           13 :                 *out_bytes_read = 1;
    4194           13 :                 if (zerop (cst))
    4195            0 :                   return tristate (true);
    4196              :                 else
    4197           13 :                   return tristate (false);
    4198              :               }
    4199              :             /* Treat any other access to an INTEGER_CST as unknown.  */
    4200            2 :             return tristate::TS_UNKNOWN;
    4201              : 
    4202              :           default:
    4203              :             break;
    4204              :           }
    4205              :       }
    4206              :       break;
    4207              : 
    4208          158 :     case SK_INITIAL:
    4209          158 :       {
    4210          158 :         const initial_svalue *initial_sval = (const initial_svalue *)sval;
    4211          158 :         const region *reg = initial_sval->get_region ();
    4212          158 :         if (const string_region *string_reg = reg->dyn_cast_string_region ())
    4213              :           {
    4214          137 :             tree string_cst = string_reg->get_string_cst ();
    4215          137 :             return string_cst_has_null_terminator (string_cst,
    4216              :                                                    bytes,
    4217          137 :                                                    out_bytes_read);
    4218              :           }
    4219           21 :         return tristate::TS_UNKNOWN;
    4220              :       }
    4221           74 :       break;
    4222              : 
    4223           74 :     case SK_BITS_WITHIN:
    4224           74 :       {
    4225           74 :         const bits_within_svalue *bits_within_sval
    4226              :           = (const bits_within_svalue *)sval;
    4227           74 :         byte_range bytes_within_inner (0, 0);
    4228           74 :         if (bits_within_sval->get_bits ().as_byte_range (&bytes_within_inner))
    4229              :           {
    4230              :             /* Consider e.g. looking for null terminator of
    4231              :                bytes 2-4 of BITS_WITHIN(bytes 10-15 of inner_sval)
    4232              : 
    4233              :                This is equivalent to looking within bytes 12-14 of
    4234              :                inner_sval. */
    4235           74 :             const byte_offset_t start_byte_relative_to_inner
    4236           74 :               = (bytes.m_start_byte_offset
    4237           74 :                  + bytes_within_inner.m_start_byte_offset);
    4238           74 :             const byte_offset_t next_byte_relative_to_inner
    4239           74 :               = (bytes.get_next_byte_offset ()
    4240           74 :                  + bytes_within_inner.m_start_byte_offset);
    4241           74 :             if (next_byte_relative_to_inner > start_byte_relative_to_inner)
    4242              :               {
    4243           74 :                 const byte_range relative_to_inner
    4244              :                   (start_byte_relative_to_inner,
    4245           74 :                    next_byte_relative_to_inner - start_byte_relative_to_inner);
    4246           74 :                 const svalue *inner_sval
    4247           74 :                   = bits_within_sval->get_inner_svalue ();
    4248           74 :                 return svalue_byte_range_has_null_terminator (inner_sval,
    4249              :                                                               relative_to_inner,
    4250              :                                                               out_bytes_read,
    4251              :                                                               logger);
    4252              :               }
    4253              :           }
    4254              :       }
    4255            0 :       break;
    4256              : 
    4257              :     default:
    4258              :       // TODO: it may be possible to handle other cases here.
    4259              :       break;
    4260              :     }
    4261          255 :   return tristate::TS_UNKNOWN;
    4262              : }
    4263              : 
    4264              : /* Like svalue_byte_range_has_null_terminator_1, but add logging.  */
    4265              : 
    4266              : static tristate
    4267          849 : svalue_byte_range_has_null_terminator (const svalue *sval,
    4268              :                                        const byte_range &bytes,
    4269              :                                        byte_offset_t *out_bytes_read,
    4270              :                                        logger *logger)
    4271              : {
    4272          849 :   LOG_SCOPE (logger);
    4273          849 :   if (logger)
    4274              :     {
    4275            1 :       pretty_printer *pp = logger->get_printer ();
    4276            1 :       logger->start_log_line ();
    4277            1 :       bytes.dump_to_pp (pp);
    4278            1 :       logger->log_partial (" of sval: ");
    4279            1 :       sval->dump_to_pp (pp, true);
    4280            1 :       logger->end_log_line ();
    4281              :     }
    4282          849 :   tristate ts
    4283          849 :     = svalue_byte_range_has_null_terminator_1 (sval, bytes,
    4284              :                                                out_bytes_read, logger);
    4285          849 :   if (logger)
    4286              :     {
    4287            1 :       pretty_printer *pp = logger->get_printer ();
    4288            1 :       logger->start_log_line ();
    4289            1 :       pp_printf (pp, "has null terminator: %s", ts.as_string ());
    4290            1 :       if (ts.is_true ())
    4291              :         {
    4292            1 :           pp_string (pp, "; bytes read: ");
    4293            1 :           pp_wide_int (pp, *out_bytes_read, SIGNED);
    4294              :         }
    4295            1 :       logger->end_log_line ();
    4296              :     }
    4297         1698 :   return ts;
    4298          849 : }
    4299              : 
    4300              : /* A frozen copy of a single base region's binding_cluster within a store,
    4301              :    optimized for traversal of the concrete parts in byte order.
    4302              :    This only captures concrete bindings, and is an implementation detail
    4303              :    of region_model::scan_for_null_terminator.  */
    4304              : 
    4305         3709 : class iterable_cluster
    4306              : {
    4307              : public:
    4308         3709 :   iterable_cluster (const binding_cluster *cluster)
    4309         3709 :   {
    4310         3709 :     if (!cluster)
    4311              :       return;
    4312         3217 :     for (auto iter : cluster->get_map ().get_concrete_bindings ())
    4313              :       {
    4314         1033 :         const bit_range &bits = iter.first;
    4315         1033 :         const svalue *sval = iter.second;
    4316              : 
    4317         1033 :         byte_range fragment_bytes (0, 0);
    4318         1033 :         if (bits.as_byte_range (&fragment_bytes))
    4319         1033 :           m_fragments.safe_push (fragment (fragment_bytes, sval));
    4320              :       }
    4321         2308 :     for (auto iter : cluster->get_map ().get_symbolic_bindings ())
    4322          124 :       m_symbolic_bindings.safe_push (iter);
    4323         2184 :     m_fragments.qsort (fragment::cmp_ptrs);
    4324              :   }
    4325              : 
    4326              :   bool
    4327         3851 :   get_fragment_for_byte (byte_offset_t byte, fragment *out_frag) const
    4328              :   {
    4329              :     /* TODO: binary search rather than linear.  */
    4330         3851 :     unsigned iter_idx;
    4331         4085 :     for (iter_idx = 0; iter_idx < m_fragments.length (); iter_idx++)
    4332              :       {
    4333         1009 :         if (m_fragments[iter_idx].m_byte_range.contains_p (byte))
    4334              :         {
    4335          775 :           *out_frag = m_fragments[iter_idx];
    4336          775 :           return true;
    4337              :         }
    4338              :       }
    4339              :     return false;
    4340              :   }
    4341              : 
    4342         3076 :   bool has_symbolic_bindings_p () const
    4343              :   {
    4344         6152 :     return !m_symbolic_bindings.is_empty ();
    4345              :   }
    4346              : 
    4347            2 :   void dump_to_pp (pretty_printer *pp) const
    4348              :   {
    4349            2 :     pp_string (pp, "iterable_cluster (fragments: [");
    4350            5 :     for (auto const &iter : &m_fragments)
    4351              :       {
    4352            2 :         if (&iter != m_fragments.begin ())
    4353            0 :           pp_string (pp, ", ");
    4354            1 :         iter.dump_to_pp (pp);
    4355              :       }
    4356            2 :     pp_printf (pp, "], symbolic bindings: [");
    4357            2 :     for (auto const &iter : m_symbolic_bindings)
    4358              :       {
    4359            0 :         if (&iter != m_symbolic_bindings.begin ())
    4360            0 :           pp_string (pp, ", ");
    4361            0 :         iter.m_region->dump_to_pp (pp, true);
    4362              :       }
    4363            2 :     pp_string (pp, "])");
    4364            2 :   }
    4365              : 
    4366              : private:
    4367              :   auto_vec<fragment> m_fragments;
    4368              :   auto_vec<binding_map::symbolic_binding> m_symbolic_bindings;
    4369              : };
    4370              : 
    4371              : /* Simulate reading the bytes at BYTES from BASE_REG.
    4372              :    Complain to CTXT about any issues with the read e.g. out-of-bounds.  */
    4373              : 
    4374              : const svalue *
    4375         8165 : region_model::get_store_bytes (const region *base_reg,
    4376              :                                const byte_range &bytes,
    4377              :                                region_model_context *ctxt) const
    4378              : {
    4379              :   /* Shortcut reading all of a string_region.  */
    4380         8165 :   if (bytes.get_start_byte_offset () == 0)
    4381         7938 :     if (const string_region *string_reg = base_reg->dyn_cast_string_region ())
    4382         4712 :       if (bytes.m_size_in_bytes
    4383         4712 :           == TREE_STRING_LENGTH (string_reg->get_string_cst ()))
    4384         4712 :         return m_mgr->get_or_create_initial_value (base_reg);
    4385              : 
    4386         3453 :   const svalue *index_sval
    4387         3453 :     = m_mgr->get_or_create_int_cst (size_type_node,
    4388         3453 :                                     bytes.get_start_byte_offset ());
    4389         3453 :   const region *offset_reg = m_mgr->get_offset_region (base_reg,
    4390              :                                                        NULL_TREE,
    4391              :                                                        index_sval);
    4392         3453 :   const svalue *byte_size_sval
    4393         3453 :     = m_mgr->get_or_create_int_cst (size_type_node, bytes.m_size_in_bytes);
    4394         3453 :   const region *read_reg = m_mgr->get_sized_region (offset_reg,
    4395              :                                                     NULL_TREE,
    4396              :                                                     byte_size_sval);
    4397              : 
    4398              :   /* Simulate reading those bytes from the store.  */
    4399         3453 :   const svalue *sval = get_store_value (read_reg, ctxt);
    4400         3453 :   return sval;
    4401              : }
    4402              : 
    4403              : static tree
    4404         2826 : get_tree_for_byte_offset (tree ptr_expr, byte_offset_t byte_offset)
    4405              : {
    4406         2826 :   gcc_assert (ptr_expr);
    4407         2826 :   tree ptype = build_pointer_type_for_mode (char_type_node, ptr_mode, true);
    4408         2826 :   return fold_build2 (MEM_REF,
    4409              :                       char_type_node,
    4410              :                       ptr_expr, wide_int_to_tree (ptype, byte_offset));
    4411              : }
    4412              : 
    4413              : /* Simulate a series of reads of REG until we find a 0 byte
    4414              :    (equivalent to calling strlen).
    4415              : 
    4416              :    Complain to CTXT and return NULL if:
    4417              :    - the buffer pointed to isn't null-terminated
    4418              :    - the buffer pointed to has any uninitialized bytes before any 0-terminator
    4419              :    - any of the reads aren't within the bounds of the underlying base region
    4420              : 
    4421              :    Otherwise, return a svalue for the number of bytes read (strlen + 1),
    4422              :    and, if OUT_SVAL is non-NULL, write to *OUT_SVAL with an svalue
    4423              :    representing the content of REG up to and including the terminator.
    4424              : 
    4425              :    Algorithm
    4426              :    =========
    4427              : 
    4428              :    Get offset for first byte to read.
    4429              :    Find the binding (if any) that contains it.
    4430              :    Find the size in bits of that binding.
    4431              :    Round to the nearest byte (which way???)
    4432              :      Or maybe give up if we have a partial binding there.
    4433              :    Get the svalue from the binding.
    4434              :    Determine the strlen (if any) of that svalue.
    4435              :      Does it have a 0-terminator within it?
    4436              :       If so, we have a partial read up to and including that terminator
    4437              :        Read those bytes from the store; add to the result in the correct place.
    4438              :        Finish
    4439              :       If not, we have a full read of that svalue
    4440              :        Read those bytes from the store; add to the result in the correct place.
    4441              :        Update read/write offsets
    4442              :        Continue
    4443              :       If unknown:
    4444              :        Result is unknown
    4445              :        Finish
    4446              : */
    4447              : 
    4448              : const svalue *
    4449         8540 : region_model::scan_for_null_terminator_1 (const region *reg,
    4450              :                                           tree expr,
    4451              :                                           const svalue **out_sval,
    4452              :                                           region_model_context *ctxt) const
    4453              : {
    4454         8540 :   logger *logger = ctxt ? ctxt->get_logger () : nullptr;
    4455              : 
    4456         8540 :   region_offset offset = reg->get_offset (m_mgr);
    4457         8540 :   if (offset.symbolic_p ())
    4458              :     {
    4459          115 :       if (out_sval)
    4460            0 :         *out_sval = get_store_value (reg, nullptr);
    4461          115 :       if (logger)
    4462            0 :         logger->log ("offset is symbolic");
    4463          115 :       return m_mgr->get_or_create_unknown_svalue (size_type_node);
    4464              :     }
    4465         8425 :   byte_offset_t src_byte_offset;
    4466         8425 :   if (!offset.get_concrete_byte_offset (&src_byte_offset))
    4467              :     {
    4468            0 :       if (out_sval)
    4469            0 :         *out_sval = get_store_value (reg, nullptr);
    4470            0 :       if (logger)
    4471            0 :         logger->log ("can't get concrete byte offset");
    4472            0 :       return m_mgr->get_or_create_unknown_svalue (size_type_node);
    4473              :     }
    4474         8425 :   const byte_offset_t initial_src_byte_offset = src_byte_offset;
    4475         8425 :   byte_offset_t dst_byte_offset = 0;
    4476              : 
    4477         8425 :   const region *base_reg = reg->get_base_region ();
    4478              : 
    4479         8425 :   if (const string_region *str_reg = base_reg->dyn_cast_string_region ())
    4480              :     {
    4481         4718 :       tree string_cst = str_reg->get_string_cst ();
    4482         4720 :       if (src_byte_offset >= 0
    4483         4717 :           && src_byte_offset < TREE_STRING_LENGTH (string_cst)
    4484         9434 :           && wi::fits_shwi_p (src_byte_offset))
    4485              :         {
    4486         4716 :           HOST_WIDE_INT str_byte_offset = src_byte_offset.to_shwi ();
    4487         4716 :           const char *effective_start
    4488         4716 :             = TREE_STRING_POINTER (string_cst) + str_byte_offset;
    4489         4716 :           size_t effective_len
    4490         4716 :             = TREE_STRING_LENGTH (string_cst) - str_byte_offset;
    4491         4716 :           if (const void *p = memchr (effective_start, 0, effective_len))
    4492              :             {
    4493         4716 :               size_t num_bytes_read
    4494         4716 :                 = (const char *)p - effective_start + 1;
    4495              :               /* Simulate the read.  */
    4496         4716 :               byte_range bytes_to_read (0, num_bytes_read);
    4497         4716 :               const svalue *sval = get_store_bytes (reg, bytes_to_read, ctxt);
    4498         4716 :               if (out_sval)
    4499          834 :                 *out_sval = sval;
    4500         4716 :               if (logger)
    4501            0 :                 logger->log ("using string_cst");
    4502         4716 :               return m_mgr->get_or_create_int_cst (size_type_node,
    4503         4716 :                                                    num_bytes_read);
    4504              :             }
    4505              :         }
    4506              :     }
    4507         3709 :   const binding_cluster *cluster = m_store.get_cluster (base_reg);
    4508         3709 :   iterable_cluster c (cluster);
    4509         3709 :   if (logger)
    4510              :     {
    4511            2 :       pretty_printer *pp = logger->get_printer ();
    4512            2 :       logger->start_log_line ();
    4513            2 :       c.dump_to_pp (pp);
    4514            2 :       logger->end_log_line ();
    4515              :     }
    4516              : 
    4517         3709 :   concrete_binding_map result;
    4518              : 
    4519         3993 :   while (1)
    4520              :     {
    4521         3851 :       fragment f;
    4522         3851 :       if (c.get_fragment_for_byte (src_byte_offset, &f))
    4523              :         {
    4524          775 :           if (logger)
    4525              :             {
    4526            1 :               logger->start_log_line ();
    4527            1 :               pretty_printer *pp = logger->get_printer ();
    4528            1 :               pp_printf (pp, "src_byte_offset: ");
    4529            1 :               pp_wide_int (pp, src_byte_offset, SIGNED);
    4530            1 :               pp_string (pp, ": ");
    4531            1 :               f.dump_to_pp (pp);
    4532            1 :               logger->end_log_line ();
    4533              :             }
    4534          775 :           gcc_assert (f.m_byte_range.contains_p (src_byte_offset));
    4535              :           /* src_byte_offset and f.m_byte_range are both expressed relative to
    4536              :              the base region.
    4537              :              Convert to a byte_range relative to the svalue.  */
    4538          775 :           const byte_range bytes_relative_to_svalue
    4539          775 :             (src_byte_offset - f.m_byte_range.get_start_byte_offset (),
    4540          775 :              f.m_byte_range.get_next_byte_offset () - src_byte_offset);
    4541          775 :           byte_offset_t fragment_bytes_read;
    4542          775 :           tristate is_terminated
    4543          775 :             = svalue_byte_range_has_null_terminator (f.m_sval,
    4544              :                                                      bytes_relative_to_svalue,
    4545              :                                                      &fragment_bytes_read,
    4546              :                                                      logger);
    4547          775 :           if (is_terminated.is_unknown ())
    4548              :             {
    4549          278 :               if (out_sval)
    4550            2 :                 *out_sval = get_store_value (reg, nullptr);
    4551          633 :               return m_mgr->get_or_create_unknown_svalue (size_type_node);
    4552              :             }
    4553              : 
    4554              :           /* Simulate reading those bytes from the store.  */
    4555          497 :           byte_range bytes_to_read (src_byte_offset, fragment_bytes_read);
    4556          497 :           const svalue *sval = get_store_bytes (base_reg, bytes_to_read, ctxt);
    4557          497 :           check_for_poison (sval, expr, nullptr, ctxt);
    4558              : 
    4559          497 :           if (out_sval)
    4560              :             {
    4561            9 :               byte_range bytes_to_write (dst_byte_offset, fragment_bytes_read);
    4562            9 :               result.insert (bytes_to_write, sval);
    4563              :             }
    4564              : 
    4565          497 :           src_byte_offset += fragment_bytes_read;
    4566          497 :           dst_byte_offset += fragment_bytes_read;
    4567              : 
    4568          497 :           if (is_terminated.is_true ())
    4569              :             {
    4570          355 :               if (out_sval)
    4571            6 :                 *out_sval = m_mgr->get_or_create_compound_svalue (NULL_TREE,
    4572              :                                                                   std::move (result));
    4573          355 :               if (logger)
    4574            1 :                 logger->log ("got terminator");
    4575          355 :               return m_mgr->get_or_create_int_cst (size_type_node,
    4576          355 :                                                    dst_byte_offset);
    4577              :             }
    4578              :         }
    4579              :       else
    4580              :         break;
    4581          142 :     }
    4582              : 
    4583              :   /* No binding for this base_region, or no binding at src_byte_offset
    4584              :      (or a symbolic binding).  */
    4585              : 
    4586         3076 :   if (c.has_symbolic_bindings_p ())
    4587              :     {
    4588          124 :       if (out_sval)
    4589           40 :         *out_sval = get_store_value (reg, nullptr);
    4590          124 :       if (logger)
    4591            0 :         logger->log ("got symbolic binding");
    4592          124 :       return m_mgr->get_or_create_unknown_svalue (size_type_node);
    4593              :     }
    4594              : 
    4595              :   /* TODO: the various special-cases seen in
    4596              :      region_model::get_store_value.  */
    4597              : 
    4598              :   /* Simulate reading from this byte, then give up.  */
    4599         2952 :   byte_range bytes_to_read (src_byte_offset, 1);
    4600         2952 :   const svalue *sval = get_store_bytes (base_reg, bytes_to_read, ctxt);
    4601         2952 :   tree byte_expr
    4602              :     = (expr
    4603         5778 :        ? get_tree_for_byte_offset (expr,
    4604              :                                    src_byte_offset - initial_src_byte_offset)
    4605              :        : NULL_TREE);
    4606         2952 :   check_for_poison (sval, byte_expr, nullptr, ctxt);
    4607         2952 :   if (base_reg->can_have_initial_svalue_p ())
    4608              :     {
    4609         2744 :       if (out_sval)
    4610          276 :         *out_sval = get_store_value (reg, nullptr);
    4611         2744 :       return m_mgr->get_or_create_unknown_svalue (size_type_node);
    4612              :     }
    4613              :   else
    4614              :     return nullptr;
    4615         7418 : }
    4616              : 
    4617              : /* Like region_model::scan_for_null_terminator_1, but add logging.  */
    4618              : 
    4619              : const svalue *
    4620         8540 : region_model::scan_for_null_terminator (const region *reg,
    4621              :                                         tree expr,
    4622              :                                         const svalue **out_sval,
    4623              :                                         region_model_context *ctxt) const
    4624              : {
    4625         8540 :   logger *logger = ctxt ? ctxt->get_logger () : nullptr;
    4626         8540 :   LOG_SCOPE (logger);
    4627         8540 :   if (logger)
    4628              :     {
    4629            2 :       pretty_printer *pp = logger->get_printer ();
    4630            2 :       logger->start_log_line ();
    4631            2 :       logger->log_partial ("region: ");
    4632            2 :       reg->dump_to_pp (pp, true);
    4633            2 :       logger->end_log_line ();
    4634              :     }
    4635         8540 :   if (out_sval)
    4636         1165 :     *out_sval = nullptr;
    4637         8540 :   const svalue *sval = scan_for_null_terminator_1 (reg, expr, out_sval, ctxt);
    4638         8540 :   if (sval && out_sval)
    4639         1158 :     gcc_assert (*out_sval);
    4640         8540 :   if (logger)
    4641              :     {
    4642            2 :       pretty_printer *pp = logger->get_printer ();
    4643            2 :       logger->start_log_line ();
    4644            2 :       logger->log_partial ("length result: ");
    4645            2 :       if (sval)
    4646            1 :         sval->dump_to_pp (pp, true);
    4647              :       else
    4648            1 :         pp_printf (pp, "NULL");
    4649            2 :       logger->end_log_line ();
    4650            2 :       if (out_sval)
    4651              :         {
    4652            2 :           logger->start_log_line ();
    4653            2 :           logger->log_partial ("content result: ");
    4654            2 :           if (*out_sval)
    4655            1 :             (*out_sval)->dump_to_pp (pp, true);
    4656              :           else
    4657            1 :             pp_printf (pp, "NULL");
    4658            2 :           logger->end_log_line ();
    4659              :         }
    4660              :     }
    4661        17080 :   return sval;
    4662         8540 : }
    4663              : 
    4664              : /* Check that argument ARG_IDX (0-based) to the call described by CD
    4665              :    is a pointer to a valid null-terminated string.
    4666              : 
    4667              :    Simulate scanning through the buffer, reading until we find a 0 byte
    4668              :    (equivalent to calling strlen).
    4669              : 
    4670              :    Complain and return nullptr if:
    4671              :    - the buffer pointed to isn't null-terminated
    4672              :    - the buffer pointed to has any uninitialized bytes before any 0-terminator
    4673              :    - any of the reads aren't within the bounds of the underlying base region
    4674              : 
    4675              :    Otherwise, return a svalue for strlen of the buffer (*not* including
    4676              :    the null terminator).
    4677              : 
    4678              :    TODO: we should also complain if:
    4679              :    - the pointer is NULL (or could be).  */
    4680              : 
    4681              : const svalue *
    4682          209 : region_model::check_for_null_terminated_string_arg (const call_details &cd,
    4683              :                                                     unsigned arg_idx) const
    4684              : {
    4685          209 :   return check_for_null_terminated_string_arg (cd,
    4686              :                                                arg_idx,
    4687              :                                                false, /* include_terminator */
    4688          209 :                                                nullptr); // out_sval
    4689              : }
    4690              : 
    4691              : 
    4692              : /* Check that argument ARG_IDX (0-based) to the call described by CD
    4693              :    is a pointer to a valid null-terminated string.
    4694              : 
    4695              :    Simulate scanning through the buffer, reading until we find a 0 byte
    4696              :    (equivalent to calling strlen).
    4697              : 
    4698              :    Complain and return nullptr if:
    4699              :    - the buffer pointed to isn't null-terminated
    4700              :    - the buffer pointed to has any uninitialized bytes before any 0-terminator
    4701              :    - any of the reads aren't within the bounds of the underlying base region
    4702              : 
    4703              :    Otherwise, return a svalue.  This will be the number of bytes read
    4704              :    (including the null terminator) if INCLUDE_TERMINATOR is true, or strlen
    4705              :    of the buffer (not including the null terminator) if it is false.
    4706              : 
    4707              :    Also, when returning an svalue, if OUT_SVAL is non-nullptr, write to
    4708              :    *OUT_SVAL with an svalue representing the content of the buffer up to
    4709              :    and including the terminator.
    4710              : 
    4711              :    TODO: we should also complain if:
    4712              :    - the pointer is NULL (or could be).  */
    4713              : 
    4714              : const svalue *
    4715         8069 : region_model::check_for_null_terminated_string_arg (const call_details &cd,
    4716              :                                                     unsigned arg_idx,
    4717              :                                                     bool include_terminator,
    4718              :                                                     const svalue **out_sval) const
    4719              : {
    4720            0 :   class null_terminator_check_event : public custom_event
    4721              :   {
    4722              :   public:
    4723          164 :     null_terminator_check_event (const event_loc_info &loc_info,
    4724              :                                  const call_arg_details &arg_details)
    4725              :     : custom_event (loc_info),
    4726          164 :       m_arg_details (arg_details)
    4727              :     {
    4728              :     }
    4729              : 
    4730          310 :     void print_desc (pretty_printer &pp) const final override
    4731              :     {
    4732          310 :       if (m_arg_details.m_arg_expr)
    4733          310 :         pp_printf (&pp,
    4734              :                    "while looking for null terminator"
    4735              :                    " for argument %i (%qE) of %qD...",
    4736          310 :                    m_arg_details.m_arg_idx + 1,
    4737              :                    m_arg_details.m_arg_expr,
    4738          310 :                    m_arg_details.m_called_fndecl);
    4739              :       else
    4740            0 :         pp_printf (&pp,
    4741              :                    "while looking for null terminator"
    4742              :                    " for argument %i of %qD...",
    4743            0 :                    m_arg_details.m_arg_idx + 1,
    4744            0 :                    m_arg_details.m_called_fndecl);
    4745          310 :     }
    4746              : 
    4747              :   private:
    4748              :     const call_arg_details m_arg_details;
    4749              :   };
    4750              : 
    4751            0 :   class null_terminator_check_decl_note
    4752              :     : public pending_note_subclass<null_terminator_check_decl_note>
    4753              :   {
    4754              :   public:
    4755          164 :     null_terminator_check_decl_note (const call_arg_details &arg_details)
    4756          164 :     : m_arg_details (arg_details)
    4757              :     {
    4758              :     }
    4759              : 
    4760         1300 :     const char *get_kind () const final override
    4761              :     {
    4762         1300 :       return "null_terminator_check_decl_note";
    4763              :     }
    4764              : 
    4765          152 :     void emit () const final override
    4766              :     {
    4767          152 :       inform_about_expected_null_terminated_string_arg (m_arg_details);
    4768          152 :     }
    4769              : 
    4770          650 :     bool operator== (const null_terminator_check_decl_note &other) const
    4771              :     {
    4772          650 :       return m_arg_details == other.m_arg_details;
    4773              :     }
    4774              : 
    4775              :   private:
    4776              :     const call_arg_details m_arg_details;
    4777              :   };
    4778              : 
    4779              :   /* Subclass of decorated_region_model_context that
    4780              :      adds the above event and note to any saved diagnostics.  */
    4781         8069 :   class annotating_ctxt : public annotating_context
    4782              :   {
    4783              :   public:
    4784         8069 :     annotating_ctxt (const call_details &cd,
    4785              :                      unsigned arg_idx)
    4786              :     : annotating_context (cd.get_ctxt ()),
    4787         8069 :       m_cd (cd),
    4788         8069 :       m_arg_idx (arg_idx)
    4789              :     {
    4790              :     }
    4791          164 :     void add_annotations () final override
    4792              :     {
    4793          164 :       call_arg_details arg_details (m_cd, m_arg_idx);
    4794          328 :       event_loc_info loc_info (m_cd.get_location (),
    4795          164 :                                m_cd.get_model ()->get_current_function ()->decl,
    4796          328 :                                m_cd.get_model ()->get_stack_depth ());
    4797              : 
    4798          164 :       add_event
    4799          164 :         (std::make_unique<null_terminator_check_event> (loc_info,
    4800              :                                                         arg_details));
    4801          164 :       add_note
    4802          164 :         (std::make_unique <null_terminator_check_decl_note> (arg_details));
    4803          164 :     }
    4804              :   private:
    4805              :     const call_details &m_cd;
    4806              :     unsigned m_arg_idx;
    4807              :   };
    4808              : 
    4809              :   /* Use this ctxt below so that any diagnostics that get added
    4810              :      get annotated.  */
    4811         8069 :   annotating_ctxt my_ctxt (cd, arg_idx);
    4812              : 
    4813         8069 :   const svalue *arg_sval = cd.get_arg_svalue (arg_idx);
    4814         8069 :   const region *buf_reg
    4815         8069 :     = deref_rvalue (arg_sval, cd.get_arg_tree (arg_idx), &my_ctxt);
    4816              : 
    4817        16138 :   if (const svalue *num_bytes_read_sval
    4818         8069 :       = scan_for_null_terminator (buf_reg,
    4819              :                                   cd.get_arg_tree (arg_idx),
    4820              :                                   out_sval,
    4821              :                                   &my_ctxt))
    4822              :     {
    4823         7899 :       if (out_sval)
    4824         1158 :         gcc_assert (*out_sval);
    4825         7899 :       if (include_terminator)
    4826              :         return num_bytes_read_sval;
    4827              :       else
    4828              :         {
    4829              :           /* strlen is (bytes_read - 1).  */
    4830         6741 :           const svalue *one = m_mgr->get_or_create_int_cst (size_type_node, 1);
    4831         6741 :           return m_mgr->get_or_create_binop (size_type_node,
    4832              :                                              MINUS_EXPR,
    4833              :                                              num_bytes_read_sval,
    4834         6741 :                                              one);
    4835              :         }
    4836              :     }
    4837              :   else
    4838              :     return nullptr;
    4839              : }
    4840              : 
    4841              : /* Remove all bindings overlapping REG within the store.  */
    4842              : 
    4843              : void
    4844         8067 : region_model::clobber_region (const region *reg)
    4845              : {
    4846         8067 :   m_store.clobber_region (m_mgr->get_store_manager(), reg);
    4847         8067 : }
    4848              : 
    4849              : /* Remove any bindings for REG within the store.  */
    4850              : 
    4851              : void
    4852       231799 : region_model::purge_region (const region *reg)
    4853              : {
    4854       231799 :   m_store.purge_region (m_mgr->get_store_manager(), reg);
    4855       231799 : }
    4856              : 
    4857              : /* Fill REG with SVAL.
    4858              :    Use CTXT to report any warnings associated with the write
    4859              :    (e.g. out-of-bounds).  */
    4860              : 
    4861              : void
    4862          746 : region_model::fill_region (const region *reg,
    4863              :                            const svalue *sval,
    4864              :                            region_model_context *ctxt)
    4865              : {
    4866          746 :   check_region_for_write (reg, nullptr, ctxt);
    4867          746 :   m_store.fill_region (m_mgr->get_store_manager(), reg, sval);
    4868          746 : }
    4869              : 
    4870              : /* Zero-fill REG.
    4871              :    Use CTXT to report any warnings associated with the write
    4872              :    (e.g. out-of-bounds).  */
    4873              : 
    4874              : void
    4875          861 : region_model::zero_fill_region (const region *reg,
    4876              :                                 region_model_context *ctxt)
    4877              : {
    4878          861 :   check_region_for_write (reg, nullptr, ctxt);
    4879          861 :   m_store.zero_fill_region (m_mgr->get_store_manager(), reg);
    4880          861 : }
    4881              : 
    4882              : /* Copy NUM_BYTES_SVAL of SVAL to DEST_REG.
    4883              :    Use CTXT to report any warnings associated with the copy
    4884              :    (e.g. out-of-bounds writes).  */
    4885              : 
    4886              : void
    4887         2300 : region_model::write_bytes (const region *dest_reg,
    4888              :                            const svalue *num_bytes_sval,
    4889              :                            const svalue *sval,
    4890              :                            region_model_context *ctxt)
    4891              : {
    4892         2300 :   const region *sized_dest_reg
    4893         2300 :     = m_mgr->get_sized_region (dest_reg, NULL_TREE, num_bytes_sval);
    4894         2300 :   set_value (sized_dest_reg, sval, ctxt);
    4895         2300 : }
    4896              : 
    4897              : /* Read NUM_BYTES_SVAL from SRC_REG.
    4898              :    Use CTXT to report any warnings associated with the copy
    4899              :    (e.g. out-of-bounds reads, copying of uninitialized values, etc).  */
    4900              : 
    4901              : const svalue *
    4902         1270 : region_model::read_bytes (const region *src_reg,
    4903              :                           tree src_ptr_expr,
    4904              :                           const svalue *num_bytes_sval,
    4905              :                           region_model_context *ctxt) const
    4906              : {
    4907         1270 :   if (num_bytes_sval->get_kind () == SK_UNKNOWN)
    4908          224 :     return m_mgr->get_or_create_unknown_svalue (NULL_TREE);
    4909         1046 :   const region *sized_src_reg
    4910         1046 :     = m_mgr->get_sized_region (src_reg, NULL_TREE, num_bytes_sval);
    4911         1046 :   const svalue *src_contents_sval = get_store_value (sized_src_reg, ctxt);
    4912         1046 :   check_for_poison (src_contents_sval, src_ptr_expr,
    4913              :                     sized_src_reg, ctxt);
    4914         1046 :   return src_contents_sval;
    4915              : }
    4916              : 
    4917              : /* Copy NUM_BYTES_SVAL bytes from SRC_REG to DEST_REG.
    4918              :    Use CTXT to report any warnings associated with the copy
    4919              :    (e.g. out-of-bounds reads/writes, copying of uninitialized values,
    4920              :    etc).  */
    4921              : 
    4922              : void
    4923          646 : region_model::copy_bytes (const region *dest_reg,
    4924              :                           const region *src_reg,
    4925              :                           tree src_ptr_expr,
    4926              :                           const svalue *num_bytes_sval,
    4927              :                           region_model_context *ctxt)
    4928              : {
    4929          646 :   const svalue *data_sval
    4930          646 :     = read_bytes (src_reg, src_ptr_expr, num_bytes_sval, ctxt);
    4931          646 :   write_bytes (dest_reg, num_bytes_sval, data_sval, ctxt);
    4932          646 : }
    4933              : 
    4934              : /* Mark REG as having unknown content.  */
    4935              : 
    4936              : void
    4937          309 : region_model::mark_region_as_unknown (const region *reg,
    4938              :                                       uncertainty_t *uncertainty)
    4939              : {
    4940          309 :   svalue_set maybe_live_values;
    4941          309 :   m_store.mark_region_as_unknown (m_mgr->get_store_manager(), reg,
    4942              :                                   uncertainty, &maybe_live_values);
    4943          309 :   m_store.on_maybe_live_values (*m_mgr->get_store_manager (),
    4944              :                                 maybe_live_values);
    4945          309 : }
    4946              : 
    4947              : /* Determine what is known about the condition "LHS_SVAL OP RHS_SVAL" within
    4948              :    this model.  */
    4949              : 
    4950              : tristate
    4951       231396 : region_model::eval_condition (const svalue *lhs,
    4952              :                                enum tree_code op,
    4953              :                                const svalue *rhs) const
    4954              : {
    4955       231396 :   gcc_assert (lhs);
    4956       231396 :   gcc_assert (rhs);
    4957              : 
    4958              :   /* For now, make no attempt to capture constraints on floating-point
    4959              :      values.  */
    4960       231396 :   if ((lhs->get_type () && FLOAT_TYPE_P (lhs->get_type ()))
    4961       400116 :       || (rhs->get_type () && FLOAT_TYPE_P (rhs->get_type ())))
    4962           72 :     return tristate::unknown ();
    4963              : 
    4964              :   /* See what we know based on the values.  */
    4965              : 
    4966              :   /* Unwrap any unmergeable values.  */
    4967       231324 :   lhs = lhs->unwrap_any_unmergeable ();
    4968       231324 :   rhs = rhs->unwrap_any_unmergeable ();
    4969              : 
    4970       231324 :   if (lhs == rhs)
    4971              :     {
    4972              :       /* If we have the same svalue, then we have equality
    4973              :          (apart from NaN-handling).
    4974              :          TODO: should this definitely be the case for poisoned values?  */
    4975              :       /* Poisoned and unknown values are "unknowable".  */
    4976        22566 :       if (lhs->get_kind () == SK_POISONED
    4977        22566 :           || lhs->get_kind () == SK_UNKNOWN)
    4978         9720 :         return tristate::TS_UNKNOWN;
    4979              : 
    4980        12846 :       switch (op)
    4981              :         {
    4982         9584 :         case EQ_EXPR:
    4983         9584 :         case GE_EXPR:
    4984         9584 :         case LE_EXPR:
    4985         9584 :           return tristate::TS_TRUE;
    4986              : 
    4987         3262 :         case NE_EXPR:
    4988         3262 :         case GT_EXPR:
    4989         3262 :         case LT_EXPR:
    4990         3262 :           return tristate::TS_FALSE;
    4991              : 
    4992              :         default:
    4993              :           /* For other ops, use the logic below.  */
    4994              :           break;
    4995              :         }
    4996              :     }
    4997              : 
    4998              :   /* If we have a pair of region_svalues, compare them.  */
    4999       208758 :   if (const region_svalue *lhs_ptr = lhs->dyn_cast_region_svalue ())
    5000        24558 :     if (const region_svalue *rhs_ptr = rhs->dyn_cast_region_svalue ())
    5001              :       {
    5002          922 :         tristate res = region_svalue::eval_condition (lhs_ptr, op, rhs_ptr,
    5003              :                                                       *this);
    5004          922 :         if (res.is_known ())
    5005          632 :           return res;
    5006              :         /* Otherwise, only known through constraints.  */
    5007              :       }
    5008              : 
    5009       208126 :   if (const constant_svalue *cst_lhs = lhs->dyn_cast_constant_svalue ())
    5010              :     {
    5011              :       /* If we have a pair of constants, compare them.  */
    5012        54401 :       if (const constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
    5013        16206 :         return constant_svalue::eval_condition (cst_lhs, op, cst_rhs);
    5014              :       else
    5015              :         {
    5016              :           /* When we have one constant, put it on the RHS.  */
    5017        38195 :           std::swap (lhs, rhs);
    5018        38195 :           op = swap_tree_comparison (op);
    5019              :         }
    5020              :     }
    5021       191920 :   gcc_assert (lhs->get_kind () != SK_CONSTANT);
    5022              : 
    5023              :   /* Handle comparison against zero.  */
    5024       191920 :   if (const constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
    5025       161452 :     if (zerop (cst_rhs->get_constant ()))
    5026              :       {
    5027       102223 :         if (const region_svalue *ptr = lhs->dyn_cast_region_svalue ())
    5028              :           {
    5029              :             /* A region_svalue is a non-NULL pointer, except in certain
    5030              :                special cases (see the comment for region::non_null_p).  */
    5031        23374 :             const region *pointee = ptr->get_pointee ();
    5032        23374 :             if (pointee->non_null_p ())
    5033              :               {
    5034        12758 :                 switch (op)
    5035              :                   {
    5036            0 :                   default:
    5037            0 :                     gcc_unreachable ();
    5038              : 
    5039          322 :                   case EQ_EXPR:
    5040          322 :                   case GE_EXPR:
    5041          322 :                   case LE_EXPR:
    5042          322 :                     return tristate::TS_FALSE;
    5043              : 
    5044        12436 :                   case NE_EXPR:
    5045        12436 :                   case GT_EXPR:
    5046        12436 :                   case LT_EXPR:
    5047        12436 :                     return tristate::TS_TRUE;
    5048              :                   }
    5049              :               }
    5050              :           }
    5051        78849 :         else if (const binop_svalue *binop = lhs->dyn_cast_binop_svalue ())
    5052              :           {
    5053              :             /* Treat offsets from a non-NULL pointer as being non-NULL.  This
    5054              :                isn't strictly true, in that eventually ptr++ will wrap
    5055              :                around and be NULL, but it won't occur in practise and thus
    5056              :                can be used to suppress effectively false positives that we
    5057              :                shouldn't warn for.  */
    5058        21320 :             if (binop->get_op () == POINTER_PLUS_EXPR)
    5059              :               {
    5060        13199 :                 tristate lhs_ts = eval_condition (binop->get_arg0 (), op, rhs);
    5061        13199 :                 if (lhs_ts.is_known ())
    5062        12480 :                   return lhs_ts;
    5063              :               }
    5064              :           }
    5065       115058 :         else if (const unaryop_svalue *unaryop
    5066        57529 :                    = lhs->dyn_cast_unaryop_svalue ())
    5067              :           {
    5068         3409 :             if (unaryop->get_op () == NEGATE_EXPR)
    5069              :               {
    5070              :                 /* e.g. "-X <= 0" is equivalent to X >= 0".  */
    5071           51 :                 tristate lhs_ts = eval_condition (unaryop->get_arg (),
    5072              :                                                   swap_tree_comparison (op),
    5073              :                                                   rhs);
    5074           51 :                 if (lhs_ts.is_known ())
    5075           48 :                   return lhs_ts;
    5076              :               }
    5077              :           }
    5078              :       }
    5079              : 
    5080              :   /* Handle rejection of equality for comparisons of the initial values of
    5081              :      "external" values (such as params) with the address of locals.  */
    5082       166634 :   if (const initial_svalue *init_lhs = lhs->dyn_cast_initial_svalue ())
    5083        40131 :     if (const region_svalue *rhs_ptr = rhs->dyn_cast_region_svalue ())
    5084              :       {
    5085          271 :         tristate res = compare_initial_and_pointer (init_lhs, rhs_ptr);
    5086          271 :         if (res.is_known ())
    5087           72 :           return res;
    5088              :       }
    5089       166562 :   if (const initial_svalue *init_rhs = rhs->dyn_cast_initial_svalue ())
    5090         5254 :     if (const region_svalue *lhs_ptr = lhs->dyn_cast_region_svalue ())
    5091              :       {
    5092          166 :         tristate res = compare_initial_and_pointer (init_rhs, lhs_ptr);
    5093          166 :         if (res.is_known ())
    5094            0 :           return res;
    5095              :       }
    5096              : 
    5097       166562 :   if (const widening_svalue *widen_lhs = lhs->dyn_cast_widening_svalue ())
    5098         5194 :     if (tree rhs_cst = rhs->maybe_get_constant ())
    5099              :       {
    5100         2814 :         tristate res = widen_lhs->eval_condition_without_cm (op, rhs_cst);
    5101         2814 :         if (res.is_known ())
    5102           69 :           return res;
    5103              :       }
    5104              : 
    5105              :   /* Handle comparisons between two svalues with more than one operand.  */
    5106       166493 :   if (const binop_svalue *binop = lhs->dyn_cast_binop_svalue ())
    5107              :     {
    5108        27774 :       switch (op)
    5109              :         {
    5110              :         default:
    5111              :           break;
    5112         3837 :         case EQ_EXPR:
    5113         3837 :           {
    5114              :             /* TODO: binops can be equal even if they are not structurally
    5115              :                      equal in case of commutative operators.  */
    5116         3837 :             tristate res = structural_equality (lhs, rhs);
    5117         3837 :             if (res.is_true ())
    5118           44 :               return res;
    5119              :           }
    5120         3793 :           break;
    5121         1120 :         case LE_EXPR:
    5122         1120 :           {
    5123         1120 :             tristate res = structural_equality (lhs, rhs);
    5124         1120 :             if (res.is_true ())
    5125            0 :               return res;
    5126              :           }
    5127         1120 :           break;
    5128         7238 :         case GE_EXPR:
    5129         7238 :           {
    5130         7238 :             tristate res = structural_equality (lhs, rhs);
    5131         7238 :             if (res.is_true ())
    5132           46 :               return res;
    5133         7192 :             res = symbolic_greater_than (binop, rhs);
    5134         7192 :             if (res.is_true ())
    5135           56 :               return res;
    5136              :           }
    5137              :           break;
    5138         8888 :         case GT_EXPR:
    5139         8888 :           {
    5140         8888 :             tristate res = symbolic_greater_than (binop, rhs);
    5141         8888 :             if (res.is_true ())
    5142          167 :               return res;
    5143              :           }
    5144         8721 :           break;
    5145              :         }
    5146              :     }
    5147              : 
    5148              :   /* Try range_op, but avoid cases where we have been sloppy about types.  */
    5149       166180 :   if (lhs->get_type ()
    5150       114233 :       && rhs->get_type ()
    5151       274718 :       && range_compatible_p (lhs->get_type (), rhs->get_type ()))
    5152              :     {
    5153       101774 :       value_range lhs_vr, rhs_vr;
    5154       101774 :       if (lhs->maybe_get_value_range (lhs_vr))
    5155        46408 :         if (rhs->maybe_get_value_range (rhs_vr))
    5156              :           {
    5157        45834 :             range_op_handler handler (op);
    5158        45834 :             if (handler)
    5159              :               {
    5160        45834 :                 int_range_max out;
    5161        45834 :                 if (handler.fold_range (out, boolean_type_node, lhs_vr, rhs_vr))
    5162              :                   {
    5163        45834 :                     if (out.zero_p ())
    5164          183 :                       return tristate::TS_FALSE;
    5165        45651 :                     if (!out.contains_zero_p ())
    5166          164 :                       return tristate::TS_TRUE;
    5167              :                   }
    5168        45834 :               }
    5169              :           }
    5170       101774 :     }
    5171              : 
    5172              :   /* Attempt to unwrap cast if there is one, and the types match.  */
    5173       165833 :   tree lhs_type = lhs->get_type ();
    5174       165833 :   tree rhs_type = rhs->get_type ();
    5175       165833 :   if (lhs_type && rhs_type)
    5176              :   {
    5177       108191 :     const unaryop_svalue *lhs_un_op = dyn_cast <const unaryop_svalue *> (lhs);
    5178       108191 :     const unaryop_svalue *rhs_un_op = dyn_cast <const unaryop_svalue *> (rhs);
    5179         4478 :     if (lhs_un_op && CONVERT_EXPR_CODE_P (lhs_un_op->get_op ())
    5180         4273 :         && rhs_un_op && CONVERT_EXPR_CODE_P (rhs_un_op->get_op ())
    5181       108524 :         && lhs_type == rhs_type)
    5182              :       {
    5183          333 :         tristate res = eval_condition (lhs_un_op->get_arg (),
    5184              :                                        op,
    5185              :                                        rhs_un_op->get_arg ());
    5186          333 :         if (res.is_known ())
    5187            0 :           return res;
    5188              :       }
    5189         4145 :     else if (lhs_un_op && CONVERT_EXPR_CODE_P (lhs_un_op->get_op ())
    5190       111798 :              && lhs_type == rhs_type)
    5191              :       {
    5192         3212 :         tristate res = eval_condition (lhs_un_op->get_arg (), op, rhs);
    5193         3212 :         if (res.is_known ())
    5194           56 :           return res;
    5195              :       }
    5196         2420 :     else if (rhs_un_op && CONVERT_EXPR_CODE_P (rhs_un_op->get_op ())
    5197       107066 :              && lhs_type == rhs_type)
    5198              :       {
    5199         1557 :         tristate res = eval_condition (lhs, op, rhs_un_op->get_arg ());
    5200         1557 :         if (res.is_known ())
    5201            0 :           return res;
    5202              :       }
    5203              :   }
    5204              : 
    5205              :   /* Otherwise, try constraints.
    5206              :      Cast to const to ensure we don't change the constraint_manager as we
    5207              :      do this (e.g. by creating equivalence classes).  */
    5208       165777 :   const constraint_manager *constraints = m_constraints;
    5209       165777 :   return constraints->eval_condition (lhs, op, rhs);
    5210              : }
    5211              : 
    5212              : /* Subroutine of region_model::eval_condition, for rejecting
    5213              :    equality of INIT_VAL(PARM) with &LOCAL.  */
    5214              : 
    5215              : tristate
    5216          437 : region_model::compare_initial_and_pointer (const initial_svalue *init,
    5217              :                                             const region_svalue *ptr) const
    5218              : {
    5219          437 :   const region *pointee = ptr->get_pointee ();
    5220              : 
    5221              :   /* If we have a pointer to something within a stack frame, it can't be the
    5222              :      initial value of a param.  */
    5223          437 :   if (pointee->maybe_get_frame_region ())
    5224           72 :     if (init->initial_value_of_param_p ())
    5225           72 :       return tristate::TS_FALSE;
    5226              : 
    5227          365 :   return tristate::TS_UNKNOWN;
    5228              : }
    5229              : 
    5230              : /* Return true if SVAL is definitely positive.  */
    5231              : 
    5232              : static bool
    5233        14557 : is_positive_svalue (const svalue *sval)
    5234              : {
    5235        14557 :   if (tree cst = sval->maybe_get_constant ())
    5236        14285 :     return !zerop (cst) && get_range_pos_neg (cst) == 1;
    5237          272 :   tree type = sval->get_type ();
    5238          272 :   if (!type)
    5239              :     return false;
    5240              :   /* Consider a binary operation size_t + int.  The analyzer wraps the int in
    5241              :      an unaryop_svalue, converting it to a size_t, but in the dynamic execution
    5242              :      the result is smaller than the first operand.  Thus, we have to look if
    5243              :      the argument of the unaryop_svalue is also positive.  */
    5244          215 :   if (const unaryop_svalue *un_op = dyn_cast <const unaryop_svalue *> (sval))
    5245           10 :     return CONVERT_EXPR_CODE_P (un_op->get_op ()) && TYPE_UNSIGNED (type)
    5246           18 :            && is_positive_svalue (un_op->get_arg ());
    5247          205 :   return TYPE_UNSIGNED (type);
    5248              : }
    5249              : 
    5250              : /* Return true if A is definitely larger than B.
    5251              : 
    5252              :    Limitation: does not account for integer overflows and does not try to
    5253              :                return false, so it can not be used negated.  */
    5254              : 
    5255              : tristate
    5256        16080 : region_model::symbolic_greater_than (const binop_svalue *bin_a,
    5257              :                                      const svalue *b) const
    5258              : {
    5259        16080 :   if (bin_a->get_op () == PLUS_EXPR || bin_a->get_op () == MULT_EXPR)
    5260              :     {
    5261              :       /* Eliminate the right-hand side of both svalues.  */
    5262        14589 :       if (const binop_svalue *bin_b = dyn_cast <const binop_svalue *> (b))
    5263         2570 :         if (bin_a->get_op () == bin_b->get_op ()
    5264         1438 :             && eval_condition (bin_a->get_arg1 (),
    5265              :                                GT_EXPR,
    5266         1438 :                                bin_b->get_arg1 ()).is_true ()
    5267         4008 :             && eval_condition (bin_a->get_arg0 (),
    5268              :                                GE_EXPR,
    5269           63 :                                bin_b->get_arg0 ()).is_true ())
    5270           40 :           return tristate (tristate::TS_TRUE);
    5271              : 
    5272              :       /* Otherwise, try to remove a positive offset or factor from BIN_A.  */
    5273        14549 :       if (is_positive_svalue (bin_a->get_arg1 ())
    5274        14549 :           && eval_condition (bin_a->get_arg0 (),
    5275        13833 :                              GE_EXPR, b).is_true ())
    5276          183 :           return tristate (tristate::TS_TRUE);
    5277              :     }
    5278        15857 :   return tristate::unknown ();
    5279              : }
    5280              : 
    5281              : /* Return true if A and B are equal structurally.
    5282              : 
    5283              :    Structural equality means that A and B are equal if the svalues A and B have
    5284              :    the same nodes at the same positions in the tree and the leafs are equal.
    5285              :    Equality for conjured_svalues and initial_svalues is determined by comparing
    5286              :    the pointers while constants are compared by value.  That behavior is useful
    5287              :    to check for binaryop_svlaues that evaluate to the same concrete value but
    5288              :    might use one operand with a different type but the same constant value.
    5289              : 
    5290              :    For example,
    5291              :      binop_svalue (mult_expr,
    5292              :        initial_svalue (‘size_t’, decl_region (..., 'some_var')),
    5293              :        constant_svalue (‘size_t’, 4))
    5294              :    and
    5295              :      binop_svalue (mult_expr,
    5296              :        initial_svalue (‘size_t’, decl_region (..., 'some_var'),
    5297              :        constant_svalue (‘sizetype’, 4))
    5298              :    are structurally equal.  A concrete C code example, where this occurs, can
    5299              :    be found in test7 of out-of-bounds-5.c.  */
    5300              : 
    5301              : tristate
    5302        15065 : region_model::structural_equality (const svalue *a, const svalue *b) const
    5303              : {
    5304              :   /* If A and B are referentially equal, they are also structurally equal.  */
    5305        15065 :   if (a == b)
    5306          431 :     return tristate (tristate::TS_TRUE);
    5307              : 
    5308        14634 :   switch (a->get_kind ())
    5309              :     {
    5310         1257 :     default:
    5311         1257 :       return tristate::unknown ();
    5312              :     /* SK_CONJURED and SK_INITIAL are already handled
    5313              :        by the referential equality above.  */
    5314         1055 :     case SK_CONSTANT:
    5315         1055 :       {
    5316         1055 :         tree a_cst = a->maybe_get_constant ();
    5317         1055 :         tree b_cst = b->maybe_get_constant ();
    5318         1055 :         if (a_cst && b_cst)
    5319         1809 :           return tristate (tree_int_cst_equal (a_cst, b_cst));
    5320              :       }
    5321          126 :       return tristate (tristate::TS_FALSE);
    5322            9 :     case SK_UNARYOP:
    5323            9 :       {
    5324            9 :         const unaryop_svalue *un_a = as_a <const unaryop_svalue *> (a);
    5325            9 :         if (const unaryop_svalue *un_b = dyn_cast <const unaryop_svalue *> (b))
    5326            8 :           return tristate (pending_diagnostic::same_tree_p (un_a->get_type (),
    5327              :                                                             un_b->get_type ())
    5328            8 :                            && un_a->get_op () == un_b->get_op ()
    5329              :                            && structural_equality (un_a->get_arg (),
    5330           16 :                                                    un_b->get_arg ()));
    5331              :       }
    5332            1 :       return tristate (tristate::TS_FALSE);
    5333        12313 :     case SK_BINOP:
    5334        12313 :       {
    5335        12313 :         const binop_svalue *bin_a = as_a <const binop_svalue *> (a);
    5336        12313 :         if (const binop_svalue *bin_b = dyn_cast <const binop_svalue *> (b))
    5337         2377 :           return tristate (bin_a->get_op () == bin_b->get_op ()
    5338              :                            && structural_equality (bin_a->get_arg0 (),
    5339         2862 :                                                    bin_b->get_arg0 ())
    5340              :                            && structural_equality (bin_a->get_arg1 (),
    5341         2862 :                                                    bin_b->get_arg1 ()));
    5342              :       }
    5343        10882 :       return tristate (tristate::TS_FALSE);
    5344              :     }
    5345              : }
    5346              : 
    5347              : /* Handle various constraints of the form:
    5348              :      LHS: ((bool)INNER_LHS INNER_OP INNER_RHS))
    5349              :      OP : == or !=
    5350              :      RHS: zero
    5351              :    and (with a cast):
    5352              :      LHS: CAST([long]int, ((bool)INNER_LHS INNER_OP INNER_RHS))
    5353              :      OP : == or !=
    5354              :      RHS: zero
    5355              :    by adding constraints for INNER_LHS INNEROP INNER_RHS.
    5356              : 
    5357              :    Return true if this function can fully handle the constraint; if
    5358              :    so, add the implied constraint(s) and write true to *OUT if they
    5359              :    are consistent with existing constraints, or write false to *OUT
    5360              :    if they contradicts existing constraints.
    5361              : 
    5362              :    Return false for cases that this function doeesn't know how to handle.
    5363              : 
    5364              :    For example, if we're checking a stored conditional, we'll have
    5365              :    something like:
    5366              :      LHS: CAST(long int, (&HEAP_ALLOCATED_REGION(8)!=(int *)0B))
    5367              :      OP : NE_EXPR
    5368              :      RHS: zero
    5369              :    which this function can turn into an add_constraint of:
    5370              :      (&HEAP_ALLOCATED_REGION(8) != (int *)0B)
    5371              : 
    5372              :    Similarly, optimized && and || conditionals lead to e.g.
    5373              :      if (p && q)
    5374              :    becoming gimple like this:
    5375              :      _1 = p_6 == 0B;
    5376              :      _2 = q_8 == 0B
    5377              :      _3 = _1 | _2
    5378              :    On the "_3 is false" branch we can have constraints of the form:
    5379              :      ((&HEAP_ALLOCATED_REGION(8)!=(int *)0B)
    5380              :       | (&HEAP_ALLOCATED_REGION(10)!=(int *)0B))
    5381              :      == 0
    5382              :    which implies that both _1 and _2 are false,
    5383              :    which this function can turn into a pair of add_constraints of
    5384              :      (&HEAP_ALLOCATED_REGION(8)!=(int *)0B)
    5385              :    and:
    5386              :      (&HEAP_ALLOCATED_REGION(10)!=(int *)0B).  */
    5387              : 
    5388              : bool
    5389        58095 : region_model::add_constraints_from_binop (const svalue *outer_lhs,
    5390              :                                           enum tree_code outer_op,
    5391              :                                           const svalue *outer_rhs,
    5392              :                                           bool *out,
    5393              :                                           region_model_context *ctxt)
    5394              : {
    5395        60426 :   while (const svalue *cast = outer_lhs->maybe_undo_cast ())
    5396              :     outer_lhs = cast;
    5397        58095 :   const binop_svalue *binop_sval = outer_lhs->dyn_cast_binop_svalue ();
    5398        58095 :   if (!binop_sval)
    5399              :     return false;
    5400         8583 :   if (!outer_rhs->all_zeroes_p ())
    5401              :     return false;
    5402              : 
    5403         5928 :   const svalue *inner_lhs = binop_sval->get_arg0 ();
    5404         5928 :   enum tree_code inner_op = binop_sval->get_op ();
    5405         5928 :   const svalue *inner_rhs = binop_sval->get_arg1 ();
    5406              : 
    5407         5928 :   if (outer_op != NE_EXPR && outer_op != EQ_EXPR)
    5408              :     return false;
    5409              : 
    5410              :   /* We have either
    5411              :      - "OUTER_LHS != false" (i.e. OUTER is true), or
    5412              :      - "OUTER_LHS == false" (i.e. OUTER is false).  */
    5413         5248 :   bool is_true = outer_op == NE_EXPR;
    5414              : 
    5415         5248 :   switch (inner_op)
    5416              :     {
    5417              :     default:
    5418              :       return false;
    5419              : 
    5420         2890 :     case EQ_EXPR:
    5421         2890 :     case NE_EXPR:
    5422         2890 :     case GE_EXPR:
    5423         2890 :     case GT_EXPR:
    5424         2890 :     case LE_EXPR:
    5425         2890 :     case LT_EXPR:
    5426         2890 :       {
    5427              :         /* ...and "(inner_lhs OP inner_rhs) == 0"
    5428              :            then (inner_lhs OP inner_rhs) must have the same
    5429              :            logical value as LHS.  */
    5430         2890 :         if (!is_true)
    5431         1367 :           inner_op = invert_tree_comparison (inner_op, false /* honor_nans */);
    5432         2890 :         *out = add_constraint (inner_lhs, inner_op, inner_rhs, ctxt);
    5433         2890 :         return true;
    5434              :       }
    5435          913 :       break;
    5436              : 
    5437          913 :     case BIT_AND_EXPR:
    5438          913 :       if (is_true)
    5439              :         {
    5440              :           /* ...and "(inner_lhs & inner_rhs) != 0"
    5441              :              then both inner_lhs and inner_rhs must be true.  */
    5442          457 :           const svalue *false_sval
    5443          457 :             = m_mgr->get_or_create_constant_svalue (boolean_false_node);
    5444          457 :           bool sat1 = add_constraint (inner_lhs, NE_EXPR, false_sval, ctxt);
    5445          457 :           bool sat2 = add_constraint (inner_rhs, NE_EXPR, false_sval, ctxt);
    5446          457 :           *out = sat1 && sat2;
    5447          457 :           return true;
    5448              :         }
    5449              :       return false;
    5450              : 
    5451          644 :     case BIT_IOR_EXPR:
    5452          644 :       if (!is_true)
    5453              :         {
    5454              :           /* ...and "(inner_lhs | inner_rhs) == 0"
    5455              :              i.e. "(inner_lhs | inner_rhs)" is false
    5456              :              then both inner_lhs and inner_rhs must be false.  */
    5457          362 :           const svalue *false_sval
    5458          362 :             = m_mgr->get_or_create_constant_svalue (boolean_false_node);
    5459          362 :           bool sat1 = add_constraint (inner_lhs, EQ_EXPR, false_sval, ctxt);
    5460          362 :           bool sat2 = add_constraint (inner_rhs, EQ_EXPR, false_sval, ctxt);
    5461          362 :           *out = sat1 && sat2;
    5462          362 :           return true;
    5463              :         }
    5464              :       return false;
    5465              :     }
    5466              : }
    5467              : 
    5468              : /* Attempt to add the constraint "LHS OP RHS" to this region_model.
    5469              :    If it is consistent with existing constraints, add it, and return true.
    5470              :    Return false if it contradicts existing constraints.
    5471              :    Use CTXT for reporting any diagnostics associated with the accesses.  */
    5472              : 
    5473              : bool
    5474        78759 : region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
    5475              :                               region_model_context *ctxt)
    5476              : {
    5477              :   /* For now, make no attempt to capture constraints on floating-point
    5478              :      values.  */
    5479        78759 :   if (FLOAT_TYPE_P (TREE_TYPE (lhs)) || FLOAT_TYPE_P (TREE_TYPE (rhs)))
    5480              :     return true;
    5481              : 
    5482        78389 :   const svalue *lhs_sval = get_rvalue (lhs, ctxt);
    5483        78389 :   const svalue *rhs_sval = get_rvalue (rhs, ctxt);
    5484              : 
    5485        78389 :   return add_constraint (lhs_sval, op, rhs_sval, ctxt);
    5486              : }
    5487              : 
    5488              : static bool
    5489        17092 : unusable_in_infinite_loop_constraint_p (const svalue *sval)
    5490              : {
    5491        17092 :   if (sval->get_kind () == SK_WIDENING)
    5492            0 :     return true;
    5493              :   return false;
    5494              : }
    5495              : 
    5496              : /* Attempt to add the constraint "LHS OP RHS" to this region_model.
    5497              :    If it is consistent with existing constraints, add it, and return true.
    5498              :    Return false if it contradicts existing constraints.
    5499              :    Use CTXT for reporting any diagnostics associated with the accesses.  */
    5500              : 
    5501              : bool
    5502        88698 : region_model::add_constraint (const svalue *lhs,
    5503              :                               enum tree_code op,
    5504              :                               const svalue *rhs,
    5505              :                               region_model_context *ctxt)
    5506              : {
    5507        88698 :   const bool checking_for_infinite_loop
    5508        88698 :     = ctxt ? ctxt->checking_for_infinite_loop_p () : false;
    5509              : 
    5510         8673 :   if (checking_for_infinite_loop)
    5511              :     {
    5512        17092 :       if (unusable_in_infinite_loop_constraint_p (lhs)
    5513        88698 :           || unusable_in_infinite_loop_constraint_p (rhs))
    5514              :         {
    5515          257 :           gcc_assert (ctxt);
    5516          257 :           ctxt->on_unusable_in_infinite_loop ();
    5517          257 :           return false;
    5518              :         }
    5519              :     }
    5520              : 
    5521        88441 :   tristate t_cond = eval_condition (lhs, op, rhs);
    5522              : 
    5523              :   /* If we already have the condition, do nothing.  */
    5524        88441 :   if (t_cond.is_true ())
    5525              :     return true;
    5526              : 
    5527              :   /* Reject a constraint that would contradict existing knowledge, as
    5528              :      unsatisfiable.  */
    5529        71475 :   if (t_cond.is_false ())
    5530              :     return false;
    5531              : 
    5532        61675 :   if (checking_for_infinite_loop)
    5533              :     {
    5534              :       /* Here, we don't have a definite true/false value, so bail out
    5535              :          when checking for infinite loops.  */
    5536         3580 :       gcc_assert (ctxt);
    5537         3580 :       ctxt->on_unusable_in_infinite_loop ();
    5538         3580 :       return false;
    5539              :     }
    5540              : 
    5541        58095 :   bool out;
    5542        58095 :   if (add_constraints_from_binop (lhs, op, rhs, &out, ctxt))
    5543         3709 :     return out;
    5544              : 
    5545              :   /* Attempt to store the constraint.  */
    5546        54386 :   if (!m_constraints->add_constraint (lhs, op, rhs))
    5547              :     return false;
    5548              : 
    5549              :   /* Notify the context, if any.  This exists so that the state machines
    5550              :      in a program_state can be notified about the condition, and so can
    5551              :      set sm-state for e.g. unchecked->checked, both for cfg-edges, and
    5552              :      when synthesizing constraints as above.  */
    5553        54282 :   if (ctxt)
    5554        35870 :     ctxt->on_condition (lhs, op, rhs);
    5555              : 
    5556              :   /* If we have &REGION == NULL, then drop dynamic extents for REGION (for
    5557              :      the case where REGION is heap-allocated and thus could be NULL).  */
    5558        54282 :   if (tree rhs_cst = rhs->maybe_get_constant ())
    5559        44904 :     if (op == EQ_EXPR && zerop (rhs_cst))
    5560        13374 :       if (const region_svalue *region_sval = lhs->dyn_cast_region_svalue ())
    5561         1895 :         unset_dynamic_extents (region_sval->get_pointee ());
    5562              : 
    5563              :   return true;
    5564              : }
    5565              : 
    5566              : /* As above, but when returning false, if OUT is non-NULL, write a
    5567              :    new rejected_constraint to *OUT.  */
    5568              : 
    5569              : bool
    5570        77615 : region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
    5571              :                               region_model_context *ctxt,
    5572              :                               std::unique_ptr<rejected_constraint> *out)
    5573              : {
    5574        77615 :   bool sat = add_constraint (lhs, op, rhs, ctxt);
    5575        77615 :   if (!sat && out)
    5576              :     {
    5577         2194 :       const svalue *lhs_sval = get_rvalue (lhs, nullptr);
    5578         2194 :       const svalue *rhs_sval = get_rvalue (rhs, nullptr);
    5579         4388 :       *out = std::make_unique <rejected_op_constraint> (*this,
    5580         2194 :                                                         lhs_sval, op, rhs_sval);
    5581              :     }
    5582        77615 :   return sat;
    5583              : }
    5584              : 
    5585              : /* Determine what is known about the condition "LHS OP RHS" within
    5586              :    this model.
    5587              :    Use CTXT for reporting any diagnostics associated with the accesses.  */
    5588              : 
    5589              : tristate
    5590        37336 : region_model::eval_condition (tree lhs,
    5591              :                               enum tree_code op,
    5592              :                               tree rhs,
    5593              :                               region_model_context *ctxt) const
    5594              : {
    5595              :   /* For now, make no attempt to model constraints on floating-point
    5596              :      values.  */
    5597        37336 :   if (FLOAT_TYPE_P (TREE_TYPE (lhs)) || FLOAT_TYPE_P (TREE_TYPE (rhs)))
    5598           16 :     return tristate::unknown ();
    5599              : 
    5600        37320 :   return eval_condition (get_rvalue (lhs, ctxt), op, get_rvalue (rhs, ctxt));
    5601              : }
    5602              : 
    5603              : /* Implementation of region_model::get_representative_path_var.
    5604              :    Attempt to return a path_var that represents SVAL, or return NULL_TREE.
    5605              :    Use VISITED to prevent infinite mutual recursion with the overload for
    5606              :    regions.  */
    5607              : 
    5608              : path_var
    5609        13227 : region_model::get_representative_path_var_1 (const svalue *sval,
    5610              :                                              svalue_set *visited,
    5611              :                                              logger *logger) const
    5612              : {
    5613        13227 :   gcc_assert (sval);
    5614              : 
    5615              :   /* Prevent infinite recursion.  */
    5616        13227 :   if (visited->contains (sval))
    5617              :     {
    5618           14 :       if (sval->get_kind () == SK_CONSTANT)
    5619           14 :         return path_var (sval->maybe_get_constant (), 0);
    5620              :       else
    5621            0 :         return path_var (NULL_TREE, 0);
    5622              :     }
    5623        13213 :   visited->add (sval);
    5624              : 
    5625              :   /* Handle casts by recursion into get_representative_path_var.  */
    5626        13213 :   if (const svalue *cast_sval = sval->maybe_undo_cast ())
    5627              :     {
    5628          402 :       path_var result = get_representative_path_var (cast_sval, visited,
    5629              :                                                      logger);
    5630          402 :       tree orig_type = sval->get_type ();
    5631              :       /* If necessary, wrap the result in a cast.  */
    5632          402 :       if (result.m_tree && orig_type)
    5633          332 :         result.m_tree = build1 (NOP_EXPR, orig_type, result.m_tree);
    5634          402 :       return result;
    5635              :     }
    5636              : 
    5637        12811 :   auto_vec<path_var> pvs;
    5638        12811 :   m_store.get_representative_path_vars (this, visited, sval, logger, &pvs);
    5639              : 
    5640        12811 :   if (tree cst = sval->maybe_get_constant ())
    5641         1918 :     pvs.safe_push (path_var (cst, 0));
    5642              : 
    5643              :   /* Handle string literals and various other pointers.  */
    5644        12811 :   if (const region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
    5645              :     {
    5646         4470 :       const region *reg = ptr_sval->get_pointee ();
    5647         4470 :       if (path_var pv = get_representative_path_var (reg, visited, logger))
    5648           30 :         return path_var (build1 (ADDR_EXPR,
    5649              :                                  sval->get_type (),
    5650              :                                  pv.m_tree),
    5651           30 :                          pv.m_stack_depth);
    5652              :     }
    5653              : 
    5654              :   /* If we have a sub_svalue, look for ways to represent the parent.  */
    5655        12781 :   if (const sub_svalue *sub_sval = sval->dyn_cast_sub_svalue ())
    5656              :     {
    5657          370 :       const svalue *parent_sval = sub_sval->get_parent ();
    5658          370 :       const region *subreg = sub_sval->get_subregion ();
    5659          740 :       if (path_var parent_pv
    5660          370 :             = get_representative_path_var (parent_sval, visited, logger))
    5661          153 :         if (const field_region *field_reg = subreg->dyn_cast_field_region ())
    5662          111 :           return path_var (build3 (COMPONENT_REF,
    5663              :                                    sval->get_type (),
    5664              :                                    parent_pv.m_tree,
    5665              :                                    field_reg->get_field (),
    5666              :                                    NULL_TREE),
    5667          111 :                            parent_pv.m_stack_depth);
    5668              :     }
    5669              : 
    5670              :   /* Handle binops.  */
    5671        12670 :   if (const binop_svalue *binop_sval = sval->dyn_cast_binop_svalue ())
    5672          534 :     if (path_var lhs_pv
    5673          534 :         = get_representative_path_var (binop_sval->get_arg0 (), visited,
    5674          534 :                                        logger))
    5675          468 :       if (path_var rhs_pv
    5676          468 :           = get_representative_path_var (binop_sval->get_arg1 (), visited,
    5677          468 :                                          logger))
    5678          439 :         return path_var (build2 (binop_sval->get_op (),
    5679              :                                  sval->get_type (),
    5680              :                                  lhs_pv.m_tree, rhs_pv.m_tree),
    5681          439 :                          lhs_pv.m_stack_depth);
    5682              : 
    5683        12231 :   if (pvs.length () < 1)
    5684         2189 :     return path_var (NULL_TREE, 0);
    5685              : 
    5686        10042 :   pvs.qsort (readability_comparator);
    5687        10042 :   return pvs[0];
    5688        12811 : }
    5689              : 
    5690              : /* Attempt to return a path_var that represents SVAL, or return NULL_TREE.
    5691              :    Use VISITED to prevent infinite mutual recursion with the overload for
    5692              :    regions
    5693              : 
    5694              :    This function defers to get_representative_path_var_1 to do the work;
    5695              :    it adds verification that get_representative_path_var_1 returned a tree
    5696              :    of the correct type.  */
    5697              : 
    5698              : path_var
    5699        18655 : region_model::get_representative_path_var (const svalue *sval,
    5700              :                                            svalue_set *visited,
    5701              :                                            logger *logger) const
    5702              : {
    5703        18655 :   if (sval == nullptr)
    5704         5428 :     return path_var (NULL_TREE, 0);
    5705              : 
    5706        13227 :   LOG_SCOPE (logger);
    5707        13227 :   if (logger)
    5708              :     {
    5709            0 :       logger->start_log_line ();
    5710            0 :       logger->log_partial ("sval: ");
    5711            0 :       sval->dump_to_pp (logger->get_printer (), true);
    5712            0 :       logger->end_log_line ();
    5713              :     }
    5714              : 
    5715        13227 :   tree orig_type = sval->get_type ();
    5716              : 
    5717        13227 :   path_var result = get_representative_path_var_1 (sval, visited, logger);
    5718              : 
    5719              :   /* Verify that the result has the same type as SVAL, if any.  */
    5720        13227 :   if (result.m_tree && orig_type)
    5721        10880 :     gcc_assert (TREE_TYPE (result.m_tree) == orig_type);
    5722              : 
    5723        13227 :   if (logger)
    5724              :     {
    5725            0 :       logger->start_log_line ();
    5726            0 :       logger->log_partial ("sval: ");
    5727            0 :       sval->dump_to_pp (logger->get_printer (), true);
    5728            0 :       logger->end_log_line ();
    5729              : 
    5730            0 :       if (result.m_tree)
    5731            0 :         logger->log ("tree: %qE", result.m_tree);
    5732              :       else
    5733            0 :         logger->log ("tree: NULL");
    5734              :     }
    5735              : 
    5736        13227 :   return result;
    5737        13227 : }
    5738              : 
    5739              : /* Attempt to return a tree that represents SVAL, or return NULL_TREE.
    5740              : 
    5741              :    Strip off any top-level cast, to avoid messages like
    5742              :      double-free of '(void *)ptr'
    5743              :    from analyzer diagnostics.  */
    5744              : 
    5745              : tree
    5746        14819 : region_model::get_representative_tree (const svalue *sval, logger *logger) const
    5747              : {
    5748        14819 :   svalue_set visited;
    5749        14819 :   tree expr = get_representative_path_var (sval, &visited, logger).m_tree;
    5750              : 
    5751              :   /* Strip off any top-level cast.  */
    5752        14819 :   if (expr && TREE_CODE (expr) == NOP_EXPR)
    5753          572 :     expr = TREE_OPERAND (expr, 0);
    5754              : 
    5755        14819 :   return fixup_tree_for_diagnostic (expr);
    5756        14819 : }
    5757              : 
    5758              : tree
    5759          838 : region_model::get_representative_tree (const region *reg, logger *logger) const
    5760              : {
    5761          838 :   svalue_set visited;
    5762          838 :   tree expr = get_representative_path_var (reg, &visited, logger).m_tree;
    5763              : 
    5764              :   /* Strip off any top-level cast.  */
    5765          838 :   if (expr && TREE_CODE (expr) == NOP_EXPR)
    5766            1 :     expr = TREE_OPERAND (expr, 0);
    5767              : 
    5768          838 :   return fixup_tree_for_diagnostic (expr);
    5769          838 : }
    5770              : 
    5771              : /* Implementation of region_model::get_representative_path_var.
    5772              : 
    5773              :    Attempt to return a path_var that represents REG, or return
    5774              :    the NULL path_var.
    5775              :    For example, a region for a field of a local would be a path_var
    5776              :    wrapping a COMPONENT_REF.
    5777              :    Use VISITED to prevent infinite mutual recursion with the overload for
    5778              :    svalues.  */
    5779              : 
    5780              : path_var
    5781        16679 : region_model::get_representative_path_var_1 (const region *reg,
    5782              :                                              svalue_set *visited,
    5783              :                                              logger *logger) const
    5784              : {
    5785        16679 :   switch (reg->get_kind ())
    5786              :     {
    5787            0 :     default:
    5788            0 :       gcc_unreachable ();
    5789              : 
    5790            0 :     case RK_FRAME:
    5791            0 :     case RK_GLOBALS:
    5792            0 :     case RK_CODE:
    5793            0 :     case RK_HEAP:
    5794            0 :     case RK_STACK:
    5795            0 :     case RK_THREAD_LOCAL:
    5796            0 :     case RK_ROOT:
    5797              :        /* Regions that represent memory spaces are not expressible as trees.  */
    5798            0 :       return path_var (NULL_TREE, 0);
    5799              : 
    5800            1 :     case RK_FUNCTION:
    5801            1 :       {
    5802            1 :         const function_region *function_reg
    5803            1 :           = as_a <const function_region *> (reg);
    5804            1 :         return path_var (function_reg->get_fndecl (), 0);
    5805              :       }
    5806            1 :     case RK_LABEL:
    5807            1 :       {
    5808            1 :         const label_region *label_reg = as_a <const label_region *> (reg);
    5809            1 :         return path_var (label_reg->get_label (), 0);
    5810              :       }
    5811              : 
    5812          225 :     case RK_SYMBOLIC:
    5813          225 :       {
    5814          225 :         const symbolic_region *symbolic_reg
    5815          225 :           = as_a <const symbolic_region *> (reg);
    5816          225 :         const svalue *pointer = symbolic_reg->get_pointer ();
    5817          225 :         path_var pointer_pv = get_representative_path_var (pointer, visited,
    5818              :                                                            logger);
    5819          225 :         if (!pointer_pv)
    5820           16 :           return path_var (NULL_TREE, 0);
    5821          209 :         tree offset = build_int_cst (pointer->get_type (), 0);
    5822          209 :         return path_var (build2 (MEM_REF,
    5823              :                                  reg->get_type (),
    5824              :                                  pointer_pv.m_tree,
    5825              :                                  offset),
    5826          209 :                          pointer_pv.m_stack_depth);
    5827              :       }
    5828        10195 :     case RK_DECL:
    5829        10195 :       {
    5830        10195 :         const decl_region *decl_reg = as_a <const decl_region *> (reg);
    5831        10195 :         return path_var (decl_reg->get_decl (), decl_reg->get_stack_depth ());
    5832              :       }
    5833         1373 :     case RK_FIELD:
    5834         1373 :       {
    5835         1373 :         const field_region *field_reg = as_a <const field_region *> (reg);
    5836         1373 :         path_var parent_pv
    5837         1373 :           = get_representative_path_var (reg->get_parent_region (), visited,
    5838              :                                          logger);
    5839         1373 :         if (!parent_pv)
    5840           37 :           return path_var (NULL_TREE, 0);
    5841         1336 :         return path_var (build3 (COMPONENT_REF,
    5842              :                                  reg->get_type (),
    5843              :                                  parent_pv.m_tree,
    5844              :                                  field_reg->get_field (),
    5845              :                                  NULL_TREE),
    5846         1336 :                          parent_pv.m_stack_depth);
    5847              :       }
    5848              : 
    5849          150 :     case RK_ELEMENT:
    5850          150 :       {
    5851          150 :         const element_region *element_reg
    5852          150 :           = as_a <const element_region *> (reg);
    5853          150 :         path_var parent_pv
    5854          150 :           = get_representative_path_var (reg->get_parent_region (), visited,
    5855              :                                          logger);
    5856          150 :         if (!parent_pv)
    5857            0 :           return path_var (NULL_TREE, 0);
    5858          150 :         path_var index_pv
    5859          150 :           = get_representative_path_var (element_reg->get_index (), visited,
    5860              :                                          logger);
    5861          150 :         if (!index_pv)
    5862            0 :           return path_var (NULL_TREE, 0);
    5863          150 :         return path_var (build4 (ARRAY_REF,
    5864              :                                  reg->get_type (),
    5865              :                                  parent_pv.m_tree, index_pv.m_tree,
    5866              :                                  NULL_TREE, NULL_TREE),
    5867          150 :                          parent_pv.m_stack_depth);
    5868              :       }
    5869              : 
    5870           42 :     case RK_OFFSET:
    5871           42 :       {
    5872           42 :         const offset_region *offset_reg
    5873           42 :           = as_a <const offset_region *> (reg);
    5874           42 :         path_var parent_pv
    5875           42 :           = get_representative_path_var (reg->get_parent_region (), visited,
    5876              :                                          logger);
    5877           42 :         if (!parent_pv)
    5878            0 :           return path_var (NULL_TREE, 0);
    5879           42 :         path_var offset_pv
    5880           42 :           = get_representative_path_var (offset_reg->get_byte_offset (),
    5881              :                                          visited, logger);
    5882           42 :         if (!offset_pv || TREE_CODE (offset_pv.m_tree) != INTEGER_CST)
    5883           42 :           return path_var (NULL_TREE, 0);
    5884            0 :         tree addr_parent = build1 (ADDR_EXPR,
    5885              :                                    build_pointer_type (reg->get_type ()),
    5886              :                                    parent_pv.m_tree);
    5887            0 :         tree ptype = build_pointer_type_for_mode (char_type_node, ptr_mode,
    5888              :                                                   true);
    5889            0 :         return path_var (build2 (MEM_REF, reg->get_type (), addr_parent,
    5890              :                                  fold_convert (ptype, offset_pv.m_tree)),
    5891            0 :                          parent_pv.m_stack_depth);
    5892              :       }
    5893              : 
    5894           46 :     case RK_SIZED:
    5895           46 :       return path_var (NULL_TREE, 0);
    5896              : 
    5897           17 :     case RK_CAST:
    5898           17 :       {
    5899           17 :         path_var parent_pv
    5900           17 :           = get_representative_path_var (reg->get_parent_region (), visited,
    5901              :                                          logger);
    5902           17 :         if (!parent_pv)
    5903            1 :           return path_var (NULL_TREE, 0);
    5904           16 :         return path_var (build1 (NOP_EXPR,
    5905              :                                  reg->get_type (),
    5906              :                                  parent_pv.m_tree),
    5907           16 :                          parent_pv.m_stack_depth);
    5908              :       }
    5909              : 
    5910         4615 :     case RK_HEAP_ALLOCATED:
    5911         4615 :     case RK_ALLOCA:
    5912              :       /* No good way to express heap-allocated/alloca regions as trees.  */
    5913         4615 :       return path_var (NULL_TREE, 0);
    5914              : 
    5915           10 :     case RK_STRING:
    5916           10 :       {
    5917           10 :         const string_region *string_reg = as_a <const string_region *> (reg);
    5918           10 :         return path_var (string_reg->get_string_cst (), 0);
    5919              :       }
    5920              : 
    5921            4 :     case RK_VAR_ARG:
    5922            4 :     case RK_ERRNO:
    5923            4 :     case RK_UNKNOWN:
    5924            4 :     case RK_PRIVATE:
    5925            4 :       return path_var (NULL_TREE, 0);
    5926              :     }
    5927              : }
    5928              : 
    5929              : /* Attempt to return a path_var that represents REG, or return
    5930              :    the NULL path_var.
    5931              :    For example, a region for a field of a local would be a path_var
    5932              :    wrapping a COMPONENT_REF.
    5933              :    Use VISITED to prevent infinite mutual recursion with the overload for
    5934              :    svalues.
    5935              : 
    5936              :    This function defers to get_representative_path_var_1 to do the work;
    5937              :    it adds verification that get_representative_path_var_1 returned a tree
    5938              :    of the correct type.  */
    5939              : 
    5940              : path_var
    5941        16679 : region_model::get_representative_path_var (const region *reg,
    5942              :                                            svalue_set *visited,
    5943              :                                            logger *logger) const
    5944              : {
    5945        16679 :   LOG_SCOPE (logger);
    5946        16679 :   if (logger)
    5947              :     {
    5948            0 :       logger->start_log_line ();
    5949            0 :       logger->log_partial ("reg: ");
    5950            0 :       reg->dump_to_pp (logger->get_printer (), true);
    5951            0 :       logger->end_log_line ();
    5952              :     }
    5953              : 
    5954        16679 :   path_var result = get_representative_path_var_1 (reg, visited, logger);
    5955              : 
    5956              :   /* Verify that the result has the same type as REG, if any.  */
    5957        16679 :   if (result.m_tree && reg->get_type ())
    5958        11917 :     gcc_assert (TREE_TYPE (result.m_tree) == reg->get_type ());
    5959              : 
    5960        16679 :   if (logger)
    5961              :     {
    5962            0 :       logger->start_log_line ();
    5963            0 :       logger->log_partial ("reg: ");
    5964            0 :       reg->dump_to_pp (logger->get_printer (), true);
    5965            0 :       logger->end_log_line ();
    5966              : 
    5967            0 :       if (result.m_tree)
    5968            0 :         logger->log ("tree: %qE", result.m_tree);
    5969              :       else
    5970            0 :         logger->log ("tree: NULL");
    5971              :     }
    5972              : 
    5973        33358 :   return result;
    5974        16679 : }
    5975              : 
    5976              : /* Push a new frame_region on to the stack region.
    5977              :    Populate the frame_region with child regions for the function call's
    5978              :    parameters, using values from the arguments at the callsite in the
    5979              :    caller's frame.  */
    5980              : 
    5981              : void
    5982        15590 : region_model::update_for_gcall (const gcall &call_stmt,
    5983              :                                 region_model_context *ctxt,
    5984              :                                 function *callee)
    5985              : {
    5986              :   /* Build a vec of argument svalues, using the current top
    5987              :      frame for resolving tree expressions.  */
    5988        15590 :   auto_vec<const svalue *> arg_svals (gimple_call_num_args (&call_stmt));
    5989              : 
    5990        49188 :   for (unsigned i = 0; i < gimple_call_num_args (&call_stmt); i++)
    5991              :     {
    5992        18008 :       tree arg = gimple_call_arg (&call_stmt, i);
    5993        18008 :       arg_svals.quick_push (get_rvalue (arg, ctxt));
    5994              :     }
    5995              : 
    5996        15590 :   if(!callee)
    5997              :   {
    5998              :     /* Get the function * from the gcall.  */
    5999            0 :     tree fn_decl = get_fndecl_for_call (call_stmt, ctxt);
    6000            0 :     callee = DECL_STRUCT_FUNCTION (fn_decl);
    6001              :   }
    6002              : 
    6003            0 :   gcc_assert (callee);
    6004        15590 :   push_frame (*callee, &call_stmt, &arg_svals, ctxt);
    6005        15590 : }
    6006              : 
    6007              : /* Pop the top-most frame_region from the stack, and copy the return
    6008              :    region's values (if any) into the region for the lvalue of the LHS of
    6009              :    the call (if any).  */
    6010              : 
    6011              : void
    6012        11964 : region_model::update_for_return_gcall (const gcall &call_stmt,
    6013              :                                        region_model_context *ctxt)
    6014              : {
    6015              :   /* Get the lvalue for the result of the call, passing it to pop_frame,
    6016              :      so that pop_frame can determine the region with respect to the
    6017              :      *caller* frame.  */
    6018        11964 :   tree lhs = gimple_call_lhs (&call_stmt);
    6019        11964 :   pop_frame (lhs, nullptr, ctxt, &call_stmt);
    6020        11964 : }
    6021              : 
    6022              : /* Attempt to use R to replay SUMMARY into this object.
    6023              :    Return true if it is possible.  */
    6024              : 
    6025              : bool
    6026         1664 : region_model::replay_call_summary (call_summary_replay &r,
    6027              :                                    const region_model &summary)
    6028              : {
    6029         1664 :   gcc_assert (summary.get_stack_depth () == 1);
    6030              : 
    6031         1664 :   m_store.replay_call_summary (r, summary.m_store);
    6032              : 
    6033         1664 :   if (r.get_ctxt ())
    6034         1542 :     r.get_ctxt ()->maybe_did_work ();
    6035              : 
    6036         1664 :   if (!m_constraints->replay_call_summary (r, *summary.m_constraints))
    6037              :     return false;
    6038              : 
    6039         3020 :   for (auto kv : summary.m_dynamic_extents)
    6040              :     {
    6041         1479 :       const region *summary_reg = kv.first;
    6042         1479 :       const region *caller_reg = r.convert_region_from_summary (summary_reg);
    6043         1479 :       if (!caller_reg)
    6044            2 :         continue;
    6045         1477 :       const svalue *summary_sval = kv.second;
    6046         1477 :       const svalue *caller_sval = r.convert_svalue_from_summary (summary_sval);
    6047         1477 :       if (!caller_sval)
    6048            0 :         continue;
    6049         1477 :       m_dynamic_extents.put (caller_reg, caller_sval);
    6050              :     }
    6051              : 
    6052         1541 :   return true;
    6053              : }
    6054              : 
    6055              : /* For use with push_frame when handling a top-level call within the analysis.
    6056              :    PARAM has a defined but unknown initial value.
    6057              :    Anything it points to has escaped, since the calling context "knows"
    6058              :    the pointer, and thus calls to unknown functions could read/write into
    6059              :    the region.
    6060              :    If NONNULL is true, then assume that PARAM must be non-NULL.  */
    6061              : 
    6062              : void
    6063        23454 : region_model::on_top_level_param (tree param,
    6064              :                                   bool nonnull,
    6065              :                                   region_model_context *ctxt)
    6066              : {
    6067        23454 :   if (POINTER_TYPE_P (TREE_TYPE (param)))
    6068              :     {
    6069        11437 :       const region *param_reg = get_lvalue (param, ctxt);
    6070        11437 :       const svalue *init_ptr_sval
    6071        11437 :         = m_mgr->get_or_create_initial_value (param_reg);
    6072        11437 :       const region *pointee_reg = m_mgr->get_symbolic_region (init_ptr_sval);
    6073        11437 :       store_manager *store_mgr = m_mgr->get_store_manager ();
    6074        11437 :       m_store.mark_as_escaped (*store_mgr, pointee_reg);
    6075        11437 :       if (nonnull)
    6076              :         {
    6077         1085 :           const svalue *null_ptr_sval
    6078         1085 :             = m_mgr->get_or_create_null_ptr (TREE_TYPE (param));
    6079         1085 :           add_constraint (init_ptr_sval, NE_EXPR, null_ptr_sval, ctxt);
    6080              :         }
    6081              :     }
    6082        23454 : }
    6083              : 
    6084              : /* Update this region_model to reflect pushing a frame onto the stack
    6085              :    for a call to FUN.
    6086              : 
    6087              :    If CALL_STMT is non-NULL, this is for the interprocedural case where
    6088              :    we already have an execution path into the caller.  It can be NULL for
    6089              :    top-level entrypoints into the analysis, or in selftests.
    6090              : 
    6091              :    If ARG_SVALS is non-NULL, use it to populate the parameters
    6092              :    in the new frame.
    6093              :    Otherwise, the params have their initial_svalues.
    6094              : 
    6095              :    Return the frame_region for the new frame.  */
    6096              : 
    6097              : const region *
    6098        41197 : region_model::push_frame (const function &fun,
    6099              :                           const gcall *call_stmt,
    6100              :                           const vec<const svalue *> *arg_svals,
    6101              :                           region_model_context *ctxt)
    6102              : {
    6103        41197 :   tree fndecl = fun.decl;
    6104        41197 :   if (arg_svals)
    6105              :     {
    6106              :       /* If the result of the callee is DECL_BY_REFERENCE, then
    6107              :          we'll need to store a reference to the caller's lhs of
    6108              :          CALL_STMT within callee's result.
    6109              :          If so, determine the region of CALL_STMT's lhs within
    6110              :          the caller's frame before updating m_current_frame.  */
    6111        15590 :       const region *caller_return_by_reference_reg = nullptr;
    6112        15590 :       if (tree result = DECL_RESULT (fndecl))
    6113        15590 :         if (DECL_BY_REFERENCE (result))
    6114              :           {
    6115           55 :             gcc_assert (call_stmt);
    6116           55 :             tree lhs = gimple_call_lhs (call_stmt);
    6117           55 :             gcc_assert (lhs);
    6118           55 :             caller_return_by_reference_reg = get_lvalue (lhs, ctxt);
    6119              :           }
    6120              : 
    6121              :       /* Update m_current_frame.  */
    6122        15590 :       m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
    6123              : 
    6124              :       /* Arguments supplied from a caller frame.  */
    6125        15590 :       unsigned idx = 0;
    6126        33122 :       for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
    6127        17532 :            iter_parm = DECL_CHAIN (iter_parm), ++idx)
    6128              :         {
    6129              :           /* If there's a mismatching declaration, the call stmt might
    6130              :              not have enough args.  Handle this case by leaving the
    6131              :              rest of the params as uninitialized.  */
    6132        17536 :           if (idx >= arg_svals->length ())
    6133              :             break;
    6134        17532 :           tree parm_lval = iter_parm;
    6135        17532 :           if (tree parm_default_ssa = get_ssa_default_def (fun, iter_parm))
    6136        16183 :             parm_lval = parm_default_ssa;
    6137        17532 :           const region *parm_reg = get_lvalue (parm_lval, ctxt);
    6138        17532 :           const svalue *arg_sval = (*arg_svals)[idx];
    6139        17532 :           set_value (parm_reg, arg_sval, ctxt);
    6140              :         }
    6141              : 
    6142              :       /* Handle any variadic args.  */
    6143        16066 :       unsigned va_arg_idx = 0;
    6144        16066 :       for (; idx < arg_svals->length (); idx++, va_arg_idx++)
    6145              :         {
    6146          476 :           const svalue *arg_sval = (*arg_svals)[idx];
    6147          476 :           const region *var_arg_reg
    6148          476 :             = m_mgr->get_var_arg_region (m_current_frame,
    6149              :                                          va_arg_idx);
    6150          476 :           set_value (var_arg_reg, arg_sval, ctxt);
    6151              :         }
    6152              : 
    6153              :       /* If the result of the callee is DECL_BY_REFERENCE, then above
    6154              :          we should have determined the region within the
    6155              :          caller's frame that the callee will be writing back to.
    6156              :          Use this now to initialize the reference in callee's frame.  */
    6157        15590 :       if (tree result = DECL_RESULT (fndecl))
    6158        15590 :         if (DECL_BY_REFERENCE (result))
    6159              :           {
    6160              :             /* Get reference to the caller lhs.  */
    6161           55 :             gcc_assert (caller_return_by_reference_reg);
    6162           55 :             const svalue *ref_sval
    6163           55 :               = m_mgr->get_ptr_svalue (TREE_TYPE (result),
    6164              :                                        caller_return_by_reference_reg);
    6165              : 
    6166              :             /* Get region for default val of DECL_RESULT within the
    6167              :                callee.  */
    6168           55 :             if (tree result_default_ssa = get_ssa_default_def (fun, result))
    6169              :               {
    6170           52 :                 const region *callee_result_reg
    6171           52 :                   = get_lvalue (result_default_ssa, ctxt);
    6172              : 
    6173              :                 /* Set the callee's reference to refer to the caller's lhs.  */
    6174           52 :                 set_value (callee_result_reg, ref_sval, ctxt);
    6175              :               }
    6176              :           }
    6177              :     }
    6178              :   else
    6179              :     {
    6180              :       /* Otherwise we have a top-level call within the analysis.  The params
    6181              :          have defined but unknown initial values.
    6182              :          Anything they point to has escaped.  */
    6183              : 
    6184              :       /* Update m_current_frame.  */
    6185        25607 :       m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
    6186              : 
    6187              :       /* Handle "__attribute__((nonnull))".   */
    6188        25607 :       tree fntype = TREE_TYPE (fndecl);
    6189        25607 :       bitmap nonnull_args = get_nonnull_args (fntype);
    6190              : 
    6191        25607 :       unsigned parm_idx = 0;
    6192        49061 :       for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
    6193        23454 :            iter_parm = DECL_CHAIN (iter_parm))
    6194              :         {
    6195        23454 :           bool non_null = (nonnull_args
    6196        23454 :                            ? (bitmap_empty_p (nonnull_args)
    6197         1454 :                               || bitmap_bit_p (nonnull_args, parm_idx))
    6198        23454 :                            : false);
    6199        23454 :           if (tree parm_default_ssa = get_ssa_default_def (fun, iter_parm))
    6200        20097 :             on_top_level_param (parm_default_ssa, non_null, ctxt);
    6201              :           else
    6202         3357 :             on_top_level_param (iter_parm, non_null, ctxt);
    6203        23454 :           parm_idx++;
    6204              :         }
    6205              : 
    6206        25607 :       BITMAP_FREE (nonnull_args);
    6207              :     }
    6208              : 
    6209        41197 :   return m_current_frame;
    6210              : }
    6211              : 
    6212              : /* Get the function of the top-most frame in this region_model's stack.
    6213              :    There must be such a frame.  */
    6214              : 
    6215              : const function *
    6216         1123 : region_model::get_current_function () const
    6217              : {
    6218         1123 :   const frame_region *frame = get_current_frame ();
    6219         1123 :   gcc_assert (frame);
    6220         1123 :   return &frame->get_function ();
    6221              : }
    6222              : 
    6223              : /* Custom region_model_context for the assignment to the result
    6224              :    at a call statement when popping a frame (PR analyzer/106203).  */
    6225              : 
    6226              : class caller_context : public region_model_context_decorator
    6227              : {
    6228              : public:
    6229         5723 :   caller_context (region_model_context *inner,
    6230              :                   const gcall *call_stmt,
    6231              :                   const frame_region &caller_frame)
    6232              :     : region_model_context_decorator (inner),
    6233         5723 :       m_call_stmt (call_stmt),
    6234         5723 :       m_caller_frame (caller_frame)
    6235              :   {}
    6236              : 
    6237              :   pending_location
    6238            9 :   get_pending_location_for_diag () const override
    6239              :   {
    6240            9 :     pending_location ploc
    6241            9 :       = region_model_context_decorator::get_pending_location_for_diag ();
    6242              : 
    6243            9 :     ploc.m_event_loc_info
    6244            9 :       = event_loc_info (m_call_stmt->location,
    6245            9 :                         m_caller_frame.get_fndecl (),
    6246            9 :                         m_caller_frame.get_stack_depth ());
    6247              : 
    6248            9 :     return ploc;
    6249              :   }
    6250              : 
    6251        11455 :   const gimple *get_stmt () const override
    6252              :   {
    6253        11455 :     return m_call_stmt;
    6254              :   };
    6255              : 
    6256              : private:
    6257              :   const gcall *m_call_stmt;
    6258              :   const frame_region &m_caller_frame;
    6259              : };
    6260              : 
    6261              : 
    6262              : /* Pop the topmost frame_region from this region_model's stack;
    6263              : 
    6264              :    If RESULT_LVALUE is non-null, copy any return value from the frame
    6265              :    into the corresponding region (evaluated with respect to the *caller*
    6266              :    frame, rather than the called frame).
    6267              :    If OUT_RESULT is non-null, copy any return value from the frame
    6268              :    into *OUT_RESULT.
    6269              : 
    6270              :    If non-null, use CALL_STMT as the location when complaining about
    6271              :    assignment of the return value to RESULT_LVALUE.
    6272              : 
    6273              :    If EVAL_RETURN_SVALUE is false, then don't evaluate the return value.
    6274              :    This is for use when unwinding frames e.g. due to longjmp, to suppress
    6275              :    erroneously reporting uninitialized return values.
    6276              : 
    6277              :    Purge the frame region and all its descendent regions.
    6278              :    Convert any pointers that point into such regions into
    6279              :    poison_kind::popped_stack svalues.  */
    6280              : 
    6281              : void
    6282        31098 : region_model::pop_frame (tree result_lvalue,
    6283              :                          const svalue **out_result,
    6284              :                          region_model_context *ctxt,
    6285              :                          const gcall *call_stmt,
    6286              :                          bool eval_return_svalue)
    6287              : {
    6288        31098 :   gcc_assert (m_current_frame);
    6289              : 
    6290        31098 :   const region_model pre_popped_model = *this;
    6291        31098 :   const frame_region *frame_reg = m_current_frame;
    6292              : 
    6293              :   /* Notify state machines.  */
    6294        31098 :   if (ctxt)
    6295        27806 :     ctxt->on_pop_frame (frame_reg);
    6296              : 
    6297              :   /* Evaluate the result, within the callee frame.  */
    6298        31098 :   tree fndecl = m_current_frame->get_function ().decl;
    6299        31098 :   tree result = DECL_RESULT (fndecl);
    6300        31098 :   const svalue *retval = nullptr;
    6301        31098 :   if (result
    6302        31090 :       && TREE_TYPE (result) != void_type_node
    6303        45085 :       && eval_return_svalue)
    6304              :     {
    6305        11619 :       retval = get_rvalue (result, ctxt);
    6306        11619 :       if (out_result)
    6307         5425 :         *out_result = retval;
    6308              :     }
    6309              : 
    6310              :   /* Pop the frame.  */
    6311        31098 :   m_current_frame = m_current_frame->get_calling_frame ();
    6312              : 
    6313        31098 :   if (result_lvalue
    6314        31098 :       && retval
    6315              :       /* Don't write back for DECL_BY_REFERENCE; the writes
    6316              :          should have happened within the callee already.  */
    6317        31098 :       && !DECL_BY_REFERENCE (result))
    6318              :     {
    6319         5723 :       gcc_assert (eval_return_svalue);
    6320              : 
    6321              :       /* Compute result_dst_reg using RESULT_LVALUE *after* popping
    6322              :          the frame, but before poisoning pointers into the old frame.  */
    6323         5723 :       const region *result_dst_reg = get_lvalue (result_lvalue, ctxt);
    6324              : 
    6325              :       /* Assign retval to result_dst_reg, using caller_context
    6326              :          to set the call_stmt and the popped_frame for any diagnostics
    6327              :          due to the assignment.  */
    6328         5723 :       gcc_assert (m_current_frame);
    6329         5723 :       caller_context caller_ctxt (ctxt, call_stmt, *m_current_frame);
    6330        11446 :       set_value (result_dst_reg, retval, call_stmt ? &caller_ctxt : ctxt);
    6331              :     }
    6332              : 
    6333        31098 :   unbind_region_and_descendents (frame_reg,poison_kind::popped_stack);
    6334              : 
    6335        31098 :   if (auto chan = g->get_channels ().analyzer_events_channel.get_if_active ())
    6336              :     {
    6337          237 :       gcc::topics::analyzer_events::on_frame_popped msg
    6338          237 :         {this, &pre_popped_model, retval, ctxt};
    6339          237 :       chan->publish (msg);
    6340              :     }
    6341        31098 : }
    6342              : 
    6343              : /* Get the number of frames in this region_model's stack.  */
    6344              : 
    6345              : int
    6346      5875758 : region_model::get_stack_depth () const
    6347              : {
    6348      5875758 :   const frame_region *frame = get_current_frame ();
    6349      5875758 :   if (frame)
    6350      5857784 :     return frame->get_stack_depth ();
    6351              :   else
    6352              :     return 0;
    6353              : }
    6354              : 
    6355              : /* Get the frame_region with the given index within the stack.
    6356              :    The frame_region must exist.  */
    6357              : 
    6358              : const frame_region *
    6359      1811582 : region_model::get_frame_at_index (int index) const
    6360              : {
    6361      1811582 :   const frame_region *frame = get_current_frame ();
    6362      1811582 :   gcc_assert (frame);
    6363      1811582 :   gcc_assert (index >= 0);
    6364      1811582 :   gcc_assert (index <= frame->get_index ());
    6365      2122576 :   while (index != frame->get_index ())
    6366              :     {
    6367       310994 :       frame = frame->get_calling_frame ();
    6368       310994 :       gcc_assert (frame);
    6369              :     }
    6370      1811582 :   return frame;
    6371              : }
    6372              : 
    6373              : /* Unbind svalues for any regions in REG and below.
    6374              :    Find any pointers to such regions; convert them to
    6375              :    poisoned values of kind PKIND.
    6376              :    Also purge any dynamic extents.  */
    6377              : 
    6378              : void
    6379        42052 : region_model::unbind_region_and_descendents (const region *reg,
    6380              :                                              enum poison_kind pkind)
    6381              : {
    6382              :   /* Gather a set of base regions to be unbound.  */
    6383        42052 :   hash_set<const region *> base_regs;
    6384       244980 :   for (store::cluster_map_t::iterator iter = m_store.begin ();
    6385       244980 :        iter != m_store.end (); ++iter)
    6386              :     {
    6387       202928 :       const region *iter_base_reg = (*iter).first;
    6388       202928 :       if (iter_base_reg->descendent_of_p (reg))
    6389        41195 :         base_regs.add (iter_base_reg);
    6390              :     }
    6391        83247 :   for (hash_set<const region *>::iterator iter = base_regs.begin ();
    6392        83247 :        iter != base_regs.end (); ++iter)
    6393        41195 :     m_store.purge_cluster (*iter);
    6394              : 
    6395              :   /* Find any pointers to REG or its descendents; convert to poisoned.  */
    6396        42052 :   poison_any_pointers_to_descendents (reg, pkind);
    6397              : 
    6398              :   /* Purge dynamic extents of any base regions in REG and below
    6399              :      (e.g. VLAs and alloca stack regions).  */
    6400       103963 :   for (auto iter : m_dynamic_extents)
    6401              :     {
    6402        19859 :       const region *iter_reg = iter.first;
    6403        19859 :       if (iter_reg->descendent_of_p (reg))
    6404         6310 :         unset_dynamic_extents (iter_reg);
    6405              :     }
    6406        42052 : }
    6407              : 
    6408              : /* Find any pointers to REG or its descendents; convert them to
    6409              :    poisoned values of kind PKIND.  */
    6410              : 
    6411              : void
    6412        42052 : region_model::poison_any_pointers_to_descendents (const region *reg,
    6413              :                                                   enum poison_kind pkind)
    6414              : {
    6415       203785 :   for (const auto &cluster_iter : m_store)
    6416              :     {
    6417       161733 :       binding_cluster *cluster = cluster_iter.second;
    6418       161733 :       for (auto iter = cluster->begin ();
    6419       324301 :            iter != cluster->end ();
    6420       162568 :            ++iter)
    6421              :         {
    6422       162568 :           auto bp = *iter;
    6423       162568 :           const svalue *sval = bp.m_sval;
    6424       162568 :           if (const region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
    6425              :             {
    6426        42218 :               const region *ptr_dst = ptr_sval->get_pointee ();
    6427              :               /* Poison ptrs to descendents of REG, but not to REG itself,
    6428              :                  otherwise double-free detection doesn't work (since sm-state
    6429              :                  for "free" is stored on the original ptr svalue).  */
    6430        42218 :               if (ptr_dst->descendent_of_p (reg)
    6431        42218 :                   && ptr_dst != reg)
    6432              :                 {
    6433          286 :                   const svalue *new_sval
    6434          286 :                     = m_mgr->get_or_create_poisoned_svalue (pkind,
    6435              :                                                             sval->get_type ());
    6436          286 :                   cluster->get_map ().overwrite (iter, new_sval);
    6437              :                 }
    6438              :             }
    6439              :         }
    6440              :     }
    6441        42052 : }
    6442              : 
    6443              : /* Attempt to merge THIS with OTHER_MODEL, writing the result
    6444              :    to OUT_MODEL.  Use POINT to distinguish values created as a
    6445              :    result of merging.  */
    6446              : 
    6447              : bool
    6448       149580 : region_model::can_merge_with_p (const region_model &other_model,
    6449              :                                 const program_point &point,
    6450              :                                 region_model *out_model,
    6451              :                                 const extrinsic_state *ext_state,
    6452              :                                 const program_state *state_a,
    6453              :                                 const program_state *state_b) const
    6454              : {
    6455       149580 :   gcc_assert (out_model);
    6456       149580 :   gcc_assert (m_mgr == other_model.m_mgr);
    6457       149580 :   gcc_assert (m_mgr == out_model->m_mgr);
    6458              : 
    6459       149580 :   if (m_current_frame != other_model.m_current_frame)
    6460              :     return false;
    6461       149580 :   out_model->m_current_frame = m_current_frame;
    6462              : 
    6463       149580 :   model_merger m (this, &other_model, point, out_model,
    6464       149580 :                   ext_state, state_a, state_b);
    6465              : 
    6466       149580 :   if (!store::can_merge_p (&m_store, &other_model.m_store,
    6467       149580 :                            &out_model->m_store, m_mgr->get_store_manager (),
    6468              :                            &m))
    6469              :     return false;
    6470              : 
    6471        42550 :   if (!m_dynamic_extents.can_merge_with_p (other_model.m_dynamic_extents,
    6472              :                                            &out_model->m_dynamic_extents))
    6473              :     return false;
    6474              : 
    6475              :   /* Merge constraints.  */
    6476        40682 :   constraint_manager::merge (*m_constraints,
    6477        40682 :                               *other_model.m_constraints,
    6478              :                               out_model->m_constraints);
    6479              : 
    6480        41410 :   for (auto iter : m.m_svals_changing_meaning)
    6481          728 :     out_model->m_constraints->purge_state_involving (iter);
    6482              : 
    6483        40682 :   if (m_thrown_exceptions_stack != other_model.m_thrown_exceptions_stack)
    6484              :     return false;
    6485        40653 :   out_model->m_thrown_exceptions_stack = m_thrown_exceptions_stack;
    6486              : 
    6487        40653 :   if (m_caught_exceptions_stack != other_model.m_caught_exceptions_stack)
    6488              :     return false;
    6489        40653 :   out_model->m_caught_exceptions_stack = m_caught_exceptions_stack;
    6490              : 
    6491        40653 :   return true;
    6492       149580 : }
    6493              : 
    6494              : /* Recover the vtable OBJ's vptr (for OBJ_TYPE) actually points to, plus the
    6495              :    byte offset into it, so callers can recover the most-derived type from the
    6496              :    vtable's DECL_CONTEXT and BINFO.
    6497              : 
    6498              :    Only recognizes the shape we model for a vptr store, "vptr_field =
    6499              :    &vtable_decl + offset", i.e. a POINTER_PLUS_EXPR binop_svalue of a
    6500              :    region_svalue for the _ZTV* decl and a constant offset.  The offset is
    6501              :    nonzero when this vptr slot belongs to a non-primary base's own sub-vtable
    6502              :    group within the same decl; we return it via OUT for callers that need to
    6503              :    index into the vtable (e.g. gimple_get_virt_method_for_vtable).  */
    6504              : 
    6505              : tree
    6506         1962 : region_model::get_vtable_from_obj (tree obj, tree obj_type,
    6507              :                                    region_model_manager *mgr,
    6508              :                                    region_model_context *ctxt,
    6509              :                                    unsigned HOST_WIDE_INT *out) const
    6510              : {
    6511         1962 :   if (!obj_type)
    6512              :     return NULL_TREE;
    6513         1962 :   tree vfield = TYPE_VFIELD (obj_type);
    6514         1962 :   if (!vfield)
    6515              :     return NULL_TREE;
    6516              : 
    6517         1962 :   const svalue *obj_sval = get_rvalue (obj, ctxt);
    6518         1962 :   const region *obj_reg = deref_rvalue (obj_sval, obj, ctxt);
    6519         1962 :   const region *vptr_reg = mgr->get_field_region (obj_reg, vfield);
    6520              : 
    6521         1962 :   const svalue *vptr_sval = get_store_value (vptr_reg, ctxt);
    6522         1962 :   while (const svalue *cast = vptr_sval->maybe_undo_cast ())
    6523              :     vptr_sval = cast;
    6524              : 
    6525         1962 :   const binop_svalue *b = vptr_sval->dyn_cast_binop_svalue ();
    6526         1962 :   if (!b || b->get_op () != POINTER_PLUS_EXPR)
    6527              :     return NULL_TREE;
    6528              : 
    6529          261 :   const svalue *offset_sval = b->get_arg1 ();
    6530          261 :   tree offset_const = offset_sval->maybe_get_constant ();
    6531          261 :   if (!offset_const || TREE_CODE (offset_const) != INTEGER_CST)
    6532              :     return NULL_TREE;
    6533          261 :   if (out)
    6534          261 :     *out = tree_to_uhwi (offset_const);
    6535              : 
    6536          261 :   vptr_sval = b->get_arg0 ();
    6537          261 :   const region_svalue *vptr = vptr_sval->dyn_cast_region_svalue ();
    6538              :   /* Give up if we have a conjured vptr.  */
    6539          261 :   if (!vptr)
    6540              :     return NULL_TREE;
    6541              : 
    6542          261 :   tree vtable = vptr->get_pointee ()->maybe_get_decl ();
    6543          261 :   return vtable;
    6544              : }
    6545              : 
    6546              : /* Attempt to get the fndecl for a virtual call via OBJ_TYPE_REF, or
    6547              :    NULL_TREE if it can't be resolved.
    6548              : 
    6549              :    A virtual call's callee is a GIMPLE OBJ_TYPE_REF:
    6550              :      OBJ_TYPE_REF(EXPR; (TYPE)OBJECT->TOKEN)
    6551              :    EXPR is the function pointer actually loaded and called; OBJECT, TYPE and
    6552              :    TOKEN are devirtualization metadata, not needed to perform the call itself.
    6553              :    OBJECT is the "this" pointer, TYPE its static type, TOKEN the vtable slot
    6554              :    index.  We ignore EXPR and instead resolve TOKEN against OBJECT's modeled
    6555              :    dynamic type rather than its static TYPE.
    6556              : 
    6557              :    Reads the value bound to the object's vptr field (OBJ_TYPE_REF_OBJECT's
    6558              :    vfield).
    6559              :    If that value has the form "&vtable_decl + constant" (a region_svalue for a
    6560              :    _ZTV* decl plus a byte offset), recover the vtable decl and offset and use
    6561              :    gimple_get_virt_method_for_vtable, together with OBJ_TYPE_REF_TOKEN, to look
    6562              :    up the concrete fndecl in the vtable's initializer.
    6563              : 
    6564              :    Relies on the store having bound the vptr field to the _ZTV* instance, so no
    6565              :    separate modeling of the object's dynamic type is needed.  */
    6566              : 
    6567              : tree
    6568         1863 : region_model::get_fndecl_for_virtual_call (const_tree obj_type_ref,
    6569              :                                            region_model_context *ctxt)
    6570              : {
    6571         1863 :   tree obj = OBJ_TYPE_REF_OBJECT (obj_type_ref);
    6572         1863 :   tree obj_type = obj_type_ref_class (obj_type_ref);
    6573              : 
    6574         1863 :   unsigned HOST_WIDE_INT offset;
    6575         1863 :   tree vtable = get_vtable_from_obj (obj, obj_type, m_mgr, ctxt, &offset);
    6576         1863 :   if (!vtable)
    6577              :     return NULL_TREE;
    6578              : 
    6579          165 :   unsigned HOST_WIDE_INT token
    6580          165 :     = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (obj_type_ref));
    6581          165 :   bool can_refer;
    6582          165 :   tree vptr_fn
    6583          165 :     = gimple_get_virt_method_for_vtable (token, vtable, offset, &can_refer);
    6584          165 :   if (!vptr_fn || !can_refer)
    6585              :     return NULL_TREE;
    6586              : 
    6587          165 :   if (cgraph_node *node = cgraph_node::get_create (vptr_fn))
    6588          165 :     if (const cgraph_node *ultimate = node->ultimate_alias_target ())
    6589          165 :       return ultimate->decl;
    6590              : 
    6591              :   return NULL_TREE;
    6592              : }
    6593              : 
    6594              : /* Attempt to get the fndecl used at CALL, if known, or NULL_TREE
    6595              :    otherwise.  */
    6596              : 
    6597              : tree
    6598       981212 : region_model::get_fndecl_for_call (const gcall &call,
    6599              :                                    region_model_context *ctxt)
    6600              : {
    6601       981212 :   tree fn_ptr = gimple_call_fn (&call);
    6602       981212 :   if (fn_ptr == NULL_TREE)
    6603              :     return NULL_TREE;
    6604              : 
    6605              :   /* Handle OBJ_TYPE_REF so that we can try to find the definition for a virtual
    6606              :      call and treat it like any other call.  */
    6607       937824 :   if (TREE_CODE (fn_ptr) == OBJ_TYPE_REF)
    6608         1863 :     return get_fndecl_for_virtual_call (fn_ptr, ctxt);
    6609              : 
    6610       935961 :   const svalue *fn_ptr_sval = get_rvalue (fn_ptr, ctxt);
    6611      1871922 :   if (const region_svalue *fn_ptr_ptr
    6612       935961 :         = fn_ptr_sval->dyn_cast_region_svalue ())
    6613              :     {
    6614       931369 :       const region *reg = fn_ptr_ptr->get_pointee ();
    6615       931369 :       if (const function_region *fn_reg = reg->dyn_cast_function_region ())
    6616              :         {
    6617       931313 :           tree fn_decl = fn_reg->get_fndecl ();
    6618       931313 :           cgraph_node *node = cgraph_node::get (fn_decl);
    6619       931313 :           if (!node)
    6620              :             return NULL_TREE;
    6621       931313 :           const cgraph_node *ultimate_node = node->ultimate_alias_target ();
    6622       931313 :           if (ultimate_node)
    6623       931313 :             return ultimate_node->decl;
    6624              :         }
    6625              :     }
    6626              : 
    6627              :   return NULL_TREE;
    6628              : }
    6629              : 
    6630              : /* Would be much simpler to use a lambda here, if it were supported.  */
    6631              : 
    6632              : struct append_regions_cb_data
    6633              : {
    6634              :   const region_model *model;
    6635              :   auto_vec<const decl_region *> *out;
    6636              : };
    6637              : 
    6638              : /* Populate *OUT with all decl_regions in the current
    6639              :    frame that have clusters within the store.  */
    6640              : 
    6641              : void
    6642       432126 : region_model::
    6643              : get_regions_for_current_frame (auto_vec<const decl_region *> *out) const
    6644              : {
    6645       432126 :   append_regions_cb_data data;
    6646       432126 :   data.model = this;
    6647       432126 :   data.out = out;
    6648       432126 :   m_store.for_each_cluster (append_regions_cb, &data);
    6649       432126 : }
    6650              : 
    6651              : /* Implementation detail of get_regions_for_current_frame.  */
    6652              : 
    6653              : void
    6654      3269034 : region_model::append_regions_cb (const region *base_reg,
    6655              :                                  append_regions_cb_data *cb_data)
    6656              : {
    6657      3269034 :   if (base_reg->get_parent_region () != cb_data->model->m_current_frame)
    6658              :     return;
    6659      1819005 :   if (const decl_region *decl_reg = base_reg->dyn_cast_decl_region ())
    6660      1800671 :     cb_data->out->safe_push (decl_reg);
    6661              : }
    6662              : 
    6663              : 
    6664              : /* Abstract class for diagnostics related to the use of
    6665              :    floating-point arithmetic where precision is needed.  */
    6666              : 
    6667           25 : class imprecise_floating_point_arithmetic : public pending_diagnostic
    6668              : {
    6669              : public:
    6670           50 :   int get_controlling_option () const final override
    6671              :   {
    6672           50 :     return OPT_Wanalyzer_imprecise_fp_arithmetic;
    6673              :   }
    6674              : };
    6675              : 
    6676              : /* Concrete diagnostic to complain about uses of floating-point arithmetic
    6677              :    in the size argument of malloc etc.  */
    6678              : 
    6679              : class float_as_size_arg : public imprecise_floating_point_arithmetic
    6680              : {
    6681              : public:
    6682           25 :   float_as_size_arg (tree arg) : m_arg (arg)
    6683              :   {}
    6684              : 
    6685          305 :   const char *get_kind () const final override
    6686              :   {
    6687          305 :     return "float_as_size_arg_diagnostic";
    6688              :   }
    6689              : 
    6690           25 :   bool subclass_equal_p (const pending_diagnostic &other) const final override
    6691              :   {
    6692           25 :     return same_tree_p (m_arg, ((const float_as_size_arg &) other).m_arg);
    6693              :   }
    6694              : 
    6695           25 :   bool emit (diagnostic_emission_context &ctxt) final override
    6696              :   {
    6697           25 :     bool warned = ctxt.warn ("use of floating-point arithmetic here might"
    6698              :                              " yield unexpected results");
    6699           25 :     if (warned)
    6700           25 :       inform (ctxt.get_location (),
    6701              :               "only use operands of an integer type"
    6702              :               " inside the size argument");
    6703           25 :     return warned;
    6704              :   }
    6705              : 
    6706              :   bool
    6707           50 :   describe_final_event (pretty_printer &pp,
    6708              :                         const evdesc::final_event &) final override
    6709              :   {
    6710           50 :     if (m_arg)
    6711           50 :       pp_printf (&pp,
    6712              :                  "operand %qE is of type %qT",
    6713           50 :                  m_arg, TREE_TYPE (m_arg));
    6714              :     else
    6715            0 :       pp_printf (&pp,
    6716              :                  "at least one operand of the size argument is"
    6717              :                  " of a floating-point type");
    6718           50 :     return true;
    6719              :   }
    6720              : 
    6721              : private:
    6722              :   tree m_arg;
    6723              : };
    6724              : 
    6725              : /* Visitor to find uses of floating-point variables/constants in an svalue.  */
    6726              : 
    6727              : class contains_floating_point_visitor : public visitor
    6728              : {
    6729              : public:
    6730         7952 :   contains_floating_point_visitor (const svalue *root_sval) : m_result (nullptr)
    6731              :   {
    6732         7952 :     root_sval->accept (this);
    6733              :   }
    6734              : 
    6735         7952 :   const svalue *get_svalue_to_report ()
    6736              :   {
    6737         7952 :     return m_result;
    6738              :   }
    6739              : 
    6740         7696 :   void visit_constant_svalue (const constant_svalue *sval) final override
    6741              :   {
    6742              :     /* At the point the analyzer runs, constant integer operands in a floating
    6743              :        point expression are already implicitly converted to floating-points.
    6744              :        Thus, we do prefer to report non-constants such that the diagnostic
    6745              :        always reports a floating-point operand.  */
    6746         7696 :     tree type = sval->get_type ();
    6747         7696 :     if (type && FLOAT_TYPE_P (type) && !m_result)
    6748            9 :       m_result = sval;
    6749         7696 :   }
    6750              : 
    6751          506 :   void visit_conjured_svalue (const conjured_svalue *sval) final override
    6752              :   {
    6753          506 :     tree type = sval->get_type ();
    6754          506 :     if (type && FLOAT_TYPE_P (type))
    6755            0 :       m_result = sval;
    6756          506 :   }
    6757              : 
    6758          993 :   void visit_initial_svalue (const initial_svalue *sval) final override
    6759              :   {
    6760          993 :     tree type = sval->get_type ();
    6761          993 :     if (type && FLOAT_TYPE_P (type))
    6762           16 :       m_result = sval;
    6763          993 :   }
    6764              : 
    6765              : private:
    6766              :   /* Non-null if at least one floating-point operand was found.  */
    6767              :   const svalue *m_result;
    6768              : };
    6769              : 
    6770              : /* May complain about uses of floating-point operands in SIZE_IN_BYTES.  */
    6771              : 
    6772              : void
    6773         7952 : region_model::check_dynamic_size_for_floats (const svalue *size_in_bytes,
    6774              :                                              region_model_context *ctxt) const
    6775              : {
    6776         7952 :   gcc_assert (ctxt);
    6777              : 
    6778         7952 :   contains_floating_point_visitor v (size_in_bytes);
    6779         7952 :   if (const svalue *float_sval = v.get_svalue_to_report ())
    6780              :         {
    6781           25 :           tree diag_arg = get_representative_tree (float_sval);
    6782           25 :           ctxt->warn (std::make_unique<float_as_size_arg> (diag_arg));
    6783              :         }
    6784         7952 : }
    6785              : 
    6786              : /* Return a region describing a heap-allocated block of memory.
    6787              :    Use CTXT to complain about tainted sizes.
    6788              : 
    6789              :    Reuse an existing heap_allocated_region if it's not being referenced by
    6790              :    this region_model; otherwise create a new one.
    6791              : 
    6792              :    Optionally (update_state_machine) transitions the pointer pointing to the
    6793              :    heap_allocated_region from start to assumed non-null.  */
    6794              : 
    6795              : const region *
    6796        19196 : region_model::get_or_create_region_for_heap_alloc (const svalue *size_in_bytes,
    6797              :        region_model_context *ctxt,
    6798              :        bool update_state_machine,
    6799              :        const call_details *cd)
    6800              : {
    6801              :   /* Determine which regions are referenced in this region_model, so that
    6802              :      we can reuse an existing heap_allocated_region if it's not in use on
    6803              :      this path.  */
    6804        19196 :   auto_bitmap base_regs_in_use;
    6805        19196 :   get_referenced_base_regions (base_regs_in_use);
    6806              : 
    6807              :   /* Don't reuse regions that are marked as TOUCHED.  */
    6808       115385 :   for (store::cluster_map_t::iterator iter = m_store.begin ();
    6809       115385 :        iter != m_store.end (); ++iter)
    6810        96189 :     if ((*iter).second->touched_p ())
    6811              :       {
    6812         9896 :         const region *base_reg = (*iter).first;
    6813         9896 :         bitmap_set_bit (base_regs_in_use, base_reg->get_id ());
    6814              :       }
    6815              : 
    6816        19196 :   const region *reg
    6817        19196 :     = m_mgr->get_or_create_region_for_heap_alloc (base_regs_in_use);
    6818        19196 :   if (size_in_bytes)
    6819        13520 :     if (compat_types_p (size_in_bytes->get_type (), size_type_node))
    6820        13520 :       set_dynamic_extents (reg, size_in_bytes, ctxt);
    6821              : 
    6822        19196 :         if (update_state_machine && cd)
    6823              :                 {
    6824            0 :                   const svalue *ptr_sval
    6825            0 :                     = m_mgr->get_ptr_svalue (cd->get_lhs_type (), reg);
    6826            0 :                   transition_ptr_sval_non_null (ctxt, ptr_sval);
    6827              :                 }
    6828              : 
    6829        19196 :   return reg;
    6830        19196 : }
    6831              : 
    6832              : /* Populate OUT_IDS with the set of IDs of those base regions which are
    6833              :    reachable in this region_model.  */
    6834              : 
    6835              : void
    6836        21133 : region_model::get_referenced_base_regions (auto_bitmap &out_ids) const
    6837              : {
    6838        21133 :   reachable_regions reachable_regs (const_cast<region_model *> (this));
    6839        21133 :   m_store.for_each_cluster (reachable_regions::init_cluster_cb,
    6840              :                             &reachable_regs);
    6841              :   /* Get regions for locals that have explicitly bound values.  */
    6842       148530 :   for (store::cluster_map_t::iterator iter = m_store.begin ();
    6843       148530 :        iter != m_store.end (); ++iter)
    6844              :     {
    6845       127397 :       const region *base_reg = (*iter).first;
    6846       127397 :       if (const region *parent = base_reg->get_parent_region ())
    6847       127397 :         if (parent->get_kind () == RK_FRAME)
    6848        81314 :           reachable_regs.add (base_reg, false);
    6849              :     }
    6850              : 
    6851        21137 :   for (auto &eh_node : m_thrown_exceptions_stack)
    6852            4 :     eh_node.add_to_reachable_regions (reachable_regs);
    6853        21193 :   for (auto &eh_node : m_caught_exceptions_stack)
    6854           60 :     eh_node.add_to_reachable_regions (reachable_regs);
    6855              : 
    6856              : 
    6857        21133 :   bitmap_clear (out_ids);
    6858       152672 :   for (auto iter_reg : reachable_regs)
    6859       131539 :     bitmap_set_bit (out_ids, iter_reg->get_id ());
    6860        21133 : }
    6861              : 
    6862              : /* Return a new region describing a block of memory allocated within the
    6863              :    current frame.
    6864              :    Use CTXT to complain about tainted sizes.  */
    6865              : 
    6866              : const region *
    6867          529 : region_model::create_region_for_alloca (const svalue *size_in_bytes,
    6868              :                                         region_model_context *ctxt)
    6869              : {
    6870          529 :   const region *reg = m_mgr->create_region_for_alloca (m_current_frame);
    6871          529 :   if (compat_types_p (size_in_bytes->get_type (), size_type_node))
    6872          528 :     set_dynamic_extents (reg, size_in_bytes, ctxt);
    6873          529 :   return reg;
    6874              : }
    6875              : 
    6876              : /* Record that the size of REG is SIZE_IN_BYTES.
    6877              :    Use CTXT to complain about tainted sizes.  */
    6878              : 
    6879              : void
    6880        14554 : region_model::set_dynamic_extents (const region *reg,
    6881              :                                    const svalue *size_in_bytes,
    6882              :                                    region_model_context *ctxt)
    6883              : {
    6884        14554 :   assert_compat_types (size_in_bytes->get_type (), size_type_node);
    6885        14554 :   if (ctxt)
    6886              :     {
    6887         7952 :       check_dynamic_size_for_taint (reg->get_memory_space (), size_in_bytes,
    6888              :                                     ctxt);
    6889         7952 :       check_dynamic_size_for_floats (size_in_bytes, ctxt);
    6890              :     }
    6891        14554 :   m_dynamic_extents.put (reg, size_in_bytes);
    6892        14554 : }
    6893              : 
    6894              : /* Get the recording of REG in bytes, or nullptr if no dynamic size was
    6895              :    recorded.  */
    6896              : 
    6897              : const svalue *
    6898        71348 : region_model::get_dynamic_extents (const region *reg) const
    6899              : {
    6900        71348 :   if (const svalue * const *slot = m_dynamic_extents.get (reg))
    6901        13814 :     return *slot;
    6902              :   return nullptr;
    6903              : }
    6904              : 
    6905              : /* Unset any recorded dynamic size of REG.  */
    6906              : 
    6907              : void
    6908        52054 : region_model::unset_dynamic_extents (const region *reg)
    6909              : {
    6910        52054 :   m_dynamic_extents.remove (reg);
    6911        52054 : }
    6912              : 
    6913              : /* A subclass of pending_diagnostic for complaining about uninitialized data
    6914              :    being copied across a trust boundary to an untrusted output
    6915              :    (e.g. copy_to_user infoleaks in the Linux kernel).  */
    6916              : 
    6917              : class exposure_through_uninit_copy
    6918              :   : public pending_diagnostic_subclass<exposure_through_uninit_copy>
    6919              : {
    6920              : public:
    6921           25 :   exposure_through_uninit_copy (const region *src_region,
    6922              :                                 const region *dest_region,
    6923              :                                 const svalue *copied_sval)
    6924           25 :   : m_src_region (src_region),
    6925           25 :     m_dest_region (dest_region),
    6926           25 :     m_copied_sval (copied_sval)
    6927              :   {
    6928           25 :     gcc_assert (m_copied_sval->get_kind () == SK_POISONED
    6929              :                 || m_copied_sval->get_kind () == SK_COMPOUND);
    6930           25 :   }
    6931              : 
    6932          294 :   const char *get_kind () const final override
    6933              :   {
    6934          294 :     return "exposure_through_uninit_copy";
    6935              :   }
    6936              : 
    6937           25 :   bool operator== (const exposure_through_uninit_copy &other) const
    6938              :   {
    6939           25 :     return (m_src_region == other.m_src_region
    6940           25 :             && m_dest_region == other.m_dest_region
    6941           50 :             && m_copied_sval == other.m_copied_sval);
    6942              :   }
    6943              : 
    6944           50 :   int get_controlling_option () const final override
    6945              :   {
    6946           50 :     return OPT_Wanalyzer_exposure_through_uninit_copy;
    6947              :   }
    6948              : 
    6949           25 :   bool emit (diagnostic_emission_context &ctxt) final override
    6950              :   {
    6951              :     /* CWE-200: Exposure of Sensitive Information to an Unauthorized Actor.  */
    6952           25 :     ctxt.add_cwe (200);
    6953           50 :     enum memory_space mem_space = get_src_memory_space ();
    6954           25 :     bool warned;
    6955           25 :     switch (mem_space)
    6956              :       {
    6957            0 :       default:
    6958            0 :         warned = ctxt.warn ("potential exposure of sensitive information"
    6959              :                             " by copying uninitialized data"
    6960              :                             " across trust boundary");
    6961            0 :         break;
    6962           25 :       case MEMSPACE_STACK:
    6963           25 :         warned = ctxt.warn ("potential exposure of sensitive information"
    6964              :                             " by copying uninitialized data from stack"
    6965              :                             " across trust boundary");
    6966           25 :         break;
    6967            0 :       case MEMSPACE_HEAP:
    6968            0 :         warned = ctxt.warn ("potential exposure of sensitive information"
    6969              :                             " by copying uninitialized data from heap"
    6970              :                             " across trust boundary");
    6971            0 :         break;
    6972              :       }
    6973           25 :     if (warned)
    6974              :       {
    6975           25 :         const location_t loc = ctxt.get_location ();
    6976           25 :         inform_number_of_uninit_bits (loc);
    6977           25 :         complain_about_uninit_ranges (loc);
    6978              : 
    6979           25 :         if (mem_space == MEMSPACE_STACK)
    6980           25 :           maybe_emit_fixit_hint ();
    6981              :       }
    6982           25 :     return warned;
    6983              :   }
    6984              : 
    6985              :   bool
    6986           50 :   describe_final_event (pretty_printer &pp,
    6987              :                         const evdesc::final_event &) final override
    6988              :   {
    6989          100 :     enum memory_space mem_space = get_src_memory_space ();
    6990           50 :     switch (mem_space)
    6991              :       {
    6992            0 :       default:
    6993            0 :         pp_string (&pp, "uninitialized data copied here");
    6994            0 :         return true;
    6995              : 
    6996           50 :       case MEMSPACE_STACK:
    6997           50 :         pp_string (&pp, "uninitialized data copied from stack here");
    6998           50 :         return true;
    6999              : 
    7000            0 :       case MEMSPACE_HEAP:
    7001            0 :         pp_string (&pp, "uninitialized data copied from heap here");
    7002            0 :         return true;
    7003              :       }
    7004              :   }
    7005              : 
    7006           50 :   void mark_interesting_stuff (interesting_t *interest) final override
    7007              :   {
    7008           50 :     if (m_src_region)
    7009           50 :       interest->add_region_creation (m_src_region);
    7010           50 :   }
    7011              : 
    7012              :   void
    7013            0 :   maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
    7014              :     const final override
    7015              :   {
    7016            0 :     auto &props = result_obj.get_or_create_properties ();
    7017              : #define PROPERTY_PREFIX "gcc/-Wanalyzer-exposure-through-uninit-copy/"
    7018            0 :     props.set (PROPERTY_PREFIX "src_region", m_src_region->to_json ());
    7019            0 :     props.set (PROPERTY_PREFIX "dest_region", m_dest_region->to_json ());
    7020            0 :     props.set (PROPERTY_PREFIX "copied_sval", m_copied_sval->to_json ());
    7021              : #undef PROPERTY_PREFIX
    7022            0 :   }
    7023              : 
    7024              : private:
    7025           75 :   enum memory_space get_src_memory_space () const
    7026              :   {
    7027           75 :     return m_src_region ? m_src_region->get_memory_space () : MEMSPACE_UNKNOWN;
    7028              :   }
    7029              : 
    7030           25 :   bit_size_t calc_num_uninit_bits () const
    7031              :   {
    7032           25 :     switch (m_copied_sval->get_kind ())
    7033              :       {
    7034            0 :       default:
    7035            0 :         gcc_unreachable ();
    7036            4 :         break;
    7037            4 :       case SK_POISONED:
    7038            4 :         {
    7039            4 :           const poisoned_svalue *poisoned_sval
    7040            4 :             = as_a <const poisoned_svalue *> (m_copied_sval);
    7041            4 :           gcc_assert (poisoned_sval->get_poison_kind () == poison_kind::uninit);
    7042              : 
    7043              :           /* Give up if don't have type information.  */
    7044            4 :           if (m_copied_sval->get_type () == NULL_TREE)
    7045            0 :             return 0;
    7046              : 
    7047            4 :           bit_size_t size_in_bits;
    7048            4 :           if (int_size_in_bits (m_copied_sval->get_type (), &size_in_bits))
    7049            4 :             return size_in_bits;
    7050              : 
    7051              :           /* Give up if we can't get the size of the type.  */
    7052            0 :           return 0;
    7053              :         }
    7054           21 :         break;
    7055           21 :       case SK_COMPOUND:
    7056           21 :         {
    7057           21 :           const compound_svalue *compound_sval
    7058           21 :             = as_a <const compound_svalue *> (m_copied_sval);
    7059           21 :           bit_size_t result = 0;
    7060              :           /* Find keys for uninit svals.  */
    7061           82 :           for (auto iter : compound_sval->get_concrete_bindings ())
    7062              :             {
    7063           61 :               const svalue *sval = iter.second;
    7064          122 :               if (const poisoned_svalue *psval
    7065           61 :                   = sval->dyn_cast_poisoned_svalue ())
    7066           24 :                 if (psval->get_poison_kind () == poison_kind::uninit)
    7067              :                   {
    7068           24 :                     const bit_range &bits = iter.first;
    7069           24 :                     result += bits.m_size_in_bits;
    7070              :                   }
    7071              :             }
    7072           21 :           return result;
    7073              :         }
    7074              :       }
    7075              :   }
    7076              : 
    7077           25 :   void inform_number_of_uninit_bits (location_t loc) const
    7078              :   {
    7079           25 :     bit_size_t num_uninit_bits = calc_num_uninit_bits ();
    7080           25 :     if (num_uninit_bits <= 0)
    7081            0 :       return;
    7082           25 :     if (num_uninit_bits % BITS_PER_UNIT == 0)
    7083              :       {
    7084              :         /* Express in bytes.  */
    7085           25 :         byte_size_t num_uninit_bytes = num_uninit_bits / BITS_PER_UNIT;
    7086           25 :         if (num_uninit_bytes == 1)
    7087            3 :           inform (loc, "1 byte is uninitialized");
    7088              :         else
    7089           22 :           inform (loc,
    7090              :                   "%wu bytes are uninitialized", num_uninit_bytes.to_uhwi ());
    7091              :       }
    7092              :     else
    7093              :       {
    7094              :         /* Express in bits.  */
    7095            0 :         if (num_uninit_bits == 1)
    7096            0 :           inform (loc, "1 bit is uninitialized");
    7097              :         else
    7098            0 :           inform (loc,
    7099              :                   "%wu bits are uninitialized", num_uninit_bits.to_uhwi ());
    7100              :       }
    7101              :   }
    7102              : 
    7103           25 :   void complain_about_uninit_ranges (location_t loc) const
    7104              :   {
    7105           50 :     if (const compound_svalue *compound_sval
    7106           25 :         = m_copied_sval->dyn_cast_compound_svalue ())
    7107              :       {
    7108              :         /* Find keys for uninit svals.  */
    7109           21 :         auto_vec<bit_range> uninit_bit_ranges;
    7110           82 :         for (auto iter : compound_sval->get_concrete_bindings ())
    7111              :           {
    7112           61 :             const svalue *sval = iter.second;
    7113          122 :             if (const poisoned_svalue *psval
    7114           61 :                 = sval->dyn_cast_poisoned_svalue ())
    7115           24 :               if (psval->get_poison_kind () == poison_kind::uninit)
    7116           24 :                 uninit_bit_ranges.safe_push (iter.first);
    7117              :           }
    7118              : 
    7119           21 :         std::unique_ptr<record_layout> layout;
    7120              : 
    7121           21 :         tree type = m_copied_sval->get_type ();
    7122           21 :         if (type && TREE_CODE (type) == RECORD_TYPE)
    7123              :           {
    7124           17 :             layout = std::make_unique<record_layout> (type);
    7125              : 
    7126           17 :             if (0)
    7127              :               layout->dump ();
    7128              :           }
    7129              : 
    7130           21 :         unsigned i;
    7131           21 :         bit_range *bits;
    7132           45 :         FOR_EACH_VEC_ELT (uninit_bit_ranges, i, bits)
    7133              :           {
    7134           24 :             bit_offset_t start_bit = bits->get_start_bit_offset ();
    7135           24 :             bit_offset_t next_bit = bits->get_next_bit_offset ();
    7136           24 :             complain_about_uninit_range (loc, start_bit, next_bit,
    7137           24 :                                          layout.get ());
    7138              :           }
    7139           21 :       }
    7140           25 :   }
    7141              : 
    7142           24 :   void complain_about_uninit_range (location_t loc,
    7143              :                                     bit_offset_t start_bit,
    7144              :                                     bit_offset_t next_bit,
    7145              :                                     const record_layout *layout) const
    7146              :   {
    7147           24 :     if (layout)
    7148              :       {
    7149           75 :         while (start_bit < next_bit)
    7150              :           {
    7151          165 :             if (const record_layout::item *item
    7152           55 :                   = layout->get_item_at (start_bit))
    7153              :               {
    7154           55 :                 gcc_assert (start_bit >= item->get_start_bit_offset ());
    7155           55 :                 gcc_assert (start_bit < item->get_next_bit_offset ());
    7156           55 :                 if (item->get_start_bit_offset () == start_bit
    7157          108 :                     && item->get_next_bit_offset () <= next_bit)
    7158           53 :                   complain_about_fully_uninit_item (*item);
    7159              :                 else
    7160            2 :                   complain_about_partially_uninit_item (*item);
    7161           55 :                 start_bit = item->get_next_bit_offset ();
    7162           55 :                 continue;
    7163              :               }
    7164              :             else
    7165              :               break;
    7166              :           }
    7167              :       }
    7168              : 
    7169           24 :     if (start_bit >= next_bit)
    7170              :       return;
    7171              : 
    7172            4 :     if (start_bit % 8 == 0 && next_bit % 8 == 0)
    7173              :       {
    7174              :         /* Express in bytes.  */
    7175            4 :         byte_offset_t start_byte = start_bit / 8;
    7176            4 :         byte_offset_t last_byte = (next_bit / 8) - 1;
    7177            4 :         if (last_byte == start_byte)
    7178            0 :           inform (loc,
    7179              :                   "byte %wu is uninitialized",
    7180              :                   start_byte.to_uhwi ());
    7181              :         else
    7182            4 :           inform (loc,
    7183              :                   "bytes %wu - %wu are uninitialized",
    7184              :                   start_byte.to_uhwi (),
    7185              :                   last_byte.to_uhwi ());
    7186              :       }
    7187              :     else
    7188              :       {
    7189              :         /* Express in bits.  */
    7190            0 :         bit_offset_t last_bit = next_bit - 1;
    7191            0 :         if (last_bit == start_bit)
    7192            0 :           inform (loc,
    7193              :                   "bit %wu is uninitialized",
    7194              :                   start_bit.to_uhwi ());
    7195              :         else
    7196            0 :           inform (loc,
    7197              :                   "bits %wu - %wu are uninitialized",
    7198              :                   start_bit.to_uhwi (),
    7199              :                   last_bit.to_uhwi ());
    7200              :       }
    7201              :   }
    7202              : 
    7203              :   static void
    7204           53 :   complain_about_fully_uninit_item (const record_layout::item &item)
    7205              :   {
    7206           53 :     const_tree field = item.m_field;
    7207           53 :     bit_size_t num_bits = item.m_bit_range.m_size_in_bits;
    7208           53 :     if (item.m_is_padding)
    7209              :       {
    7210           11 :         if (num_bits % 8 == 0)
    7211              :           {
    7212              :             /* Express in bytes.  */
    7213            9 :             byte_size_t num_bytes = num_bits / BITS_PER_UNIT;
    7214            9 :             if (num_bytes == 1)
    7215            2 :               inform (DECL_SOURCE_LOCATION (field),
    7216              :                       "padding after field %qD is uninitialized (1 byte)",
    7217              :                       field);
    7218              :             else
    7219            7 :               inform (DECL_SOURCE_LOCATION (field),
    7220              :                       "padding after field %qD is uninitialized (%wu bytes)",
    7221              :                       field, num_bytes.to_uhwi ());
    7222              :           }
    7223              :         else
    7224              :           {
    7225              :             /* Express in bits.  */
    7226            2 :             if (num_bits == 1)
    7227            0 :               inform (DECL_SOURCE_LOCATION (field),
    7228              :                       "padding after field %qD is uninitialized (1 bit)",
    7229              :                       field);
    7230              :             else
    7231            2 :               inform (DECL_SOURCE_LOCATION (field),
    7232              :                       "padding after field %qD is uninitialized (%wu bits)",
    7233              :                       field, num_bits.to_uhwi ());
    7234              :           }
    7235              :       }
    7236              :     else
    7237              :       {
    7238           42 :         if (num_bits % 8 == 0)
    7239              :           {
    7240              :             /* Express in bytes.  */
    7241           32 :             byte_size_t num_bytes = num_bits / BITS_PER_UNIT;
    7242           32 :             if (num_bytes == 1)
    7243            1 :               inform (DECL_SOURCE_LOCATION (field),
    7244              :                       "field %qD is uninitialized (1 byte)", field);
    7245              :             else
    7246           31 :               inform (DECL_SOURCE_LOCATION (field),
    7247              :                       "field %qD is uninitialized (%wu bytes)",
    7248              :                       field, num_bytes.to_uhwi ());
    7249              :           }
    7250              :         else
    7251              :           {
    7252              :             /* Express in bits.  */
    7253           10 :             if (num_bits == 1)
    7254            9 :               inform (DECL_SOURCE_LOCATION (field),
    7255              :                       "field %qD is uninitialized (1 bit)", field);
    7256              :             else
    7257            1 :               inform (DECL_SOURCE_LOCATION (field),
    7258              :                       "field %qD is uninitialized (%wu bits)",
    7259              :                       field, num_bits.to_uhwi ());
    7260              :           }
    7261              :       }
    7262           53 :   }
    7263              : 
    7264              :   static void
    7265            2 :   complain_about_partially_uninit_item (const record_layout::item &item)
    7266              :   {
    7267            2 :     const_tree field = item.m_field;
    7268            2 :     if (item.m_is_padding)
    7269            0 :       inform (DECL_SOURCE_LOCATION (field),
    7270              :               "padding after field %qD is partially uninitialized",
    7271              :               field);
    7272              :     else
    7273            2 :       inform (DECL_SOURCE_LOCATION (field),
    7274              :               "field %qD is partially uninitialized",
    7275              :               field);
    7276              :     /* TODO: ideally we'd describe what parts are uninitialized.  */
    7277            2 :   }
    7278              : 
    7279           25 :   void maybe_emit_fixit_hint () const
    7280              :   {
    7281           25 :     if (tree decl = m_src_region->maybe_get_decl ())
    7282              :       {
    7283           25 :         gcc_rich_location hint_richloc (DECL_SOURCE_LOCATION (decl));
    7284           25 :         hint_richloc.add_fixit_insert_after (" = {0}");
    7285           25 :         inform (&hint_richloc,
    7286              :                 "suggest forcing zero-initialization by"
    7287              :                 " providing a %<{0}%> initializer");
    7288           25 :       }
    7289           25 :   }
    7290              : 
    7291              : private:
    7292              :   const region *m_src_region;
    7293              :   const region *m_dest_region;
    7294              :   const svalue *m_copied_sval;
    7295              : };
    7296              : 
    7297              : /* Return true if any part of SVAL is uninitialized.  */
    7298              : 
    7299              : static bool
    7300           80 : contains_uninit_p (const svalue *sval)
    7301              : {
    7302           80 :   switch (sval->get_kind ())
    7303              :     {
    7304              :     default:
    7305              :       return false;
    7306            4 :     case SK_POISONED:
    7307            4 :       {
    7308            4 :         const poisoned_svalue *psval
    7309            4 :           = as_a <const poisoned_svalue *> (sval);
    7310            4 :         return psval->get_poison_kind () == poison_kind::uninit;
    7311              :       }
    7312           43 :     case SK_COMPOUND:
    7313           43 :       {
    7314           43 :         const compound_svalue *compound_sval
    7315           43 :           = as_a <const compound_svalue *> (sval);
    7316              : 
    7317          141 :         for (auto iter = compound_sval->begin ();
    7318          141 :              iter != compound_sval->end (); ++iter)
    7319              :           {
    7320          119 :             const svalue *inner_sval = iter->second;
    7321          238 :             if (const poisoned_svalue *psval
    7322          119 :                 = inner_sval->dyn_cast_poisoned_svalue ())
    7323           21 :               if (psval->get_poison_kind () == poison_kind::uninit)
    7324           80 :                 return true;
    7325              :           }
    7326              : 
    7327              :         return false;
    7328              :       }
    7329              :     }
    7330              : }
    7331              : 
    7332              : /* Function for use by plugins when simulating writing data through a
    7333              :    pointer to an "untrusted" region DST_REG (and thus crossing a security
    7334              :    boundary), such as copying data to user space in an OS kernel.
    7335              : 
    7336              :    Check that COPIED_SVAL is fully initialized.  If not, complain about
    7337              :    an infoleak to CTXT.
    7338              : 
    7339              :    SRC_REG can be nullptr; if non-NULL it is used as a hint in the diagnostic
    7340              :    as to where COPIED_SVAL came from.  */
    7341              : 
    7342              : void
    7343           80 : region_model::maybe_complain_about_infoleak (const region *dst_reg,
    7344              :                                              const svalue *copied_sval,
    7345              :                                              const region *src_reg,
    7346              :                                              region_model_context *ctxt)
    7347              : {
    7348              :   /* Check for exposure.  */
    7349           80 :   if (contains_uninit_p (copied_sval))
    7350           25 :     ctxt->warn
    7351           25 :       (std::make_unique<exposure_through_uninit_copy> (src_reg,
    7352              :                                                        dst_reg,
    7353              :                                                        copied_sval));
    7354           80 : }
    7355              : 
    7356              : /* Set errno to a positive symbolic int, as if some error has occurred.  */
    7357              : 
    7358              : void
    7359          537 : region_model::set_errno (const call_details &cd)
    7360              : {
    7361          537 :   const region *errno_reg = m_mgr->get_errno_region ();
    7362          537 :   conjured_purge p (this, cd.get_ctxt ());
    7363          537 :   const svalue *new_errno_sval
    7364          537 :     = m_mgr->get_or_create_conjured_svalue (integer_type_node,
    7365          537 :                                             &cd.get_call_stmt (),
    7366              :                                             errno_reg, p);
    7367          537 :   const svalue *zero
    7368          537 :     = m_mgr->get_or_create_int_cst (integer_type_node, 0);
    7369          537 :   add_constraint (new_errno_sval, GT_EXPR, zero, cd.get_ctxt ());
    7370          537 :   set_value (errno_reg, new_errno_sval, cd.get_ctxt ());
    7371          537 : }
    7372              : 
    7373              : // class region_model_context
    7374              : 
    7375              : bool
    7376         4155 : region_model_context::
    7377              : warn (std::unique_ptr<pending_diagnostic> d,
    7378              :       std::unique_ptr<pending_location::fixer_for_epath> ploc_fixer)
    7379              : {
    7380         4155 :   pending_location ploc (get_pending_location_for_diag ());
    7381         4155 :   ploc.m_fixer_for_epath = std::move (ploc_fixer);
    7382         4155 :   return warn_at (std::move (d), std::move (ploc));
    7383         4155 : }
    7384              : 
    7385              : /* class noop_region_model_context : public region_model_context.  */
    7386              : 
    7387              : void
    7388            0 : noop_region_model_context::add_note (std::unique_ptr<pending_note>)
    7389              : {
    7390            0 : }
    7391              : 
    7392              : void
    7393            0 : noop_region_model_context::add_event (std::unique_ptr<checker_event>)
    7394              : {
    7395            0 : }
    7396              : 
    7397              : void
    7398           78 : noop_region_model_context::bifurcate (std::unique_ptr<custom_edge_info>)
    7399              : {
    7400           78 : }
    7401              : 
    7402              : void
    7403            0 : noop_region_model_context::terminate_path ()
    7404              : {
    7405            0 : }
    7406              : 
    7407              : /* class region_model_context_decorator : public region_model_context.  */
    7408              : 
    7409              : void
    7410          172 : region_model_context_decorator::add_event (std::unique_ptr<checker_event> event)
    7411              : {
    7412          172 :   if (m_inner)
    7413          172 :     m_inner->add_event (std::move (event));
    7414          172 : }
    7415              : 
    7416              : /* struct model_merger.  */
    7417              : 
    7418              : /* Dump a multiline representation of this merger to PP.  */
    7419              : 
    7420              : void
    7421            0 : model_merger::dump_to_pp (pretty_printer *pp, bool simple) const
    7422              : {
    7423            0 :   pp_string (pp, "model A:");
    7424            0 :   pp_newline (pp);
    7425            0 :   m_model_a->dump_to_pp (pp, simple, true);
    7426            0 :   pp_newline (pp);
    7427              : 
    7428            0 :   pp_string (pp, "model B:");
    7429            0 :   pp_newline (pp);
    7430            0 :   m_model_b->dump_to_pp (pp, simple, true);
    7431            0 :   pp_newline (pp);
    7432              : 
    7433            0 :   pp_string (pp, "merged model:");
    7434            0 :   pp_newline (pp);
    7435            0 :   m_merged_model->dump_to_pp (pp, simple, true);
    7436            0 :   pp_newline (pp);
    7437            0 : }
    7438              : 
    7439              : /* Dump a multiline representation of this merger to FILE.  */
    7440              : 
    7441              : void
    7442            0 : model_merger::dump (FILE *fp, bool simple) const
    7443              : {
    7444            0 :   tree_dump_pretty_printer pp (fp);
    7445            0 :   dump_to_pp (&pp, simple);
    7446            0 : }
    7447              : 
    7448              : /* Dump a multiline representation of this merger to stderr.  */
    7449              : 
    7450              : DEBUG_FUNCTION void
    7451            0 : model_merger::dump (bool simple) const
    7452              : {
    7453            0 :   dump (stderr, simple);
    7454            0 : }
    7455              : 
    7456              : /* Return true if it's OK to merge SVAL with other svalues.  */
    7457              : 
    7458              : bool
    7459       560726 : model_merger::mergeable_svalue_p (const svalue *sval) const
    7460              : {
    7461       560726 :   if (m_ext_state)
    7462              :     {
    7463              :       /* Reject merging svalues that have non-purgeable sm-state,
    7464              :          to avoid falsely reporting memory leaks by merging them
    7465              :          with something else.  For example, given a local var "p",
    7466              :          reject the merger of a:
    7467              :            store_a mapping "p" to a malloc-ed ptr
    7468              :          with:
    7469              :            store_b mapping "p" to a NULL ptr.  */
    7470       560678 :       if (m_state_a)
    7471       560678 :         if (!m_state_a->can_purge_p (*m_ext_state, sval))
    7472              :           return false;
    7473       558842 :       if (m_state_b)
    7474       558842 :         if (!m_state_b->can_purge_p (*m_ext_state, sval))
    7475              :           return false;
    7476              :     }
    7477              :   return true;
    7478              : }
    7479              : 
    7480              : /* Mark WIDENING_SVAL as changing meaning during the merge.  */
    7481              : 
    7482              : void
    7483          843 : model_merger::on_widening_reuse (const widening_svalue *widening_sval)
    7484              : {
    7485          843 :   m_svals_changing_meaning.add (widening_sval);
    7486          843 : }
    7487              : 
    7488              : } // namespace ana
    7489              : 
    7490              : /* Dump RMODEL fully to stderr (i.e. without summarization).  */
    7491              : 
    7492              : DEBUG_FUNCTION void
    7493            0 : debug (const region_model &rmodel)
    7494              : {
    7495            0 :   rmodel.dump (false);
    7496            0 : }
    7497              : 
    7498              : /* class rejected_op_constraint : public rejected_constraint.  */
    7499              : 
    7500              : void
    7501            4 : rejected_op_constraint::dump_to_pp (pretty_printer *pp) const
    7502              : {
    7503            4 :   region_model m (m_model);
    7504            4 :   m_lhs->dump_to_pp (pp, true);
    7505            4 :   pp_printf (pp, " %s ", op_symbol_code (m_op));
    7506            4 :   m_rhs->dump_to_pp (pp, true);
    7507            4 : }
    7508              : 
    7509              : /* class rejected_default_case : public rejected_constraint.  */
    7510              : 
    7511              : void
    7512            0 : rejected_default_case::dump_to_pp (pretty_printer *pp) const
    7513              : {
    7514            0 :   pp_string (pp, "implicit default for enum");
    7515            0 : }
    7516              : 
    7517              : /* class rejected_ranges_constraint : public rejected_constraint.  */
    7518              : 
    7519              : void
    7520            0 : rejected_ranges_constraint::dump_to_pp (pretty_printer *pp) const
    7521              : {
    7522            0 :   region_model m (m_model);
    7523            0 :   const svalue *sval = m.get_rvalue (m_expr, nullptr);
    7524            0 :   sval->dump_to_pp (pp, true);
    7525            0 :   pp_string (pp, " in ");
    7526            0 :   m_ranges->dump_to_pp (pp, true);
    7527            0 : }
    7528              : 
    7529              : /* class engine.  */
    7530              : 
    7531              : /* engine's ctor.  */
    7532              : 
    7533         3523 : engine::engine (region_model_manager &mgr,
    7534              :                 const supergraph *sg)
    7535         3523 : : m_mgr (mgr),
    7536         3523 :   m_sg (sg)
    7537              : {
    7538         3523 : }
    7539              : 
    7540              : /* Dump the managed objects by class to LOGGER, and the per-class totals.  */
    7541              : 
    7542              : void
    7543            5 : engine::log_stats (logger *logger) const
    7544              : {
    7545            5 :   m_mgr.log_stats (logger, true);
    7546            5 : }
    7547              : 
    7548              : namespace ana {
    7549              : 
    7550              : #if CHECKING_P
    7551              : 
    7552              : namespace selftest {
    7553              : 
    7554              : /* Build a constant tree of the given type from STR.  */
    7555              : 
    7556              : static tree
    7557           64 : build_real_cst_from_string (tree type, const char *str)
    7558              : {
    7559           64 :   REAL_VALUE_TYPE real;
    7560           64 :   real_from_string (&real, str);
    7561           64 :   return build_real (type, real);
    7562              : }
    7563              : 
    7564              : /* Append various "interesting" constants to OUT (e.g. NaN).  */
    7565              : 
    7566              : static void
    7567            8 : append_interesting_constants (auto_vec<tree> *out)
    7568              : {
    7569            8 :   out->safe_push (integer_zero_node);
    7570            8 :   out->safe_push (build_int_cst (integer_type_node, 42));
    7571            8 :   out->safe_push (build_int_cst (unsigned_type_node, 0));
    7572            8 :   out->safe_push (build_int_cst (unsigned_type_node, 42));
    7573            8 :   out->safe_push (build_real_cst_from_string (float_type_node, "QNaN"));
    7574            8 :   out->safe_push (build_real_cst_from_string (float_type_node, "-QNaN"));
    7575            8 :   out->safe_push (build_real_cst_from_string (float_type_node, "SNaN"));
    7576            8 :   out->safe_push (build_real_cst_from_string (float_type_node, "-SNaN"));
    7577            8 :   out->safe_push (build_real_cst_from_string (float_type_node, "0.0"));
    7578            8 :   out->safe_push (build_real_cst_from_string (float_type_node, "-0.0"));
    7579            8 :   out->safe_push (build_real_cst_from_string (float_type_node, "Inf"));
    7580            8 :   out->safe_push (build_real_cst_from_string (float_type_node, "-Inf"));
    7581            8 : }
    7582              : 
    7583              : /* Verify that tree_cmp is a well-behaved comparator for qsort, even
    7584              :    if the underlying constants aren't comparable.  */
    7585              : 
    7586              : static void
    7587            4 : test_tree_cmp_on_constants ()
    7588              : {
    7589            4 :   auto_vec<tree> csts;
    7590            4 :   append_interesting_constants (&csts);
    7591              : 
    7592              :   /* Try sorting every triple. */
    7593            4 :   const unsigned num = csts.length ();
    7594           52 :   for (unsigned i = 0; i < num; i++)
    7595          624 :     for (unsigned j = 0; j < num; j++)
    7596         7488 :       for (unsigned k = 0; k < num; k++)
    7597              :         {
    7598         6912 :           auto_vec<tree> v (3);
    7599         6912 :           v.quick_push (csts[i]);
    7600         6912 :           v.quick_push (csts[j]);
    7601         6912 :           v.quick_push (csts[k]);
    7602         6912 :           v.qsort (tree_cmp);
    7603         6912 :         }
    7604            4 : }
    7605              : 
    7606              : /* Implementation detail of the ASSERT_CONDITION_* macros.  */
    7607              : 
    7608              : void
    7609            8 : assert_condition (const location &loc,
    7610              :                   region_model &model,
    7611              :                   const svalue *lhs, tree_code op, const svalue *rhs,
    7612              :                   tristate expected)
    7613              : {
    7614            8 :   tristate actual = model.eval_condition (lhs, op, rhs);
    7615            8 :   ASSERT_EQ_AT (loc, actual, expected);
    7616            8 : }
    7617              : 
    7618              : /* Implementation detail of the ASSERT_CONDITION_* macros.  */
    7619              : 
    7620              : void
    7621         3084 : assert_condition (const location &loc,
    7622              :                   region_model &model,
    7623              :                   tree lhs, tree_code op, tree rhs,
    7624              :                   tristate expected)
    7625              : {
    7626         3084 :   tristate actual = model.eval_condition (lhs, op, rhs, nullptr);
    7627         3084 :   ASSERT_EQ_AT (loc, actual, expected);
    7628         3084 : }
    7629              : 
    7630              : /* Implementation detail of ASSERT_DUMP_TREE_EQ.  */
    7631              : 
    7632              : static void
    7633           20 : assert_dump_tree_eq (const location &loc, tree t, const char *expected)
    7634              : {
    7635           20 :   auto_fix_quotes sentinel;
    7636           20 :   pretty_printer pp;
    7637           20 :   pp_format_decoder (&pp) = default_tree_printer;
    7638           20 :   dump_tree (&pp, t);
    7639           20 :   ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected);
    7640           20 : }
    7641              : 
    7642              : /* Assert that dump_tree (T) is EXPECTED.  */
    7643              : 
    7644              : #define ASSERT_DUMP_TREE_EQ(T, EXPECTED) \
    7645              :   SELFTEST_BEGIN_STMT                                                   \
    7646              :   assert_dump_tree_eq ((SELFTEST_LOCATION), (T), (EXPECTED)); \
    7647              :   SELFTEST_END_STMT
    7648              : 
    7649              : /* Implementation detail of ASSERT_DUMP_EQ.  */
    7650              : 
    7651              : static void
    7652            8 : assert_dump_eq (const location &loc,
    7653              :                 const region_model &model,
    7654              :                 bool summarize,
    7655              :                 const char *expected)
    7656              : {
    7657            8 :   auto_fix_quotes sentinel;
    7658            8 :   pretty_printer pp;
    7659            8 :   pp_format_decoder (&pp) = default_tree_printer;
    7660              : 
    7661            8 :   model.dump_to_pp (&pp, summarize, true);
    7662            8 :   ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected);
    7663            8 : }
    7664              : 
    7665              : /* Assert that MODEL.dump_to_pp (SUMMARIZE) is EXPECTED.  */
    7666              : 
    7667              : #define ASSERT_DUMP_EQ(MODEL, SUMMARIZE, EXPECTED) \
    7668              :   SELFTEST_BEGIN_STMT                                                   \
    7669              :   assert_dump_eq ((SELFTEST_LOCATION), (MODEL), (SUMMARIZE), (EXPECTED)); \
    7670              :   SELFTEST_END_STMT
    7671              : 
    7672              : /* Smoketest for region_model::dump_to_pp.  */
    7673              : 
    7674              : static void
    7675            4 : test_dump ()
    7676              : {
    7677            4 :   region_model_manager mgr;
    7678            4 :   region_model model (&mgr);
    7679              : 
    7680            4 :   ASSERT_DUMP_EQ (model, false,
    7681              :                   "stack depth: 0\n"
    7682              :                   "m_called_unknown_fn: FALSE\n"
    7683              :                   "constraint_manager:\n"
    7684              :                   "  equiv classes:\n"
    7685              :                   "  constraints:\n");
    7686            4 :   ASSERT_DUMP_EQ (model, true,
    7687              :                   "stack depth: 0\n"
    7688              :                   "m_called_unknown_fn: FALSE\n"
    7689              :                   "constraint_manager:\n"
    7690              :                   "  equiv classes:\n"
    7691              :                   "  constraints:\n");
    7692              : 
    7693            4 :   text_art::ascii_theme theme;
    7694            4 :   pretty_printer pp;
    7695            4 :   dump_to_pp (model, &theme, &pp);
    7696            4 :   ASSERT_STREQ ("Region Model\n"
    7697              :                 "`- Store\n"
    7698              :                 "   `- m_called_unknown_fn: false\n",
    7699              :                 pp_formatted_text (&pp));
    7700            4 : }
    7701              : 
    7702              : /* Helper function for selftests.  Create a struct or union type named NAME,
    7703              :    with the fields given by the FIELD_DECLS in FIELDS.
    7704              :    If IS_STRUCT is true create a RECORD_TYPE (aka a struct), otherwise
    7705              :    create a UNION_TYPE.  */
    7706              : 
    7707              : static tree
    7708           16 : make_test_compound_type (const char *name, bool is_struct,
    7709              :                          const auto_vec<tree> *fields)
    7710              : {
    7711           16 :   tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
    7712           16 :   TYPE_NAME (t) = get_identifier (name);
    7713           16 :   TYPE_SIZE (t) = 0;
    7714              : 
    7715           16 :   tree fieldlist = NULL_TREE;
    7716           16 :   int i;
    7717           16 :   tree field;
    7718           48 :   FOR_EACH_VEC_ELT (*fields, i, field)
    7719              :     {
    7720           32 :       gcc_assert (TREE_CODE (field) == FIELD_DECL);
    7721           32 :       DECL_CONTEXT (field) = t;
    7722           32 :       fieldlist = chainon (field, fieldlist);
    7723              :     }
    7724           16 :   fieldlist = nreverse (fieldlist);
    7725           16 :   TYPE_FIELDS (t) = fieldlist;
    7726              : 
    7727           16 :   layout_type (t);
    7728           16 :   return t;
    7729              : }
    7730              : 
    7731              : /* Selftest fixture for creating the type "struct coord {int x; int y; };".  */
    7732              : 
    7733              : struct coord_test
    7734              : {
    7735           16 :   coord_test ()
    7736              :   {
    7737           16 :     auto_vec<tree> fields;
    7738           16 :     m_x_field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
    7739              :                                get_identifier ("x"), integer_type_node);
    7740           16 :     fields.safe_push (m_x_field);
    7741           16 :     m_y_field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
    7742              :                                get_identifier ("y"), integer_type_node);
    7743           16 :     fields.safe_push (m_y_field);
    7744           16 :     m_coord_type = make_test_compound_type ("coord", true, &fields);
    7745           16 :   }
    7746              : 
    7747              :   tree m_x_field;
    7748              :   tree m_y_field;
    7749              :   tree m_coord_type;
    7750              : };
    7751              : 
    7752              : /* Verify usage of a struct.  */
    7753              : 
    7754              : static void
    7755            4 : test_struct ()
    7756              : {
    7757            4 :   coord_test ct;
    7758              : 
    7759            4 :   tree c = build_global_decl ("c", ct.m_coord_type);
    7760            4 :   tree c_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
    7761              :                      c, ct.m_x_field, NULL_TREE);
    7762            4 :   tree c_y = build3 (COMPONENT_REF, TREE_TYPE (ct.m_y_field),
    7763              :                      c, ct.m_y_field, NULL_TREE);
    7764              : 
    7765            4 :   tree int_17 = build_int_cst (integer_type_node, 17);
    7766            4 :   tree int_m3 = build_int_cst (integer_type_node, -3);
    7767              : 
    7768            4 :   region_model_manager mgr;
    7769            4 :   region_model model (&mgr);
    7770              :   /* Set fields in order y, then x.  */
    7771            4 :   model.set_value (c_y, int_m3, nullptr);
    7772            4 :   model.set_value (c_x, int_17, nullptr);
    7773              : 
    7774              :   /* Verify get_offset for "c.x".  */
    7775            4 :   {
    7776            4 :     const region *c_x_reg = model.get_lvalue (c_x, nullptr);
    7777            4 :     region_offset offset = c_x_reg->get_offset (&mgr);
    7778            4 :     ASSERT_EQ (offset.get_base_region (), model.get_lvalue (c, nullptr));
    7779            4 :     ASSERT_EQ (offset.get_bit_offset (), 0);
    7780              :   }
    7781              : 
    7782              :   /* Verify get_offset for "c.y".  */
    7783            4 :   {
    7784            4 :     const region *c_y_reg = model.get_lvalue (c_y, nullptr);
    7785            4 :     region_offset offset = c_y_reg->get_offset (&mgr);
    7786            4 :     ASSERT_EQ (offset.get_base_region (), model.get_lvalue (c, nullptr));
    7787            4 :     ASSERT_EQ (offset.get_bit_offset (), INT_TYPE_SIZE);
    7788              :   }
    7789              : 
    7790              :   /* Check iteration order of binding_cluster (and thus of binding_map).  */
    7791            4 :   {
    7792            4 :     std::vector<binding_map::binding_pair> vec;
    7793            4 :     auto cluster
    7794            4 :       = model.get_store ()->get_cluster (model.get_lvalue (c, nullptr));
    7795           16 :     for (auto iter : *cluster)
    7796            8 :       vec.push_back (iter);
    7797            4 :     ASSERT_EQ (vec.size (), 2);
    7798              :     /* we should get them back in ascending order in memory (x then y).  */
    7799              :     /* x */
    7800            4 :     ASSERT_EQ (vec[0].m_key->dyn_cast_concrete_binding ()->get_bit_range (),
    7801              :                bit_range (0, INT_TYPE_SIZE));
    7802            4 :     ASSERT_TRUE (tree_int_cst_equal(vec[0].m_sval->maybe_get_constant (),
    7803              :                                     int_17));
    7804              :     /* y */
    7805            4 :     ASSERT_EQ (vec[1].m_key->dyn_cast_concrete_binding ()->get_bit_range (),
    7806              :                bit_range (INT_TYPE_SIZE, INT_TYPE_SIZE));
    7807            4 :     ASSERT_TRUE (tree_int_cst_equal(vec[1].m_sval->maybe_get_constant (),
    7808              :                                     int_m3));
    7809            4 :   }
    7810            4 : }
    7811              : 
    7812              : /* Verify usage of an array element.  */
    7813              : 
    7814              : static void
    7815            4 : test_array_1 ()
    7816              : {
    7817            4 :   tree tlen = size_int (10);
    7818            4 :   tree arr_type = build_array_type (char_type_node, build_index_type (tlen));
    7819              : 
    7820            4 :   tree a = build_global_decl ("a", arr_type);
    7821              : 
    7822            4 :   region_model_manager mgr;
    7823            4 :   region_model model (&mgr);
    7824            4 :   tree int_0 = integer_zero_node;
    7825            4 :   tree a_0 = build4 (ARRAY_REF, char_type_node,
    7826              :                      a, int_0, NULL_TREE, NULL_TREE);
    7827            4 :   tree char_A = build_int_cst (char_type_node, 'A');
    7828            4 :   model.set_value (a_0, char_A, nullptr);
    7829            4 : }
    7830              : 
    7831              : /* Verify that region_model::get_representative_tree works as expected.  */
    7832              : 
    7833              : static void
    7834            4 : test_get_representative_tree ()
    7835              : {
    7836            4 :   region_model_manager mgr;
    7837              : 
    7838              :   /* STRING_CST.  */
    7839            4 :   {
    7840            4 :     tree string_cst = build_string (4, "foo");
    7841            4 :     region_model m (&mgr);
    7842            4 :     const svalue *str_sval = m.get_rvalue (string_cst, nullptr);
    7843            4 :     tree rep = m.get_representative_tree (str_sval);
    7844            4 :     ASSERT_EQ (rep, string_cst);
    7845            4 :   }
    7846              : 
    7847              :   /* String literal.  */
    7848            4 :   {
    7849            4 :     tree string_cst_ptr = build_string_literal (4, "foo");
    7850            4 :     region_model m (&mgr);
    7851            4 :     const svalue *str_sval = m.get_rvalue (string_cst_ptr, nullptr);
    7852            4 :     tree rep = m.get_representative_tree (str_sval);
    7853            4 :     ASSERT_DUMP_TREE_EQ (rep, "&\"foo\"[0]");
    7854            4 :   }
    7855              : 
    7856              :   /* Value of an element within an array.  */
    7857            4 :   {
    7858            4 :     tree tlen = size_int (10);
    7859            4 :     tree arr_type = build_array_type (char_type_node, build_index_type (tlen));
    7860            4 :     tree a = build_global_decl ("a", arr_type);
    7861            4 :     placeholder_svalue test_sval (mgr.alloc_symbol_id (),
    7862            4 :                                   char_type_node, "test value");
    7863              : 
    7864              :     /* Value of a[3].  */
    7865            4 :     {
    7866            4 :       test_region_model_context ctxt;
    7867            4 :       region_model model (&mgr);
    7868            4 :       tree int_3 = build_int_cst (integer_type_node, 3);
    7869            4 :       tree a_3 = build4 (ARRAY_REF, char_type_node,
    7870              :                          a, int_3, NULL_TREE, NULL_TREE);
    7871            4 :       const region *a_3_reg = model.get_lvalue (a_3, &ctxt);
    7872            4 :       model.set_value (a_3_reg, &test_sval, &ctxt);
    7873            4 :       tree rep = model.get_representative_tree (&test_sval);
    7874            4 :       ASSERT_DUMP_TREE_EQ (rep, "a[3]");
    7875            4 :     }
    7876              : 
    7877              :     /* Value of a[0].  */
    7878            4 :     {
    7879            4 :       test_region_model_context ctxt;
    7880            4 :       region_model model (&mgr);
    7881            4 :       tree idx = integer_zero_node;
    7882            4 :       tree a_0 = build4 (ARRAY_REF, char_type_node,
    7883              :                          a, idx, NULL_TREE, NULL_TREE);
    7884            4 :       const region *a_0_reg = model.get_lvalue (a_0, &ctxt);
    7885            4 :       model.set_value (a_0_reg, &test_sval, &ctxt);
    7886            4 :       tree rep = model.get_representative_tree (&test_sval);
    7887            4 :       ASSERT_DUMP_TREE_EQ (rep, "a[0]");
    7888            4 :     }
    7889            4 :   }
    7890              : 
    7891              :   /* Value of a field within a struct.  */
    7892            4 :   {
    7893            4 :     coord_test ct;
    7894              : 
    7895            4 :     tree c = build_global_decl ("c", ct.m_coord_type);
    7896            4 :     tree c_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
    7897              :                        c, ct.m_x_field, NULL_TREE);
    7898            4 :     tree c_y = build3 (COMPONENT_REF, TREE_TYPE (ct.m_y_field),
    7899              :                        c, ct.m_y_field, NULL_TREE);
    7900              : 
    7901            4 :     test_region_model_context ctxt;
    7902              : 
    7903              :     /* Value of initial field.  */
    7904            4 :     {
    7905            4 :       region_model m (&mgr);
    7906            4 :       const region *c_x_reg = m.get_lvalue (c_x, &ctxt);
    7907            4 :       placeholder_svalue test_sval_x (mgr.alloc_symbol_id (),
    7908            4 :                                       integer_type_node, "test x val");
    7909            4 :       m.set_value (c_x_reg, &test_sval_x, &ctxt);
    7910            4 :       tree rep = m.get_representative_tree (&test_sval_x);
    7911            4 :       ASSERT_DUMP_TREE_EQ (rep, "c.x");
    7912            4 :     }
    7913              : 
    7914              :     /* Value of non-initial field.  */
    7915            4 :     {
    7916            4 :       region_model m (&mgr);
    7917            4 :       const region *c_y_reg = m.get_lvalue (c_y, &ctxt);
    7918            4 :       placeholder_svalue test_sval_y (mgr.alloc_symbol_id (),
    7919            4 :                                       integer_type_node, "test y val");
    7920            4 :       m.set_value (c_y_reg, &test_sval_y, &ctxt);
    7921            4 :       tree rep = m.get_representative_tree (&test_sval_y);
    7922            4 :       ASSERT_DUMP_TREE_EQ (rep, "c.y");
    7923            4 :     }
    7924            4 :   }
    7925            4 : }
    7926              : 
    7927              : /* Verify that calling region_model::get_rvalue repeatedly on the same
    7928              :    tree constant retrieves the same svalue *.  */
    7929              : 
    7930              : static void
    7931            4 : test_unique_constants ()
    7932              : {
    7933            4 :   tree int_0 = integer_zero_node;
    7934            4 :   tree int_42 = build_int_cst (integer_type_node, 42);
    7935              : 
    7936            4 :   test_region_model_context ctxt;
    7937            4 :   region_model_manager mgr;
    7938            4 :   region_model model (&mgr);
    7939            4 :   ASSERT_EQ (model.get_rvalue (int_0, &ctxt), model.get_rvalue (int_0, &ctxt));
    7940            4 :   ASSERT_EQ (model.get_rvalue (int_42, &ctxt),
    7941              :              model.get_rvalue (int_42, &ctxt));
    7942            4 :   ASSERT_NE (model.get_rvalue (int_0, &ctxt), model.get_rvalue (int_42, &ctxt));
    7943            4 :   ASSERT_EQ (ctxt.get_num_diagnostics (), 0);
    7944              : 
    7945              :   /* A "(const int)42" will be a different tree from "(int)42)"...  */
    7946            4 :   tree const_int_type_node
    7947            4 :     = build_qualified_type (integer_type_node, TYPE_QUAL_CONST);
    7948            4 :   tree const_int_42 = build_int_cst (const_int_type_node, 42);
    7949            4 :   ASSERT_NE (int_42, const_int_42);
    7950              :   /* It should have a different const_svalue.  */
    7951            4 :   const svalue *int_42_sval = model.get_rvalue (int_42, &ctxt);
    7952            4 :   const svalue *const_int_42_sval = model.get_rvalue (const_int_42, &ctxt);
    7953            4 :   ASSERT_NE (int_42_sval, const_int_42_sval);
    7954              :   /* But they should compare as equal.  */
    7955            4 :   ASSERT_CONDITION_TRUE (model, int_42_sval, EQ_EXPR, const_int_42_sval);
    7956            4 :   ASSERT_CONDITION_FALSE (model, int_42_sval, NE_EXPR, const_int_42_sval);
    7957            4 : }
    7958              : 
    7959              : /* Verify that each type gets its own singleton unknown_svalue within a
    7960              :    region_model_manager, and that NULL_TREE gets its own singleton.  */
    7961              : 
    7962              : static void
    7963            4 : test_unique_unknowns ()
    7964              : {
    7965            4 :   region_model_manager mgr;
    7966            4 :   const svalue *unknown_int
    7967            4 :     = mgr.get_or_create_unknown_svalue (integer_type_node);
    7968              :   /* Repeated calls with the same type should get the same "unknown"
    7969              :      svalue.  */
    7970            4 :   const svalue *unknown_int_2
    7971            4 :     = mgr.get_or_create_unknown_svalue (integer_type_node);
    7972            4 :   ASSERT_EQ (unknown_int, unknown_int_2);
    7973              : 
    7974              :   /* Different types (or the NULL type) should have different
    7975              :      unknown_svalues.  */
    7976            4 :   const svalue *unknown_NULL_type = mgr.get_or_create_unknown_svalue (nullptr);
    7977            4 :   ASSERT_NE (unknown_NULL_type, unknown_int);
    7978              : 
    7979              :   /* Repeated calls with NULL for the type should get the same "unknown"
    7980              :      svalue.  */
    7981            4 :   const svalue *unknown_NULL_type_2 = mgr.get_or_create_unknown_svalue (nullptr);
    7982            4 :   ASSERT_EQ (unknown_NULL_type, unknown_NULL_type_2);
    7983            4 : }
    7984              : 
    7985              : /* Verify that initial_svalue are handled as expected.  */
    7986              : 
    7987              : static void
    7988            4 : test_initial_svalue_folding ()
    7989              : {
    7990            4 :   region_model_manager mgr;
    7991            4 :   tree x = build_global_decl ("x", integer_type_node);
    7992            4 :   tree y = build_global_decl ("y", integer_type_node);
    7993              : 
    7994            4 :   test_region_model_context ctxt;
    7995            4 :   region_model model (&mgr);
    7996            4 :   const svalue *x_init = model.get_rvalue (x, &ctxt);
    7997            4 :   const svalue *y_init = model.get_rvalue (y, &ctxt);
    7998            4 :   ASSERT_NE (x_init, y_init);
    7999            4 :   const region *x_reg = model.get_lvalue (x, &ctxt);
    8000            4 :   ASSERT_EQ (x_init, mgr.get_or_create_initial_value (x_reg));
    8001              : 
    8002            4 : }
    8003              : 
    8004              : /* Verify that unary ops are folded as expected.  */
    8005              : 
    8006              : static void
    8007            4 : test_unaryop_svalue_folding ()
    8008              : {
    8009            4 :   region_model_manager mgr;
    8010            4 :   tree x = build_global_decl ("x", integer_type_node);
    8011            4 :   tree y = build_global_decl ("y", integer_type_node);
    8012              : 
    8013            4 :   test_region_model_context ctxt;
    8014            4 :   region_model model (&mgr);
    8015            4 :   const svalue *x_init = model.get_rvalue (x, &ctxt);
    8016            4 :   const svalue *y_init = model.get_rvalue (y, &ctxt);
    8017            4 :   const region *x_reg = model.get_lvalue (x, &ctxt);
    8018            4 :   ASSERT_EQ (x_init, mgr.get_or_create_initial_value (x_reg));
    8019              : 
    8020              :   /* "(int)x" -> "x".  */
    8021            4 :   ASSERT_EQ (x_init, mgr.get_or_create_cast (integer_type_node, x_init));
    8022              : 
    8023              :   /* "(void *)x" -> something other than "x".  */
    8024            4 :   ASSERT_NE (x_init, mgr.get_or_create_cast (ptr_type_node, x_init));
    8025              : 
    8026              :   /* "!(x == y)" -> "x != y".  */
    8027            4 :   ASSERT_EQ (mgr.get_or_create_unaryop
    8028              :                (boolean_type_node, TRUTH_NOT_EXPR,
    8029              :                 mgr.get_or_create_binop (boolean_type_node, EQ_EXPR,
    8030              :                                          x_init, y_init)),
    8031              :              mgr.get_or_create_binop (boolean_type_node, NE_EXPR,
    8032              :                                       x_init, y_init));
    8033              :   /* "!(x > y)" -> "x <= y".  */
    8034            4 :   ASSERT_EQ (mgr.get_or_create_unaryop
    8035              :                (boolean_type_node, TRUTH_NOT_EXPR,
    8036              :                 mgr.get_or_create_binop (boolean_type_node, GT_EXPR,
    8037              :                                          x_init, y_init)),
    8038              :              mgr.get_or_create_binop (boolean_type_node, LE_EXPR,
    8039              :                                       x_init, y_init));
    8040            4 : }
    8041              : 
    8042              : /* Verify that binops on constant svalues are folded.  */
    8043              : 
    8044              : static void
    8045            4 : test_binop_svalue_folding ()
    8046              : {
    8047              : #define NUM_CSTS 10
    8048            4 :   tree cst_int[NUM_CSTS];
    8049            4 :   region_model_manager mgr;
    8050            4 :   const svalue *cst_sval[NUM_CSTS];
    8051           48 :   for (int i = 0; i < NUM_CSTS; i++)
    8052              :     {
    8053           40 :       cst_int[i] = build_int_cst (integer_type_node, i);
    8054           40 :       cst_sval[i] = mgr.get_or_create_constant_svalue (cst_int[i]);
    8055           40 :       ASSERT_EQ (cst_sval[i]->get_kind (), SK_CONSTANT);
    8056           40 :       ASSERT_EQ (cst_sval[i]->maybe_get_constant (), cst_int[i]);
    8057              :     }
    8058              : 
    8059           44 :   for (int i = 0; i < NUM_CSTS; i++)
    8060          440 :     for (int j = 0; j < NUM_CSTS; j++)
    8061              :       {
    8062          400 :         if (i != j)
    8063          360 :           ASSERT_NE (cst_sval[i], cst_sval[j]);
    8064          400 :         if (i + j < NUM_CSTS)
    8065              :           {
    8066          220 :             const svalue *sum
    8067          220 :               = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR,
    8068              :                                          cst_sval[i], cst_sval[j]);
    8069          220 :             ASSERT_EQ (sum, cst_sval[i + j]);
    8070              :           }
    8071          400 :         if (i - j >= 0)
    8072              :           {
    8073          220 :             const svalue *difference
    8074          220 :               = mgr.get_or_create_binop (integer_type_node, MINUS_EXPR,
    8075              :                                          cst_sval[i], cst_sval[j]);
    8076          220 :             ASSERT_EQ (difference, cst_sval[i - j]);
    8077              :           }
    8078          400 :         if (i * j < NUM_CSTS)
    8079              :           {
    8080          168 :             const svalue *product
    8081          168 :               = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
    8082              :                                          cst_sval[i], cst_sval[j]);
    8083          168 :             ASSERT_EQ (product, cst_sval[i * j]);
    8084              :           }
    8085          400 :         const svalue *eq = mgr.get_or_create_binop (integer_type_node, EQ_EXPR,
    8086              :                                                cst_sval[i], cst_sval[j]);
    8087          400 :         ASSERT_EQ (eq, i == j ? cst_sval[1] : cst_sval [0]);
    8088          400 :         const svalue *neq = mgr.get_or_create_binop (integer_type_node, NE_EXPR,
    8089              :                                                 cst_sval[i], cst_sval[j]);
    8090          400 :         ASSERT_EQ (neq, i != j ? cst_sval[1] : cst_sval [0]);
    8091              :         // etc
    8092              :       }
    8093              : 
    8094            4 :   tree x = build_global_decl ("x", integer_type_node);
    8095              : 
    8096            4 :   test_region_model_context ctxt;
    8097            4 :   region_model model (&mgr);
    8098            4 :   const svalue *x_init = model.get_rvalue (x, &ctxt);
    8099              : 
    8100              :   /* PLUS_EXPR folding.  */
    8101            4 :   const svalue *x_init_plus_zero
    8102            4 :     = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR,
    8103              :                                x_init, cst_sval[0]);
    8104            4 :   ASSERT_EQ (x_init_plus_zero, x_init);
    8105            4 :   const svalue *zero_plus_x_init
    8106            4 :     = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR,
    8107              :                                cst_sval[0], x_init);
    8108            4 :   ASSERT_EQ (zero_plus_x_init, x_init);
    8109              : 
    8110              :   /* MULT_EXPR folding.  */
    8111            4 :   const svalue *x_init_times_zero
    8112            4 :     = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
    8113              :                                x_init, cst_sval[0]);
    8114            4 :   ASSERT_EQ (x_init_times_zero, cst_sval[0]);
    8115            4 :   const svalue *zero_times_x_init
    8116            4 :     = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
    8117              :                                cst_sval[0], x_init);
    8118            4 :   ASSERT_EQ (zero_times_x_init, cst_sval[0]);
    8119              : 
    8120            4 :   const svalue *x_init_times_one
    8121            4 :     = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
    8122              :                                x_init, cst_sval[1]);
    8123            4 :   ASSERT_EQ (x_init_times_one, x_init);
    8124            4 :   const svalue *one_times_x_init
    8125            4 :     = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
    8126              :                                cst_sval[1], x_init);
    8127            4 :   ASSERT_EQ (one_times_x_init, x_init);
    8128              : 
    8129              :   // etc
    8130              :   // TODO: do we want to use the match-and-simplify DSL for this?
    8131              : 
    8132              :   /* Verify that binops put any constants on the RHS.  */
    8133            4 :   const svalue *four_times_x_init
    8134            4 :     = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
    8135              :                                cst_sval[4], x_init);
    8136            4 :   const svalue *x_init_times_four
    8137            4 :     = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
    8138              :                                x_init, cst_sval[4]);
    8139            4 :   ASSERT_EQ (four_times_x_init, x_init_times_four);
    8140            4 :   const binop_svalue *binop = four_times_x_init->dyn_cast_binop_svalue ();
    8141            4 :   ASSERT_EQ (binop->get_op (), MULT_EXPR);
    8142            4 :   ASSERT_EQ (binop->get_arg0 (), x_init);
    8143            4 :   ASSERT_EQ (binop->get_arg1 (), cst_sval[4]);
    8144              : 
    8145              :   /* Verify that ((x + 1) + 1) == (x + 2).  */
    8146            4 :   const svalue *x_init_plus_one
    8147            4 :     = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR,
    8148              :                                x_init, cst_sval[1]);
    8149            4 :   const svalue *x_init_plus_two
    8150            4 :     = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR,
    8151              :                                x_init, cst_sval[2]);
    8152            4 :   const svalue *x_init_plus_one_plus_one
    8153            4 :     = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR,
    8154              :                                x_init_plus_one, cst_sval[1]);
    8155            4 :   ASSERT_EQ (x_init_plus_one_plus_one, x_init_plus_two);
    8156              : 
    8157              :   /* Verify various binops on booleans.  */
    8158            4 :   {
    8159            4 :     const svalue *sval_true = mgr.get_or_create_int_cst (boolean_type_node, 1);
    8160            4 :     const svalue *sval_false = mgr.get_or_create_int_cst (boolean_type_node, 0);
    8161            4 :     const svalue *sval_unknown
    8162            4 :       = mgr.get_or_create_unknown_svalue (boolean_type_node);
    8163            4 :     const placeholder_svalue sval_placeholder (mgr.alloc_symbol_id (),
    8164            4 :                                                boolean_type_node, "v");
    8165           12 :     for (auto op : {BIT_IOR_EXPR, TRUTH_OR_EXPR})
    8166              :       {
    8167            8 :         ASSERT_EQ (mgr.get_or_create_binop (boolean_type_node, op,
    8168              :                                             sval_true, sval_unknown),
    8169              :                    sval_true);
    8170            8 :         ASSERT_EQ (mgr.get_or_create_binop (boolean_type_node, op,
    8171              :                                             sval_false, sval_unknown),
    8172              :                    sval_unknown);
    8173            8 :         ASSERT_EQ (mgr.get_or_create_binop (boolean_type_node, op,
    8174              :                                             sval_false, &sval_placeholder),
    8175              :                    &sval_placeholder);
    8176              :       }
    8177           12 :     for (auto op : {BIT_AND_EXPR, TRUTH_AND_EXPR})
    8178              :       {
    8179            8 :         ASSERT_EQ (mgr.get_or_create_binop (boolean_type_node, op,
    8180              :                                             sval_false, sval_unknown),
    8181              :                    sval_false);
    8182            8 :         ASSERT_EQ (mgr.get_or_create_binop (boolean_type_node, op,
    8183              :                                             sval_true, sval_unknown),
    8184              :                    sval_unknown);
    8185            8 :         ASSERT_EQ (mgr.get_or_create_binop (boolean_type_node, op,
    8186              :                                             sval_true, &sval_placeholder),
    8187              :                    &sval_placeholder);
    8188              :       }
    8189            4 :   }
    8190            4 : }
    8191              : 
    8192              : /* Verify that sub_svalues are folded as expected.  */
    8193              : 
    8194              : static void
    8195            4 : test_sub_svalue_folding ()
    8196              : {
    8197            4 :   coord_test ct;
    8198            4 :   tree c = build_global_decl ("c", ct.m_coord_type);
    8199            4 :   tree c_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
    8200              :                      c, ct.m_x_field, NULL_TREE);
    8201              : 
    8202            4 :   region_model_manager mgr;
    8203            4 :   region_model model (&mgr);
    8204            4 :   test_region_model_context ctxt;
    8205            4 :   const region *c_x_reg = model.get_lvalue (c_x, &ctxt);
    8206              : 
    8207              :   /* Verify that sub_svalue of "unknown" simply
    8208              :      yields an unknown.  */
    8209              : 
    8210            4 :   const svalue *unknown = mgr.get_or_create_unknown_svalue (ct.m_coord_type);
    8211            4 :   const svalue *sub = mgr.get_or_create_sub_svalue (TREE_TYPE (ct.m_x_field),
    8212              :                                                       unknown, c_x_reg);
    8213            4 :   ASSERT_EQ (sub->get_kind (), SK_UNKNOWN);
    8214            4 :   ASSERT_EQ (sub->get_type (), TREE_TYPE (ct.m_x_field));
    8215            4 : }
    8216              : 
    8217              : /* Get BIT within VAL as a symbolic value within MGR.  */
    8218              : 
    8219              : static const svalue *
    8220          256 : get_bit (region_model_manager *mgr,
    8221              :          bit_offset_t bit,
    8222              :          unsigned HOST_WIDE_INT val)
    8223              : {
    8224          256 :   const svalue *inner_svalue
    8225          256 :     = mgr->get_or_create_int_cst (unsigned_type_node, val);
    8226          256 :   return mgr->get_or_create_bits_within (boolean_type_node,
    8227          256 :                                          bit_range (bit, 1),
    8228          256 :                                          inner_svalue);
    8229              : }
    8230              : 
    8231              : /* Verify that bits_within_svalues are folded as expected.  */
    8232              : 
    8233              : static void
    8234            4 : test_bits_within_svalue_folding ()
    8235              : {
    8236            4 :   region_model_manager mgr;
    8237              : 
    8238            4 :   const svalue *zero = mgr.get_or_create_int_cst (boolean_type_node, 0);
    8239            4 :   const svalue *one = mgr.get_or_create_int_cst (boolean_type_node, 1);
    8240              : 
    8241            4 :   {
    8242            4 :     const unsigned val = 0x0000;
    8243           68 :     for (unsigned bit = 0; bit < 16; bit++)
    8244           64 :       ASSERT_EQ (get_bit (&mgr, bit, val), zero);
    8245              :   }
    8246              : 
    8247            4 :   {
    8248            4 :     const unsigned val = 0x0001;
    8249            4 :     ASSERT_EQ (get_bit (&mgr, 0, val), one);
    8250           64 :     for (unsigned bit = 1; bit < 16; bit++)
    8251           60 :       ASSERT_EQ (get_bit (&mgr, bit, val), zero);
    8252              :   }
    8253              : 
    8254            4 :   {
    8255            4 :     const unsigned val = 0x8000;
    8256           64 :     for (unsigned bit = 0; bit < 15; bit++)
    8257           60 :       ASSERT_EQ (get_bit (&mgr, bit, val), zero);
    8258            4 :     ASSERT_EQ (get_bit (&mgr, 15, val), one);
    8259              :   }
    8260              : 
    8261            4 :   {
    8262            4 :     const unsigned val = 0xFFFF;
    8263           68 :     for (unsigned bit = 0; bit < 16; bit++)
    8264           64 :       ASSERT_EQ (get_bit (&mgr, bit, val), one);
    8265              :   }
    8266            4 : }
    8267              : 
    8268              : /* Test that region::descendent_of_p works as expected.  */
    8269              : 
    8270              : static void
    8271            4 : test_descendent_of_p ()
    8272              : {
    8273            4 :   region_model_manager mgr;
    8274            4 :   const region *stack = mgr.get_stack_region ();
    8275            4 :   const region *heap = mgr.get_heap_region ();
    8276            4 :   const region *code = mgr.get_code_region ();
    8277            4 :   const region *globals = mgr.get_globals_region ();
    8278              : 
    8279              :   /* descendent_of_p should return true when used on the region itself.  */
    8280            4 :   ASSERT_TRUE (stack->descendent_of_p (stack));
    8281            4 :   ASSERT_FALSE (stack->descendent_of_p (heap));
    8282            4 :   ASSERT_FALSE (stack->descendent_of_p (code));
    8283            4 :   ASSERT_FALSE (stack->descendent_of_p (globals));
    8284              : 
    8285            4 :   tree x = build_global_decl ("x", integer_type_node);
    8286            4 :   const region *x_reg = mgr.get_region_for_global (x);
    8287            4 :   ASSERT_TRUE (x_reg->descendent_of_p (globals));
    8288              : 
    8289              :   /* A cast_region should be a descendent of the original region.  */
    8290            4 :   const region *cast_reg = mgr.get_cast_region (x_reg, ptr_type_node);
    8291            4 :   ASSERT_TRUE (cast_reg->descendent_of_p (x_reg));
    8292            4 : }
    8293              : 
    8294              : /* Verify that bit_range_region works as expected.  */
    8295              : 
    8296              : static void
    8297            4 : test_bit_range_regions ()
    8298              : {
    8299            4 :   tree x = build_global_decl ("x", integer_type_node);
    8300            4 :   region_model_manager mgr;
    8301            4 :   const region *x_reg = mgr.get_region_for_global (x);
    8302            4 :   const region *byte0
    8303            4 :     = mgr.get_bit_range (x_reg, char_type_node, bit_range (0, 8));
    8304            4 :   const region *byte1
    8305            4 :     = mgr.get_bit_range (x_reg, char_type_node, bit_range (8, 8));
    8306            4 :   ASSERT_TRUE (byte0->descendent_of_p (x_reg));
    8307            4 :   ASSERT_TRUE (byte1->descendent_of_p (x_reg));
    8308            4 :   ASSERT_NE (byte0, byte1);
    8309            4 : }
    8310              : 
    8311              : /* Verify that simple assignments work as expected.  */
    8312              : 
    8313              : static void
    8314            4 : test_assignment ()
    8315              : {
    8316            4 :   tree int_0 = integer_zero_node;
    8317            4 :   tree x = build_global_decl ("x", integer_type_node);
    8318            4 :   tree y = build_global_decl ("y", integer_type_node);
    8319              : 
    8320              :   /* "x == 0", then use of y, then "y = 0;".  */
    8321            4 :   region_model_manager mgr;
    8322            4 :   region_model model (&mgr);
    8323            4 :   ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
    8324            4 :   ASSERT_CONDITION_UNKNOWN (model, y, EQ_EXPR, int_0);
    8325            4 :   model.set_value (model.get_lvalue (y, nullptr),
    8326              :                    model.get_rvalue (int_0, nullptr),
    8327              :                    nullptr);
    8328            4 :   ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, int_0);
    8329            4 :   ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, x);
    8330            4 : }
    8331              : 
    8332              : /* Verify that compound assignments work as expected.  */
    8333              : 
    8334              : static void
    8335            4 : test_compound_assignment ()
    8336              : {
    8337            4 :   coord_test ct;
    8338              : 
    8339            4 :   tree c = build_global_decl ("c", ct.m_coord_type);
    8340            4 :   tree c_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
    8341              :                      c, ct.m_x_field, NULL_TREE);
    8342            4 :   tree c_y = build3 (COMPONENT_REF, TREE_TYPE (ct.m_y_field),
    8343              :                      c, ct.m_y_field, NULL_TREE);
    8344            4 :   tree d = build_global_decl ("d", ct.m_coord_type);
    8345            4 :   tree d_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
    8346              :                      d, ct.m_x_field, NULL_TREE);
    8347            4 :   tree d_y = build3 (COMPONENT_REF, TREE_TYPE (ct.m_y_field),
    8348              :                      d, ct.m_y_field, NULL_TREE);
    8349              : 
    8350            4 :   tree int_17 = build_int_cst (integer_type_node, 17);
    8351            4 :   tree int_m3 = build_int_cst (integer_type_node, -3);
    8352              : 
    8353            4 :   region_model_manager mgr;
    8354            4 :   region_model model (&mgr);
    8355            4 :   model.set_value (c_x, int_17, nullptr);
    8356            4 :   model.set_value (c_y, int_m3, nullptr);
    8357              : 
    8358              :   /* Copy c to d.  */
    8359            4 :   const svalue *sval = model.get_rvalue (c, nullptr);
    8360            4 :   model.set_value (model.get_lvalue (d, nullptr), sval, nullptr);
    8361              : 
    8362              :   /* Check that the fields have the same svalues.  */
    8363            4 :   ASSERT_EQ (model.get_rvalue (c_x, nullptr), model.get_rvalue (d_x, nullptr));
    8364            4 :   ASSERT_EQ (model.get_rvalue (c_y, nullptr), model.get_rvalue (d_y, nullptr));
    8365            4 : }
    8366              : 
    8367              : /* Verify the details of pushing and popping stack frames.  */
    8368              : 
    8369              : static void
    8370            4 : test_stack_frames ()
    8371              : {
    8372            4 :   tree int_42 = build_int_cst (integer_type_node, 42);
    8373            4 :   tree int_10 = build_int_cst (integer_type_node, 10);
    8374            4 :   tree int_5 = build_int_cst (integer_type_node, 5);
    8375            4 :   tree int_0 = integer_zero_node;
    8376              : 
    8377            4 :   auto_vec <tree> param_types;
    8378            4 :   tree parent_fndecl = make_fndecl (integer_type_node,
    8379              :                                     "parent_fn",
    8380              :                                     param_types);
    8381            4 :   allocate_struct_function (parent_fndecl, true);
    8382              : 
    8383            4 :   tree child_fndecl = make_fndecl (integer_type_node,
    8384              :                                    "child_fn",
    8385              :                                    param_types);
    8386            4 :   allocate_struct_function (child_fndecl, true);
    8387              : 
    8388              :   /* "a" and "b" in the parent frame.  */
    8389            4 :   tree a = build_decl (UNKNOWN_LOCATION, PARM_DECL,
    8390              :                        get_identifier ("a"),
    8391              :                        integer_type_node);
    8392            4 :   DECL_CONTEXT (a) = parent_fndecl;
    8393            4 :   tree b = build_decl (UNKNOWN_LOCATION, PARM_DECL,
    8394              :                        get_identifier ("b"),
    8395              :                        integer_type_node);
    8396            4 :   DECL_CONTEXT (b) = parent_fndecl;
    8397              :   /* "x" and "y" in a child frame.  */
    8398            4 :   tree x = build_decl (UNKNOWN_LOCATION, PARM_DECL,
    8399              :                        get_identifier ("x"),
    8400              :                        integer_type_node);
    8401            4 :   DECL_CONTEXT (x) = child_fndecl;
    8402            4 :   tree y = build_decl (UNKNOWN_LOCATION, PARM_DECL,
    8403              :                        get_identifier ("y"),
    8404              :                        integer_type_node);
    8405            4 :   DECL_CONTEXT (y) = child_fndecl;
    8406              : 
    8407              :   /* "p" global.  */
    8408            4 :   tree p = build_global_decl ("p", ptr_type_node);
    8409              : 
    8410              :   /* "q" global.  */
    8411            4 :   tree q = build_global_decl ("q", ptr_type_node);
    8412              : 
    8413            4 :   region_model_manager mgr;
    8414            4 :   test_region_model_context ctxt;
    8415            4 :   region_model model (&mgr);
    8416              : 
    8417              :   /* Push stack frame for "parent_fn".  */
    8418            4 :   const region *parent_frame_reg
    8419            4 :     = model.push_frame (*DECL_STRUCT_FUNCTION (parent_fndecl),
    8420              :                         nullptr, nullptr, &ctxt);
    8421            4 :   ASSERT_EQ (model.get_current_frame (), parent_frame_reg);
    8422            4 :   ASSERT_TRUE (model.region_exists_p (parent_frame_reg));
    8423            4 :   const region *a_in_parent_reg = model.get_lvalue (a, &ctxt);
    8424            4 :   model.set_value (a_in_parent_reg,
    8425              :                    model.get_rvalue (int_42, &ctxt),
    8426              :                    &ctxt);
    8427            4 :   ASSERT_EQ (a_in_parent_reg->maybe_get_frame_region (), parent_frame_reg);
    8428              : 
    8429            4 :   model.add_constraint (b, LT_EXPR, int_10, &ctxt);
    8430            4 :   ASSERT_EQ (model.eval_condition (b, LT_EXPR, int_10, &ctxt),
    8431              :              tristate (tristate::TS_TRUE));
    8432              : 
    8433              :   /* Push stack frame for "child_fn".  */
    8434            4 :   const region *child_frame_reg
    8435            4 :     = model.push_frame (*DECL_STRUCT_FUNCTION (child_fndecl),
    8436              :                         nullptr, nullptr, &ctxt);
    8437            4 :   ASSERT_EQ (model.get_current_frame (), child_frame_reg);
    8438            4 :   ASSERT_TRUE (model.region_exists_p (child_frame_reg));
    8439            4 :   const region *x_in_child_reg = model.get_lvalue (x, &ctxt);
    8440            4 :   model.set_value (x_in_child_reg,
    8441              :                    model.get_rvalue (int_0, &ctxt),
    8442              :                    &ctxt);
    8443            4 :   ASSERT_EQ (x_in_child_reg->maybe_get_frame_region (), child_frame_reg);
    8444              : 
    8445            4 :   model.add_constraint (y, NE_EXPR, int_5, &ctxt);
    8446            4 :   ASSERT_EQ (model.eval_condition (y, NE_EXPR, int_5, &ctxt),
    8447              :              tristate (tristate::TS_TRUE));
    8448              : 
    8449              :   /* Point a global pointer at a local in the child frame:  p = &x.  */
    8450            4 :   const region *p_in_globals_reg = model.get_lvalue (p, &ctxt);
    8451            4 :   model.set_value (p_in_globals_reg,
    8452              :                    mgr.get_ptr_svalue (ptr_type_node, x_in_child_reg),
    8453              :                    &ctxt);
    8454            4 :   ASSERT_EQ (p_in_globals_reg->maybe_get_frame_region (), nullptr);
    8455              : 
    8456              :   /* Point another global pointer at p: q = &p.  */
    8457            4 :   const region *q_in_globals_reg = model.get_lvalue (q, &ctxt);
    8458            4 :   model.set_value (q_in_globals_reg,
    8459              :                    mgr.get_ptr_svalue (ptr_type_node, p_in_globals_reg),
    8460              :                    &ctxt);
    8461              : 
    8462              :   /* Test region::descendent_of_p.  */
    8463            4 :   ASSERT_TRUE (child_frame_reg->descendent_of_p (child_frame_reg));
    8464            4 :   ASSERT_TRUE (x_in_child_reg->descendent_of_p (child_frame_reg));
    8465            4 :   ASSERT_FALSE (a_in_parent_reg->descendent_of_p (child_frame_reg));
    8466              : 
    8467              :   /* Pop the "child_fn" frame from the stack.  */
    8468            4 :   model.pop_frame (nullptr, nullptr, &ctxt, nullptr);
    8469            4 :   ASSERT_FALSE (model.region_exists_p (child_frame_reg));
    8470            4 :   ASSERT_TRUE (model.region_exists_p (parent_frame_reg));
    8471              : 
    8472              :   /* Verify that p (which was pointing at the local "x" in the popped
    8473              :      frame) has been poisoned.  */
    8474            4 :   const svalue *new_p_sval = model.get_rvalue (p, nullptr);
    8475            4 :   ASSERT_EQ (new_p_sval->get_kind (), SK_POISONED);
    8476            4 :   ASSERT_EQ (new_p_sval->dyn_cast_poisoned_svalue ()->get_poison_kind (),
    8477              :              poison_kind::popped_stack);
    8478              : 
    8479              :   /* Verify that q still points to p, in spite of the region
    8480              :      renumbering.  */
    8481            4 :   const svalue *new_q_sval = model.get_rvalue (q, &ctxt);
    8482            4 :   ASSERT_EQ (new_q_sval->get_kind (), SK_REGION);
    8483            4 :   ASSERT_EQ (new_q_sval->maybe_get_region (),
    8484              :              model.get_lvalue (p, &ctxt));
    8485              : 
    8486              :   /* Verify that top of stack has been updated.  */
    8487            4 :   ASSERT_EQ (model.get_current_frame (), parent_frame_reg);
    8488              : 
    8489              :   /* Verify locals in parent frame.  */
    8490              :   /* Verify "a" still has its value.  */
    8491            4 :   const svalue *new_a_sval = model.get_rvalue (a, &ctxt);
    8492            4 :   ASSERT_EQ (new_a_sval->get_kind (), SK_CONSTANT);
    8493            4 :   ASSERT_EQ (new_a_sval->dyn_cast_constant_svalue ()->get_constant (),
    8494              :              int_42);
    8495              :   /* Verify "b" still has its constraint.  */
    8496            4 :   ASSERT_EQ (model.eval_condition (b, LT_EXPR, int_10, &ctxt),
    8497              :              tristate (tristate::TS_TRUE));
    8498            4 : }
    8499              : 
    8500              : /* Verify that get_representative_path_var works as expected, that
    8501              :    we can map from regions to parms and back within a recursive call
    8502              :    stack.  */
    8503              : 
    8504              : static void
    8505            4 : test_get_representative_path_var ()
    8506              : {
    8507            4 :   auto_vec <tree> param_types;
    8508            4 :   tree fndecl = make_fndecl (integer_type_node,
    8509              :                              "factorial",
    8510              :                              param_types);
    8511            4 :   allocate_struct_function (fndecl, true);
    8512              : 
    8513              :   /* Parm "n".  */
    8514            4 :   tree n = build_decl (UNKNOWN_LOCATION, PARM_DECL,
    8515              :                        get_identifier ("n"),
    8516              :                        integer_type_node);
    8517            4 :   DECL_CONTEXT (n) = fndecl;
    8518              : 
    8519            4 :   region_model_manager mgr;
    8520            4 :   test_region_model_context ctxt;
    8521            4 :   region_model model (&mgr);
    8522              : 
    8523              :   /* Push 5 stack frames for "factorial", each with a param  */
    8524            4 :   auto_vec<const region *> parm_regs;
    8525            4 :   auto_vec<const svalue *> parm_svals;
    8526           24 :   for (int depth = 0; depth < 5; depth++)
    8527              :     {
    8528           20 :       const region *frame_n_reg
    8529           20 :         = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl),
    8530              :                             nullptr, nullptr, &ctxt);
    8531           20 :       const region *parm_n_reg = model.get_lvalue (path_var (n, depth), &ctxt);
    8532           20 :       parm_regs.safe_push (parm_n_reg);
    8533              : 
    8534           20 :       ASSERT_EQ (parm_n_reg->get_parent_region (), frame_n_reg);
    8535           20 :       const svalue *sval_n = mgr.get_or_create_initial_value (parm_n_reg);
    8536           20 :       parm_svals.safe_push (sval_n);
    8537              :     }
    8538              : 
    8539              :   /* Verify that we can recognize that the regions are the parms,
    8540              :      at every depth.  */
    8541           24 :   for (int depth = 0; depth < 5; depth++)
    8542              :     {
    8543           20 :       {
    8544           20 :         svalue_set visited;
    8545           40 :         ASSERT_EQ (model.get_representative_path_var (parm_regs[depth],
    8546              :                                                       &visited,
    8547              :                                                       nullptr),
    8548              :                    path_var (n, depth + 1));
    8549           20 :       }
    8550              :       /* ...and that we can lookup lvalues for locals for all frames,
    8551              :          not just the top.  */
    8552           20 :       ASSERT_EQ (model.get_lvalue (path_var (n, depth), nullptr),
    8553              :                  parm_regs[depth]);
    8554              :       /* ...and that we can locate the svalues.  */
    8555           20 :       {
    8556           20 :         svalue_set visited;
    8557           40 :         ASSERT_EQ (model.get_representative_path_var (parm_svals[depth],
    8558              :                                                       &visited,
    8559              :                                                       nullptr),
    8560              :                    path_var (n, depth + 1));
    8561           20 :       }
    8562              :     }
    8563            4 : }
    8564              : 
    8565              : /* Ensure that region_model::operator== works as expected.  */
    8566              : 
    8567              : static void
    8568            4 : test_equality_1 ()
    8569              : {
    8570            4 :   tree int_42 = build_int_cst (integer_type_node, 42);
    8571            4 :   tree int_17 = build_int_cst (integer_type_node, 17);
    8572              : 
    8573              : /* Verify that "empty" region_model instances are equal to each other.  */
    8574            4 :   region_model_manager mgr;
    8575            4 :   region_model model0 (&mgr);
    8576            4 :   region_model model1 (&mgr);
    8577            4 :   ASSERT_EQ (model0, model1);
    8578              : 
    8579              :   /* Verify that setting state in model1 makes the models non-equal.  */
    8580            4 :   tree x = build_global_decl ("x", integer_type_node);
    8581            4 :   model0.set_value (x, int_42, nullptr);
    8582            4 :   ASSERT_EQ (model0.get_rvalue (x, nullptr)->maybe_get_constant (), int_42);
    8583            4 :   ASSERT_NE (model0, model1);
    8584              : 
    8585              :   /* Verify the copy-ctor.  */
    8586            4 :   region_model model2 (model0);
    8587            4 :   ASSERT_EQ (model0, model2);
    8588            4 :   ASSERT_EQ (model2.get_rvalue (x, nullptr)->maybe_get_constant (), int_42);
    8589            4 :   ASSERT_NE (model1, model2);
    8590              : 
    8591              :   /* Verify that models obtained from copy-ctor are independently editable
    8592              :      w/o affecting the original model.  */
    8593            4 :   model2.set_value (x, int_17, nullptr);
    8594            4 :   ASSERT_NE (model0, model2);
    8595            4 :   ASSERT_EQ (model2.get_rvalue (x, nullptr)->maybe_get_constant (), int_17);
    8596            4 :   ASSERT_EQ (model0.get_rvalue (x, nullptr)->maybe_get_constant (), int_42);
    8597            4 : }
    8598              : 
    8599              : /* Verify that region models for
    8600              :       x = 42; y = 113;
    8601              :    and
    8602              :       y = 113; x = 42;
    8603              :    are equal.  */
    8604              : 
    8605              : static void
    8606            4 : test_canonicalization_2 ()
    8607              : {
    8608            4 :   tree int_42 = build_int_cst (integer_type_node, 42);
    8609            4 :   tree int_113 = build_int_cst (integer_type_node, 113);
    8610            4 :   tree x = build_global_decl ("x", integer_type_node);
    8611            4 :   tree y = build_global_decl ("y", integer_type_node);
    8612              : 
    8613            4 :   region_model_manager mgr;
    8614            4 :   region_model model0 (&mgr);
    8615            4 :   model0.set_value (model0.get_lvalue (x, nullptr),
    8616              :                     model0.get_rvalue (int_42, nullptr),
    8617              :                     nullptr);
    8618            4 :   model0.set_value (model0.get_lvalue (y, nullptr),
    8619              :                     model0.get_rvalue (int_113, nullptr),
    8620              :                     nullptr);
    8621              : 
    8622            4 :   region_model model1 (&mgr);
    8623            4 :   model1.set_value (model1.get_lvalue (y, nullptr),
    8624              :                     model1.get_rvalue (int_113, nullptr),
    8625              :                     nullptr);
    8626            4 :   model1.set_value (model1.get_lvalue (x, nullptr),
    8627              :                     model1.get_rvalue (int_42, nullptr),
    8628              :                     nullptr);
    8629              : 
    8630            4 :   ASSERT_EQ (model0, model1);
    8631            4 : }
    8632              : 
    8633              : /* Verify that constraints for
    8634              :      x > 3 && y > 42
    8635              :    and
    8636              :      y > 42 && x > 3
    8637              :    are equal after canonicalization.  */
    8638              : 
    8639              : static void
    8640            4 : test_canonicalization_3 ()
    8641              : {
    8642            4 :   tree int_3 = build_int_cst (integer_type_node, 3);
    8643            4 :   tree int_42 = build_int_cst (integer_type_node, 42);
    8644            4 :   tree x = build_global_decl ("x", integer_type_node);
    8645            4 :   tree y = build_global_decl ("y", integer_type_node);
    8646              : 
    8647            4 :   region_model_manager mgr;
    8648            4 :   region_model model0 (&mgr);
    8649            4 :   model0.add_constraint (x, GT_EXPR, int_3, nullptr);
    8650            4 :   model0.add_constraint (y, GT_EXPR, int_42, nullptr);
    8651              : 
    8652            4 :   region_model model1 (&mgr);
    8653            4 :   model1.add_constraint (y, GT_EXPR, int_42, nullptr);
    8654            4 :   model1.add_constraint (x, GT_EXPR, int_3, nullptr);
    8655              : 
    8656            4 :   model0.canonicalize ();
    8657            4 :   model1.canonicalize ();
    8658            4 :   ASSERT_EQ (model0, model1);
    8659            4 : }
    8660              : 
    8661              : /* Verify that we can canonicalize a model containing NaN and other real
    8662              :    constants.  */
    8663              : 
    8664              : static void
    8665            4 : test_canonicalization_4 ()
    8666              : {
    8667            4 :   auto_vec<tree> csts;
    8668            4 :   append_interesting_constants (&csts);
    8669              : 
    8670            4 :   region_model_manager mgr;
    8671            4 :   region_model model (&mgr);
    8672              : 
    8673           60 :   for (tree cst : csts)
    8674           48 :     model.get_rvalue (cst, nullptr);
    8675              : 
    8676            4 :   model.canonicalize ();
    8677            4 : }
    8678              : 
    8679              : /* Assert that if we have two region_model instances
    8680              :    with values VAL_A and VAL_B for EXPR that they are
    8681              :    mergeable.  Write the merged model to *OUT_MERGED_MODEL,
    8682              :    and the merged svalue ptr to *OUT_MERGED_SVALUE.
    8683              :    If VAL_A or VAL_B are nullptr_TREE, don't populate EXPR
    8684              :    for that region_model.  */
    8685              : 
    8686              : static void
    8687           20 : assert_region_models_merge (tree expr, tree val_a, tree val_b,
    8688              :                              region_model *out_merged_model,
    8689              :                              const svalue **out_merged_svalue)
    8690              : {
    8691           20 :   region_model_manager *mgr = out_merged_model->get_manager ();
    8692           20 :   program_point point (program_point::origin (*mgr));
    8693           20 :   test_region_model_context ctxt;
    8694           20 :   region_model model0 (mgr);
    8695           20 :   region_model model1 (mgr);
    8696           20 :   if (val_a)
    8697           16 :     model0.set_value (model0.get_lvalue (expr, &ctxt),
    8698              :                       model0.get_rvalue (val_a, &ctxt),
    8699              :                       &ctxt);
    8700           20 :   if (val_b)
    8701           16 :     model1.set_value (model1.get_lvalue (expr, &ctxt),
    8702              :                       model1.get_rvalue (val_b, &ctxt),
    8703              :                       &ctxt);
    8704              : 
    8705              :   /* They should be mergeable.  */
    8706           20 :   ASSERT_TRUE (model0.can_merge_with_p (model1, point, out_merged_model));
    8707           20 :   *out_merged_svalue = out_merged_model->get_rvalue (expr, &ctxt);
    8708           20 : }
    8709              : 
    8710              : /* Verify that we can merge region_model instances.  */
    8711              : 
    8712              : static void
    8713            4 : test_state_merging ()
    8714              : {
    8715            4 :   tree int_42 = build_int_cst (integer_type_node, 42);
    8716            4 :   tree int_113 = build_int_cst (integer_type_node, 113);
    8717            4 :   tree x = build_global_decl ("x", integer_type_node);
    8718            4 :   tree y = build_global_decl ("y", integer_type_node);
    8719            4 :   tree z = build_global_decl ("z", integer_type_node);
    8720            4 :   tree p = build_global_decl ("p", ptr_type_node);
    8721              : 
    8722            4 :   tree addr_of_y = build1 (ADDR_EXPR, ptr_type_node, y);
    8723            4 :   tree addr_of_z = build1 (ADDR_EXPR, ptr_type_node, z);
    8724              : 
    8725            4 :   auto_vec <tree> param_types;
    8726            4 :   tree test_fndecl = make_fndecl (integer_type_node, "test_fn", param_types);
    8727            4 :   allocate_struct_function (test_fndecl, true);
    8728              : 
    8729              :   /* Param "a".  */
    8730            4 :   tree a = build_decl (UNKNOWN_LOCATION, PARM_DECL,
    8731              :                        get_identifier ("a"),
    8732              :                        integer_type_node);
    8733            4 :   DECL_CONTEXT (a) = test_fndecl;
    8734            4 :   tree addr_of_a = build1 (ADDR_EXPR, ptr_type_node, a);
    8735              : 
    8736              :   /* Param "q", a pointer.  */
    8737            4 :   tree q = build_decl (UNKNOWN_LOCATION, PARM_DECL,
    8738              :                        get_identifier ("q"),
    8739              :                        ptr_type_node);
    8740            4 :   DECL_CONTEXT (q) = test_fndecl;
    8741              : 
    8742            4 :   region_model_manager mgr;
    8743            4 :   program_point point (program_point::origin (mgr));
    8744              : 
    8745            4 :   {
    8746            4 :     region_model model0 (&mgr);
    8747            4 :     region_model model1 (&mgr);
    8748            4 :     region_model merged (&mgr);
    8749              :     /* Verify empty models can be merged.  */
    8750            4 :     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    8751            4 :     ASSERT_EQ (model0, merged);
    8752            4 :   }
    8753              : 
    8754              :   /* Verify that we can merge two contradictory constraints on the
    8755              :      value for a global.  */
    8756              :   /* TODO: verify that the merged model doesn't have a value for
    8757              :      the global  */
    8758            4 :   {
    8759            4 :     region_model model0 (&mgr);
    8760            4 :     region_model model1 (&mgr);
    8761            4 :     region_model merged (&mgr);
    8762            4 :     test_region_model_context ctxt;
    8763            4 :     model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
    8764            4 :     model1.add_constraint (x, EQ_EXPR, int_113, &ctxt);
    8765            4 :     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    8766            4 :     ASSERT_NE (model0, merged);
    8767            4 :     ASSERT_NE (model1, merged);
    8768            4 :   }
    8769              : 
    8770              :   /* Verify handling of a PARM_DECL.  */
    8771            4 :   {
    8772            4 :     test_region_model_context ctxt;
    8773            4 :     region_model model0 (&mgr);
    8774            4 :     region_model model1 (&mgr);
    8775            4 :     ASSERT_EQ (model0.get_stack_depth (), 0);
    8776            4 :     model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
    8777              :                        nullptr, nullptr, &ctxt);
    8778            4 :     ASSERT_EQ (model0.get_stack_depth (), 1);
    8779            4 :     model1.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
    8780              :                        nullptr, nullptr, &ctxt);
    8781              : 
    8782            4 :     placeholder_svalue test_sval (mgr.alloc_symbol_id (),
    8783            4 :                                   integer_type_node, "test sval");
    8784            4 :     model0.set_value (model0.get_lvalue (a, &ctxt), &test_sval, &ctxt);
    8785            4 :     model1.set_value (model1.get_lvalue (a, &ctxt), &test_sval, &ctxt);
    8786            4 :     ASSERT_EQ (model0, model1);
    8787              : 
    8788              :     /* They should be mergeable, and the result should be the same.  */
    8789            4 :     region_model merged (&mgr);
    8790            4 :     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    8791            4 :     ASSERT_EQ (model0, merged);
    8792              :     /* In particular, "a" should have the placeholder value.  */
    8793            4 :     ASSERT_EQ (merged.get_rvalue (a, &ctxt), &test_sval);
    8794            4 :   }
    8795              : 
    8796              :   /* Verify handling of a global.  */
    8797            4 :   {
    8798            4 :     test_region_model_context ctxt;
    8799            4 :     region_model model0 (&mgr);
    8800            4 :     region_model model1 (&mgr);
    8801              : 
    8802            4 :     placeholder_svalue test_sval (mgr.alloc_symbol_id (),
    8803            4 :                                   integer_type_node, "test sval");
    8804            4 :     model0.set_value (model0.get_lvalue (x, &ctxt), &test_sval, &ctxt);
    8805            4 :     model1.set_value (model1.get_lvalue (x, &ctxt), &test_sval, &ctxt);
    8806            4 :     ASSERT_EQ (model0, model1);
    8807              : 
    8808              :     /* They should be mergeable, and the result should be the same.  */
    8809            4 :     region_model merged (&mgr);
    8810            4 :     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    8811            4 :     ASSERT_EQ (model0, merged);
    8812              :     /* In particular, "x" should have the placeholder value.  */
    8813            4 :     ASSERT_EQ (merged.get_rvalue (x, &ctxt), &test_sval);
    8814            4 :   }
    8815              : 
    8816              :   /* Use global-handling to verify various combinations of values.  */
    8817              : 
    8818              :   /* Two equal constant values.  */
    8819            4 :   {
    8820            4 :     region_model merged (&mgr);
    8821            4 :     const svalue *merged_x_sval;
    8822            4 :     assert_region_models_merge (x, int_42, int_42, &merged, &merged_x_sval);
    8823              : 
    8824              :     /* In particular, there should be a constant value for "x".  */
    8825            4 :     ASSERT_EQ (merged_x_sval->get_kind (), SK_CONSTANT);
    8826            4 :     ASSERT_EQ (merged_x_sval->dyn_cast_constant_svalue ()->get_constant (),
    8827              :                int_42);
    8828            4 :   }
    8829              : 
    8830              :   /* Two non-equal constant values.  */
    8831            4 :   {
    8832            4 :     region_model merged (&mgr);
    8833            4 :     const svalue *merged_x_sval;
    8834            4 :     assert_region_models_merge (x, int_42, int_113, &merged, &merged_x_sval);
    8835              : 
    8836              :     /* In particular, there should be a "widening" value for "x".  */
    8837            4 :     ASSERT_EQ (merged_x_sval->get_kind (), SK_WIDENING);
    8838            4 :   }
    8839              : 
    8840              :   /* Initial and constant.  */
    8841            4 :   {
    8842            4 :     region_model merged (&mgr);
    8843            4 :     const svalue *merged_x_sval;
    8844            4 :     assert_region_models_merge (x, NULL_TREE, int_113, &merged, &merged_x_sval);
    8845              : 
    8846              :     /* In particular, there should be an unknown value for "x".  */
    8847            4 :     ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
    8848            4 :   }
    8849              : 
    8850              :   /* Constant and initial.  */
    8851            4 :   {
    8852            4 :     region_model merged (&mgr);
    8853            4 :     const svalue *merged_x_sval;
    8854            4 :     assert_region_models_merge (x, int_42, NULL_TREE, &merged, &merged_x_sval);
    8855              : 
    8856              :     /* In particular, there should be an unknown value for "x".  */
    8857            4 :     ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
    8858            4 :   }
    8859              : 
    8860              :   /* Unknown and constant.  */
    8861              :   // TODO
    8862              : 
    8863              :   /* Pointers: NULL and NULL.  */
    8864              :   // TODO
    8865              : 
    8866              :   /* Pointers: NULL and non-NULL.  */
    8867              :   // TODO
    8868              : 
    8869              :   /* Pointers: non-NULL and non-NULL: ptr to a local.  */
    8870            4 :   {
    8871            4 :     region_model model0 (&mgr);
    8872            4 :     model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
    8873              :                        nullptr, nullptr, nullptr);
    8874            4 :     model0.set_value (model0.get_lvalue (p, nullptr),
    8875              :                       model0.get_rvalue (addr_of_a, nullptr), nullptr);
    8876              : 
    8877            4 :     region_model model1 (model0);
    8878            4 :     ASSERT_EQ (model0, model1);
    8879              : 
    8880              :     /* They should be mergeable, and the result should be the same.  */
    8881            4 :     region_model merged (&mgr);
    8882            4 :     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    8883            4 :     ASSERT_EQ (model0, merged);
    8884            4 :   }
    8885              : 
    8886              :   /* Pointers: non-NULL and non-NULL: ptr to a global.  */
    8887            4 :   {
    8888            4 :     region_model merged (&mgr);
    8889              :     /* p == &y in both input models.  */
    8890            4 :     const svalue *merged_p_sval;
    8891            4 :     assert_region_models_merge (p, addr_of_y, addr_of_y, &merged,
    8892              :                                 &merged_p_sval);
    8893              : 
    8894              :     /* We should get p == &y in the merged model.  */
    8895            4 :     ASSERT_EQ (merged_p_sval->get_kind (), SK_REGION);
    8896            4 :     const region_svalue *merged_p_ptr
    8897            4 :       = merged_p_sval->dyn_cast_region_svalue ();
    8898            4 :     const region *merged_p_star_reg = merged_p_ptr->get_pointee ();
    8899            4 :     ASSERT_EQ (merged_p_star_reg, merged.get_lvalue (y, nullptr));
    8900            4 :   }
    8901              : 
    8902              :   /* Pointers: non-NULL ptrs to different globals should not merge;
    8903              :      see e.g. gcc.dg/analyzer/torture/uninit-pr108725.c  */
    8904            4 :   {
    8905            4 :     region_model merged_model (&mgr);
    8906            4 :     program_point point (program_point::origin (mgr));
    8907            4 :     test_region_model_context ctxt;
    8908              :     /* x == &y vs x == &z in the input models; these are actually casts
    8909              :        of the ptrs to "int".  */
    8910            4 :     region_model model0 (&mgr);
    8911            4 :     region_model model1 (&mgr);
    8912            4 :     model0.set_value (model0.get_lvalue (x, &ctxt),
    8913              :                       model0.get_rvalue (addr_of_y, &ctxt),
    8914              :                       &ctxt);
    8915            4 :     model1.set_value (model1.get_lvalue (x, &ctxt),
    8916              :                       model1.get_rvalue (addr_of_z, &ctxt),
    8917              :                       &ctxt);
    8918              :     /* They should not be mergeable.  */
    8919            4 :     ASSERT_FALSE (model0.can_merge_with_p (model1, point, &merged_model));
    8920            4 :   }
    8921              : 
    8922              :   /* Pointers: non-NULL and non-NULL: ptr to a heap region.  */
    8923            4 :   {
    8924            4 :     test_region_model_context ctxt;
    8925            4 :     region_model model0 (&mgr);
    8926            4 :     tree size = build_int_cst (size_type_node, 1024);
    8927            4 :     const svalue *size_sval = mgr.get_or_create_constant_svalue (size);
    8928            4 :     const region *new_reg
    8929            4 :       = model0.get_or_create_region_for_heap_alloc (size_sval, &ctxt);
    8930            4 :     const svalue *ptr_sval = mgr.get_ptr_svalue (ptr_type_node, new_reg);
    8931            4 :     model0.set_value (model0.get_lvalue (p, &ctxt),
    8932              :                       ptr_sval, &ctxt);
    8933              : 
    8934            4 :     region_model model1 (model0);
    8935              : 
    8936            4 :     ASSERT_EQ (model0, model1);
    8937              : 
    8938            4 :     region_model merged (&mgr);
    8939            4 :     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    8940              : 
    8941              :     /* The merged model ought to be identical.  */
    8942            4 :     ASSERT_EQ (model0, merged);
    8943            4 :   }
    8944              : 
    8945              :   /* Two regions sharing the same placeholder svalue should continue sharing
    8946              :      it after self-merger.  */
    8947            4 :   {
    8948            4 :     test_region_model_context ctxt;
    8949            4 :     region_model model0 (&mgr);
    8950            4 :     placeholder_svalue placeholder_sval (mgr.alloc_symbol_id (),
    8951            4 :                                          integer_type_node, "test");
    8952            4 :     model0.set_value (model0.get_lvalue (x, &ctxt),
    8953              :                       &placeholder_sval, &ctxt);
    8954            4 :     model0.set_value (model0.get_lvalue (y, &ctxt), &placeholder_sval, &ctxt);
    8955            4 :     region_model model1 (model0);
    8956              : 
    8957              :     /* They should be mergeable, and the result should be the same.  */
    8958            4 :     region_model merged (&mgr);
    8959            4 :     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    8960            4 :     ASSERT_EQ (model0, merged);
    8961              : 
    8962              :     /* In particular, we should have x == y.  */
    8963            4 :     ASSERT_EQ (merged.eval_condition (x, EQ_EXPR, y, &ctxt),
    8964              :                tristate (tristate::TS_TRUE));
    8965            4 :   }
    8966              : 
    8967            4 :   {
    8968            4 :     region_model model0 (&mgr);
    8969            4 :     region_model model1 (&mgr);
    8970            4 :     test_region_model_context ctxt;
    8971            4 :     model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
    8972            4 :     model1.add_constraint (x, NE_EXPR, int_42, &ctxt);
    8973            4 :     region_model merged (&mgr);
    8974            4 :     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    8975            4 :   }
    8976              : 
    8977            4 :   {
    8978            4 :     region_model model0 (&mgr);
    8979            4 :     region_model model1 (&mgr);
    8980            4 :     test_region_model_context ctxt;
    8981            4 :     model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
    8982            4 :     model1.add_constraint (x, NE_EXPR, int_42, &ctxt);
    8983            4 :     model1.add_constraint (x, EQ_EXPR, int_113, &ctxt);
    8984            4 :     region_model merged (&mgr);
    8985            4 :     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    8986            4 :   }
    8987              : 
    8988              :   // TODO: what can't we merge? need at least one such test
    8989              : 
    8990              :   /* TODO: various things
    8991              :      - heap regions
    8992              :      - value merging:
    8993              :        - every combination, but in particular
    8994              :            - pairs of regions
    8995              :    */
    8996              : 
    8997              :   /* Views.  */
    8998            4 :   {
    8999            4 :     test_region_model_context ctxt;
    9000            4 :     region_model model0 (&mgr);
    9001              : 
    9002            4 :     const region *x_reg = model0.get_lvalue (x, &ctxt);
    9003            4 :     const region *x_as_ptr = mgr.get_cast_region (x_reg, ptr_type_node);
    9004            4 :     model0.set_value (x_as_ptr, model0.get_rvalue (addr_of_y, &ctxt), &ctxt);
    9005              : 
    9006            4 :     region_model model1 (model0);
    9007            4 :     ASSERT_EQ (model1, model0);
    9008              : 
    9009              :     /* They should be mergeable, and the result should be the same.  */
    9010            4 :     region_model merged (&mgr);
    9011            4 :     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    9012            4 :   }
    9013              : 
    9014              :   /* Verify that we can merge a model in which a local in an older stack
    9015              :      frame points to a local in a more recent stack frame.  */
    9016            4 :   {
    9017            4 :     region_model model0 (&mgr);
    9018            4 :     model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
    9019              :                        nullptr, nullptr, nullptr);
    9020            4 :     const region *q_in_first_frame = model0.get_lvalue (q, nullptr);
    9021              : 
    9022              :     /* Push a second frame.  */
    9023            4 :     const region *reg_2nd_frame
    9024            4 :       = model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
    9025              :                            nullptr, nullptr, nullptr);
    9026              : 
    9027              :     /* Have a pointer in the older frame point to a local in the
    9028              :        more recent frame.  */
    9029            4 :     const svalue *sval_ptr = model0.get_rvalue (addr_of_a, nullptr);
    9030            4 :     model0.set_value (q_in_first_frame, sval_ptr, nullptr);
    9031              : 
    9032              :     /* Verify that it's pointing at the newer frame.  */
    9033            4 :     const region *reg_pointee = sval_ptr->maybe_get_region ();
    9034            4 :     ASSERT_EQ (reg_pointee->get_parent_region (), reg_2nd_frame);
    9035              : 
    9036            4 :     model0.canonicalize ();
    9037              : 
    9038            4 :     region_model model1 (model0);
    9039            4 :     ASSERT_EQ (model0, model1);
    9040              : 
    9041              :     /* They should be mergeable, and the result should be the same
    9042              :        (after canonicalization, at least).  */
    9043            4 :     region_model merged (&mgr);
    9044            4 :     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    9045            4 :     merged.canonicalize ();
    9046            4 :     ASSERT_EQ (model0, merged);
    9047            4 :   }
    9048              : 
    9049              :   /* Verify that we can merge a model in which a local points to a global.  */
    9050            4 :   {
    9051            4 :     region_model model0 (&mgr);
    9052            4 :     model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
    9053              :                        nullptr, nullptr, nullptr);
    9054            4 :     model0.set_value (model0.get_lvalue (q, nullptr),
    9055              :                       model0.get_rvalue (addr_of_y, nullptr), nullptr);
    9056              : 
    9057            4 :     region_model model1 (model0);
    9058            4 :     ASSERT_EQ (model0, model1);
    9059              : 
    9060              :     /* They should be mergeable, and the result should be the same
    9061              :        (after canonicalization, at least).  */
    9062            4 :     region_model merged (&mgr);
    9063            4 :     ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    9064            4 :     ASSERT_EQ (model0, merged);
    9065            4 :   }
    9066            4 : }
    9067              : 
    9068              : /* Verify that constraints are correctly merged when merging region_model
    9069              :    instances.  */
    9070              : 
    9071              : static void
    9072            4 : test_constraint_merging ()
    9073              : {
    9074            4 :   tree int_0 = integer_zero_node;
    9075            4 :   tree int_5 = build_int_cst (integer_type_node, 5);
    9076            4 :   tree x = build_global_decl ("x", integer_type_node);
    9077            4 :   tree y = build_global_decl ("y", integer_type_node);
    9078            4 :   tree z = build_global_decl ("z", integer_type_node);
    9079            4 :   tree n = build_global_decl ("n", integer_type_node);
    9080              : 
    9081            4 :   region_model_manager mgr;
    9082            4 :   test_region_model_context ctxt;
    9083              : 
    9084              :   /* model0: 0 <= (x == y) < n.  */
    9085            4 :   region_model model0 (&mgr);
    9086            4 :   model0.add_constraint (x, EQ_EXPR, y, &ctxt);
    9087            4 :   model0.add_constraint (x, GE_EXPR, int_0, nullptr);
    9088            4 :   model0.add_constraint (x, LT_EXPR, n, nullptr);
    9089              : 
    9090              :   /* model1: z != 5 && (0 <= x < n).  */
    9091            4 :   region_model model1 (&mgr);
    9092            4 :   model1.add_constraint (z, NE_EXPR, int_5, nullptr);
    9093            4 :   model1.add_constraint (x, GE_EXPR, int_0, nullptr);
    9094            4 :   model1.add_constraint (x, LT_EXPR, n, nullptr);
    9095              : 
    9096              :   /* They should be mergeable; the merged constraints should
    9097              :      be: (0 <= x < n).  */
    9098            4 :   program_point point (program_point::origin (mgr));
    9099            4 :   region_model merged (&mgr);
    9100            4 :   ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
    9101              : 
    9102            4 :   ASSERT_EQ (merged.eval_condition (x, GE_EXPR, int_0, &ctxt),
    9103              :              tristate (tristate::TS_TRUE));
    9104            4 :   ASSERT_EQ (merged.eval_condition (x, LT_EXPR, n, &ctxt),
    9105              :              tristate (tristate::TS_TRUE));
    9106              : 
    9107            4 :   ASSERT_EQ (merged.eval_condition (z, NE_EXPR, int_5, &ctxt),
    9108              :              tristate (tristate::TS_UNKNOWN));
    9109            4 :   ASSERT_EQ (merged.eval_condition (x, LT_EXPR, y, &ctxt),
    9110              :              tristate (tristate::TS_UNKNOWN));
    9111            4 : }
    9112              : 
    9113              : /* Verify that widening_svalue::eval_condition_without_cm works as
    9114              :    expected.  */
    9115              : 
    9116              : static void
    9117            4 : test_widening_constraints ()
    9118              : {
    9119            4 :   region_model_manager mgr;
    9120            4 :   const supernode *snode = nullptr;
    9121            4 :   tree int_0 = integer_zero_node;
    9122            4 :   tree int_m1 = build_int_cst (integer_type_node, -1);
    9123            4 :   tree int_1 = integer_one_node;
    9124            4 :   tree int_256 = build_int_cst (integer_type_node, 256);
    9125            4 :   test_region_model_context ctxt;
    9126            4 :   const svalue *int_0_sval = mgr.get_or_create_constant_svalue (int_0);
    9127            4 :   const svalue *int_1_sval = mgr.get_or_create_constant_svalue (int_1);
    9128            4 :   const svalue *w_zero_then_one_sval
    9129            4 :     = mgr.get_or_create_widening_svalue (integer_type_node, snode,
    9130              :                                           int_0_sval, int_1_sval);
    9131            4 :   const widening_svalue *w_zero_then_one
    9132            4 :     = w_zero_then_one_sval->dyn_cast_widening_svalue ();
    9133            4 :   ASSERT_EQ (w_zero_then_one->get_direction (),
    9134              :              widening_svalue::DIR_ASCENDING);
    9135            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LT_EXPR, int_m1),
    9136              :              tristate::TS_FALSE);
    9137            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LT_EXPR, int_0),
    9138              :              tristate::TS_FALSE);
    9139            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LT_EXPR, int_1),
    9140              :              tristate::TS_UNKNOWN);
    9141            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LT_EXPR, int_256),
    9142              :              tristate::TS_UNKNOWN);
    9143              : 
    9144            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LE_EXPR, int_m1),
    9145              :              tristate::TS_FALSE);
    9146            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LE_EXPR, int_0),
    9147              :              tristate::TS_UNKNOWN);
    9148            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LE_EXPR, int_1),
    9149              :              tristate::TS_UNKNOWN);
    9150            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LE_EXPR, int_256),
    9151              :              tristate::TS_UNKNOWN);
    9152              : 
    9153            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GT_EXPR, int_m1),
    9154              :              tristate::TS_TRUE);
    9155            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GT_EXPR, int_0),
    9156              :              tristate::TS_UNKNOWN);
    9157            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GT_EXPR, int_1),
    9158              :              tristate::TS_UNKNOWN);
    9159            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GT_EXPR, int_256),
    9160              :              tristate::TS_UNKNOWN);
    9161              : 
    9162            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GE_EXPR, int_m1),
    9163              :              tristate::TS_TRUE);
    9164            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GE_EXPR, int_0),
    9165              :              tristate::TS_TRUE);
    9166            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GE_EXPR, int_1),
    9167              :              tristate::TS_UNKNOWN);
    9168            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GE_EXPR, int_256),
    9169              :              tristate::TS_UNKNOWN);
    9170              : 
    9171            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (EQ_EXPR, int_m1),
    9172              :              tristate::TS_FALSE);
    9173            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (EQ_EXPR, int_0),
    9174              :              tristate::TS_UNKNOWN);
    9175            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (EQ_EXPR, int_1),
    9176              :              tristate::TS_UNKNOWN);
    9177            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (EQ_EXPR, int_256),
    9178              :              tristate::TS_UNKNOWN);
    9179              : 
    9180            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (NE_EXPR, int_m1),
    9181              :              tristate::TS_TRUE);
    9182            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (NE_EXPR, int_0),
    9183              :              tristate::TS_UNKNOWN);
    9184            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (NE_EXPR, int_1),
    9185              :              tristate::TS_UNKNOWN);
    9186            4 :   ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (NE_EXPR, int_256),
    9187              :              tristate::TS_UNKNOWN);
    9188            4 : }
    9189              : 
    9190              : /* Verify merging constraints for states simulating successive iterations
    9191              :    of a loop.
    9192              :    Simulate:
    9193              :      for (i = 0; i < 256; i++)
    9194              :        [...body...]
    9195              :    i.e. this gimple:.
    9196              :      i_15 = 0;
    9197              :      goto <bb 4>;
    9198              : 
    9199              :    <bb 4> :
    9200              :      i_11 = PHI <i_15(2), i_23(3)>
    9201              :      if (i_11 <= 255)
    9202              :        goto <bb 3>;
    9203              :      else
    9204              :        goto [AFTER LOOP]
    9205              : 
    9206              :    <bb 3> :
    9207              :      [LOOP BODY]
    9208              :      i_23 = i_11 + 1;
    9209              : 
    9210              :    and thus these ops (and resultant states):
    9211              :      i_11 = PHI()
    9212              :        {i_11: 0}
    9213              :      add_constraint (i_11 <= 255) [for the true edge]
    9214              :        {i_11: 0}  [constraint was a no-op]
    9215              :      i_23 = i_11 + 1;
    9216              :        {i_22: 1}
    9217              :      i_11 = PHI()
    9218              :        {i_11: WIDENED (at phi, 0, 1)}
    9219              :      add_constraint (i_11 <= 255) [for the true edge]
    9220              :        {i_11: WIDENED (at phi, 0, 1); WIDENED <= 255}
    9221              :      i_23 = i_11 + 1;
    9222              :        {i_23: (WIDENED (at phi, 0, 1) + 1); WIDENED <= 255}
    9223              :      i_11 = PHI(); merge with state at phi above
    9224              :        {i_11: WIDENED (at phi, 0, 1); WIDENED <= 256}
    9225              :          [changing meaning of "WIDENED" here]
    9226              :      if (i_11 <= 255)
    9227              :         T: {i_11: WIDENED (at phi, 0, 1); WIDENED <= 255}; cache hit
    9228              :         F: {i_11: 256}
    9229              :  */
    9230              : 
    9231              : static void
    9232            4 : test_iteration_1 ()
    9233              : {
    9234            4 :   region_model_manager mgr;
    9235            4 :   program_point point (program_point::origin (mgr));
    9236              : 
    9237            4 :   tree int_0 = integer_zero_node;
    9238            4 :   tree int_1 = integer_one_node;
    9239            4 :   tree int_256 = build_int_cst (integer_type_node, 256);
    9240            4 :   tree i = build_global_decl ("i", integer_type_node);
    9241              : 
    9242            4 :   test_region_model_context ctxt;
    9243              : 
    9244              :   /* model0: i: 0.  */
    9245            4 :   region_model model0 (&mgr);
    9246            4 :   model0.set_value (i, int_0, &ctxt);
    9247              : 
    9248              :   /* model1: i: 1.  */
    9249            4 :   region_model model1 (&mgr);
    9250            4 :   model1.set_value (i, int_1, &ctxt);
    9251              : 
    9252              :   /* Should merge "i" to a widened value.  */
    9253            4 :   region_model model2 (&mgr);
    9254            4 :   ASSERT_TRUE (model1.can_merge_with_p (model0, point, &model2));
    9255            4 :   const svalue *merged_i = model2.get_rvalue (i, &ctxt);
    9256            4 :   ASSERT_EQ (merged_i->get_kind (), SK_WIDENING);
    9257            4 :   const widening_svalue *w = merged_i->dyn_cast_widening_svalue ();
    9258            4 :   ASSERT_EQ (w->get_direction (), widening_svalue::DIR_ASCENDING);
    9259              : 
    9260              :   /* Add constraint: i < 256  */
    9261            4 :   model2.add_constraint (i, LT_EXPR, int_256, &ctxt);
    9262            4 :   ASSERT_EQ (model2.eval_condition (i, LT_EXPR, int_256, &ctxt),
    9263              :              tristate (tristate::TS_TRUE));
    9264            4 :   ASSERT_EQ (model2.eval_condition (i, GE_EXPR, int_0, &ctxt),
    9265              :              tristate (tristate::TS_TRUE));
    9266              : 
    9267              :   /* Try merging with the initial state.  */
    9268            4 :   region_model model3 (&mgr);
    9269            4 :   ASSERT_TRUE (model2.can_merge_with_p (model0, point, &model3));
    9270              :   /* Merging the merged value with the initial value should be idempotent,
    9271              :      so that the analysis converges.  */
    9272            4 :   ASSERT_EQ (model3.get_rvalue (i, &ctxt), merged_i);
    9273              :   /* Merger of 0 and a widening value with constraint < CST
    9274              :      should retain the constraint, even though it was implicit
    9275              :      for the 0 case.  */
    9276            4 :   ASSERT_EQ (model3.eval_condition (i, LT_EXPR, int_256, &ctxt),
    9277              :              tristate (tristate::TS_TRUE));
    9278              :   /* ...and we should have equality: the analysis should have converged.  */
    9279            4 :   ASSERT_EQ (model3, model2);
    9280              : 
    9281              :   /* "i_23 = i_11 + 1;"  */
    9282            4 :   region_model model4 (model3);
    9283            4 :   ASSERT_EQ (model4, model2);
    9284            4 :   model4.set_value (i, build2 (PLUS_EXPR, integer_type_node, i, int_1), &ctxt);
    9285            4 :   const svalue *plus_one = model4.get_rvalue (i, &ctxt);
    9286            4 :   ASSERT_EQ (plus_one->get_kind (), SK_BINOP);
    9287              : 
    9288              :   /* Try merging with the "i: 1" state.  */
    9289            4 :   region_model model5 (&mgr);
    9290            4 :   ASSERT_TRUE (model4.can_merge_with_p (model1, point, &model5));
    9291            4 :   ASSERT_EQ (model5.get_rvalue (i, &ctxt), plus_one);
    9292            4 :   ASSERT_EQ (model5, model4);
    9293              : 
    9294              :   /* "i_11 = PHI();" merge with state at phi above.
    9295              :      For i, we should have a merger of WIDENING with WIDENING + 1,
    9296              :      and this should be WIDENING again.  */
    9297            4 :   region_model model6 (&mgr);
    9298            4 :   ASSERT_TRUE (model5.can_merge_with_p (model2, point, &model6));
    9299            4 :   const svalue *merged_widening = model6.get_rvalue (i, &ctxt);
    9300            4 :   ASSERT_EQ (merged_widening->get_kind (), SK_WIDENING);
    9301            4 : }
    9302              : 
    9303              : /* Verify that if we mark a pointer to a malloc-ed region as non-NULL,
    9304              :    all cast pointers to that region are also known to be non-NULL.  */
    9305              : 
    9306              : static void
    9307            4 : test_malloc_constraints ()
    9308              : {
    9309            4 :   region_model_manager mgr;
    9310            4 :   region_model model (&mgr);
    9311            4 :   tree p = build_global_decl ("p", ptr_type_node);
    9312            4 :   tree char_star = build_pointer_type (char_type_node);
    9313            4 :   tree q = build_global_decl ("q", char_star);
    9314            4 :   tree null_ptr = build_int_cst (ptr_type_node, 0);
    9315              : 
    9316            4 :   const svalue *size_in_bytes
    9317            4 :     = mgr.get_or_create_unknown_svalue (size_type_node);
    9318            4 :   const region *reg
    9319            4 :     = model.get_or_create_region_for_heap_alloc (size_in_bytes, nullptr);
    9320            4 :   const svalue *sval = mgr.get_ptr_svalue (ptr_type_node, reg);
    9321            4 :   model.set_value (model.get_lvalue (p, nullptr), sval, nullptr);
    9322            4 :   model.set_value (q, p, nullptr);
    9323              : 
    9324            4 :   ASSERT_CONDITION_UNKNOWN (model, p, NE_EXPR, null_ptr);
    9325            4 :   ASSERT_CONDITION_UNKNOWN (model, p, EQ_EXPR, null_ptr);
    9326            4 :   ASSERT_CONDITION_UNKNOWN (model, q, NE_EXPR, null_ptr);
    9327            4 :   ASSERT_CONDITION_UNKNOWN (model, q, EQ_EXPR, null_ptr);
    9328              : 
    9329            4 :   model.add_constraint (p, NE_EXPR, null_ptr, nullptr);
    9330              : 
    9331            4 :   ASSERT_CONDITION_TRUE (model, p, NE_EXPR, null_ptr);
    9332            4 :   ASSERT_CONDITION_FALSE (model, p, EQ_EXPR, null_ptr);
    9333            4 :   ASSERT_CONDITION_TRUE (model, q, NE_EXPR, null_ptr);
    9334            4 :   ASSERT_CONDITION_FALSE (model, q, EQ_EXPR, null_ptr);
    9335            4 : }
    9336              : 
    9337              : /* Smoketest of getting and setting the value of a variable.  */
    9338              : 
    9339              : static void
    9340            4 : test_var ()
    9341              : {
    9342              :   /* "int i;"  */
    9343            4 :   tree i = build_global_decl ("i", integer_type_node);
    9344              : 
    9345            4 :   tree int_17 = build_int_cst (integer_type_node, 17);
    9346            4 :   tree int_m3 = build_int_cst (integer_type_node, -3);
    9347              : 
    9348            4 :   region_model_manager mgr;
    9349            4 :   region_model model (&mgr);
    9350              : 
    9351            4 :   const region *i_reg = model.get_lvalue (i, nullptr);
    9352            4 :   ASSERT_EQ (i_reg->get_kind (), RK_DECL);
    9353              : 
    9354              :   /* Reading "i" should give a symbolic "initial value".  */
    9355            4 :   const svalue *sval_init = model.get_rvalue (i, nullptr);
    9356            4 :   ASSERT_EQ (sval_init->get_kind (), SK_INITIAL);
    9357            4 :   ASSERT_EQ (sval_init->dyn_cast_initial_svalue ()->get_region (), i_reg);
    9358              :   /* ..and doing it again should give the same "initial value".  */
    9359            4 :   ASSERT_EQ (model.get_rvalue (i, nullptr), sval_init);
    9360              : 
    9361              :   /* "i = 17;".  */
    9362            4 :   model.set_value (i, int_17, nullptr);
    9363            4 :   ASSERT_EQ (model.get_rvalue (i, nullptr),
    9364              :              model.get_rvalue (int_17, nullptr));
    9365              : 
    9366              :   /* "i = -3;".  */
    9367            4 :   model.set_value (i, int_m3, nullptr);
    9368            4 :   ASSERT_EQ (model.get_rvalue (i, nullptr),
    9369              :              model.get_rvalue (int_m3, nullptr));
    9370              : 
    9371              :   /* Verify get_offset for "i".  */
    9372            4 :   {
    9373            4 :     region_offset offset = i_reg->get_offset (&mgr);
    9374            4 :     ASSERT_EQ (offset.get_base_region (), i_reg);
    9375            4 :     ASSERT_EQ (offset.get_bit_offset (), 0);
    9376              :   }
    9377            4 : }
    9378              : 
    9379              : static void
    9380            4 : test_array_2 ()
    9381              : {
    9382              :   /* "int arr[10];"  */
    9383            4 :   tree tlen = size_int (10);
    9384            4 :   tree arr_type
    9385            4 :     = build_array_type (integer_type_node, build_index_type (tlen));
    9386            4 :   tree arr = build_global_decl ("arr", arr_type);
    9387              : 
    9388              :   /* "int i;"  */
    9389            4 :   tree i = build_global_decl ("i", integer_type_node);
    9390              : 
    9391            4 :   tree int_0 = integer_zero_node;
    9392            4 :   tree int_1 = integer_one_node;
    9393              : 
    9394            4 :   tree arr_0 = build4 (ARRAY_REF, integer_type_node,
    9395              :                        arr, int_0, NULL_TREE, NULL_TREE);
    9396            4 :   tree arr_1 = build4 (ARRAY_REF, integer_type_node,
    9397              :                        arr, int_1, NULL_TREE, NULL_TREE);
    9398            4 :   tree arr_i = build4 (ARRAY_REF, integer_type_node,
    9399              :                        arr, i, NULL_TREE, NULL_TREE);
    9400              : 
    9401            4 :   tree int_17 = build_int_cst (integer_type_node, 17);
    9402            4 :   tree int_42 = build_int_cst (integer_type_node, 42);
    9403            4 :   tree int_m3 = build_int_cst (integer_type_node, -3);
    9404              : 
    9405            4 :   region_model_manager mgr;
    9406            4 :   region_model model (&mgr);
    9407              :   /* "arr[0] = 17;".  */
    9408            4 :   model.set_value (arr_0, int_17, nullptr);
    9409              :   /* "arr[1] = -3;".  */
    9410            4 :   model.set_value (arr_1, int_m3, nullptr);
    9411              : 
    9412            4 :   ASSERT_EQ (model.get_rvalue (arr_0, nullptr),
    9413              :              model.get_rvalue (int_17, nullptr));
    9414            4 :   ASSERT_EQ (model.get_rvalue (arr_1, nullptr),
    9415              :              model.get_rvalue (int_m3, nullptr));
    9416              : 
    9417              :   /* Overwrite a pre-existing binding: "arr[1] = 42;".  */
    9418            4 :   model.set_value (arr_1, int_42, nullptr);
    9419            4 :   ASSERT_EQ (model.get_rvalue (arr_1, nullptr),
    9420              :              model.get_rvalue (int_42, nullptr));
    9421              : 
    9422              :   /* Verify get_offset for "arr[0]".  */
    9423            4 :   {
    9424            4 :     const region *arr_0_reg = model.get_lvalue (arr_0, nullptr);
    9425            4 :     region_offset offset = arr_0_reg->get_offset (&mgr);
    9426            4 :     ASSERT_EQ (offset.get_base_region (), model.get_lvalue (arr, nullptr));
    9427            4 :     ASSERT_EQ (offset.get_bit_offset (), 0);
    9428              :   }
    9429              : 
    9430              :   /* Verify get_offset for "arr[1]".  */
    9431            4 :   {
    9432            4 :     const region *arr_1_reg = model.get_lvalue (arr_1, nullptr);
    9433            4 :     region_offset offset = arr_1_reg->get_offset (&mgr);
    9434            4 :     ASSERT_EQ (offset.get_base_region (), model.get_lvalue (arr, nullptr));
    9435            4 :     ASSERT_EQ (offset.get_bit_offset (), INT_TYPE_SIZE);
    9436              :   }
    9437              : 
    9438              :   /* Verify get_offset for "arr[i]".  */
    9439            4 :   {
    9440            4 :     const region *arr_i_reg = model.get_lvalue (arr_i, nullptr);
    9441            4 :     region_offset offset = arr_i_reg->get_offset (&mgr);
    9442            4 :     ASSERT_EQ (offset.get_base_region (), model.get_lvalue (arr, nullptr));
    9443            4 :     const svalue *offset_sval = offset.get_symbolic_byte_offset ();
    9444            4 :     if (const svalue *cast = offset_sval->maybe_undo_cast ())
    9445            4 :       offset_sval = cast;
    9446            4 :     ASSERT_EQ (offset_sval->get_kind (), SK_BINOP);
    9447              :   }
    9448              : 
    9449              :   /* "arr[i] = i;" - this should remove the earlier bindings.  */
    9450            4 :   model.set_value (arr_i, i, nullptr);
    9451            4 :   ASSERT_EQ (model.get_rvalue (arr_i, nullptr), model.get_rvalue (i, nullptr));
    9452            4 :   ASSERT_EQ (model.get_rvalue (arr_0, nullptr)->get_kind (), SK_UNKNOWN);
    9453              : 
    9454              :   /* "arr[0] = 17;" - this should remove the arr[i] binding.  */
    9455            4 :   model.set_value (arr_0, int_17, nullptr);
    9456            4 :   ASSERT_EQ (model.get_rvalue (arr_0, nullptr),
    9457              :              model.get_rvalue (int_17, nullptr));
    9458            4 :   ASSERT_EQ (model.get_rvalue (arr_i, nullptr)->get_kind (), SK_UNKNOWN);
    9459            4 : }
    9460              : 
    9461              : /* Smoketest of dereferencing a pointer via MEM_REF.  */
    9462              : 
    9463              : static void
    9464            4 : test_mem_ref ()
    9465              : {
    9466              :   /*
    9467              :     x = 17;
    9468              :     p = &x;
    9469              :     *p;
    9470              :    */
    9471            4 :   tree x = build_global_decl ("x", integer_type_node);
    9472            4 :   tree int_star = build_pointer_type (integer_type_node);
    9473            4 :   tree p = build_global_decl ("p", int_star);
    9474              : 
    9475            4 :   tree int_17 = build_int_cst (integer_type_node, 17);
    9476            4 :   tree addr_of_x = build1 (ADDR_EXPR, int_star, x);
    9477            4 :   tree ptype = build_pointer_type_for_mode (char_type_node, ptr_mode, true);
    9478            4 :   tree offset_0 = build_int_cst (ptype, 0);
    9479            4 :   tree star_p = build2 (MEM_REF, integer_type_node, p, offset_0);
    9480              : 
    9481            4 :   region_model_manager mgr;
    9482            4 :   region_model model (&mgr);
    9483              : 
    9484              :   /* "x = 17;".  */
    9485            4 :   model.set_value (x, int_17, nullptr);
    9486              : 
    9487              :   /* "p = &x;".  */
    9488            4 :   model.set_value (p, addr_of_x, nullptr);
    9489              : 
    9490            4 :   const svalue *sval = model.get_rvalue (star_p, nullptr);
    9491            4 :   ASSERT_EQ (sval->maybe_get_constant (), int_17);
    9492            4 : }
    9493              : 
    9494              : /* Test for a POINTER_PLUS_EXPR followed by a MEM_REF.
    9495              :    Analogous to this code:
    9496              :      void test_6 (int a[10])
    9497              :      {
    9498              :        __analyzer_eval (a[3] == 42); [should be UNKNOWN]
    9499              :        a[3] = 42;
    9500              :        __analyzer_eval (a[3] == 42); [should be TRUE]
    9501              :      }
    9502              :    from data-model-1.c, which looks like this at the gimple level:
    9503              :        # __analyzer_eval (a[3] == 42); [should be UNKNOWN]
    9504              :        int *_1 = a_10(D) + 12;   # POINTER_PLUS_EXPR
    9505              :        int _2 = *_1;             # MEM_REF
    9506              :        _Bool _3 = _2 == 42;
    9507              :        int _4 = (int) _3;
    9508              :        __analyzer_eval (_4);
    9509              : 
    9510              :        # a[3] = 42;
    9511              :        int *_5 = a_10(D) + 12;   # POINTER_PLUS_EXPR
    9512              :        *_5 = 42;                 # MEM_REF
    9513              : 
    9514              :        # __analyzer_eval (a[3] == 42); [should be TRUE]
    9515              :        int *_6 = a_10(D) + 12;   # POINTER_PLUS_EXPR
    9516              :        int _7 = *_6;             # MEM_REF
    9517              :        _Bool _8 = _7 == 42;
    9518              :        int _9 = (int) _8;
    9519              :        __analyzer_eval (_9);  */
    9520              : 
    9521              : static void
    9522            4 : test_POINTER_PLUS_EXPR_then_MEM_REF ()
    9523              : {
    9524            4 :   tree int_star = build_pointer_type (integer_type_node);
    9525            4 :   tree a = build_global_decl ("a", int_star);
    9526            4 :   tree offset_12 = build_int_cst (size_type_node, 12);
    9527            4 :   tree pointer_plus_expr = build2 (POINTER_PLUS_EXPR, int_star, a, offset_12);
    9528            4 :   tree ptype = build_pointer_type_for_mode (char_type_node, ptr_mode, true);
    9529            4 :   tree offset_0 = build_int_cst (ptype, 0);
    9530            4 :   tree mem_ref = build2 (MEM_REF, integer_type_node,
    9531              :                          pointer_plus_expr, offset_0);
    9532            4 :   region_model_manager mgr;
    9533            4 :   region_model m (&mgr);
    9534              : 
    9535            4 :   tree int_42 = build_int_cst (integer_type_node, 42);
    9536            4 :   m.set_value (mem_ref, int_42, nullptr);
    9537            4 :   ASSERT_EQ (m.get_rvalue (mem_ref, nullptr)->maybe_get_constant (), int_42);
    9538            4 : }
    9539              : 
    9540              : /* Verify that malloc works.  */
    9541              : 
    9542              : static void
    9543            4 : test_malloc ()
    9544              : {
    9545            4 :   tree int_star = build_pointer_type (integer_type_node);
    9546            4 :   tree p = build_global_decl ("p", int_star);
    9547            4 :   tree n = build_global_decl ("n", integer_type_node);
    9548            4 :   tree n_times_4 = build2 (MULT_EXPR, size_type_node,
    9549              :                            n, build_int_cst (size_type_node, 4));
    9550              : 
    9551            4 :   region_model_manager mgr;
    9552            4 :   test_region_model_context ctxt;
    9553            4 :   region_model model (&mgr);
    9554              : 
    9555              :   /* "p = malloc (n * 4);".  */
    9556            4 :   const svalue *size_sval = model.get_rvalue (n_times_4, &ctxt);
    9557            4 :   const region *reg
    9558            4 :     = model.get_or_create_region_for_heap_alloc (size_sval, &ctxt);
    9559            4 :   const svalue *ptr = mgr.get_ptr_svalue (int_star, reg);
    9560            4 :   model.set_value (model.get_lvalue (p, &ctxt), ptr, &ctxt);
    9561            4 :   ASSERT_EQ (model.get_capacity (reg), size_sval);
    9562            4 : }
    9563              : 
    9564              : /* Verify that alloca works.  */
    9565              : 
    9566              : static void
    9567            4 : test_alloca ()
    9568              : {
    9569            4 :   auto_vec <tree> param_types;
    9570            4 :   tree fndecl = make_fndecl (integer_type_node,
    9571              :                              "test_fn",
    9572              :                              param_types);
    9573            4 :   allocate_struct_function (fndecl, true);
    9574              : 
    9575              : 
    9576            4 :   tree int_star = build_pointer_type (integer_type_node);
    9577            4 :   tree p = build_global_decl ("p", int_star);
    9578            4 :   tree n = build_global_decl ("n", integer_type_node);
    9579            4 :   tree n_times_4 = build2 (MULT_EXPR, size_type_node,
    9580              :                            n, build_int_cst (size_type_node, 4));
    9581              : 
    9582            4 :   region_model_manager mgr;
    9583            4 :   test_region_model_context ctxt;
    9584            4 :   region_model model (&mgr);
    9585              : 
    9586              :   /* Push stack frame.  */
    9587            4 :   const region *frame_reg
    9588            4 :     = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl),
    9589              :                         nullptr, nullptr, &ctxt);
    9590              :   /* "p = alloca (n * 4);".  */
    9591            4 :   const svalue *size_sval = model.get_rvalue (n_times_4, &ctxt);
    9592            4 :   const region *reg = model.create_region_for_alloca (size_sval, &ctxt);
    9593            4 :   ASSERT_EQ (reg->get_parent_region (), frame_reg);
    9594            4 :   const svalue *ptr = mgr.get_ptr_svalue (int_star, reg);
    9595            4 :   model.set_value (model.get_lvalue (p, &ctxt), ptr, &ctxt);
    9596            4 :   ASSERT_EQ (model.get_capacity (reg), size_sval);
    9597              : 
    9598              :   /* Verify that the pointers to the alloca region are replaced by
    9599              :      poisoned values when the frame is popped.  */
    9600            4 :   model.pop_frame (nullptr, nullptr, &ctxt, nullptr);
    9601            4 :   ASSERT_EQ (model.get_rvalue (p, nullptr)->get_kind (), SK_POISONED);
    9602            4 : }
    9603              : 
    9604              : /* Verify that svalue::involves_p works.  */
    9605              : 
    9606              : static void
    9607            4 : test_involves_p ()
    9608              : {
    9609            4 :   region_model_manager mgr;
    9610            4 :   tree int_star = build_pointer_type (integer_type_node);
    9611            4 :   tree p = build_global_decl ("p", int_star);
    9612            4 :   tree q = build_global_decl ("q", int_star);
    9613              : 
    9614            4 :   test_region_model_context ctxt;
    9615            4 :   region_model model (&mgr);
    9616            4 :   const svalue *p_init = model.get_rvalue (p, &ctxt);
    9617            4 :   const svalue *q_init = model.get_rvalue (q, &ctxt);
    9618              : 
    9619            4 :   ASSERT_TRUE (p_init->involves_p (p_init));
    9620            4 :   ASSERT_FALSE (p_init->involves_p (q_init));
    9621              : 
    9622            4 :   const region *star_p_reg = mgr.get_symbolic_region (p_init);
    9623            4 :   const region *star_q_reg = mgr.get_symbolic_region (q_init);
    9624              : 
    9625            4 :   const svalue *init_star_p = mgr.get_or_create_initial_value (star_p_reg);
    9626            4 :   const svalue *init_star_q = mgr.get_or_create_initial_value (star_q_reg);
    9627              : 
    9628            4 :   ASSERT_TRUE (init_star_p->involves_p (p_init));
    9629            4 :   ASSERT_FALSE (p_init->involves_p (init_star_p));
    9630            4 :   ASSERT_FALSE (init_star_p->involves_p (q_init));
    9631            4 :   ASSERT_TRUE (init_star_q->involves_p (q_init));
    9632            4 :   ASSERT_FALSE (init_star_q->involves_p (p_init));
    9633            4 : }
    9634              : 
    9635              : /* Run all of the selftests within this file.  */
    9636              : 
    9637              : void
    9638            4 : analyzer_region_model_cc_tests ()
    9639              : {
    9640            4 :   test_tree_cmp_on_constants ();
    9641            4 :   test_dump ();
    9642            4 :   test_struct ();
    9643            4 :   test_array_1 ();
    9644            4 :   test_get_representative_tree ();
    9645            4 :   test_unique_constants ();
    9646            4 :   test_unique_unknowns ();
    9647            4 :   test_initial_svalue_folding ();
    9648            4 :   test_unaryop_svalue_folding ();
    9649            4 :   test_binop_svalue_folding ();
    9650            4 :   test_sub_svalue_folding ();
    9651            4 :   test_bits_within_svalue_folding ();
    9652            4 :   test_descendent_of_p ();
    9653            4 :   test_bit_range_regions ();
    9654            4 :   test_assignment ();
    9655            4 :   test_compound_assignment ();
    9656            4 :   test_stack_frames ();
    9657            4 :   test_get_representative_path_var ();
    9658            4 :   test_equality_1 ();
    9659            4 :   test_canonicalization_2 ();
    9660            4 :   test_canonicalization_3 ();
    9661            4 :   test_canonicalization_4 ();
    9662            4 :   test_state_merging ();
    9663            4 :   test_constraint_merging ();
    9664            4 :   test_widening_constraints ();
    9665            4 :   test_iteration_1 ();
    9666            4 :   test_malloc_constraints ();
    9667            4 :   test_var ();
    9668            4 :   test_array_2 ();
    9669            4 :   test_mem_ref ();
    9670            4 :   test_POINTER_PLUS_EXPR_then_MEM_REF ();
    9671            4 :   test_malloc ();
    9672            4 :   test_alloca ();
    9673            4 :   test_involves_p ();
    9674            4 : }
    9675              : 
    9676              : } // namespace selftest
    9677              : 
    9678              : #endif /* CHECKING_P */
    9679              : 
    9680              : } // namespace ana
    9681              : 
    9682              : #endif /* #if ENABLE_ANALYZER */
        

Generated by: LCOV version 2.5.0-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.