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-05-11 19:44:49 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       829244 : 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       829244 : inline one_way_id_map<T>::one_way_id_map (int num_svalues)
      72       829244 : : m_src_to_dst (num_svalues)
      73              : {
      74      4104912 :   for (int i = 0; i < num_svalues; i++)
      75      3275668 :     m_src_to_dst.quick_push (T::null ());
      76       829244 : }
      77              : 
      78              : /* Record that SRC is to be mapped to DST.  */
      79              : 
      80              : template <typename T>
      81              : inline void
      82      3246230 : one_way_id_map<T>::put (T src, T dst)
      83              : {
      84      3246230 :   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      4375888 : one_way_id_map<T>::get_dst_for_src (T src) const
      92              : {
      93      4375888 :   if (src.null_p ())
      94            0 :     return src;
      95      4375888 :   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      4375888 : one_way_id_map<T>::update (T *id) const
     137              : {
     138      2193152 :   *id = get_dst_for_src (*id);
     139              : }
     140              : 
     141              : /* A mapping from region to svalue for use when tracking state.  */
     142              : 
     143      3896153 : 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       415012 :   region_to_value_map () : m_hash_map () {}
     150      3481141 :   region_to_value_map (const region_to_value_map &other)
     151      3481141 :   : 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       447526 :   bool operator!= (const region_to_value_map &other) const
     156              :   {
     157       447526 :     return !(*this == other);
     158              :   }
     159              : 
     160       112161 :   iterator begin () const { return m_hash_map.begin (); }
     161       557563 :   iterator end () const { return m_hash_map.end (); }
     162              : 
     163       205641 :   const svalue * const *get (const region *reg) const
     164              :   {
     165       205641 :     return const_cast <hash_map_t &> (m_hash_map).get (reg);
     166              :   }
     167        23070 :   void put (const region *reg, const svalue *sval)
     168              :   {
     169        23070 :     m_hash_map.put (reg, sval);
     170              :   }
     171        51662 :   void remove (const region *reg)
     172              :   {
     173        51662 :     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       748895 : class visitor
     223              : {
     224              : public:
     225       752794 :   virtual void visit_region_svalue (const region_svalue *) {}
     226      9311258 :   virtual void visit_constant_svalue (const constant_svalue *) {}
     227      1900379 :   virtual void visit_unknown_svalue (const unknown_svalue *) {}
     228        12768 :   virtual void visit_poisoned_svalue (const poisoned_svalue *) {}
     229          942 :   virtual void visit_setjmp_svalue (const setjmp_svalue *) {}
     230      1273953 :   virtual void visit_initial_svalue (const initial_svalue *) {}
     231      7054227 :   virtual void visit_unaryop_svalue (const unaryop_svalue *) {}
     232      6260130 :   virtual void visit_binop_svalue (const binop_svalue *) {}
     233      3944631 :   virtual void visit_sub_svalue (const sub_svalue *) {}
     234        45188 :   virtual void visit_repeated_svalue (const repeated_svalue *) {}
     235        49232 :   virtual void visit_bits_within_svalue (const bits_within_svalue *) {}
     236         6752 :   virtual void visit_unmergeable_svalue (const unmergeable_svalue *) {}
     237        38169 :   virtual void visit_placeholder_svalue (const placeholder_svalue *) {}
     238       111459 :   virtual void visit_widening_svalue (const widening_svalue *) {}
     239           38 :   virtual void visit_compound_svalue (const compound_svalue *) {}
     240      5010425 :   virtual void visit_conjured_svalue (const conjured_svalue *) {}
     241         6099 :   virtual void visit_asm_output_svalue (const asm_output_svalue *) {}
     242         8497 :   virtual void visit_const_fn_result_svalue (const const_fn_result_svalue *) {}
     243              : 
     244      3368612 :   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         5740 :   exception_node (const svalue *exception_sval,
     255              :                   const svalue *typeinfo_sval,
     256              :                   const svalue *destructor_sval)
     257         5740 :   : m_exception_sval (exception_sval),
     258         5740 :     m_typeinfo_sval (typeinfo_sval),
     259         5740 :     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_null_return (const call_details &cd,
     356              :                                bool unmergeable);
     357              :   void update_for_nonzero_return (const call_details &cd);
     358              : 
     359              :   void handle_unrecognized_call (const gcall &call,
     360              :                                  region_model_context *ctxt);
     361              :   void get_reachable_svalues (svalue_set *out,
     362              :                               const svalue *extra_sval,
     363              :                               const uncertainty_t *uncertainty);
     364              : 
     365              :   void on_return (const greturn *stmt, region_model_context *ctxt);
     366              :   void on_setjmp (const gcall &stmt,
     367              :                   const exploded_node &enode,
     368              :                   const superedge &sedge,
     369              :                   region_model_context *ctxt);
     370              :   void on_longjmp (const gcall &longjmp_call, const gcall &setjmp_call,
     371              :                    int setjmp_stack_depth, region_model_context *ctxt);
     372              : 
     373              :   void update_for_gcall (const gcall &call_stmt,
     374              :                          region_model_context *ctxt,
     375              :                          function *callee = nullptr);
     376              : 
     377              :   void update_for_return_gcall (const gcall &call_stmt,
     378              :                                 region_model_context *ctxt);
     379              : 
     380              :   const region *push_frame (const function &fun,
     381              :                             const gcall *call_stmt,
     382              :                             const vec<const svalue *> *arg_sids,
     383              :                             region_model_context *ctxt);
     384     10083197 :   const frame_region *get_current_frame () const { return m_current_frame; }
     385              :   const function *get_current_function () const;
     386              :   void pop_frame (tree result_lvalue,
     387              :                   const svalue **out_result,
     388              :                   region_model_context *ctxt,
     389              :                   const gcall *call_stmt,
     390              :                   bool eval_return_svalue = true);
     391              :   int get_stack_depth () const;
     392              :   const frame_region *get_frame_at_index (int index) const;
     393              : 
     394              :   const region *get_lvalue (path_var pv, region_model_context *ctxt) const;
     395              :   const region *get_lvalue (tree expr, region_model_context *ctxt) const;
     396              :   const svalue *get_rvalue (path_var pv, region_model_context *ctxt) const;
     397              :   const svalue *get_rvalue (tree expr, region_model_context *ctxt) const;
     398              : 
     399              :   const region *deref_rvalue (const svalue *ptr_sval, tree ptr_tree,
     400              :                               region_model_context *ctxt,
     401              :                               bool add_nonnull_constraint = true) const;
     402              : 
     403              :   const svalue *get_rvalue_for_bits (tree type,
     404              :                                      const region *reg,
     405              :                                      const bit_range &bits,
     406              :                                      region_model_context *ctxt) const;
     407              : 
     408              :   void set_value (const region *lhs_reg, const svalue *rhs_sval,
     409              :                   region_model_context *ctxt);
     410              :   void set_value (tree lhs, tree rhs, region_model_context *ctxt);
     411              :   void clobber_region (const region *reg);
     412              :   void purge_region (const region *reg);
     413              :   void fill_region (const region *reg,
     414              :                     const svalue *sval,
     415              :                     region_model_context *ctxt);
     416              :   void zero_fill_region (const region *reg,
     417              :                          region_model_context *ctxt);
     418              :   void write_bytes (const region *dest_reg,
     419              :                     const svalue *num_bytes_sval,
     420              :                     const svalue *sval,
     421              :                     region_model_context *ctxt);
     422              :   const svalue *read_bytes (const region *src_reg,
     423              :                             tree src_ptr_expr,
     424              :                             const svalue *num_bytes_sval,
     425              :                             region_model_context *ctxt) const;
     426              :   void copy_bytes (const region *dest_reg,
     427              :                    const region *src_reg,
     428              :                    tree src_ptr_expr,
     429              :                    const svalue *num_bytes_sval,
     430              :                    region_model_context *ctxt);
     431              :   void mark_region_as_unknown (const region *reg, uncertainty_t *uncertainty);
     432              : 
     433              :   tristate eval_condition (const svalue *lhs,
     434              :                            enum tree_code op,
     435              :                            const svalue *rhs) const;
     436              :   tristate compare_initial_and_pointer (const initial_svalue *init,
     437              :                                         const region_svalue *ptr) const;
     438              :   tristate symbolic_greater_than (const binop_svalue *a,
     439              :                                   const svalue *b) const;
     440              :   tristate structural_equality (const svalue *a, const svalue *b) const;
     441              :   tristate eval_condition (tree lhs,
     442              :                            enum tree_code op,
     443              :                            tree rhs,
     444              :                            region_model_context *ctxt) const;
     445              :   bool add_constraint (tree lhs, enum tree_code op, tree rhs,
     446              :                        region_model_context *ctxt);
     447              :   bool add_constraint (tree lhs, enum tree_code op, tree rhs,
     448              :                        region_model_context *ctxt,
     449              :                        std::unique_ptr<rejected_constraint> *out);
     450              : 
     451              :         const region *
     452              :         get_or_create_region_for_heap_alloc (const svalue *size_in_bytes,
     453              :                                 region_model_context *ctxt,
     454              :                                 bool update_state_machine = false,
     455              :                                 const call_details *cd = nullptr);
     456              : 
     457              :   const region *create_region_for_alloca (const svalue *size_in_bytes,
     458              :                                           region_model_context *ctxt);
     459              :   void get_referenced_base_regions (auto_bitmap &out_ids) const;
     460              : 
     461              :   tree get_representative_tree (const svalue *sval,
     462              :                                 logger *logger = nullptr) const;
     463              :   tree get_representative_tree (const region *reg,
     464              :                                 logger *logger = nullptr) const;
     465              :   path_var
     466              :   get_representative_path_var (const svalue *sval,
     467              :                                svalue_set *visited,
     468              :                                logger *logger) const;
     469              :   path_var
     470              :   get_representative_path_var (const region *reg,
     471              :                                svalue_set *visited,
     472              :                                logger *logger) const;
     473              : 
     474              :   /* For selftests.  */
     475       527280 :   constraint_manager *get_constraints ()
     476              :   {
     477       527280 :     return m_constraints;
     478              :   }
     479              : 
     480      1015279 :   store *get_store () { return &m_store; }
     481       268546 :   const store *get_store () const { return &m_store; }
     482              : 
     483              :   const dynamic_extents_t &
     484        44845 :   get_dynamic_extents () const
     485              :   {
     486        44845 :     return m_dynamic_extents;
     487              :   }
     488              :   const svalue *get_dynamic_extents (const region *reg) const;
     489              :   void set_dynamic_extents (const region *reg,
     490              :                             const svalue *size_in_bytes,
     491              :                             region_model_context *ctxt);
     492              :   void unset_dynamic_extents (const region *reg);
     493              : 
     494        92423 :   region_model_manager *get_manager () const { return m_mgr; }
     495              :   bounded_ranges_manager *get_range_manager () const
     496              :   {
     497              :     return m_mgr->get_range_manager ();
     498              :   }
     499              : 
     500              :   void unbind_region_and_descendents (const region *reg,
     501              :                                       enum poison_kind pkind);
     502              : 
     503              :   bool can_merge_with_p (const region_model &other_model,
     504              :                          const program_point &point,
     505              :                          region_model *out_model,
     506              :                          const extrinsic_state *ext_state = nullptr,
     507              :                          const program_state *state_a = nullptr,
     508              :                          const program_state *state_b = nullptr) const;
     509              : 
     510              :   tree get_fndecl_for_call (const gcall &call,
     511              :                             region_model_context *ctxt);
     512              : 
     513              :   void get_regions_for_current_frame (auto_vec<const decl_region *> *out) const;
     514              :   static void append_regions_cb (const region *base_reg,
     515              :                                  struct append_regions_cb_data *data);
     516              : 
     517              :   const svalue *get_store_value (const region *reg,
     518              :                                  region_model_context *ctxt) const;
     519              :   const svalue *get_store_bytes (const region *base_reg,
     520              :                                  const byte_range &bytes,
     521              :                                  region_model_context *ctxt) const;
     522              :   const svalue *scan_for_null_terminator (const region *reg,
     523              :                                           tree expr,
     524              :                                           const svalue **out_sval,
     525              :                                           region_model_context *ctxt) const;
     526              :   const svalue *scan_for_null_terminator_1 (const region *reg,
     527              :                                             tree expr,
     528              :                                             const svalue **out_sval,
     529              :                                             region_model_context *ctxt) const;
     530              : 
     531              :   bool region_exists_p (const region *reg) const;
     532              : 
     533              :   void loop_replay_fixup (const region_model *dst_state);
     534              : 
     535              :   const svalue *get_capacity (const region *reg) const;
     536              : 
     537              :   bool replay_call_summary (call_summary_replay &r,
     538              :                             const region_model &summary);
     539              : 
     540              :   void maybe_complain_about_infoleak (const region *dst_reg,
     541              :                                       const svalue *copied_sval,
     542              :                                       const region *src_reg,
     543              :                                       region_model_context *ctxt);
     544              : 
     545              :   void set_errno (const call_details &cd);
     546              : 
     547              :   /* Implemented in sm-fd.cc  */
     548              :   void mark_as_valid_fd (const svalue *sval, region_model_context *ctxt);
     549              : 
     550              :   /* Implemented in sm-malloc.cc  */
     551              :   void on_realloc_with_move (const call_details &cd,
     552              :                              const svalue *old_ptr_sval,
     553              :                              const svalue *new_ptr_sval);
     554              : 
     555              :   /* Implemented in sm-malloc.cc.  */
     556              :   void
     557              :   transition_ptr_sval_non_null (region_model_context *ctxt,
     558              :       const svalue *new_ptr_sval);
     559              : 
     560              :   /* Implemented in sm-taint.cc.  */
     561              :   void mark_as_tainted (const svalue *sval,
     562              :                         region_model_context *ctxt);
     563              : 
     564              :   bool add_constraint (const svalue *lhs,
     565              :                        enum tree_code op,
     566              :                        const svalue *rhs,
     567              :                        region_model_context *ctxt);
     568              : 
     569              :   const svalue *check_for_poison (const svalue *sval,
     570              :                                   tree expr,
     571              :                                   const region *src_region,
     572              :                                   region_model_context *ctxt) const;
     573              : 
     574              :   void check_region_for_write (const region *dest_reg,
     575              :                                const svalue *sval_hint,
     576              :                                region_model_context *ctxt) const;
     577              : 
     578              :   const svalue *
     579              :   check_for_null_terminated_string_arg (const call_details &cd,
     580              :                                         unsigned idx) const;
     581              :   const svalue *
     582              :   check_for_null_terminated_string_arg (const call_details &cd,
     583              :                                         unsigned idx,
     584              :                                         bool include_terminator,
     585              :                                         const svalue **out_sval) const;
     586              : 
     587              :   const builtin_known_function *
     588              :   get_builtin_kf (const gcall &call,
     589              :                   region_model_context *ctxt = nullptr) const;
     590              : 
     591              :   bool called_from_main_p () const;
     592              : 
     593         5824 :   void push_thrown_exception (const exception_node &node)
     594              :   {
     595         5824 :     m_thrown_exceptions_stack.push_back (node);
     596           84 :   }
     597          490 :   const exception_node *get_current_thrown_exception () const
     598              :   {
     599          490 :     if (m_thrown_exceptions_stack.empty ())
     600              :       return nullptr;
     601          487 :     return &m_thrown_exceptions_stack.back ();
     602              :   }
     603          262 :   exception_node pop_thrown_exception ()
     604              :   {
     605          262 :     gcc_assert (!m_thrown_exceptions_stack.empty ());
     606          262 :     const exception_node retval = m_thrown_exceptions_stack.back ();
     607          262 :     m_thrown_exceptions_stack.pop_back ();
     608          262 :     return retval;
     609              :   }
     610              : 
     611          262 :   void push_caught_exception (const exception_node &node)
     612              :   {
     613          262 :     m_caught_exceptions_stack.push_back (node);
     614              :   }
     615          198 :   const exception_node *get_current_caught_exception () const
     616              :   {
     617          198 :     if (m_caught_exceptions_stack.empty ())
     618              :       return nullptr;
     619          150 :     return &m_caught_exceptions_stack.back ();
     620              :   }
     621          196 :   exception_node pop_caught_exception ()
     622              :   {
     623          196 :     gcc_assert (!m_caught_exceptions_stack.empty ());
     624          196 :     const exception_node retval = m_caught_exceptions_stack.back ();
     625          196 :     m_caught_exceptions_stack.pop_back ();
     626          196 :     return retval;
     627              :   }
     628              : 
     629              : private:
     630              :   const region *get_lvalue_1 (path_var pv, region_model_context *ctxt) const;
     631              :   const svalue *get_rvalue_1 (path_var pv, region_model_context *ctxt) const;
     632              : 
     633              :   path_var
     634              :   get_representative_path_var_1 (const svalue *sval,
     635              :                                  svalue_set *visited,
     636              :                                  logger *logger) const;
     637              :   path_var
     638              :   get_representative_path_var_1 (const region *reg,
     639              :                                  svalue_set *visited,
     640              :                                  logger *logger) const;
     641              : 
     642              :   const known_function *get_known_function (tree fndecl,
     643              :                                             const call_details &cd) const;
     644              :   const known_function *get_known_function (enum internal_fn) const;
     645              : 
     646              :   bool add_constraints_from_binop (const svalue *outer_lhs,
     647              :                                    enum tree_code outer_op,
     648              :                                    const svalue *outer_rhs,
     649              :                                    bool *out,
     650              :                                    region_model_context *ctxt);
     651              : 
     652              :   void poison_any_pointers_to_descendents (const region *reg,
     653              :                                            enum poison_kind pkind);
     654              : 
     655              :   void on_top_level_param (tree param,
     656              :                            bool nonnull,
     657              :                            region_model_context *ctxt);
     658              : 
     659              :   const svalue *get_initial_value_for_global (const region *reg) const;
     660              : 
     661              :   const region * get_region_for_poisoned_expr (tree expr) const;
     662              : 
     663              :   void check_dynamic_size_for_taint (enum memory_space mem_space,
     664              :                                      const svalue *size_in_bytes,
     665              :                                      region_model_context *ctxt) const;
     666              :   void check_dynamic_size_for_floats (const svalue *size_in_bytes,
     667              :                                       region_model_context *ctxt) const;
     668              : 
     669              :   void check_region_for_taint (const region *reg,
     670              :                                enum access_direction dir,
     671              :                                region_model_context *ctxt) const;
     672              : 
     673              :   void check_for_writable_region (const region* dest_reg,
     674              :                                   region_model_context *ctxt) const;
     675              :   bool check_region_access (const region *reg,
     676              :                             enum access_direction dir,
     677              :                             const svalue *sval_hint,
     678              :                             region_model_context *ctxt) const;
     679              :   bool check_region_for_read (const region *src_reg,
     680              :                               region_model_context *ctxt) const;
     681              :   void check_region_size (const region *lhs_reg, const svalue *rhs_sval,
     682              :                           region_model_context *ctxt) const;
     683              : 
     684              :   /* Implemented in bounds-checking.cc  */
     685              :   bool check_symbolic_bounds (const region *base_reg,
     686              :                               const svalue *sym_byte_offset,
     687              :                               const svalue *num_bytes_sval,
     688              :                               const svalue *capacity,
     689              :                               enum access_direction dir,
     690              :                               const svalue *sval_hint,
     691              :                               region_model_context *ctxt) const;
     692              :   bool check_region_bounds (const region *reg, enum access_direction dir,
     693              :                             const svalue *sval_hint,
     694              :                             region_model_context *ctxt) const;
     695              : 
     696              :   void check_call_args (const call_details &cd) const;
     697              :   void check_call_format_attr (const call_details &cd,
     698              :                                tree format_attr) const;
     699              :   void check_function_attr_access (const gcall &call,
     700              :                                    tree callee_fndecl,
     701              :                                    region_model_context *ctxt,
     702              :                                    rdwr_map &rdwr_idx) const;
     703              :   void check_function_attr_null_terminated_string_arg (const gcall &call,
     704              :                                                        tree callee_fndecl,
     705              :                                                        region_model_context *ctxt,
     706              :                                                        rdwr_map &rdwr_idx);
     707              :   void check_one_function_attr_null_terminated_string_arg (const gcall &call,
     708              :                                                            tree callee_fndecl,
     709              :                                                            region_model_context *ctxt,
     710              :                                                            rdwr_map &rdwr_idx,
     711              :                                                            tree attr);
     712              :   void check_function_attrs (const gcall &call,
     713              :                              tree callee_fndecl,
     714              :                              region_model_context *ctxt);
     715              : 
     716              :   void check_for_throw_inside_call (const gcall &call,
     717              :                                     tree fndecl,
     718              :                                     region_model_context *ctxt);
     719              : 
     720              :   /* Storing this here to avoid passing it around everywhere.  */
     721              :   region_model_manager *const m_mgr;
     722              : 
     723              :   store m_store;
     724              : 
     725              :   constraint_manager *m_constraints; // TODO: embed, rather than dynalloc?
     726              : 
     727              :   const frame_region *m_current_frame;
     728              : 
     729              :   std::vector<exception_node> m_thrown_exceptions_stack;
     730              :   std::vector<exception_node> m_caught_exceptions_stack;
     731              : 
     732              :   /* Map from base region to size in bytes, for tracking the sizes of
     733              :      dynamically-allocated regions.
     734              :      This is part of the region_model rather than the region to allow for
     735              :      memory regions to be resized (e.g. by realloc).  */
     736              :   dynamic_extents_t m_dynamic_extents;
     737              : };
     738              : 
     739              : /* Some region_model activity could lead to warnings (e.g. attempts to use an
     740              :    uninitialized value).  This abstract base class encapsulates an interface
     741              :    for the region model to use when emitting such warnings.
     742              : 
     743              :    Having this as an abstract base class allows us to support the various
     744              :    operations needed by program_state in the analyzer within region_model,
     745              :    whilst keeping them somewhat modularized.  */
     746              : 
     747      1434405 : class region_model_context
     748              : {
     749              :  public:
     750              :   bool
     751              :   warn (std::unique_ptr<pending_diagnostic> d,
     752              :         std::unique_ptr<pending_location::fixer_for_epath> ploc_fixer = nullptr);
     753              : 
     754              :   /* Hook for determining where diagnostics are to currently be emitted.  */
     755              :   virtual pending_location
     756              :   get_pending_location_for_diag () const = 0;
     757              : 
     758              :   /* Hook for clients to store pending diagnostics.
     759              :      Return true if the diagnostic was stored, or false if it was deleted.  */
     760              :   virtual bool
     761              :   warn_at (std::unique_ptr<pending_diagnostic> d,
     762              :            pending_location &&ploc) = 0;
     763              : 
     764              :   /* Hook for clients to add a note to the last previously stored
     765              :      pending diagnostic.  */
     766              :   virtual void add_note (std::unique_ptr<pending_note> pn) = 0;
     767              : 
     768              :   /* Hook for clients to add an event to the last previously stored
     769              :      pending diagnostic.  */
     770              :   virtual void add_event (std::unique_ptr<checker_event> event) = 0;
     771              : 
     772              :   /* Hook for clients to be notified when an SVAL that was reachable
     773              :      in a previous state is no longer live, so that clients can emit warnings
     774              :      about leaks.  */
     775              :   virtual void on_svalue_leak (const svalue *sval) = 0;
     776              : 
     777              :   /* Hook for clients to be notified when the set of explicitly live
     778              :      svalues changes, so that they can purge state relating to dead
     779              :      svalues.  */
     780              :   virtual void on_liveness_change (const svalue_set &live_svalues,
     781              :                                    const region_model *model) = 0;
     782              : 
     783              :   virtual logger *get_logger () = 0;
     784              : 
     785              :   /* Hook for clients to be notified when the condition
     786              :      "LHS OP RHS" is added to the region model.
     787              :      This exists so that state machines can detect tests on edges,
     788              :      and use them to trigger sm-state transitions (e.g. transitions due
     789              :      to ptrs becoming known to be NULL or non-NULL, rather than just
     790              :      "unchecked") */
     791              :   virtual void on_condition (const svalue *lhs,
     792              :                              enum tree_code op,
     793              :                              const svalue *rhs) = 0;
     794              : 
     795              :   /* Hook for clients to be notified when the condition that
     796              :      SVAL is within RANGES is added to the region model.
     797              :      Similar to on_condition, but for use when handling switch statements.
     798              :      RANGES is non-empty.  */
     799              :   virtual void on_bounded_ranges (const svalue &sval,
     800              :                                   const bounded_ranges &ranges) = 0;
     801              : 
     802              :   /* Hook for clients to be notified when a frame is popped from the stack.  */
     803              :   virtual void on_pop_frame (const frame_region *) = 0;
     804              : 
     805              :   /* Hooks for clients to be notified when an unknown change happens
     806              :      to SVAL (in response to a call to an unknown function).  */
     807              :   virtual void on_unknown_change (const svalue *sval, bool is_mutable) = 0;
     808              : 
     809              :   /* Hooks for clients to be notified when a phi node is handled,
     810              :      where RHS is the pertinent argument.  */
     811              :   virtual void on_phi (const gphi *phi, tree rhs) = 0;
     812              : 
     813              :   /* Hooks for clients to be notified when the region model doesn't
     814              :      know how to handle the tree code of T at LOC.  */
     815              :   virtual void on_unexpected_tree_code (tree t,
     816              :                                         const dump_location_t &loc) = 0;
     817              : 
     818              :   /* Hook for clients to be notified when a function_decl escapes.  */
     819              :   virtual void on_escaped_function (tree fndecl) = 0;
     820              : 
     821              :   virtual uncertainty_t *get_uncertainty () = 0;
     822              : 
     823              :   /* Hook for clients to purge state involving SVAL.  */
     824              :   virtual void purge_state_involving (const svalue *sval) = 0;
     825              : 
     826              :   /* Hook for clients to split state with a non-standard path.  */
     827              :   virtual void bifurcate (std::unique_ptr<custom_edge_info> info) = 0;
     828              : 
     829              :   /* Hook for clients to terminate the standard path.  */
     830              :   virtual void terminate_path () = 0;
     831              : 
     832              :   virtual const extrinsic_state *get_ext_state () const = 0;
     833              : 
     834              :   /* Hook for clients to access the a specific state machine in
     835              :      any underlying program_state.  */
     836              :   virtual bool
     837              :   get_state_map_by_name (const char *name,
     838              :                          sm_state_map **out_smap,
     839              :                          const state_machine **out_sm,
     840              :                          unsigned *out_sm_idx,
     841              :                          std::unique_ptr<sm_context> *out_sm_context) = 0;
     842              : 
     843              :   /* Precanned ways for clients to access specific state machines.  */
     844          818 :   bool get_fd_map (sm_state_map **out_smap,
     845              :                    const state_machine **out_sm,
     846              :                    unsigned *out_sm_idx,
     847              :                    std::unique_ptr<sm_context> *out_sm_context)
     848              :   {
     849          818 :     return get_state_map_by_name ("file-descriptor", out_smap, out_sm,
     850              :                                   out_sm_idx, out_sm_context);
     851              :   }
     852          310 :   bool get_malloc_map (sm_state_map **out_smap,
     853              :                        const state_machine **out_sm,
     854              :                        unsigned *out_sm_idx)
     855              :   {
     856          310 :     return get_state_map_by_name ("malloc", out_smap, out_sm, out_sm_idx,
     857              :                                   nullptr);
     858              :   }
     859       848162 :   bool get_taint_map (sm_state_map **out_smap,
     860              :                       const state_machine **out_sm,
     861              :                       unsigned *out_sm_idx)
     862              :   {
     863       848162 :     return get_state_map_by_name ("taint", out_smap, out_sm, out_sm_idx,
     864              :                                   nullptr);
     865              :   }
     866              : 
     867              :   bool possibly_tainted_p (const svalue *sval);
     868              : 
     869              :   /* Get the current statement, if any.  */
     870              :   virtual const gimple *get_stmt () const = 0;
     871              : 
     872              :   virtual const exploded_graph *get_eg () const = 0;
     873              : 
     874              :   virtual const program_state *get_state () const = 0;
     875              : 
     876              :   /* Hooks for detecting infinite loops.  */
     877              :   virtual void maybe_did_work () = 0;
     878              :   virtual bool checking_for_infinite_loop_p () const = 0;
     879              :   virtual void on_unusable_in_infinite_loop () = 0;
     880              : };
     881              : 
     882              : /* A "do nothing" subclass of region_model_context.  */
     883              : 
     884        64287 : class noop_region_model_context : public region_model_context
     885              : {
     886              : public:
     887              :   pending_location
     888          919 :   get_pending_location_for_diag () const override
     889              :   {
     890          919 :     return pending_location ();
     891              :   }
     892              :   bool
     893          915 :   warn_at (std::unique_ptr<pending_diagnostic>,
     894              :            pending_location &&) override
     895              :   {
     896          915 :     return false;
     897              :   }
     898              :   void add_note (std::unique_ptr<pending_note>) override;
     899              :   void add_event (std::unique_ptr<checker_event>) override;
     900            0 :   void on_svalue_leak (const svalue *) override {}
     901            0 :   void on_liveness_change (const svalue_set &,
     902            0 :                            const region_model *) override {}
     903       119726 :   logger *get_logger () override { return nullptr; }
     904           44 :   void on_condition (const svalue *lhs ATTRIBUTE_UNUSED,
     905              :                      enum tree_code op ATTRIBUTE_UNUSED,
     906              :                      const svalue *rhs ATTRIBUTE_UNUSED) override
     907              :   {
     908           44 :   }
     909          103 :   void on_bounded_ranges (const svalue &,
     910              :                           const bounded_ranges &) override
     911              :   {
     912          103 :   }
     913          302 :   void on_pop_frame (const frame_region *) override {}
     914         2272 :   void on_unknown_change (const svalue *sval ATTRIBUTE_UNUSED,
     915              :                           bool is_mutable ATTRIBUTE_UNUSED) override
     916              :   {
     917         2272 :   }
     918            0 :   void on_phi (const gphi *phi ATTRIBUTE_UNUSED,
     919              :                tree rhs ATTRIBUTE_UNUSED) override
     920              :   {
     921            0 :   }
     922            0 :   void on_unexpected_tree_code (tree, const dump_location_t &) override {}
     923              : 
     924            0 :   void on_escaped_function (tree) override {}
     925              : 
     926        45347 :   uncertainty_t *get_uncertainty () override { return nullptr; }
     927              : 
     928         2084 :   void purge_state_involving (const svalue *sval ATTRIBUTE_UNUSED) override {}
     929              : 
     930              :   void bifurcate (std::unique_ptr<custom_edge_info> info) override;
     931              :   void terminate_path () override;
     932              : 
     933        64014 :   const extrinsic_state *get_ext_state () const override { return nullptr; }
     934              : 
     935       119488 :   bool get_state_map_by_name (const char *,
     936              :                               sm_state_map **,
     937              :                               const state_machine **,
     938              :                               unsigned *,
     939              :                               std::unique_ptr<sm_context> *) override
     940              :   {
     941       119488 :     return false;
     942              :   }
     943              : 
     944        45601 :   const gimple *get_stmt () const override { return nullptr; }
     945            0 :   const exploded_graph *get_eg () const override { return nullptr; }
     946            0 :   const program_state *get_state () const override { return nullptr; }
     947              : 
     948          821 :   void maybe_did_work () override {}
     949           44 :   bool checking_for_infinite_loop_p () const override { return false; }
     950            0 :   void on_unusable_in_infinite_loop () override {}
     951              : };
     952              : 
     953              : /* A subclass of region_model_context for determining if operations fail
     954              :    e.g. "can we generate a region for the lvalue of EXPR?".  */
     955              : 
     956              : class tentative_region_model_context : public noop_region_model_context
     957              : {
     958              : public:
     959              :   tentative_region_model_context () : m_num_unexpected_codes (0) {}
     960              : 
     961            0 :   void on_unexpected_tree_code (tree, const dump_location_t &)
     962              :     final override
     963              :   {
     964            0 :     m_num_unexpected_codes++;
     965            0 :   }
     966              : 
     967              :   bool had_errors_p () const { return m_num_unexpected_codes > 0; }
     968              : 
     969              : private:
     970              :   int m_num_unexpected_codes;
     971              : };
     972              : 
     973              : /* Subclass of region_model_context that wraps another context, allowing
     974              :    for extra code to be added to the various hooks.  */
     975              : 
     976              : class region_model_context_decorator : public region_model_context
     977              : {
     978              :  public:
     979              :   pending_location
     980          218 :   get_pending_location_for_diag () const override
     981              :   {
     982          218 :     if (m_inner)
     983          212 :       return m_inner->get_pending_location_for_diag ();
     984              :     else
     985            6 :       return pending_location ();
     986              :   }
     987              : 
     988              :   bool
     989            9 :   warn_at (std::unique_ptr<pending_diagnostic> d,
     990              :            pending_location &&ploc) override
     991              :   {
     992            9 :     if (m_inner)
     993            9 :       return m_inner->warn_at (std::move (d), std::move (ploc));
     994              :     else
     995              :       return false;
     996              :   }
     997              : 
     998          207 :   void add_note (std::unique_ptr<pending_note> pn) override
     999              :   {
    1000          207 :     if (m_inner)
    1001          207 :       m_inner->add_note (std::move (pn));
    1002          207 :   }
    1003              :   void add_event (std::unique_ptr<checker_event> event) override;
    1004              : 
    1005            0 :   void on_svalue_leak (const svalue *sval) override
    1006              :   {
    1007            0 :     if (m_inner)
    1008            0 :       m_inner->on_svalue_leak (sval);
    1009            0 :   }
    1010              : 
    1011            0 :   void on_liveness_change (const svalue_set &live_svalues,
    1012              :                            const region_model *model) override
    1013              :   {
    1014            0 :     if (m_inner)
    1015            0 :       m_inner->on_liveness_change (live_svalues, model);
    1016            0 :   }
    1017              : 
    1018        26036 :   logger *get_logger () override
    1019              :   {
    1020        26036 :     if (m_inner)
    1021        15314 :       return m_inner->get_logger ();
    1022              :     else
    1023              :       return nullptr;
    1024              :   }
    1025              : 
    1026            0 :   void on_condition (const svalue *lhs,
    1027              :                      enum tree_code op,
    1028              :                      const svalue *rhs) override
    1029              :   {
    1030            0 :     if (m_inner)
    1031            0 :       m_inner->on_condition (lhs, op, rhs);
    1032            0 :   }
    1033              : 
    1034            0 :   void on_bounded_ranges (const svalue &sval,
    1035              :                           const bounded_ranges &ranges) override
    1036              :   {
    1037            0 :     if (m_inner)
    1038            0 :       m_inner->on_bounded_ranges (sval, ranges);
    1039            0 :   }
    1040              : 
    1041            0 :   void on_pop_frame (const frame_region *frame_reg) override
    1042              :   {
    1043            0 :     if (m_inner)
    1044            0 :       m_inner->on_pop_frame (frame_reg);
    1045            0 :   }
    1046              : 
    1047            0 :   void on_unknown_change (const svalue *sval, bool is_mutable) override
    1048              :   {
    1049            0 :     if (m_inner)
    1050            0 :       m_inner->on_unknown_change (sval, is_mutable);
    1051            0 :   }
    1052              : 
    1053            0 :   void on_phi (const gphi *phi, tree rhs) override
    1054              :   {
    1055            0 :     if (m_inner)
    1056            0 :       m_inner->on_phi (phi, rhs);
    1057            0 :   }
    1058              : 
    1059            0 :   void on_unexpected_tree_code (tree t,
    1060              :                                 const dump_location_t &loc) override
    1061              :   {
    1062            0 :     if (m_inner)
    1063            0 :       m_inner->on_unexpected_tree_code (t, loc);
    1064            0 :   }
    1065              : 
    1066            0 :   void on_escaped_function (tree fndecl) override
    1067              :   {
    1068            0 :     if (m_inner)
    1069            0 :       m_inner->on_escaped_function (fndecl);
    1070            0 :   }
    1071              : 
    1072         4534 :   uncertainty_t *get_uncertainty () override
    1073              :   {
    1074         4534 :     if (m_inner)
    1075         3379 :       return m_inner->get_uncertainty ();
    1076              :     else
    1077              :       return nullptr;
    1078              :   }
    1079              : 
    1080            0 :   void purge_state_involving (const svalue *sval) override
    1081              :   {
    1082            0 :     if (m_inner)
    1083            0 :       m_inner->purge_state_involving (sval);
    1084            0 :   }
    1085              : 
    1086            0 :   void bifurcate (std::unique_ptr<custom_edge_info> info) override
    1087              :   {
    1088            0 :     if (m_inner)
    1089            0 :       m_inner->bifurcate (std::move (info));
    1090            0 :   }
    1091              : 
    1092            0 :   void terminate_path () override
    1093              :   {
    1094            0 :     if (m_inner)
    1095            0 :       m_inner->terminate_path ();
    1096            0 :   }
    1097              : 
    1098         5070 :   const extrinsic_state *get_ext_state () const override
    1099              :   {
    1100         5070 :     if (m_inner)
    1101         5070 :       return m_inner->get_ext_state ();
    1102              :     else
    1103              :       return nullptr;
    1104              :   }
    1105              : 
    1106         7852 :   bool get_state_map_by_name (const char *name,
    1107              :                               sm_state_map **out_smap,
    1108              :                               const state_machine **out_sm,
    1109              :                               unsigned *out_sm_idx,
    1110              :                               std::unique_ptr<sm_context> *out_sm_context)
    1111              :     override
    1112              :   {
    1113         7852 :     if (m_inner)
    1114         5198 :       return m_inner->get_state_map_by_name (name, out_smap, out_sm, out_sm_idx,
    1115         5198 :                                              out_sm_context);
    1116              :     else
    1117              :       return false;
    1118              :   }
    1119              : 
    1120           99 :   const gimple *get_stmt () const override
    1121              :   {
    1122           99 :     if (m_inner)
    1123           99 :       return m_inner->get_stmt ();
    1124              :     else
    1125              :       return nullptr;
    1126              :   }
    1127              : 
    1128            0 :   const exploded_graph *get_eg () const override
    1129              :   {
    1130            0 :     if (m_inner)
    1131            0 :         return m_inner->get_eg ();
    1132              :     else
    1133              :         return nullptr;
    1134              :   }
    1135              : 
    1136            0 :   const program_state *get_state () const override
    1137              :   {
    1138            0 :     if (m_inner)
    1139            0 :       return m_inner->get_state ();
    1140              :     else
    1141              :       return nullptr;
    1142              :   }
    1143              : 
    1144            0 :   void maybe_did_work () override
    1145              :   {
    1146            0 :     if (m_inner)
    1147            0 :       m_inner->maybe_did_work ();
    1148            0 :   }
    1149              : 
    1150            0 :   bool checking_for_infinite_loop_p () const override
    1151              :   {
    1152            0 :     if (m_inner)
    1153            0 :       return m_inner->checking_for_infinite_loop_p ();
    1154              :     return false;
    1155              :   }
    1156            0 :   void on_unusable_in_infinite_loop () override
    1157              :   {
    1158            0 :     if (m_inner)
    1159            0 :       m_inner->on_unusable_in_infinite_loop ();
    1160            0 :   }
    1161              : 
    1162              : protected:
    1163        13666 :   region_model_context_decorator (region_model_context *inner)
    1164         4534 :   : m_inner (inner)
    1165              :   {
    1166              :   }
    1167              : 
    1168              :   region_model_context *m_inner;
    1169              : };
    1170              : 
    1171              : /* Subclass of region_model_context_decorator with a hook for adding
    1172              :    notes/events when saving diagnostics.  */
    1173              : 
    1174              : class annotating_context : public region_model_context_decorator
    1175              : {
    1176              : public:
    1177              :   bool
    1178          209 :   warn_at (std::unique_ptr<pending_diagnostic> d,
    1179              :            pending_location &&ploc) override
    1180              :   {
    1181          209 :     if (m_inner)
    1182          203 :       if (m_inner->warn_at (std::move (d), std::move (ploc)))
    1183              :         {
    1184          199 :           add_annotations ();
    1185          199 :           return true;
    1186              :         }
    1187              :     return false;
    1188              :   }
    1189              : 
    1190              :   /* Hook to add new event(s)/note(s)  */
    1191              :   virtual void add_annotations () = 0;
    1192              : 
    1193              : protected:
    1194         9132 :   annotating_context (region_model_context *inner)
    1195         9132 :   : region_model_context_decorator (inner)
    1196              :   {
    1197              :   }
    1198              : };
    1199              : 
    1200              : /* A bundle of data for use when attempting to merge two region_model
    1201              :    instances to make a third.  */
    1202              : 
    1203       148384 : struct model_merger
    1204              : {
    1205       148384 :   model_merger (const region_model *model_a,
    1206              :                 const region_model *model_b,
    1207              :                 const program_point &point,
    1208              :                 region_model *merged_model,
    1209              :                 const extrinsic_state *ext_state,
    1210              :                 const program_state *state_a,
    1211              :                 const program_state *state_b)
    1212       148384 :   : m_model_a (model_a), m_model_b (model_b),
    1213       148384 :     m_point (point),
    1214       148384 :     m_merged_model (merged_model),
    1215       148384 :     m_ext_state (ext_state),
    1216       148384 :     m_state_a (state_a), m_state_b (state_b)
    1217              :   {
    1218              :   }
    1219              : 
    1220              :   void dump_to_pp (pretty_printer *pp, bool simple) const;
    1221              :   void dump (FILE *fp, bool simple) const;
    1222              :   void dump (bool simple) const;
    1223              : 
    1224              :   region_model_manager *get_manager () const
    1225              :   {
    1226              :     return m_model_a->get_manager ();
    1227              :   }
    1228              : 
    1229              :   bool mergeable_svalue_p (const svalue *) const;
    1230              : 
    1231         4289 :   const supernode *get_supernode () const
    1232              :   {
    1233         4289 :     return m_point.get_supernode ();
    1234              :   }
    1235              : 
    1236              :   void on_widening_reuse (const widening_svalue *widening_sval);
    1237              : 
    1238              :   const region_model *m_model_a;
    1239              :   const region_model *m_model_b;
    1240              :   const program_point &m_point;
    1241              :   region_model *m_merged_model;
    1242              : 
    1243              :   const extrinsic_state *m_ext_state;
    1244              :   const program_state *m_state_a;
    1245              :   const program_state *m_state_b;
    1246              : 
    1247              :   hash_set<const svalue *> m_svals_changing_meaning;
    1248              : };
    1249              : 
    1250              : /* A record that can (optionally) be written out when
    1251              :    region_model::add_constraint fails.  */
    1252              : 
    1253              : class rejected_constraint
    1254              : {
    1255              : public:
    1256              :   virtual ~rejected_constraint () {}
    1257              :   virtual void dump_to_pp (pretty_printer *pp) const = 0;
    1258              : 
    1259            4 :   const region_model &get_model () const { return m_model; }
    1260              : 
    1261              : protected:
    1262         2264 :   rejected_constraint (const region_model &model)
    1263         2213 :   : m_model (model)
    1264              :   {}
    1265              : 
    1266              :   region_model m_model;
    1267              : };
    1268              : 
    1269              : class rejected_op_constraint : public rejected_constraint
    1270              : {
    1271              : public:
    1272         2216 :   rejected_op_constraint (const region_model &model,
    1273              :                           const svalue *lhs, enum tree_code op, const svalue *rhs)
    1274         2216 :   : rejected_constraint (model),
    1275         2216 :     m_lhs (lhs), m_op (op), m_rhs (rhs)
    1276              :   {}
    1277              : 
    1278              :   void dump_to_pp (pretty_printer *pp) const final override;
    1279              : 
    1280              :   const svalue *m_lhs;
    1281              :   enum tree_code m_op;
    1282              :   const svalue *m_rhs;
    1283              : };
    1284              : 
    1285              : class rejected_default_case : public rejected_constraint
    1286              : {
    1287              : public:
    1288            0 :   rejected_default_case (const region_model &model)
    1289            0 :   : rejected_constraint (model)
    1290              :   {}
    1291              : 
    1292              :   void dump_to_pp (pretty_printer *pp) const final override;
    1293              : };
    1294              : 
    1295              : class rejected_ranges_constraint : public rejected_constraint
    1296              : {
    1297              : public:
    1298           48 :   rejected_ranges_constraint (const region_model &model,
    1299              :                               tree expr, const bounded_ranges *ranges)
    1300           48 :   : rejected_constraint (model),
    1301           48 :     m_expr (expr), m_ranges (ranges)
    1302              :   {}
    1303              : 
    1304              :   void dump_to_pp (pretty_printer *pp) const final override;
    1305              : 
    1306              : private:
    1307              :   tree m_expr;
    1308              :   const bounded_ranges *m_ranges;
    1309              : };
    1310              : 
    1311              : /* A bundle of state.  */
    1312              : 
    1313              : class engine
    1314              : {
    1315              : public:
    1316              :   engine (region_model_manager &mgr,
    1317              :           const supergraph *sg = nullptr);
    1318       356548 :   const supergraph *get_supergraph () { return m_sg; }
    1319     16909734 :   region_model_manager *get_model_manager () { return &m_mgr; }
    1320         3461 :   known_function_manager *get_known_function_manager ()
    1321              :   {
    1322         3461 :     return m_mgr.get_known_function_manager ();
    1323              :   }
    1324              : 
    1325              :   void log_stats (logger *logger) const;
    1326              : 
    1327              : private:
    1328              :   region_model_manager &m_mgr;
    1329              :   const supergraph *m_sg;
    1330              : };
    1331              : 
    1332              : /* Factory functions for various diagnostics.  */
    1333              : 
    1334              : extern std::unique_ptr<pending_diagnostic>
    1335              : make_poisoned_value_diagnostic (tree expr, enum poison_kind pkind,
    1336              :                                 const region *src_region,
    1337              :                                 tree check_expr);
    1338              : 
    1339              : extern std::unique_ptr<pending_diagnostic>
    1340              : make_shift_count_negative_diagnostic (const gassign *assign,
    1341              :                                       tree count_cst,
    1342              :                                       const region *src_region);
    1343              : 
    1344              : extern std::unique_ptr<pending_diagnostic>
    1345              : make_shift_count_overflow_diagnostic (const gassign *assign,
    1346              :                                       int operand_precision,
    1347              :                                       tree count_cst,
    1348              :                                       const region *src_region);
    1349              : 
    1350              : extern std::unique_ptr<pending_diagnostic>
    1351              : make_write_to_const_diagnostic (const region *dest_reg, tree decl);
    1352              : 
    1353              : extern std::unique_ptr<pending_diagnostic>
    1354              : make_write_to_string_literal_diagnostic (const region *reg);
    1355              : 
    1356              : } // namespace ana
    1357              : 
    1358              : extern void debug (const region_model &rmodel);
    1359              : 
    1360              : namespace ana {
    1361              : 
    1362              : #if CHECKING_P
    1363              : 
    1364              : namespace selftest {
    1365              : 
    1366              : using namespace ::selftest;
    1367              : 
    1368              : /* An implementation of region_model_context for use in selftests, which
    1369              :    stores any pending_diagnostic instances passed to it.  */
    1370              : 
    1371          224 : class test_region_model_context : public noop_region_model_context
    1372              : {
    1373              : public:
    1374              :   bool
    1375            4 :   warn_at (std::unique_ptr<pending_diagnostic> d,
    1376              :            pending_location &&) final override
    1377              :   {
    1378            4 :     m_diagnostics.safe_push (d.release ());
    1379            4 :     return true;
    1380              :   }
    1381              : 
    1382            4 :   unsigned get_num_diagnostics () const { return m_diagnostics.length (); }
    1383              : 
    1384            0 :   void on_unexpected_tree_code (tree t, const dump_location_t &)
    1385              :     final override
    1386              :   {
    1387            0 :     internal_error ("unhandled tree code: %qs",
    1388            0 :                     get_tree_code_name (TREE_CODE (t)));
    1389              :   }
    1390              : 
    1391              : private:
    1392              :   /* Implicitly delete any diagnostics in the dtor.  */
    1393              :   auto_delete_vec<pending_diagnostic> m_diagnostics;
    1394              : };
    1395              : 
    1396              : /* Attempt to add the constraint (LHS OP RHS) to MODEL.
    1397              :    Verify that MODEL remains satisfiable.  */
    1398              : 
    1399              : #define ADD_SAT_CONSTRAINT(MODEL, LHS, OP, RHS) \
    1400              :   SELFTEST_BEGIN_STMT                                   \
    1401              :     bool sat = (MODEL).add_constraint (LHS, OP, RHS, nullptr);  \
    1402              :     ASSERT_TRUE (sat);                                  \
    1403              :   SELFTEST_END_STMT
    1404              : 
    1405              : /* Attempt to add the constraint (LHS OP RHS) to MODEL.
    1406              :    Verify that the result is not satisfiable.  */
    1407              : 
    1408              : #define ADD_UNSAT_CONSTRAINT(MODEL, LHS, OP, RHS)       \
    1409              :   SELFTEST_BEGIN_STMT                                   \
    1410              :     bool sat = (MODEL).add_constraint (LHS, OP, RHS, nullptr);  \
    1411              :     ASSERT_FALSE (sat);                         \
    1412              :   SELFTEST_END_STMT
    1413              : 
    1414              : /* Implementation detail of the ASSERT_CONDITION_* macros.  */
    1415              : 
    1416              : void assert_condition (const location &loc,
    1417              :                        region_model &model,
    1418              :                        const svalue *lhs, tree_code op, const svalue *rhs,
    1419              :                        tristate expected);
    1420              : 
    1421              : void assert_condition (const location &loc,
    1422              :                        region_model &model,
    1423              :                        tree lhs, tree_code op, tree rhs,
    1424              :                        tristate expected);
    1425              : 
    1426              : /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
    1427              :    as "true".  */
    1428              : 
    1429              : #define ASSERT_CONDITION_TRUE(REGION_MODEL, LHS, OP, RHS) \
    1430              :   SELFTEST_BEGIN_STMT                                                   \
    1431              :   assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS,      \
    1432              :                     tristate (tristate::TS_TRUE));              \
    1433              :   SELFTEST_END_STMT
    1434              : 
    1435              : /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
    1436              :    as "false".  */
    1437              : 
    1438              : #define ASSERT_CONDITION_FALSE(REGION_MODEL, LHS, OP, RHS) \
    1439              :   SELFTEST_BEGIN_STMT                                                   \
    1440              :   assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS,      \
    1441              :                     tristate (tristate::TS_FALSE));             \
    1442              :   SELFTEST_END_STMT
    1443              : 
    1444              : /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
    1445              :    as "unknown".  */
    1446              : 
    1447              : #define ASSERT_CONDITION_UNKNOWN(REGION_MODEL, LHS, OP, RHS) \
    1448              :   SELFTEST_BEGIN_STMT                                                   \
    1449              :   assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS,      \
    1450              :                     tristate (tristate::TS_UNKNOWN));           \
    1451              :   SELFTEST_END_STMT
    1452              : 
    1453              : } /* end of namespace selftest.  */
    1454              : 
    1455              : #endif /* #if CHECKING_P */
    1456              : 
    1457              : } // namespace ana
    1458              : 
    1459              : #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.