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