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