LCOV - code coverage report
Current view: top level - gcc/analyzer - region-model.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 63.0 % 276 174
Test Date: 2026-02-28 14:20:25 Functions: 62.8 % 78 49
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              : #ifndef GCC_ANALYZER_REGION_MODEL_H
      22              : #define GCC_ANALYZER_REGION_MODEL_H
      23              : 
      24              : /* Implementation of the region-based ternary model described in:
      25              :      "A Memory Model for Static Analysis of C Programs"
      26              :       (Zhongxing Xu, Ted Kremenek, and Jian Zhang)
      27              :      http://lcs.ios.ac.cn/~xuzb/canalyze/memmodel.pdf  */
      28              : 
      29              : #include "bitmap.h"
      30              : #include "stringpool.h"
      31              : #include "attribs.h" // for rdwr_map
      32              : #include "selftest.h"
      33              : #include "analyzer/svalue.h"
      34              : #include "analyzer/region.h"
      35              : #include "analyzer/known-function-manager.h"
      36              : #include "analyzer/region-model-manager.h"
      37              : #include "analyzer/pending-diagnostic.h"
      38              : #include "analyzer/diagnostic-manager.h"
      39              : #include "text-art/widget.h"
      40              : #include "text-art/dump.h"
      41              : 
      42              : using namespace ana;
      43              : 
      44              : namespace inchash
      45              : {
      46              :   extern void add_path_var (path_var pv, hash &hstate);
      47              : } // namespace inchash
      48              : 
      49              : namespace ana {
      50              : 
      51              : template <typename T>
      52       823919 : class one_way_id_map
      53              : {
      54              :  public:
      55              :   one_way_id_map (int num_ids);
      56              :   void put (T src, T dst);
      57              :   T get_dst_for_src (T src) const;
      58              :   void dump_to_pp (pretty_printer *pp) const;
      59              :   void dump () const;
      60              :   void update (T *) const;
      61              : 
      62              :  private:
      63              :   auto_vec<T> m_src_to_dst;
      64              :  };
      65              : 
      66              : /* class one_way_id_map.  */
      67              : 
      68              : /* one_way_id_map's ctor, which populates the map with dummy null values.  */
      69              : 
      70              : template <typename T>
      71       823919 : inline one_way_id_map<T>::one_way_id_map (int num_svalues)
      72       823919 : : m_src_to_dst (num_svalues)
      73              : {
      74      4091749 :   for (int i = 0; i < num_svalues; i++)
      75      3267830 :     m_src_to_dst.quick_push (T::null ());
      76       823919 : }
      77              : 
      78              : /* Record that SRC is to be mapped to DST.  */
      79              : 
      80              : template <typename T>
      81              : inline void
      82      3238580 : one_way_id_map<T>::put (T src, T dst)
      83              : {
      84      3238580 :   m_src_to_dst[src.as_int ()] = dst;
      85              : }
      86              : 
      87              : /* Get the new value for SRC within the map.  */
      88              : 
      89              : template <typename T>
      90              : inline T
      91      4367720 : one_way_id_map<T>::get_dst_for_src (T src) const
      92              : {
      93      4367720 :   if (src.null_p ())
      94            0 :     return src;
      95      4367720 :   return m_src_to_dst[src.as_int ()];
      96              : }
      97              : 
      98              : /* Dump this map to PP.  */
      99              : 
     100              : template <typename T>
     101              : inline void
     102            0 : one_way_id_map<T>::dump_to_pp (pretty_printer *pp) const
     103              : {
     104            0 :   pp_string (pp, "src to dst: {");
     105              :   unsigned i;
     106              :   T *dst;
     107            0 :   FOR_EACH_VEC_ELT (m_src_to_dst, i, dst)
     108              :     {
     109            0 :       if (i > 0)
     110            0 :         pp_string (pp, ", ");
     111            0 :       T src (T::from_int (i));
     112            0 :       src.print (pp);
     113            0 :       pp_string (pp, " -> ");
     114            0 :       dst->print (pp);
     115              :     }
     116            0 :   pp_string (pp, "}");
     117            0 :   pp_newline (pp);
     118            0 : }
     119              : 
     120              : /* Dump this map to stderr.  */
     121              : 
     122              : template <typename T>
     123              : DEBUG_FUNCTION inline void
     124            0 : one_way_id_map<T>::dump () const
     125              : {
     126            0 :   pretty_printer pp;
     127            0 :   pp.set_output_stream (stderr);
     128            0 :   dump_to_pp (&pp);
     129            0 :   pp_flush (&pp);
     130            0 : }
     131              : 
     132              : /* Update *ID from the old value to its new value in this map.  */
     133              : 
     134              : template <typename T>
     135              : inline void
     136      4367720 : one_way_id_map<T>::update (T *id) const
     137              : {
     138      2189068 :   *id = get_dst_for_src (*id);
     139              : }
     140              : 
     141              : /* A mapping from region to svalue for use when tracking state.  */
     142              : 
     143      3557103 : class region_to_value_map
     144              : {
     145              : public:
     146              :   typedef hash_map<const region *, const svalue *> hash_map_t;
     147              :   typedef hash_map_t::iterator iterator;
     148              : 
     149       370385 :   region_to_value_map () : m_hash_map () {}
     150      3186718 :   region_to_value_map (const region_to_value_map &other)
     151      3186718 :   : m_hash_map (other.m_hash_map) {}
     152              :   region_to_value_map &operator= (const region_to_value_map &other);
     153              : 
     154              :   bool operator== (const region_to_value_map &other) const;
     155       443550 :   bool operator!= (const region_to_value_map &other) const
     156              :   {
     157       443550 :     return !(*this == other);
     158              :   }
     159              : 
     160       548659 :   iterator begin () const { return m_hash_map.begin (); }
     161       549075 :   iterator end () const { return m_hash_map.end (); }
     162              : 
     163        71669 :   const svalue * const *get (const region *reg) const
     164              :   {
     165       204598 :     return const_cast <hash_map_t &> (m_hash_map).get (reg);
     166              :   }
     167        21438 :   void put (const region *reg, const svalue *sval)
     168              :   {
     169        21438 :     m_hash_map.put (reg, sval);
     170              :   }
     171        49682 :   void remove (const region *reg)
     172              :   {
     173        49682 :     m_hash_map.remove (reg);
     174              :   }
     175              : 
     176         2130 :   bool is_empty () const { return m_hash_map.is_empty (); }
     177              : 
     178              :   void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
     179              :   void dump (bool simple) const;
     180              : 
     181              :   std::unique_ptr<json::object> to_json () const;
     182              : 
     183              :   std::unique_ptr<text_art::tree_widget>
     184              :   make_dump_widget (const text_art::dump_widget_info &dwi) const;
     185              : 
     186              :   bool can_merge_with_p (const region_to_value_map &other,
     187              :                          region_to_value_map *out) const;
     188              : 
     189              :   void purge_state_involving (const svalue *sval);
     190              : 
     191              : private:
     192              :   hash_map_t m_hash_map;
     193              : };
     194              : 
     195              : /* Various operations delete information from a region_model.
     196              : 
     197              :    This struct tracks how many of each kind of entity were purged (e.g.
     198              :    for selftests, and for debugging).  */
     199              : 
     200              : struct purge_stats
     201              : {
     202              :   purge_stats ()
     203              :   : m_num_svalues (0),
     204              :     m_num_regions (0),
     205              :     m_num_equiv_classes (0),
     206              :     m_num_constraints (0),
     207              :     m_num_bounded_ranges_constraints (0),
     208              :     m_num_client_items (0)
     209              :   {}
     210              : 
     211              :   int m_num_svalues;
     212              :   int m_num_regions;
     213              :   int m_num_equiv_classes;
     214              :   int m_num_constraints;
     215              :   int m_num_bounded_ranges_constraints;
     216              :   int m_num_client_items;
     217              : };
     218              : 
     219              : /* A base class for visiting regions and svalues, with do-nothing
     220              :    base implementations of the per-subclass vfuncs.  */
     221              : 
     222       702839 : class visitor
     223              : {
     224              : public:
     225       741162 :   virtual void visit_region_svalue (const region_svalue *) {}
     226      9289584 :   virtual void visit_constant_svalue (const constant_svalue *) {}
     227      1897598 :   virtual void visit_unknown_svalue (const unknown_svalue *) {}
     228        12718 :   virtual void visit_poisoned_svalue (const poisoned_svalue *) {}
     229          942 :   virtual void visit_setjmp_svalue (const setjmp_svalue *) {}
     230      1272049 :   virtual void visit_initial_svalue (const initial_svalue *) {}
     231      7051091 :   virtual void visit_unaryop_svalue (const unaryop_svalue *) {}
     232      6247190 :   virtual void visit_binop_svalue (const binop_svalue *) {}
     233      3943719 :   virtual void visit_sub_svalue (const sub_svalue *) {}
     234        45019 :   virtual void visit_repeated_svalue (const repeated_svalue *) {}
     235        49103 :   virtual void visit_bits_within_svalue (const bits_within_svalue *) {}
     236         6698 :   virtual void visit_unmergeable_svalue (const unmergeable_svalue *) {}
     237        37957 :   virtual void visit_placeholder_svalue (const placeholder_svalue *) {}
     238       111396 :   virtual void visit_widening_svalue (const widening_svalue *) {}
     239           38 :   virtual void visit_compound_svalue (const compound_svalue *) {}
     240      5007343 :   virtual void visit_conjured_svalue (const conjured_svalue *) {}
     241         6099 :   virtual void visit_asm_output_svalue (const asm_output_svalue *) {}
     242         8433 :   virtual void visit_const_fn_result_svalue (const const_fn_result_svalue *) {}
     243              : 
     244      3192805 :   virtual void visit_region (const region *) {}
     245              : };
     246              : 
     247              : struct append_regions_cb_data;
     248              : 
     249              : /* Roughly equivalent to a struct __cxa_exception, except we store a std::vector
     250              :    rather than a linked list.    */
     251              : 
     252              : struct exception_node
     253              : {
     254         5627 :   exception_node (const svalue *exception_sval,
     255              :                   const svalue *typeinfo_sval,
     256              :                   const svalue *destructor_sval)
     257         5627 :   : m_exception_sval (exception_sval),
     258         5627 :     m_typeinfo_sval (typeinfo_sval),
     259         5627 :     m_destructor_sval (destructor_sval)
     260              :   {
     261              :   }
     262              : 
     263              :   bool operator== (const exception_node &other) const;
     264              : 
     265              :   void dump_to_pp (pretty_printer *pp, bool simple) const;
     266              :   void dump (FILE *fp, bool simple) const;
     267              :   void dump (bool simple) const;
     268              :   void dump () const;
     269              : 
     270              :   std::unique_ptr<json::object> to_json () const;
     271              : 
     272              :   std::unique_ptr<text_art::tree_widget>
     273              :   make_dump_widget (const text_art::dump_widget_info &dwi) const;
     274              : 
     275              :   tree maybe_get_type () const;
     276              : 
     277              :   void add_to_reachable_regions (reachable_regions &) const;
     278              : 
     279              :   const svalue *m_exception_sval;
     280              :   const svalue *m_typeinfo_sval;
     281              :   const svalue *m_destructor_sval;
     282              : };
     283              : 
     284              : /* A region_model encapsulates a representation of the state of memory, with
     285              :    a tree of regions, along with their associated values.
     286              :    The representation is graph-like because values can be pointers to
     287              :    regions.
     288              :    It also stores:
     289              :    - a constraint_manager, capturing relationships between the values, and
     290              :    - dynamic extents, mapping dynamically-allocated regions to svalues (their
     291              :    capacities).  */
     292              : 
     293              : class region_model
     294              : {
     295              :  public:
     296              :   typedef region_to_value_map dynamic_extents_t;
     297              : 
     298              :   region_model (region_model_manager *mgr);
     299              :   region_model (const region_model &other);
     300              :   ~region_model ();
     301              :   region_model &operator= (const region_model &other);
     302              : 
     303              :   bool operator== (const region_model &other) const;
     304           28 :   bool operator!= (const region_model &other) const
     305              :   {
     306           28 :     return !(*this == other);
     307              :   }
     308              : 
     309              :   hashval_t hash () const;
     310              : 
     311              :   void print (pretty_printer *pp) const;
     312              : 
     313              :   void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
     314              :   void dump (FILE *fp, bool simple, bool multiline) const;
     315              :   void dump (bool simple) const;
     316              :   void dump () const;
     317              : 
     318              :   void debug () const;
     319              : 
     320              :   std::unique_ptr<json::object> to_json () const;
     321              : 
     322              :   std::unique_ptr<text_art::tree_widget>
     323              :   make_dump_widget (const text_art::dump_widget_info &dwi) const;
     324              : 
     325              :   void validate () const;
     326              : 
     327              :   void canonicalize ();
     328              :   bool canonicalized_p () const;
     329              : 
     330              :   void
     331              :   on_stmt_pre (const gimple *stmt,
     332              :                bool *out_unknown_side_effects,
     333              :                region_model_context *ctxt);
     334              : 
     335              :   void on_assignment (const gassign *stmt, region_model_context *ctxt);
     336              :   const svalue *get_gassign_result (const gassign *assign,
     337              :                                     region_model_context *ctxt);
     338              :   void on_asm_stmt (const gasm *asm_stmt, region_model_context *ctxt);
     339              :   bool on_call_pre (const gcall &stmt, region_model_context *ctxt);
     340              :   void on_call_post (const gcall &stmt,
     341              :                      bool unknown_side_effects,
     342              :                      region_model_context *ctxt);
     343              : 
     344              :   void purge_state_involving (const svalue *sval, region_model_context *ctxt);
     345              : 
     346              :   void impl_deallocation_call (const call_details &cd);
     347              : 
     348              :   const svalue *maybe_get_copy_bounds (const region *src_reg,
     349              :                                        const svalue *num_bytes_sval);
     350              :   void update_for_int_cst_return (const call_details &cd,
     351              :                                   int retval,
     352              :                                   bool unmergeable);
     353              :   void update_for_zero_return (const call_details &cd,
     354              :                                bool unmergeable);
     355              :   void update_for_nonzero_return (const call_details &cd);
     356              : 
     357              :   void handle_unrecognized_call (const gcall &call,
     358              :                                  region_model_context *ctxt);
     359              :   void get_reachable_svalues (svalue_set *out,
     360              :                               const svalue *extra_sval,
     361              :                               const uncertainty_t *uncertainty);
     362              : 
     363              :   void on_return (const greturn *stmt, region_model_context *ctxt);
     364              :   void on_setjmp (const gcall &stmt,
     365              :                   const exploded_node &enode,
     366              :                   const superedge &sedge,
     367              :                   region_model_context *ctxt);
     368              :   void on_longjmp (const gcall &longjmp_call, const gcall &setjmp_call,
     369              :                    int setjmp_stack_depth, region_model_context *ctxt);
     370              : 
     371              :   void update_for_gcall (const gcall &call_stmt,
     372              :                          region_model_context *ctxt,
     373              :                          function *callee = nullptr);
     374              : 
     375              :   void update_for_return_gcall (const gcall &call_stmt,
     376              :                                 region_model_context *ctxt);
     377              : 
     378              :   const region *push_frame (const function &fun,
     379              :                             const gcall *call_stmt,
     380              :                             const vec<const svalue *> *arg_sids,
     381              :                             region_model_context *ctxt);
     382      9866348 :   const frame_region *get_current_frame () const { return m_current_frame; }
     383              :   const function *get_current_function () const;
     384              :   void pop_frame (tree result_lvalue,
     385              :                   const svalue **out_result,
     386              :                   region_model_context *ctxt,
     387              :                   const gcall *call_stmt,
     388              :                   bool eval_return_svalue = true);
     389              :   int get_stack_depth () const;
     390              :   const frame_region *get_frame_at_index (int index) const;
     391              : 
     392              :   const region *get_lvalue (path_var pv, region_model_context *ctxt) const;
     393              :   const region *get_lvalue (tree expr, region_model_context *ctxt) const;
     394              :   const svalue *get_rvalue (path_var pv, region_model_context *ctxt) const;
     395              :   const svalue *get_rvalue (tree expr, region_model_context *ctxt) const;
     396              : 
     397              :   const region *deref_rvalue (const svalue *ptr_sval, tree ptr_tree,
     398              :                               region_model_context *ctxt,
     399              :                               bool add_nonnull_constraint = true) const;
     400              : 
     401              :   const svalue *get_rvalue_for_bits (tree type,
     402              :                                      const region *reg,
     403              :                                      const bit_range &bits,
     404              :                                      region_model_context *ctxt) const;
     405              : 
     406              :   void set_value (const region *lhs_reg, const svalue *rhs_sval,
     407              :                   region_model_context *ctxt);
     408              :   void set_value (tree lhs, tree rhs, region_model_context *ctxt);
     409              :   void clobber_region (const region *reg);
     410              :   void purge_region (const region *reg);
     411              :   void fill_region (const region *reg,
     412              :                     const svalue *sval,
     413              :                     region_model_context *ctxt);
     414              :   void zero_fill_region (const region *reg,
     415              :                          region_model_context *ctxt);
     416              :   void write_bytes (const region *dest_reg,
     417              :                     const svalue *num_bytes_sval,
     418              :                     const svalue *sval,
     419              :                     region_model_context *ctxt);
     420              :   const svalue *read_bytes (const region *src_reg,
     421              :                             tree src_ptr_expr,
     422              :                             const svalue *num_bytes_sval,
     423              :                             region_model_context *ctxt) const;
     424              :   void copy_bytes (const region *dest_reg,
     425              :                    const region *src_reg,
     426              :                    tree src_ptr_expr,
     427              :                    const svalue *num_bytes_sval,
     428              :                    region_model_context *ctxt);
     429              :   void mark_region_as_unknown (const region *reg, uncertainty_t *uncertainty);
     430              : 
     431              :   tristate eval_condition (const svalue *lhs,
     432              :                            enum tree_code op,
     433              :                            const svalue *rhs) const;
     434              :   tristate compare_initial_and_pointer (const initial_svalue *init,
     435              :                                         const region_svalue *ptr) const;
     436              :   tristate symbolic_greater_than (const binop_svalue *a,
     437              :                                   const svalue *b) const;
     438              :   tristate structural_equality (const svalue *a, const svalue *b) const;
     439              :   tristate eval_condition (tree lhs,
     440              :                            enum tree_code op,
     441              :                            tree rhs,
     442              :                            region_model_context *ctxt) const;
     443              :   bool add_constraint (tree lhs, enum tree_code op, tree rhs,
     444              :                        region_model_context *ctxt);
     445              :   bool add_constraint (tree lhs, enum tree_code op, tree rhs,
     446              :                        region_model_context *ctxt,
     447              :                        std::unique_ptr<rejected_constraint> *out);
     448              : 
     449              :         const region *
     450              :         get_or_create_region_for_heap_alloc (const svalue *size_in_bytes,
     451              :                                 region_model_context *ctxt,
     452              :                                 bool update_state_machine = false,
     453              :                                 const call_details *cd = nullptr);
     454              : 
     455              :   const region *create_region_for_alloca (const svalue *size_in_bytes,
     456              :                                           region_model_context *ctxt);
     457              :   void get_referenced_base_regions (auto_bitmap &out_ids) const;
     458              : 
     459              :   tree get_representative_tree (const svalue *sval,
     460              :                                 logger *logger = nullptr) const;
     461              :   tree get_representative_tree (const region *reg,
     462              :                                 logger *logger = nullptr) const;
     463              :   path_var
     464              :   get_representative_path_var (const svalue *sval,
     465              :                                svalue_set *visited,
     466              :                                logger *logger) const;
     467              :   path_var
     468              :   get_representative_path_var (const region *reg,
     469              :                                svalue_set *visited,
     470              :                                logger *logger) const;
     471              : 
     472              :   /* For selftests.  */
     473       525107 :   constraint_manager *get_constraints ()
     474              :   {
     475       525107 :     return m_constraints;
     476              :   }
     477              : 
     478      1008906 :   store *get_store () { return &m_store; }
     479       268192 :   const store *get_store () const { return &m_store; }
     480              : 
     481              :   const dynamic_extents_t &
     482        43581 :   get_dynamic_extents () const
     483              :   {
     484        43581 :     return m_dynamic_extents;
     485              :   }
     486              :   const svalue *get_dynamic_extents (const region *reg) const;
     487              :   void set_dynamic_extents (const region *reg,
     488              :                             const svalue *size_in_bytes,
     489              :                             region_model_context *ctxt);
     490              :   void unset_dynamic_extents (const region *reg);
     491              : 
     492        88024 :   region_model_manager *get_manager () const { return m_mgr; }
     493              :   bounded_ranges_manager *get_range_manager () const
     494              :   {
     495              :     return m_mgr->get_range_manager ();
     496              :   }
     497              : 
     498              :   void unbind_region_and_descendents (const region *reg,
     499              :                                       enum poison_kind pkind);
     500              : 
     501              :   bool can_merge_with_p (const region_model &other_model,
     502              :                          const program_point &point,
     503              :                          region_model *out_model,
     504              :                          const extrinsic_state *ext_state = nullptr,
     505              :                          const program_state *state_a = nullptr,
     506              :                          const program_state *state_b = nullptr) const;
     507              : 
     508              :   tree get_fndecl_for_call (const gcall &call,
     509              :                             region_model_context *ctxt);
     510              : 
     511              :   void get_regions_for_current_frame (auto_vec<const decl_region *> *out) const;
     512              :   static void append_regions_cb (const region *base_reg,
     513              :                                  struct append_regions_cb_data *data);
     514              : 
     515              :   const svalue *get_store_value (const region *reg,
     516              :                                  region_model_context *ctxt) const;
     517              :   const svalue *get_store_bytes (const region *base_reg,
     518              :                                  const byte_range &bytes,
     519              :                                  region_model_context *ctxt) const;
     520              :   const svalue *scan_for_null_terminator (const region *reg,
     521              :                                           tree expr,
     522              :                                           const svalue **out_sval,
     523              :                                           region_model_context *ctxt) const;
     524              :   const svalue *scan_for_null_terminator_1 (const region *reg,
     525              :                                             tree expr,
     526              :                                             const svalue **out_sval,
     527              :                                             region_model_context *ctxt) const;
     528              : 
     529              :   bool region_exists_p (const region *reg) const;
     530              : 
     531              :   void loop_replay_fixup (const region_model *dst_state);
     532              : 
     533              :   const svalue *get_capacity (const region *reg) const;
     534              : 
     535              :   bool replay_call_summary (call_summary_replay &r,
     536              :                             const region_model &summary);
     537              : 
     538              :   void maybe_complain_about_infoleak (const region *dst_reg,
     539              :                                       const svalue *copied_sval,
     540              :                                       const region *src_reg,
     541              :                                       region_model_context *ctxt);
     542              : 
     543              :   void set_errno (const call_details &cd);
     544              : 
     545              :   /* Implemented in sm-fd.cc  */
     546              :   void mark_as_valid_fd (const svalue *sval, region_model_context *ctxt);
     547              : 
     548              :   /* Implemented in sm-malloc.cc  */
     549              :   void on_realloc_with_move (const call_details &cd,
     550              :                              const svalue *old_ptr_sval,
     551              :                              const svalue *new_ptr_sval);
     552              : 
     553              :   /* Implemented in sm-malloc.cc.  */
     554              :   void
     555              :   transition_ptr_sval_non_null (region_model_context *ctxt,
     556              :       const svalue *new_ptr_sval);
     557              : 
     558              :   /* Implemented in sm-taint.cc.  */
     559              :   void mark_as_tainted (const svalue *sval,
     560              :                         region_model_context *ctxt);
     561              : 
     562              :   bool add_constraint (const svalue *lhs,
     563              :                        enum tree_code op,
     564              :                        const svalue *rhs,
     565              :                        region_model_context *ctxt);
     566              : 
     567              :   const svalue *check_for_poison (const svalue *sval,
     568              :                                   tree expr,
     569              :                                   const region *src_region,
     570              :                                   region_model_context *ctxt) const;
     571              : 
     572              :   void check_region_for_write (const region *dest_reg,
     573              :                                const svalue *sval_hint,
     574              :                                region_model_context *ctxt) const;
     575              : 
     576              :   const svalue *
     577              :   check_for_null_terminated_string_arg (const call_details &cd,
     578              :                                         unsigned idx) const;
     579              :   const svalue *
     580              :   check_for_null_terminated_string_arg (const call_details &cd,
     581              :                                         unsigned idx,
     582              :                                         bool include_terminator,
     583              :                                         const svalue **out_sval) const;
     584              : 
     585              :   const builtin_known_function *
     586              :   get_builtin_kf (const gcall &call,
     587              :                   region_model_context *ctxt = nullptr) const;
     588              : 
     589              :   bool called_from_main_p () const;
     590              : 
     591         5702 :   void push_thrown_exception (const exception_node &node)
     592              :   {
     593         5702 :     m_thrown_exceptions_stack.push_back (node);
     594           75 :   }
     595          403 :   const exception_node *get_current_thrown_exception () const
     596              :   {
     597          403 :     if (m_thrown_exceptions_stack.empty ())
     598              :       return nullptr;
     599          400 :     return &m_thrown_exceptions_stack.back ();
     600              :   }
     601          187 :   exception_node pop_thrown_exception ()
     602              :   {
     603          187 :     gcc_assert (!m_thrown_exceptions_stack.empty ());
     604          187 :     const exception_node retval = m_thrown_exceptions_stack.back ();
     605          187 :     m_thrown_exceptions_stack.pop_back ();
     606          187 :     return retval;
     607              :   }
     608              : 
     609          187 :   void push_caught_exception (const exception_node &node)
     610              :   {
     611          187 :     m_caught_exceptions_stack.push_back (node);
     612              :   }
     613          183 :   const exception_node *get_current_caught_exception () const
     614              :   {
     615          183 :     if (m_caught_exceptions_stack.empty ())
     616              :       return nullptr;
     617          141 :     return &m_caught_exceptions_stack.back ();
     618              :   }
     619          166 :   exception_node pop_caught_exception ()
     620              :   {
     621          166 :     gcc_assert (!m_caught_exceptions_stack.empty ());
     622          166 :     const exception_node retval = m_caught_exceptions_stack.back ();
     623          166 :     m_caught_exceptions_stack.pop_back ();
     624          166 :     return retval;
     625              :   }
     626              : 
     627              : private:
     628              :   const region *get_lvalue_1 (path_var pv, region_model_context *ctxt) const;
     629              :   const svalue *get_rvalue_1 (path_var pv, region_model_context *ctxt) const;
     630              : 
     631              :   path_var
     632              :   get_representative_path_var_1 (const svalue *sval,
     633              :                                  svalue_set *visited,
     634              :                                  logger *logger) const;
     635              :   path_var
     636              :   get_representative_path_var_1 (const region *reg,
     637              :                                  svalue_set *visited,
     638              :                                  logger *logger) const;
     639              : 
     640              :   const known_function *get_known_function (tree fndecl,
     641              :                                             const call_details &cd) const;
     642              :   const known_function *get_known_function (enum internal_fn) const;
     643              : 
     644              :   bool add_constraints_from_binop (const svalue *outer_lhs,
     645              :                                    enum tree_code outer_op,
     646              :                                    const svalue *outer_rhs,
     647              :                                    bool *out,
     648              :                                    region_model_context *ctxt);
     649              : 
     650              :   void poison_any_pointers_to_descendents (const region *reg,
     651              :                                            enum poison_kind pkind);
     652              : 
     653              :   void on_top_level_param (tree param,
     654              :                            bool nonnull,
     655              :                            region_model_context *ctxt);
     656              : 
     657              :   const svalue *get_initial_value_for_global (const region *reg) const;
     658              : 
     659              :   const region * get_region_for_poisoned_expr (tree expr) const;
     660              : 
     661              :   void check_dynamic_size_for_taint (enum memory_space mem_space,
     662              :                                      const svalue *size_in_bytes,
     663              :                                      region_model_context *ctxt) const;
     664              :   void check_dynamic_size_for_floats (const svalue *size_in_bytes,
     665              :                                       region_model_context *ctxt) const;
     666              : 
     667              :   void check_region_for_taint (const region *reg,
     668              :                                enum access_direction dir,
     669              :                                region_model_context *ctxt) const;
     670              : 
     671              :   void check_for_writable_region (const region* dest_reg,
     672              :                                   region_model_context *ctxt) const;
     673              :   bool check_region_access (const region *reg,
     674              :                             enum access_direction dir,
     675              :                             const svalue *sval_hint,
     676              :                             region_model_context *ctxt) const;
     677              :   bool check_region_for_read (const region *src_reg,
     678              :                               region_model_context *ctxt) const;
     679              :   void check_region_size (const region *lhs_reg, const svalue *rhs_sval,
     680              :                           region_model_context *ctxt) const;
     681              : 
     682              :   /* Implemented in bounds-checking.cc  */
     683              :   bool check_symbolic_bounds (const region *base_reg,
     684              :                               const svalue *sym_byte_offset,
     685              :                               const svalue *num_bytes_sval,
     686              :                               const svalue *capacity,
     687              :                               enum access_direction dir,
     688              :                               const svalue *sval_hint,
     689              :                               region_model_context *ctxt) const;
     690              :   bool check_region_bounds (const region *reg, enum access_direction dir,
     691              :                             const svalue *sval_hint,
     692              :                             region_model_context *ctxt) const;
     693              : 
     694              :   void check_call_args (const call_details &cd) const;
     695              :   void check_call_format_attr (const call_details &cd,
     696              :                                tree format_attr) const;
     697              :   void check_function_attr_access (const gcall &call,
     698              :                                    tree callee_fndecl,
     699              :                                    region_model_context *ctxt,
     700              :                                    rdwr_map &rdwr_idx) const;
     701              :   void check_function_attr_null_terminated_string_arg (const gcall &call,
     702              :                                                        tree callee_fndecl,
     703              :                                                        region_model_context *ctxt,
     704              :                                                        rdwr_map &rdwr_idx);
     705              :   void check_one_function_attr_null_terminated_string_arg (const gcall &call,
     706              :                                                            tree callee_fndecl,
     707              :                                                            region_model_context *ctxt,
     708              :                                                            rdwr_map &rdwr_idx,
     709              :                                                            tree attr);
     710              :   void check_function_attrs (const gcall &call,
     711              :                              tree callee_fndecl,
     712              :                              region_model_context *ctxt);
     713              : 
     714              :   void check_for_throw_inside_call (const gcall &call,
     715              :                                     tree fndecl,
     716              :                                     region_model_context *ctxt);
     717              : 
     718              :   /* Storing this here to avoid passing it around everywhere.  */
     719              :   region_model_manager *const m_mgr;
     720              : 
     721              :   store m_store;
     722              : 
     723              :   constraint_manager *m_constraints; // TODO: embed, rather than dynalloc?
     724              : 
     725              :   const frame_region *m_current_frame;
     726              : 
     727              :   std::vector<exception_node> m_thrown_exceptions_stack;
     728              :   std::vector<exception_node> m_caught_exceptions_stack;
     729              : 
     730              :   /* Map from base region to size in bytes, for tracking the sizes of
     731              :      dynamically-allocated regions.
     732              :      This is part of the region_model rather than the region to allow for
     733              :      memory regions to be resized (e.g. by realloc).  */
     734              :   dynamic_extents_t m_dynamic_extents;
     735              : };
     736              : 
     737              : /* Some region_model activity could lead to warnings (e.g. attempts to use an
     738              :    uninitialized value).  This abstract base class encapsulates an interface
     739              :    for the region model to use when emitting such warnings.
     740              : 
     741              :    Having this as an abstract base class allows us to support the various
     742              :    operations needed by program_state in the analyzer within region_model,
     743              :    whilst keeping them somewhat modularized.  */
     744              : 
     745      1427400 : class region_model_context
     746              : {
     747              :  public:
     748              :   bool
     749              :   warn (std::unique_ptr<pending_diagnostic> d,
     750              :         std::unique_ptr<pending_location::fixer_for_epath> ploc_fixer = nullptr);
     751              : 
     752              :   /* Hook for determining where diagnostics are to currently be emitted.  */
     753              :   virtual pending_location
     754              :   get_pending_location_for_diag () const = 0;
     755              : 
     756              :   /* Hook for clients to store pending diagnostics.
     757              :      Return true if the diagnostic was stored, or false if it was deleted.  */
     758              :   virtual bool
     759              :   warn_at (std::unique_ptr<pending_diagnostic> d,
     760              :            pending_location &&ploc) = 0;
     761              : 
     762              :   /* Hook for clients to add a note to the last previously stored
     763              :      pending diagnostic.  */
     764              :   virtual void add_note (std::unique_ptr<pending_note> pn) = 0;
     765              : 
     766              :   /* Hook for clients to add an event to the last previously stored
     767              :      pending diagnostic.  */
     768              :   virtual void add_event (std::unique_ptr<checker_event> event) = 0;
     769              : 
     770              :   /* Hook for clients to be notified when an SVAL that was reachable
     771              :      in a previous state is no longer live, so that clients can emit warnings
     772              :      about leaks.  */
     773              :   virtual void on_svalue_leak (const svalue *sval) = 0;
     774              : 
     775              :   /* Hook for clients to be notified when the set of explicitly live
     776              :      svalues changes, so that they can purge state relating to dead
     777              :      svalues.  */
     778              :   virtual void on_liveness_change (const svalue_set &live_svalues,
     779              :                                    const region_model *model) = 0;
     780              : 
     781              :   virtual logger *get_logger () = 0;
     782              : 
     783              :   /* Hook for clients to be notified when the condition
     784              :      "LHS OP RHS" is added to the region model.
     785              :      This exists so that state machines can detect tests on edges,
     786              :      and use them to trigger sm-state transitions (e.g. transitions due
     787              :      to ptrs becoming known to be NULL or non-NULL, rather than just
     788              :      "unchecked") */
     789              :   virtual void on_condition (const svalue *lhs,
     790              :                              enum tree_code op,
     791              :                              const svalue *rhs) = 0;
     792              : 
     793              :   /* Hook for clients to be notified when the condition that
     794              :      SVAL is within RANGES is added to the region model.
     795              :      Similar to on_condition, but for use when handling switch statements.
     796              :      RANGES is non-empty.  */
     797              :   virtual void on_bounded_ranges (const svalue &sval,
     798              :                                   const bounded_ranges &ranges) = 0;
     799              : 
     800              :   /* Hook for clients to be notified when a frame is popped from the stack.  */
     801              :   virtual void on_pop_frame (const frame_region *) = 0;
     802              : 
     803              :   /* Hooks for clients to be notified when an unknown change happens
     804              :      to SVAL (in response to a call to an unknown function).  */
     805              :   virtual void on_unknown_change (const svalue *sval, bool is_mutable) = 0;
     806              : 
     807              :   /* Hooks for clients to be notified when a phi node is handled,
     808              :      where RHS is the pertinent argument.  */
     809              :   virtual void on_phi (const gphi *phi, tree rhs) = 0;
     810              : 
     811              :   /* Hooks for clients to be notified when the region model doesn't
     812              :      know how to handle the tree code of T at LOC.  */
     813              :   virtual void on_unexpected_tree_code (tree t,
     814              :                                         const dump_location_t &loc) = 0;
     815              : 
     816              :   /* Hook for clients to be notified when a function_decl escapes.  */
     817              :   virtual void on_escaped_function (tree fndecl) = 0;
     818              : 
     819              :   virtual uncertainty_t *get_uncertainty () = 0;
     820              : 
     821              :   /* Hook for clients to purge state involving SVAL.  */
     822              :   virtual void purge_state_involving (const svalue *sval) = 0;
     823              : 
     824              :   /* Hook for clients to split state with a non-standard path.  */
     825              :   virtual void bifurcate (std::unique_ptr<custom_edge_info> info) = 0;
     826              : 
     827              :   /* Hook for clients to terminate the standard path.  */
     828              :   virtual void terminate_path () = 0;
     829              : 
     830              :   virtual const extrinsic_state *get_ext_state () const = 0;
     831              : 
     832              :   /* Hook for clients to access the a specific state machine in
     833              :      any underlying program_state.  */
     834              :   virtual bool
     835              :   get_state_map_by_name (const char *name,
     836              :                          sm_state_map **out_smap,
     837              :                          const state_machine **out_sm,
     838              :                          unsigned *out_sm_idx,
     839              :                          std::unique_ptr<sm_context> *out_sm_context) = 0;
     840              : 
     841              :   /* Precanned ways for clients to access specific state machines.  */
     842          766 :   bool get_fd_map (sm_state_map **out_smap,
     843              :                    const state_machine **out_sm,
     844              :                    unsigned *out_sm_idx,
     845              :                    std::unique_ptr<sm_context> *out_sm_context)
     846              :   {
     847          766 :     return get_state_map_by_name ("file-descriptor", out_smap, out_sm,
     848              :                                   out_sm_idx, out_sm_context);
     849              :   }
     850          310 :   bool get_malloc_map (sm_state_map **out_smap,
     851              :                        const state_machine **out_sm,
     852              :                        unsigned *out_sm_idx)
     853              :   {
     854          310 :     return get_state_map_by_name ("malloc", out_smap, out_sm, out_sm_idx,
     855              :                                   nullptr);
     856              :   }
     857       844922 :   bool get_taint_map (sm_state_map **out_smap,
     858              :                       const state_machine **out_sm,
     859              :                       unsigned *out_sm_idx)
     860              :   {
     861       844922 :     return get_state_map_by_name ("taint", out_smap, out_sm, out_sm_idx,
     862              :                                   nullptr);
     863              :   }
     864              : 
     865              :   bool possibly_tainted_p (const svalue *sval);
     866              : 
     867              :   /* Get the current statement, if any.  */
     868              :   virtual const gimple *get_stmt () const = 0;
     869              : 
     870              :   virtual const exploded_graph *get_eg () const = 0;
     871              : 
     872              :   virtual const program_state *get_state () const = 0;
     873              : 
     874              :   /* Hooks for detecting infinite loops.  */
     875              :   virtual void maybe_did_work () = 0;
     876              :   virtual bool checking_for_infinite_loop_p () const = 0;
     877              :   virtual void on_unusable_in_infinite_loop () = 0;
     878              : };
     879              : 
     880              : /* A "do nothing" subclass of region_model_context.  */
     881              : 
     882        64274 : class noop_region_model_context : public region_model_context
     883              : {
     884              : public:
     885              :   pending_location
     886          917 :   get_pending_location_for_diag () const override
     887              :   {
     888          917 :     return pending_location ();
     889              :   }
     890              :   bool
     891          913 :   warn_at (std::unique_ptr<pending_diagnostic>,
     892              :            pending_location &&) override
     893              :   {
     894          913 :     return false;
     895              :   }
     896              :   void add_note (std::unique_ptr<pending_note>) override;
     897              :   void add_event (std::unique_ptr<checker_event>) override;
     898            0 :   void on_svalue_leak (const svalue *) override {}
     899            0 :   void on_liveness_change (const svalue_set &,
     900            0 :                            const region_model *) override {}
     901       119712 :   logger *get_logger () override { return nullptr; }
     902           44 :   void on_condition (const svalue *lhs ATTRIBUTE_UNUSED,
     903              :                      enum tree_code op ATTRIBUTE_UNUSED,
     904              :                      const svalue *rhs ATTRIBUTE_UNUSED) override
     905              :   {
     906           44 :   }
     907          103 :   void on_bounded_ranges (const svalue &,
     908              :                           const bounded_ranges &) override
     909              :   {
     910          103 :   }
     911          302 :   void on_pop_frame (const frame_region *) override {}
     912         2272 :   void on_unknown_change (const svalue *sval ATTRIBUTE_UNUSED,
     913              :                           bool is_mutable ATTRIBUTE_UNUSED) override
     914              :   {
     915         2272 :   }
     916            0 :   void on_phi (const gphi *phi ATTRIBUTE_UNUSED,
     917              :                tree rhs ATTRIBUTE_UNUSED) override
     918              :   {
     919            0 :   }
     920            0 :   void on_unexpected_tree_code (tree, const dump_location_t &) override {}
     921              : 
     922            0 :   void on_escaped_function (tree) override {}
     923              : 
     924        45342 :   uncertainty_t *get_uncertainty () override { return nullptr; }
     925              : 
     926         2084 :   void purge_state_involving (const svalue *sval ATTRIBUTE_UNUSED) override {}
     927              : 
     928              :   void bifurcate (std::unique_ptr<custom_edge_info> info) override;
     929              :   void terminate_path () override;
     930              : 
     931        64004 :   const extrinsic_state *get_ext_state () const override { return nullptr; }
     932              : 
     933       119474 :   bool get_state_map_by_name (const char *,
     934              :                               sm_state_map **,
     935              :                               const state_machine **,
     936              :                               unsigned *,
     937              :                               std::unique_ptr<sm_context> *) override
     938              :   {
     939       119474 :     return false;
     940              :   }
     941              : 
     942        45595 :   const gimple *get_stmt () const override { return nullptr; }
     943            0 :   const exploded_graph *get_eg () const override { return nullptr; }
     944            0 :   const program_state *get_state () const override { return nullptr; }
     945              : 
     946          820 :   void maybe_did_work () override {}
     947           44 :   bool checking_for_infinite_loop_p () const override { return false; }
     948            0 :   void on_unusable_in_infinite_loop () override {}
     949              : };
     950              : 
     951              : /* A subclass of region_model_context for determining if operations fail
     952              :    e.g. "can we generate a region for the lvalue of EXPR?".  */
     953              : 
     954              : class tentative_region_model_context : public noop_region_model_context
     955              : {
     956              : public:
     957              :   tentative_region_model_context () : m_num_unexpected_codes (0) {}
     958              : 
     959            0 :   void on_unexpected_tree_code (tree, const dump_location_t &)
     960              :     final override
     961              :   {
     962            0 :     m_num_unexpected_codes++;
     963            0 :   }
     964              : 
     965              :   bool had_errors_p () const { return m_num_unexpected_codes > 0; }
     966              : 
     967              : private:
     968              :   int m_num_unexpected_codes;
     969              : };
     970              : 
     971              : /* Subclass of region_model_context that wraps another context, allowing
     972              :    for extra code to be added to the various hooks.  */
     973              : 
     974              : class region_model_context_decorator : public region_model_context
     975              : {
     976              :  public:
     977              :   pending_location
     978          211 :   get_pending_location_for_diag () const override
     979              :   {
     980          211 :     if (m_inner)
     981          207 :       return m_inner->get_pending_location_for_diag ();
     982              :     else
     983            4 :       return pending_location ();
     984              :   }
     985              : 
     986              :   bool
     987            9 :   warn_at (std::unique_ptr<pending_diagnostic> d,
     988              :            pending_location &&ploc) override
     989              :   {
     990            9 :     if (m_inner)
     991            9 :       return m_inner->warn_at (std::move (d), std::move (ploc));
     992              :     else
     993              :       return false;
     994              :   }
     995              : 
     996          202 :   void add_note (std::unique_ptr<pending_note> pn) override
     997              :   {
     998          202 :     if (m_inner)
     999          202 :       m_inner->add_note (std::move (pn));
    1000          202 :   }
    1001              :   void add_event (std::unique_ptr<checker_event> event) override;
    1002              : 
    1003            0 :   void on_svalue_leak (const svalue *sval) override
    1004              :   {
    1005            0 :     if (m_inner)
    1006            0 :       m_inner->on_svalue_leak (sval);
    1007            0 :   }
    1008              : 
    1009            0 :   void on_liveness_change (const svalue_set &live_svalues,
    1010              :                            const region_model *model) override
    1011              :   {
    1012            0 :     if (m_inner)
    1013            0 :       m_inner->on_liveness_change (live_svalues, model);
    1014            0 :   }
    1015              : 
    1016        23330 :   logger *get_logger () override
    1017              :   {
    1018        23330 :     if (m_inner)
    1019        14614 :       return m_inner->get_logger ();
    1020              :     else
    1021              :       return nullptr;
    1022              :   }
    1023              : 
    1024            0 :   void on_condition (const svalue *lhs,
    1025              :                      enum tree_code op,
    1026              :                      const svalue *rhs) override
    1027              :   {
    1028            0 :     if (m_inner)
    1029            0 :       m_inner->on_condition (lhs, op, rhs);
    1030            0 :   }
    1031              : 
    1032            0 :   void on_bounded_ranges (const svalue &sval,
    1033              :                           const bounded_ranges &ranges) override
    1034              :   {
    1035            0 :     if (m_inner)
    1036            0 :       m_inner->on_bounded_ranges (sval, ranges);
    1037            0 :   }
    1038              : 
    1039            0 :   void on_pop_frame (const frame_region *frame_reg) override
    1040              :   {
    1041            0 :     if (m_inner)
    1042            0 :       m_inner->on_pop_frame (frame_reg);
    1043            0 :   }
    1044              : 
    1045            0 :   void on_unknown_change (const svalue *sval, bool is_mutable) override
    1046              :   {
    1047            0 :     if (m_inner)
    1048            0 :       m_inner->on_unknown_change (sval, is_mutable);
    1049            0 :   }
    1050              : 
    1051            0 :   void on_phi (const gphi *phi, tree rhs) override
    1052              :   {
    1053            0 :     if (m_inner)
    1054            0 :       m_inner->on_phi (phi, rhs);
    1055            0 :   }
    1056              : 
    1057            0 :   void on_unexpected_tree_code (tree t,
    1058              :                                 const dump_location_t &loc) override
    1059              :   {
    1060            0 :     if (m_inner)
    1061            0 :       m_inner->on_unexpected_tree_code (t, loc);
    1062            0 :   }
    1063              : 
    1064            0 :   void on_escaped_function (tree fndecl) override
    1065              :   {
    1066            0 :     if (m_inner)
    1067            0 :       m_inner->on_escaped_function (fndecl);
    1068            0 :   }
    1069              : 
    1070         4135 :   uncertainty_t *get_uncertainty () override
    1071              :   {
    1072         4135 :     if (m_inner)
    1073         3359 :       return m_inner->get_uncertainty ();
    1074              :     else
    1075              :       return nullptr;
    1076              :   }
    1077              : 
    1078            0 :   void purge_state_involving (const svalue *sval) override
    1079              :   {
    1080            0 :     if (m_inner)
    1081            0 :       m_inner->purge_state_involving (sval);
    1082            0 :   }
    1083              : 
    1084            0 :   void bifurcate (std::unique_ptr<custom_edge_info> info) override
    1085              :   {
    1086            0 :     if (m_inner)
    1087            0 :       m_inner->bifurcate (std::move (info));
    1088            0 :   }
    1089              : 
    1090            0 :   void terminate_path () override
    1091              :   {
    1092            0 :     if (m_inner)
    1093            0 :       m_inner->terminate_path ();
    1094            0 :   }
    1095              : 
    1096         4860 :   const extrinsic_state *get_ext_state () const override
    1097              :   {
    1098         4860 :     if (m_inner)
    1099         4860 :       return m_inner->get_ext_state ();
    1100              :     else
    1101              :       return nullptr;
    1102              :   }
    1103              : 
    1104         6868 :   bool get_state_map_by_name (const char *name,
    1105              :                               sm_state_map **out_smap,
    1106              :                               const state_machine **out_sm,
    1107              :                               unsigned *out_sm_idx,
    1108              :                               std::unique_ptr<sm_context> *out_sm_context)
    1109              :     override
    1110              :   {
    1111         6868 :     if (m_inner)
    1112         4988 :       return m_inner->get_state_map_by_name (name, out_smap, out_sm, out_sm_idx,
    1113         4988 :                                              out_sm_context);
    1114              :     else
    1115              :       return false;
    1116              :   }
    1117              : 
    1118           98 :   const gimple *get_stmt () const override
    1119              :   {
    1120           98 :     if (m_inner)
    1121           98 :       return m_inner->get_stmt ();
    1122              :     else
    1123              :       return nullptr;
    1124              :   }
    1125              : 
    1126            0 :   const exploded_graph *get_eg () const override
    1127              :   {
    1128            0 :     if (m_inner)
    1129            0 :         return m_inner->get_eg ();
    1130              :     else
    1131              :         return nullptr;
    1132              :   }
    1133              : 
    1134            0 :   const program_state *get_state () const override
    1135              :   {
    1136            0 :     if (m_inner)
    1137            0 :       return m_inner->get_state ();
    1138              :     else
    1139              :       return nullptr;
    1140              :   }
    1141              : 
    1142            0 :   void maybe_did_work () override
    1143              :   {
    1144            0 :     if (m_inner)
    1145            0 :       m_inner->maybe_did_work ();
    1146            0 :   }
    1147              : 
    1148            0 :   bool checking_for_infinite_loop_p () const override
    1149              :   {
    1150            0 :     if (m_inner)
    1151            0 :       return m_inner->checking_for_infinite_loop_p ();
    1152              :     return false;
    1153              :   }
    1154            0 :   void on_unusable_in_infinite_loop () override
    1155              :   {
    1156            0 :     if (m_inner)
    1157            0 :       m_inner->on_unusable_in_infinite_loop ();
    1158            0 :   }
    1159              : 
    1160              : protected:
    1161        12406 :   region_model_context_decorator (region_model_context *inner)
    1162         4135 :   : m_inner (inner)
    1163              :   {
    1164              :   }
    1165              : 
    1166              :   region_model_context *m_inner;
    1167              : };
    1168              : 
    1169              : /* Subclass of region_model_context_decorator with a hook for adding
    1170              :    notes/events when saving diagnostics.  */
    1171              : 
    1172              : class annotating_context : public region_model_context_decorator
    1173              : {
    1174              : public:
    1175              :   bool
    1176          202 :   warn_at (std::unique_ptr<pending_diagnostic> d,
    1177              :            pending_location &&ploc) override
    1178              :   {
    1179          202 :     if (m_inner)
    1180          198 :       if (m_inner->warn_at (std::move (d), std::move (ploc)))
    1181              :         {
    1182          194 :           add_annotations ();
    1183          194 :           return true;
    1184              :         }
    1185              :     return false;
    1186              :   }
    1187              : 
    1188              :   /* Hook to add new event(s)/note(s)  */
    1189              :   virtual void add_annotations () = 0;
    1190              : 
    1191              : protected:
    1192         8271 :   annotating_context (region_model_context *inner)
    1193         8271 :   : region_model_context_decorator (inner)
    1194              :   {
    1195              :   }
    1196              : };
    1197              : 
    1198              : /* A bundle of data for use when attempting to merge two region_model
    1199              :    instances to make a third.  */
    1200              : 
    1201       148012 : struct model_merger
    1202              : {
    1203       148012 :   model_merger (const region_model *model_a,
    1204              :                 const region_model *model_b,
    1205              :                 const program_point &point,
    1206              :                 region_model *merged_model,
    1207              :                 const extrinsic_state *ext_state,
    1208              :                 const program_state *state_a,
    1209              :                 const program_state *state_b)
    1210       148012 :   : m_model_a (model_a), m_model_b (model_b),
    1211       148012 :     m_point (point),
    1212       148012 :     m_merged_model (merged_model),
    1213       148012 :     m_ext_state (ext_state),
    1214       148012 :     m_state_a (state_a), m_state_b (state_b)
    1215              :   {
    1216              :   }
    1217              : 
    1218              :   void dump_to_pp (pretty_printer *pp, bool simple) const;
    1219              :   void dump (FILE *fp, bool simple) const;
    1220              :   void dump (bool simple) const;
    1221              : 
    1222              :   region_model_manager *get_manager () const
    1223              :   {
    1224              :     return m_model_a->get_manager ();
    1225              :   }
    1226              : 
    1227              :   bool mergeable_svalue_p (const svalue *) const;
    1228              : 
    1229         4337 :   const supernode *get_supernode () const
    1230              :   {
    1231         4337 :     return m_point.get_supernode ();
    1232              :   }
    1233              : 
    1234              :   void on_widening_reuse (const widening_svalue *widening_sval);
    1235              : 
    1236              :   const region_model *m_model_a;
    1237              :   const region_model *m_model_b;
    1238              :   const program_point &m_point;
    1239              :   region_model *m_merged_model;
    1240              : 
    1241              :   const extrinsic_state *m_ext_state;
    1242              :   const program_state *m_state_a;
    1243              :   const program_state *m_state_b;
    1244              : 
    1245              :   hash_set<const svalue *> m_svals_changing_meaning;
    1246              : };
    1247              : 
    1248              : /* A record that can (optionally) be written out when
    1249              :    region_model::add_constraint fails.  */
    1250              : 
    1251              : class rejected_constraint
    1252              : {
    1253              : public:
    1254              :   virtual ~rejected_constraint () {}
    1255              :   virtual void dump_to_pp (pretty_printer *pp) const = 0;
    1256              : 
    1257            4 :   const region_model &get_model () const { return m_model; }
    1258              : 
    1259              : protected:
    1260         2261 :   rejected_constraint (const region_model &model)
    1261         2213 :   : m_model (model)
    1262              :   {}
    1263              : 
    1264              :   region_model m_model;
    1265              : };
    1266              : 
    1267              : class rejected_op_constraint : public rejected_constraint
    1268              : {
    1269              : public:
    1270         2213 :   rejected_op_constraint (const region_model &model,
    1271              :                           tree lhs, enum tree_code op, tree rhs)
    1272         2213 :   : rejected_constraint (model),
    1273         2213 :     m_lhs (lhs), m_op (op), m_rhs (rhs)
    1274              :   {}
    1275              : 
    1276              :   void dump_to_pp (pretty_printer *pp) const final override;
    1277              : 
    1278              :   tree m_lhs;
    1279              :   enum tree_code m_op;
    1280              :   tree m_rhs;
    1281              : };
    1282              : 
    1283              : class rejected_default_case : public rejected_constraint
    1284              : {
    1285              : public:
    1286            0 :   rejected_default_case (const region_model &model)
    1287            0 :   : rejected_constraint (model)
    1288              :   {}
    1289              : 
    1290              :   void dump_to_pp (pretty_printer *pp) const final override;
    1291              : };
    1292              : 
    1293              : class rejected_ranges_constraint : public rejected_constraint
    1294              : {
    1295              : public:
    1296           48 :   rejected_ranges_constraint (const region_model &model,
    1297              :                               tree expr, const bounded_ranges *ranges)
    1298           48 :   : rejected_constraint (model),
    1299           48 :     m_expr (expr), m_ranges (ranges)
    1300              :   {}
    1301              : 
    1302              :   void dump_to_pp (pretty_printer *pp) const final override;
    1303              : 
    1304              : private:
    1305              :   tree m_expr;
    1306              :   const bounded_ranges *m_ranges;
    1307              : };
    1308              : 
    1309              : /* A bundle of state.  */
    1310              : 
    1311              : class engine
    1312              : {
    1313              : public:
    1314              :   engine (region_model_manager &mgr,
    1315              :           const supergraph *sg = nullptr);
    1316       355779 :   const supergraph *get_supergraph () { return m_sg; }
    1317     16959731 :   region_model_manager *get_model_manager () { return &m_mgr; }
    1318         3415 :   known_function_manager *get_known_function_manager ()
    1319              :   {
    1320         3415 :     return m_mgr.get_known_function_manager ();
    1321              :   }
    1322              : 
    1323              :   void log_stats (logger *logger) const;
    1324              : 
    1325              : private:
    1326              :   region_model_manager &m_mgr;
    1327              :   const supergraph *m_sg;
    1328              : };
    1329              : 
    1330              : } // namespace ana
    1331              : 
    1332              : extern void debug (const region_model &rmodel);
    1333              : 
    1334              : namespace ana {
    1335              : 
    1336              : #if CHECKING_P
    1337              : 
    1338              : namespace selftest {
    1339              : 
    1340              : using namespace ::selftest;
    1341              : 
    1342              : /* An implementation of region_model_context for use in selftests, which
    1343              :    stores any pending_diagnostic instances passed to it.  */
    1344              : 
    1345          224 : class test_region_model_context : public noop_region_model_context
    1346              : {
    1347              : public:
    1348              :   bool
    1349            4 :   warn_at (std::unique_ptr<pending_diagnostic> d,
    1350              :            pending_location &&) final override
    1351              :   {
    1352            4 :     m_diagnostics.safe_push (d.release ());
    1353            4 :     return true;
    1354              :   }
    1355              : 
    1356            4 :   unsigned get_num_diagnostics () const { return m_diagnostics.length (); }
    1357              : 
    1358            0 :   void on_unexpected_tree_code (tree t, const dump_location_t &)
    1359              :     final override
    1360              :   {
    1361            0 :     internal_error ("unhandled tree code: %qs",
    1362            0 :                     get_tree_code_name (TREE_CODE (t)));
    1363              :   }
    1364              : 
    1365              : private:
    1366              :   /* Implicitly delete any diagnostics in the dtor.  */
    1367              :   auto_delete_vec<pending_diagnostic> m_diagnostics;
    1368              : };
    1369              : 
    1370              : /* Attempt to add the constraint (LHS OP RHS) to MODEL.
    1371              :    Verify that MODEL remains satisfiable.  */
    1372              : 
    1373              : #define ADD_SAT_CONSTRAINT(MODEL, LHS, OP, RHS) \
    1374              :   SELFTEST_BEGIN_STMT                                   \
    1375              :     bool sat = (MODEL).add_constraint (LHS, OP, RHS, nullptr);  \
    1376              :     ASSERT_TRUE (sat);                                  \
    1377              :   SELFTEST_END_STMT
    1378              : 
    1379              : /* Attempt to add the constraint (LHS OP RHS) to MODEL.
    1380              :    Verify that the result is not satisfiable.  */
    1381              : 
    1382              : #define ADD_UNSAT_CONSTRAINT(MODEL, LHS, OP, RHS)       \
    1383              :   SELFTEST_BEGIN_STMT                                   \
    1384              :     bool sat = (MODEL).add_constraint (LHS, OP, RHS, nullptr);  \
    1385              :     ASSERT_FALSE (sat);                         \
    1386              :   SELFTEST_END_STMT
    1387              : 
    1388              : /* Implementation detail of the ASSERT_CONDITION_* macros.  */
    1389              : 
    1390              : void assert_condition (const location &loc,
    1391              :                        region_model &model,
    1392              :                        const svalue *lhs, tree_code op, const svalue *rhs,
    1393              :                        tristate expected);
    1394              : 
    1395              : void assert_condition (const location &loc,
    1396              :                        region_model &model,
    1397              :                        tree lhs, tree_code op, tree rhs,
    1398              :                        tristate expected);
    1399              : 
    1400              : /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
    1401              :    as "true".  */
    1402              : 
    1403              : #define ASSERT_CONDITION_TRUE(REGION_MODEL, LHS, OP, RHS) \
    1404              :   SELFTEST_BEGIN_STMT                                                   \
    1405              :   assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS,      \
    1406              :                     tristate (tristate::TS_TRUE));              \
    1407              :   SELFTEST_END_STMT
    1408              : 
    1409              : /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
    1410              :    as "false".  */
    1411              : 
    1412              : #define ASSERT_CONDITION_FALSE(REGION_MODEL, LHS, OP, RHS) \
    1413              :   SELFTEST_BEGIN_STMT                                                   \
    1414              :   assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS,      \
    1415              :                     tristate (tristate::TS_FALSE));             \
    1416              :   SELFTEST_END_STMT
    1417              : 
    1418              : /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
    1419              :    as "unknown".  */
    1420              : 
    1421              : #define ASSERT_CONDITION_UNKNOWN(REGION_MODEL, LHS, OP, RHS) \
    1422              :   SELFTEST_BEGIN_STMT                                                   \
    1423              :   assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS,      \
    1424              :                     tristate (tristate::TS_UNKNOWN));           \
    1425              :   SELFTEST_END_STMT
    1426              : 
    1427              : } /* end of namespace selftest.  */
    1428              : 
    1429              : #endif /* #if CHECKING_P */
    1430              : 
    1431              : } // namespace ana
    1432              : 
    1433              : #endif /* GCC_ANALYZER_REGION_MODEL_H */
        

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.