analyzer: fix ICE on certain longjmp calls [PR109094]
[platform/upstream/gcc.git] / gcc / analyzer / region-model.h
1 /* Classes for modeling the state of memory.
2    Copyright (C) 2019-2023 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 "selftest.h"
31 #include "analyzer/svalue.h"
32 #include "analyzer/region.h"
33 #include "analyzer/known-function-manager.h"
34 #include "analyzer/region-model-manager.h"
35 #include "analyzer/pending-diagnostic.h"
36
37 using namespace ana;
38
39 namespace inchash
40 {
41   extern void add_path_var (path_var pv, hash &hstate);
42 } // namespace inchash
43
44 namespace ana {
45
46 template <typename T>
47 class one_way_id_map
48 {
49  public:
50   one_way_id_map (int num_ids);
51   void put (T src, T dst);
52   T get_dst_for_src (T src) const;
53   void dump_to_pp (pretty_printer *pp) const;
54   void dump () const;
55   void update (T *) const;
56
57  private:
58   auto_vec<T> m_src_to_dst;
59  };
60
61 /* class one_way_id_map.  */
62
63 /* one_way_id_map's ctor, which populates the map with dummy null values.  */
64
65 template <typename T>
66 inline one_way_id_map<T>::one_way_id_map (int num_svalues)
67 : m_src_to_dst (num_svalues)
68 {
69   for (int i = 0; i < num_svalues; i++)
70     m_src_to_dst.quick_push (T::null ());
71 }
72
73 /* Record that SRC is to be mapped to DST.  */
74
75 template <typename T>
76 inline void
77 one_way_id_map<T>::put (T src, T dst)
78 {
79   m_src_to_dst[src.as_int ()] = dst;
80 }
81
82 /* Get the new value for SRC within the map.  */
83
84 template <typename T>
85 inline T
86 one_way_id_map<T>::get_dst_for_src (T src) const
87 {
88   if (src.null_p ())
89     return src;
90   return m_src_to_dst[src.as_int ()];
91 }
92
93 /* Dump this map to PP.  */
94
95 template <typename T>
96 inline void
97 one_way_id_map<T>::dump_to_pp (pretty_printer *pp) const
98 {
99   pp_string (pp, "src to dst: {");
100   unsigned i;
101   T *dst;
102   FOR_EACH_VEC_ELT (m_src_to_dst, i, dst)
103     {
104       if (i > 0)
105         pp_string (pp, ", ");
106       T src (T::from_int (i));
107       src.print (pp);
108       pp_string (pp, " -> ");
109       dst->print (pp);
110     }
111   pp_string (pp, "}");
112   pp_newline (pp);
113 }
114
115 /* Dump this map to stderr.  */
116
117 template <typename T>
118 DEBUG_FUNCTION inline void
119 one_way_id_map<T>::dump () const
120 {
121   pretty_printer pp;
122   pp.buffer->stream = stderr;
123   dump_to_pp (&pp);
124   pp_flush (&pp);
125 }
126
127 /* Update *ID from the old value to its new value in this map.  */
128
129 template <typename T>
130 inline void
131 one_way_id_map<T>::update (T *id) const
132 {
133   *id = get_dst_for_src (*id);
134 }
135
136 /* A mapping from region to svalue for use when tracking state.  */
137
138 class region_to_value_map
139 {
140 public:
141   typedef hash_map<const region *, const svalue *> hash_map_t;
142   typedef hash_map_t::iterator iterator;
143
144   region_to_value_map () : m_hash_map () {}
145   region_to_value_map (const region_to_value_map &other)
146   : m_hash_map (other.m_hash_map) {}
147   region_to_value_map &operator= (const region_to_value_map &other);
148
149   bool operator== (const region_to_value_map &other) const;
150   bool operator!= (const region_to_value_map &other) const
151   {
152     return !(*this == other);
153   }
154
155   iterator begin () const { return m_hash_map.begin (); }
156   iterator end () const { return m_hash_map.end (); }
157
158   const svalue * const *get (const region *reg) const
159   {
160     return const_cast <hash_map_t &> (m_hash_map).get (reg);
161   }
162   void put (const region *reg, const svalue *sval)
163   {
164     m_hash_map.put (reg, sval);
165   }
166   void remove (const region *reg)
167   {
168     m_hash_map.remove (reg);
169   }
170
171   bool is_empty () const { return m_hash_map.is_empty (); }
172
173   void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
174   void dump (bool simple) const;
175
176   bool can_merge_with_p (const region_to_value_map &other,
177                          region_to_value_map *out) const;
178
179   void purge_state_involving (const svalue *sval);
180
181 private:
182   hash_map_t m_hash_map;
183 };
184
185 /* Various operations delete information from a region_model.
186
187    This struct tracks how many of each kind of entity were purged (e.g.
188    for selftests, and for debugging).  */
189
190 struct purge_stats
191 {
192   purge_stats ()
193   : m_num_svalues (0),
194     m_num_regions (0),
195     m_num_equiv_classes (0),
196     m_num_constraints (0),
197     m_num_bounded_ranges_constraints (0),
198     m_num_client_items (0)
199   {}
200
201   int m_num_svalues;
202   int m_num_regions;
203   int m_num_equiv_classes;
204   int m_num_constraints;
205   int m_num_bounded_ranges_constraints;
206   int m_num_client_items;
207 };
208
209 /* A base class for visiting regions and svalues, with do-nothing
210    base implementations of the per-subclass vfuncs.  */
211
212 class visitor
213 {
214 public:
215   virtual void visit_region_svalue (const region_svalue *) {}
216   virtual void visit_constant_svalue (const constant_svalue *) {}
217   virtual void visit_unknown_svalue (const unknown_svalue *) {}
218   virtual void visit_poisoned_svalue (const poisoned_svalue *) {}
219   virtual void visit_setjmp_svalue (const setjmp_svalue *) {}
220   virtual void visit_initial_svalue (const initial_svalue *) {}
221   virtual void visit_unaryop_svalue (const unaryop_svalue *) {}
222   virtual void visit_binop_svalue (const binop_svalue *) {}
223   virtual void visit_sub_svalue (const sub_svalue *) {}
224   virtual void visit_repeated_svalue (const repeated_svalue *) {}
225   virtual void visit_bits_within_svalue (const bits_within_svalue *) {}
226   virtual void visit_unmergeable_svalue (const unmergeable_svalue *) {}
227   virtual void visit_placeholder_svalue (const placeholder_svalue *) {}
228   virtual void visit_widening_svalue (const widening_svalue *) {}
229   virtual void visit_compound_svalue (const compound_svalue *) {}
230   virtual void visit_conjured_svalue (const conjured_svalue *) {}
231   virtual void visit_asm_output_svalue (const asm_output_svalue *) {}
232   virtual void visit_const_fn_result_svalue (const const_fn_result_svalue *) {}
233
234   virtual void visit_region (const region *) {}
235 };
236
237 struct append_regions_cb_data;
238
239 /* A region_model encapsulates a representation of the state of memory, with
240    a tree of regions, along with their associated values.
241    The representation is graph-like because values can be pointers to
242    regions.
243    It also stores:
244    - a constraint_manager, capturing relationships between the values, and
245    - dynamic extents, mapping dynamically-allocated regions to svalues (their
246    capacities).  */
247
248 class region_model
249 {
250  public:
251   typedef region_to_value_map dynamic_extents_t;
252
253   region_model (region_model_manager *mgr);
254   region_model (const region_model &other);
255   ~region_model ();
256   region_model &operator= (const region_model &other);
257
258   bool operator== (const region_model &other) const;
259   bool operator!= (const region_model &other) const
260   {
261     return !(*this == other);
262   }
263
264   hashval_t hash () const;
265
266   void print (pretty_printer *pp) const;
267
268   void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
269   void dump (FILE *fp, bool simple, bool multiline) const;
270   void dump (bool simple) const;
271
272   void debug () const;
273
274   void validate () const;
275
276   void canonicalize ();
277   bool canonicalized_p () const;
278
279   void
280   on_stmt_pre (const gimple *stmt,
281                bool *out_unknown_side_effects,
282                region_model_context *ctxt);
283
284   void on_assignment (const gassign *stmt, region_model_context *ctxt);
285   const svalue *get_gassign_result (const gassign *assign,
286                                     region_model_context *ctxt);
287   void on_asm_stmt (const gasm *asm_stmt, region_model_context *ctxt);
288   bool on_call_pre (const gcall *stmt, region_model_context *ctxt);
289   void on_call_post (const gcall *stmt,
290                      bool unknown_side_effects,
291                      region_model_context *ctxt);
292
293   void purge_state_involving (const svalue *sval, region_model_context *ctxt);
294
295   void impl_deallocation_call (const call_details &cd);
296
297   const svalue *maybe_get_copy_bounds (const region *src_reg,
298                                        const svalue *num_bytes_sval);
299   void update_for_int_cst_return (const call_details &cd,
300                                   int retval,
301                                   bool unmergeable);
302   void update_for_zero_return (const call_details &cd,
303                                bool unmergeable);
304   void update_for_nonzero_return (const call_details &cd);
305
306   void handle_unrecognized_call (const gcall *call,
307                                  region_model_context *ctxt);
308   void get_reachable_svalues (svalue_set *out,
309                               const svalue *extra_sval,
310                               const uncertainty_t *uncertainty);
311
312   void on_return (const greturn *stmt, region_model_context *ctxt);
313   void on_setjmp (const gcall *stmt, const exploded_node *enode,
314                   region_model_context *ctxt);
315   void on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call,
316                    int setjmp_stack_depth, region_model_context *ctxt);
317
318   void update_for_phis (const supernode *snode,
319                         const cfg_superedge *last_cfg_superedge,
320                         region_model_context *ctxt);
321
322   void handle_phi (const gphi *phi, tree lhs, tree rhs,
323                    const region_model &old_state,
324                    region_model_context *ctxt);
325
326   bool maybe_update_for_edge (const superedge &edge,
327                               const gimple *last_stmt,
328                               region_model_context *ctxt,
329                               rejected_constraint **out);
330
331   void update_for_gcall (const gcall *call_stmt,
332                          region_model_context *ctxt,
333                          function *callee = NULL);
334   
335   void update_for_return_gcall (const gcall *call_stmt,
336                                 region_model_context *ctxt);
337
338   const region *push_frame (function *fun, const vec<const svalue *> *arg_sids,
339                             region_model_context *ctxt);
340   const frame_region *get_current_frame () const { return m_current_frame; }
341   function * get_current_function () const;
342   void pop_frame (tree result_lvalue,
343                   const svalue **out_result,
344                   region_model_context *ctxt,
345                   bool eval_return_svalue = true);
346   int get_stack_depth () const;
347   const frame_region *get_frame_at_index (int index) const;
348
349   const region *get_lvalue (path_var pv, region_model_context *ctxt) const;
350   const region *get_lvalue (tree expr, region_model_context *ctxt) const;
351   const svalue *get_rvalue (path_var pv, region_model_context *ctxt) const;
352   const svalue *get_rvalue (tree expr, region_model_context *ctxt) const;
353
354   const region *deref_rvalue (const svalue *ptr_sval, tree ptr_tree,
355                                region_model_context *ctxt) const;
356
357   const svalue *get_rvalue_for_bits (tree type,
358                                      const region *reg,
359                                      const bit_range &bits,
360                                      region_model_context *ctxt) const;
361
362   void set_value (const region *lhs_reg, const svalue *rhs_sval,
363                   region_model_context *ctxt);
364   void set_value (tree lhs, tree rhs, region_model_context *ctxt);
365   void clobber_region (const region *reg);
366   void purge_region (const region *reg);
367   void fill_region (const region *reg, const svalue *sval);
368   void zero_fill_region (const region *reg);
369   void mark_region_as_unknown (const region *reg, uncertainty_t *uncertainty);
370
371   tristate eval_condition (const svalue *lhs,
372                            enum tree_code op,
373                            const svalue *rhs) const;
374   tristate compare_initial_and_pointer (const initial_svalue *init,
375                                         const region_svalue *ptr) const;
376   tristate symbolic_greater_than (const binop_svalue *a,
377                                   const svalue *b) const;
378   tristate structural_equality (const svalue *a, const svalue *b) const;
379   tristate eval_condition (tree lhs,
380                            enum tree_code op,
381                            tree rhs,
382                            region_model_context *ctxt) const;
383   bool add_constraint (tree lhs, enum tree_code op, tree rhs,
384                        region_model_context *ctxt);
385   bool add_constraint (tree lhs, enum tree_code op, tree rhs,
386                        region_model_context *ctxt,
387                        rejected_constraint **out);
388
389   const region *
390   get_or_create_region_for_heap_alloc (const svalue *size_in_bytes,
391                                        region_model_context *ctxt);
392   const region *create_region_for_alloca (const svalue *size_in_bytes,
393                                           region_model_context *ctxt);
394   void get_referenced_base_regions (auto_bitmap &out_ids) const;
395
396   tree get_representative_tree (const svalue *sval) const;
397   tree get_representative_tree (const region *reg) const;
398   path_var
399   get_representative_path_var (const svalue *sval,
400                                svalue_set *visited) const;
401   path_var
402   get_representative_path_var (const region *reg,
403                                svalue_set *visited) const;
404
405   /* For selftests.  */
406   constraint_manager *get_constraints ()
407   {
408     return m_constraints;
409   }
410
411   store *get_store () { return &m_store; }
412   const store *get_store () const { return &m_store; }
413
414   const dynamic_extents_t &
415   get_dynamic_extents () const
416   {
417     return m_dynamic_extents;
418   }
419   const svalue *get_dynamic_extents (const region *reg) const;
420   void set_dynamic_extents (const region *reg,
421                             const svalue *size_in_bytes,
422                             region_model_context *ctxt);
423   void unset_dynamic_extents (const region *reg);
424
425   region_model_manager *get_manager () const { return m_mgr; }
426   bounded_ranges_manager *get_range_manager () const
427   {
428     return m_mgr->get_range_manager ();
429   }
430
431   void unbind_region_and_descendents (const region *reg,
432                                       enum poison_kind pkind);
433
434   bool can_merge_with_p (const region_model &other_model,
435                          const program_point &point,
436                          region_model *out_model,
437                          const extrinsic_state *ext_state = NULL,
438                          const program_state *state_a = NULL,
439                          const program_state *state_b = NULL) const;
440
441   tree get_fndecl_for_call (const gcall *call,
442                             region_model_context *ctxt);
443
444   void get_regions_for_current_frame (auto_vec<const decl_region *> *out) const;
445   static void append_regions_cb (const region *base_reg,
446                                  struct append_regions_cb_data *data);
447
448   const svalue *get_store_value (const region *reg,
449                                  region_model_context *ctxt) const;
450
451   bool region_exists_p (const region *reg) const;
452
453   void loop_replay_fixup (const region_model *dst_state);
454
455   const svalue *get_capacity (const region *reg) const;
456
457   const svalue *get_string_size (const svalue *sval) const;
458   const svalue *get_string_size (const region *reg) const;
459
460   bool replay_call_summary (call_summary_replay &r,
461                             const region_model &summary);
462
463   void maybe_complain_about_infoleak (const region *dst_reg,
464                                       const svalue *copied_sval,
465                                       const region *src_reg,
466                                       region_model_context *ctxt);
467
468   void set_errno (const call_details &cd);
469
470   /* Implemented in sm-fd.cc  */
471   void mark_as_valid_fd (const svalue *sval, region_model_context *ctxt);
472
473   /* Implemented in sm-malloc.cc  */
474   void on_realloc_with_move (const call_details &cd,
475                              const svalue *old_ptr_sval,
476                              const svalue *new_ptr_sval);
477
478   /* Implemented in sm-taint.cc.  */
479   void mark_as_tainted (const svalue *sval,
480                         region_model_context *ctxt);
481
482   bool add_constraint (const svalue *lhs,
483                        enum tree_code op,
484                        const svalue *rhs,
485                        region_model_context *ctxt);
486
487   const svalue *check_for_poison (const svalue *sval,
488                                   tree expr,
489                                   const region *src_region,
490                                   region_model_context *ctxt) const;
491
492   void check_region_for_write (const region *dest_reg,
493                                region_model_context *ctxt) const;
494
495 private:
496   const region *get_lvalue_1 (path_var pv, region_model_context *ctxt) const;
497   const svalue *get_rvalue_1 (path_var pv, region_model_context *ctxt) const;
498
499   path_var
500   get_representative_path_var_1 (const svalue *sval,
501                                  svalue_set *visited) const;
502   path_var
503   get_representative_path_var_1 (const region *reg,
504                                  svalue_set *visited) const;
505
506   const known_function *get_known_function (tree fndecl,
507                                             const call_details &cd) const;
508   const known_function *get_known_function (enum internal_fn) const;
509
510   bool add_constraints_from_binop (const svalue *outer_lhs,
511                                    enum tree_code outer_op,
512                                    const svalue *outer_rhs,
513                                    bool *out,
514                                    region_model_context *ctxt);
515
516   void update_for_call_superedge (const call_superedge &call_edge,
517                                   region_model_context *ctxt);
518   void update_for_return_superedge (const return_superedge &return_edge,
519                                     region_model_context *ctxt);
520   bool apply_constraints_for_gcond (const cfg_superedge &edge,
521                                     const gcond *cond_stmt,
522                                     region_model_context *ctxt,
523                                     rejected_constraint **out);
524   bool apply_constraints_for_gswitch (const switch_cfg_superedge &edge,
525                                       const gswitch *switch_stmt,
526                                       region_model_context *ctxt,
527                                       rejected_constraint **out);
528   bool apply_constraints_for_exception (const gimple *last_stmt,
529                                         region_model_context *ctxt,
530                                         rejected_constraint **out);
531
532   int poison_any_pointers_to_descendents (const region *reg,
533                                           enum poison_kind pkind);
534
535   void on_top_level_param (tree param,
536                            bool nonnull,
537                            region_model_context *ctxt);
538
539   bool called_from_main_p () const;
540   const svalue *get_initial_value_for_global (const region *reg) const;
541
542   const region * get_region_for_poisoned_expr (tree expr) const;
543
544   void check_dynamic_size_for_taint (enum memory_space mem_space,
545                                      const svalue *size_in_bytes,
546                                      region_model_context *ctxt) const;
547   void check_dynamic_size_for_floats (const svalue *size_in_bytes,
548                                       region_model_context *ctxt) const;
549
550   void check_region_for_taint (const region *reg,
551                                enum access_direction dir,
552                                region_model_context *ctxt) const;
553
554   void check_for_writable_region (const region* dest_reg,
555                                   region_model_context *ctxt) const;
556   void check_region_access (const region *reg,
557                             enum access_direction dir,
558                             region_model_context *ctxt) const;
559   void check_region_for_read (const region *src_reg,
560                               region_model_context *ctxt) const;
561   void check_region_size (const region *lhs_reg, const svalue *rhs_sval,
562                           region_model_context *ctxt) const;
563
564   /* Implemented in bounds-checking.cc  */
565   void check_symbolic_bounds (const region *base_reg,
566                               const svalue *sym_byte_offset,
567                               const svalue *num_bytes_sval,
568                               const svalue *capacity,
569                               enum access_direction dir,
570                               region_model_context *ctxt) const;
571   void check_region_bounds (const region *reg, enum access_direction dir,
572                             region_model_context *ctxt) const;
573
574   void check_call_args (const call_details &cd) const;
575   void check_external_function_for_access_attr (const gcall *call,
576                                                 tree callee_fndecl,
577                                                 region_model_context *ctxt) const;
578
579   /* Storing this here to avoid passing it around everywhere.  */
580   region_model_manager *const m_mgr;
581
582   store m_store;
583
584   constraint_manager *m_constraints; // TODO: embed, rather than dynalloc?
585
586   const frame_region *m_current_frame;
587
588   /* Map from base region to size in bytes, for tracking the sizes of
589      dynamically-allocated regions.
590      This is part of the region_model rather than the region to allow for
591      memory regions to be resized (e.g. by realloc).  */
592   dynamic_extents_t m_dynamic_extents;
593 };
594
595 /* Some region_model activity could lead to warnings (e.g. attempts to use an
596    uninitialized value).  This abstract base class encapsulates an interface
597    for the region model to use when emitting such warnings.
598
599    Having this as an abstract base class allows us to support the various
600    operations needed by program_state in the analyzer within region_model,
601    whilst keeping them somewhat modularized.  */
602
603 class region_model_context
604 {
605  public:
606   /* Hook for clients to store pending diagnostics.
607      Return true if the diagnostic was stored, or false if it was deleted.  */
608   virtual bool warn (std::unique_ptr<pending_diagnostic> d) = 0;
609
610   /* Hook for clients to add a note to the last previously stored
611      pending diagnostic.  */
612   virtual void add_note (std::unique_ptr<pending_note> pn) = 0;
613
614   /* Hook for clients to be notified when an SVAL that was reachable
615      in a previous state is no longer live, so that clients can emit warnings
616      about leaks.  */
617   virtual void on_svalue_leak (const svalue *sval) = 0;
618
619   /* Hook for clients to be notified when the set of explicitly live
620      svalues changes, so that they can purge state relating to dead
621      svalues.  */
622   virtual void on_liveness_change (const svalue_set &live_svalues,
623                                    const region_model *model) = 0;
624
625   virtual logger *get_logger () = 0;
626
627   /* Hook for clients to be notified when the condition
628      "LHS OP RHS" is added to the region model.
629      This exists so that state machines can detect tests on edges,
630      and use them to trigger sm-state transitions (e.g. transitions due
631      to ptrs becoming known to be NULL or non-NULL, rather than just
632      "unchecked") */
633   virtual void on_condition (const svalue *lhs,
634                              enum tree_code op,
635                              const svalue *rhs) = 0;
636
637   /* Hook for clients to be notified when the condition that
638      SVAL is within RANGES is added to the region model.
639      Similar to on_condition, but for use when handling switch statements.
640      RANGES is non-empty.  */
641   virtual void on_bounded_ranges (const svalue &sval,
642                                   const bounded_ranges &ranges) = 0;
643
644   /* Hook for clients to be notified when a frame is popped from the stack.  */
645   virtual void on_pop_frame (const frame_region *) = 0;
646
647   /* Hooks for clients to be notified when an unknown change happens
648      to SVAL (in response to a call to an unknown function).  */
649   virtual void on_unknown_change (const svalue *sval, bool is_mutable) = 0;
650
651   /* Hooks for clients to be notified when a phi node is handled,
652      where RHS is the pertinent argument.  */
653   virtual void on_phi (const gphi *phi, tree rhs) = 0;
654
655   /* Hooks for clients to be notified when the region model doesn't
656      know how to handle the tree code of T at LOC.  */
657   virtual void on_unexpected_tree_code (tree t,
658                                         const dump_location_t &loc) = 0;
659
660   /* Hook for clients to be notified when a function_decl escapes.  */
661   virtual void on_escaped_function (tree fndecl) = 0;
662
663   virtual uncertainty_t *get_uncertainty () = 0;
664
665   /* Hook for clients to purge state involving SVAL.  */
666   virtual void purge_state_involving (const svalue *sval) = 0;
667
668   /* Hook for clients to split state with a non-standard path.  */
669   virtual void bifurcate (std::unique_ptr<custom_edge_info> info) = 0;
670
671   /* Hook for clients to terminate the standard path.  */
672   virtual void terminate_path () = 0;
673
674   virtual const extrinsic_state *get_ext_state () const = 0;
675
676   /* Hook for clients to access the a specific state machine in
677      any underlying program_state.  */
678   virtual bool
679   get_state_map_by_name (const char *name,
680                          sm_state_map **out_smap,
681                          const state_machine **out_sm,
682                          unsigned *out_sm_idx,
683                          std::unique_ptr<sm_context> *out_sm_context) = 0;
684
685   /* Precanned ways for clients to access specific state machines.  */
686   bool get_fd_map (sm_state_map **out_smap,
687                    const state_machine **out_sm,
688                    unsigned *out_sm_idx,
689                    std::unique_ptr<sm_context> *out_sm_context)
690   {
691     return get_state_map_by_name ("file-descriptor", out_smap, out_sm,
692                                   out_sm_idx, out_sm_context);
693   }
694   bool get_malloc_map (sm_state_map **out_smap,
695                        const state_machine **out_sm,
696                        unsigned *out_sm_idx)
697   {
698     return get_state_map_by_name ("malloc", out_smap, out_sm, out_sm_idx, NULL);
699   }
700   bool get_taint_map (sm_state_map **out_smap,
701                       const state_machine **out_sm,
702                       unsigned *out_sm_idx)
703   {
704     return get_state_map_by_name ("taint", out_smap, out_sm, out_sm_idx, NULL);
705   }
706
707   bool possibly_tainted_p (const svalue *sval);
708
709   /* Get the current statement, if any.  */
710   virtual const gimple *get_stmt () const = 0;
711 };
712
713 /* A "do nothing" subclass of region_model_context.  */
714
715 class noop_region_model_context : public region_model_context
716 {
717 public:
718   bool warn (std::unique_ptr<pending_diagnostic>) override { return false; }
719   void add_note (std::unique_ptr<pending_note>) override;
720   void on_svalue_leak (const svalue *) override {}
721   void on_liveness_change (const svalue_set &,
722                            const region_model *) override {}
723   logger *get_logger () override { return NULL; }
724   void on_condition (const svalue *lhs ATTRIBUTE_UNUSED,
725                      enum tree_code op ATTRIBUTE_UNUSED,
726                      const svalue *rhs ATTRIBUTE_UNUSED) override
727   {
728   }
729   void on_bounded_ranges (const svalue &,
730                           const bounded_ranges &) override
731   {
732   }
733   void on_pop_frame (const frame_region *) override {}
734   void on_unknown_change (const svalue *sval ATTRIBUTE_UNUSED,
735                           bool is_mutable ATTRIBUTE_UNUSED) override
736   {
737   }
738   void on_phi (const gphi *phi ATTRIBUTE_UNUSED,
739                tree rhs ATTRIBUTE_UNUSED) override
740   {
741   }
742   void on_unexpected_tree_code (tree, const dump_location_t &) override {}
743
744   void on_escaped_function (tree) override {}
745
746   uncertainty_t *get_uncertainty () override { return NULL; }
747
748   void purge_state_involving (const svalue *sval ATTRIBUTE_UNUSED) override {}
749
750   void bifurcate (std::unique_ptr<custom_edge_info> info) override;
751   void terminate_path () override;
752
753   const extrinsic_state *get_ext_state () const override { return NULL; }
754
755   bool get_state_map_by_name (const char *,
756                               sm_state_map **,
757                               const state_machine **,
758                               unsigned *,
759                               std::unique_ptr<sm_context> *) override
760   {
761     return false;
762   }
763
764   const gimple *get_stmt () const override { return NULL; }
765 };
766
767 /* A subclass of region_model_context for determining if operations fail
768    e.g. "can we generate a region for the lvalue of EXPR?".  */
769
770 class tentative_region_model_context : public noop_region_model_context
771 {
772 public:
773   tentative_region_model_context () : m_num_unexpected_codes (0) {}
774
775   void on_unexpected_tree_code (tree, const dump_location_t &)
776     final override
777   {
778     m_num_unexpected_codes++;
779   }
780
781   bool had_errors_p () const { return m_num_unexpected_codes > 0; }
782
783 private:
784   int m_num_unexpected_codes;
785 };
786
787 /* Subclass of region_model_context that wraps another context, allowing
788    for extra code to be added to the various hooks.  */
789
790 class region_model_context_decorator : public region_model_context
791 {
792  public:
793   bool warn (std::unique_ptr<pending_diagnostic> d) override
794   {
795     return m_inner->warn (std::move (d));
796   }
797
798   void add_note (std::unique_ptr<pending_note> pn) override
799   {
800     m_inner->add_note (std::move (pn));
801   }
802
803   void on_svalue_leak (const svalue *sval) override
804   {
805     m_inner->on_svalue_leak (sval);
806   }
807
808   void on_liveness_change (const svalue_set &live_svalues,
809                            const region_model *model) override
810   {
811     m_inner->on_liveness_change (live_svalues, model);
812   }
813
814   logger *get_logger () override
815   {
816     return m_inner->get_logger ();
817   }
818
819   void on_condition (const svalue *lhs,
820                      enum tree_code op,
821                      const svalue *rhs) override
822   {
823     m_inner->on_condition (lhs, op, rhs);
824   }
825
826   void on_bounded_ranges (const svalue &sval,
827                           const bounded_ranges &ranges) override
828   {
829     m_inner->on_bounded_ranges (sval, ranges);
830   }
831
832   void on_pop_frame (const frame_region *frame_reg) override
833   {
834     m_inner->on_pop_frame (frame_reg);
835   }
836
837   void on_unknown_change (const svalue *sval, bool is_mutable) override
838   {
839     m_inner->on_unknown_change (sval, is_mutable);
840   }
841
842   void on_phi (const gphi *phi, tree rhs) override
843   {
844     m_inner->on_phi (phi, rhs);
845   }
846
847   void on_unexpected_tree_code (tree t,
848                                 const dump_location_t &loc) override
849   {
850     m_inner->on_unexpected_tree_code (t, loc);
851   }
852
853   void on_escaped_function (tree fndecl) override
854   {
855     m_inner->on_escaped_function (fndecl);
856   }
857
858   uncertainty_t *get_uncertainty () override
859   {
860     return m_inner->get_uncertainty ();
861   }
862
863   void purge_state_involving (const svalue *sval) override
864   {
865     m_inner->purge_state_involving (sval);
866   }
867
868   void bifurcate (std::unique_ptr<custom_edge_info> info) override
869   {
870     m_inner->bifurcate (std::move (info));
871   }
872
873   void terminate_path () override
874   {
875     m_inner->terminate_path ();
876   }
877
878   const extrinsic_state *get_ext_state () const override
879   {
880     return m_inner->get_ext_state ();
881   }
882
883   bool get_state_map_by_name (const char *name,
884                               sm_state_map **out_smap,
885                               const state_machine **out_sm,
886                               unsigned *out_sm_idx,
887                               std::unique_ptr<sm_context> *out_sm_context)
888     override
889   {
890     return m_inner->get_state_map_by_name (name, out_smap, out_sm, out_sm_idx,
891                                            out_sm_context);
892   }
893
894   const gimple *get_stmt () const override
895   {
896     return m_inner->get_stmt ();
897   }
898
899 protected:
900   region_model_context_decorator (region_model_context *inner)
901   : m_inner (inner)
902   {
903     gcc_assert (m_inner);
904   }
905
906   region_model_context *m_inner;
907 };
908
909 /* Subclass of region_model_context_decorator that adds a note
910    when saving diagnostics.  */
911
912 class note_adding_context : public region_model_context_decorator
913 {
914 public:
915   bool warn (std::unique_ptr<pending_diagnostic> d) override
916   {
917     if (m_inner->warn (std::move (d)))
918       {
919         add_note (make_note ());
920         return true;
921       }
922     else
923       return false;
924   }
925
926   /* Hook to make the new note.  */
927   virtual std::unique_ptr<pending_note> make_note () = 0;
928
929 protected:
930   note_adding_context (region_model_context *inner)
931   : region_model_context_decorator (inner)
932   {
933   }
934 };
935
936 /* A bundle of data for use when attempting to merge two region_model
937    instances to make a third.  */
938
939 struct model_merger
940 {
941   model_merger (const region_model *model_a,
942                 const region_model *model_b,
943                 const program_point &point,
944                 region_model *merged_model,
945                 const extrinsic_state *ext_state,
946                 const program_state *state_a,
947                 const program_state *state_b)
948   : m_model_a (model_a), m_model_b (model_b),
949     m_point (point),
950     m_merged_model (merged_model),
951     m_ext_state (ext_state),
952     m_state_a (state_a), m_state_b (state_b)
953   {
954   }
955
956   void dump_to_pp (pretty_printer *pp, bool simple) const;
957   void dump (FILE *fp, bool simple) const;
958   void dump (bool simple) const;
959
960   region_model_manager *get_manager () const
961   {
962     return m_model_a->get_manager ();
963   }
964
965   bool mergeable_svalue_p (const svalue *) const;
966   const function_point &get_function_point () const
967   {
968     return m_point.get_function_point ();
969   }
970
971   const region_model *m_model_a;
972   const region_model *m_model_b;
973   const program_point &m_point;
974   region_model *m_merged_model;
975
976   const extrinsic_state *m_ext_state;
977   const program_state *m_state_a;
978   const program_state *m_state_b;
979 };
980
981 /* A record that can (optionally) be written out when
982    region_model::add_constraint fails.  */
983
984 class rejected_constraint
985 {
986 public:
987   virtual ~rejected_constraint () {}
988   virtual void dump_to_pp (pretty_printer *pp) const = 0;
989
990   const region_model &get_model () const { return m_model; }
991
992 protected:
993   rejected_constraint (const region_model &model)
994   : m_model (model)
995   {}
996
997   region_model m_model;
998 };
999
1000 class rejected_op_constraint : public rejected_constraint
1001 {
1002 public:
1003   rejected_op_constraint (const region_model &model,
1004                           tree lhs, enum tree_code op, tree rhs)
1005   : rejected_constraint (model),
1006     m_lhs (lhs), m_op (op), m_rhs (rhs)
1007   {}
1008
1009   void dump_to_pp (pretty_printer *pp) const final override;
1010
1011   tree m_lhs;
1012   enum tree_code m_op;
1013   tree m_rhs;
1014 };
1015
1016 class rejected_default_case : public rejected_constraint
1017 {
1018 public:
1019   rejected_default_case (const region_model &model)
1020   : rejected_constraint (model)
1021   {}
1022
1023   void dump_to_pp (pretty_printer *pp) const final override;
1024 };
1025
1026 class rejected_ranges_constraint : public rejected_constraint
1027 {
1028 public:
1029   rejected_ranges_constraint (const region_model &model,
1030                               tree expr, const bounded_ranges *ranges)
1031   : rejected_constraint (model),
1032     m_expr (expr), m_ranges (ranges)
1033   {}
1034
1035   void dump_to_pp (pretty_printer *pp) const final override;
1036
1037 private:
1038   tree m_expr;
1039   const bounded_ranges *m_ranges;
1040 };
1041
1042 /* A bundle of state.  */
1043
1044 class engine
1045 {
1046 public:
1047   engine (const supergraph *sg = NULL, logger *logger = NULL);
1048   const supergraph *get_supergraph () { return m_sg; }
1049   region_model_manager *get_model_manager () { return &m_mgr; }
1050   known_function_manager *get_known_function_manager ()
1051   {
1052     return m_mgr.get_known_function_manager ();
1053   }
1054
1055   void log_stats (logger *logger) const;
1056
1057 private:
1058   const supergraph *m_sg;
1059   region_model_manager m_mgr;
1060 };
1061
1062 } // namespace ana
1063
1064 extern void debug (const region_model &rmodel);
1065
1066 namespace ana {
1067
1068 #if CHECKING_P
1069
1070 namespace selftest {
1071
1072 using namespace ::selftest;
1073
1074 /* An implementation of region_model_context for use in selftests, which
1075    stores any pending_diagnostic instances passed to it.  */
1076
1077 class test_region_model_context : public noop_region_model_context
1078 {
1079 public:
1080   bool warn (std::unique_ptr<pending_diagnostic> d) final override
1081   {
1082     m_diagnostics.safe_push (d.release ());
1083     return true;
1084   }
1085
1086   unsigned get_num_diagnostics () const { return m_diagnostics.length (); }
1087
1088   void on_unexpected_tree_code (tree t, const dump_location_t &)
1089     final override
1090   {
1091     internal_error ("unhandled tree code: %qs",
1092                     get_tree_code_name (TREE_CODE (t)));
1093   }
1094
1095 private:
1096   /* Implicitly delete any diagnostics in the dtor.  */
1097   auto_delete_vec<pending_diagnostic> m_diagnostics;
1098 };
1099
1100 /* Attempt to add the constraint (LHS OP RHS) to MODEL.
1101    Verify that MODEL remains satisfiable.  */
1102
1103 #define ADD_SAT_CONSTRAINT(MODEL, LHS, OP, RHS) \
1104   SELFTEST_BEGIN_STMT                                   \
1105     bool sat = (MODEL).add_constraint (LHS, OP, RHS, NULL);     \
1106     ASSERT_TRUE (sat);                                  \
1107   SELFTEST_END_STMT
1108
1109 /* Attempt to add the constraint (LHS OP RHS) to MODEL.
1110    Verify that the result is not satisfiable.  */
1111
1112 #define ADD_UNSAT_CONSTRAINT(MODEL, LHS, OP, RHS)       \
1113   SELFTEST_BEGIN_STMT                                   \
1114     bool sat = (MODEL).add_constraint (LHS, OP, RHS, NULL);     \
1115     ASSERT_FALSE (sat);                         \
1116   SELFTEST_END_STMT
1117
1118 /* Implementation detail of the ASSERT_CONDITION_* macros.  */
1119
1120 void assert_condition (const location &loc,
1121                        region_model &model,
1122                        const svalue *lhs, tree_code op, const svalue *rhs,
1123                        tristate expected);
1124
1125 void assert_condition (const location &loc,
1126                        region_model &model,
1127                        tree lhs, tree_code op, tree rhs,
1128                        tristate expected);
1129
1130 /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
1131    as "true".  */
1132
1133 #define ASSERT_CONDITION_TRUE(REGION_MODEL, LHS, OP, RHS) \
1134   SELFTEST_BEGIN_STMT                                                   \
1135   assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS,      \
1136                     tristate (tristate::TS_TRUE));              \
1137   SELFTEST_END_STMT
1138
1139 /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
1140    as "false".  */
1141
1142 #define ASSERT_CONDITION_FALSE(REGION_MODEL, LHS, OP, RHS) \
1143   SELFTEST_BEGIN_STMT                                                   \
1144   assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS,      \
1145                     tristate (tristate::TS_FALSE));             \
1146   SELFTEST_END_STMT
1147
1148 /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
1149    as "unknown".  */
1150
1151 #define ASSERT_CONDITION_UNKNOWN(REGION_MODEL, LHS, OP, RHS) \
1152   SELFTEST_BEGIN_STMT                                                   \
1153   assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS,      \
1154                     tristate (tristate::TS_UNKNOWN));           \
1155   SELFTEST_END_STMT
1156
1157 } /* end of namespace selftest.  */
1158
1159 #endif /* #if CHECKING_P */
1160
1161 } // namespace ana
1162
1163 #endif /* GCC_ANALYZER_REGION_MODEL_H */