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