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