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