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

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.