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 : #define INCLUDE_ALGORITHM
22 : #include "analyzer/common.h"
23 :
24 : #include "ordered-hash-map.h"
25 : #include "options.h"
26 : #include "cgraph.h"
27 : #include "cfg.h"
28 : #include "sbitmap.h"
29 : #include "diagnostics/event-id.h"
30 : #include "stor-layout.h"
31 : #include "stringpool.h"
32 : #include "attribs.h"
33 : #include "tree-object-size.h"
34 : #include "gimple-ssa.h"
35 : #include "tree-phinodes.h"
36 : #include "tree-ssa-operands.h"
37 : #include "ssa-iterators.h"
38 : #include "target.h"
39 : #include "calls.h"
40 : #include "is-a.h"
41 : #include "gcc-rich-location.h"
42 : #include "gcc-urlifier.h"
43 : #include "diagnostics/sarif-sink.h"
44 : #include "tree-pretty-print.h"
45 : #include "fold-const.h"
46 : #include "selftest-tree.h"
47 : #include "context.h"
48 : #include "channels.h"
49 : #include "value-relation.h"
50 : #include "range-op.h"
51 : #include "ipa-utils.h"
52 : #include "gimple-iterator.h"
53 : #include "gimple-fold.h"
54 :
55 : #include "text-art/tree-widget.h"
56 :
57 : #include "analyzer/analyzer-logging.h"
58 : #include "analyzer/supergraph.h"
59 : #include "analyzer/call-string.h"
60 : #include "analyzer/program-point.h"
61 : #include "analyzer/store.h"
62 : #include "analyzer/region-model.h"
63 : #include "analyzer/constraint-manager.h"
64 : #include "analyzer/sm.h"
65 : #include "analyzer/pending-diagnostic.h"
66 : #include "analyzer/region-model-reachability.h"
67 : #include "analyzer/analyzer-selftests.h"
68 : #include "analyzer/program-state.h"
69 : #include "analyzer/call-summary.h"
70 : #include "analyzer/checker-event.h"
71 : #include "analyzer/checker-path.h"
72 : #include "analyzer/feasible-graph.h"
73 : #include "analyzer/record-layout.h"
74 : #include "analyzer/function-set.h"
75 : #include "analyzer/state-transition.h"
76 :
77 : #if ENABLE_ANALYZER
78 :
79 : namespace ana {
80 :
81 : /* Dump T to PP in language-independent form, for debugging/logging/dumping
82 : purposes. */
83 :
84 : void
85 41739 : dump_tree (pretty_printer *pp, tree t)
86 : {
87 41739 : dump_generic_node (pp, t, 0, TDF_SLIM, 0);
88 41739 : }
89 :
90 : /* Dump T to PP in language-independent form in quotes, for
91 : debugging/logging/dumping purposes. */
92 :
93 : void
94 1366 : dump_quoted_tree (pretty_printer *pp, tree t)
95 : {
96 1366 : pp_begin_quote (pp, pp_show_color (pp));
97 1366 : dump_tree (pp, t);
98 1366 : pp_end_quote (pp, pp_show_color (pp));
99 1366 : }
100 :
101 : /* Equivalent to pp_printf (pp, "%qT", t), to avoid nesting pp_printf
102 : calls within other pp_printf calls.
103 :
104 : default_tree_printer handles 'T' and some other codes by calling
105 : dump_generic_node (pp, t, 0, TDF_SLIM, 0);
106 : dump_generic_node calls pp_printf in various places, leading to
107 : garbled output.
108 :
109 : Ideally pp_printf could be made to be reentrant, but in the meantime
110 : this function provides a workaround. */
111 :
112 : void
113 4448 : print_quoted_type (pretty_printer *pp, tree t)
114 : {
115 4448 : if (!t)
116 : return;
117 4355 : pp_begin_quote (pp, pp_show_color (pp));
118 4355 : dump_generic_node (pp, t, 0, TDF_SLIM, 0);
119 4355 : pp_end_quote (pp, pp_show_color (pp));
120 : }
121 :
122 : /* Print EXPR to PP, without quotes.
123 : For use within svalue::maybe_print_for_user
124 : and region::maybe_print_for_user. */
125 :
126 : void
127 38 : print_expr_for_user (pretty_printer *pp, tree expr)
128 : {
129 : /* Workaround for C++'s lang_hooks.decl_printable_name,
130 : which unhelpfully (for us) prefixes the decl with its
131 : type. */
132 38 : if (DECL_P (expr))
133 38 : dump_generic_node (pp, expr, 0, TDF_SLIM, 0);
134 : else
135 0 : pp_printf (pp, "%E", expr);
136 38 : }
137 :
138 : /* class region_to_value_map. */
139 :
140 : /* Assignment operator for region_to_value_map. */
141 :
142 : region_to_value_map &
143 99055 : region_to_value_map::operator= (const region_to_value_map &other)
144 : {
145 99055 : m_hash_map.empty ();
146 128886 : for (auto iter : other.m_hash_map)
147 : {
148 29831 : const region *reg = iter.first;
149 29831 : const svalue *sval = iter.second;
150 29831 : m_hash_map.put (reg, sval);
151 : }
152 99055 : return *this;
153 : }
154 :
155 : /* Equality operator for region_to_value_map. */
156 :
157 : bool
158 485247 : region_to_value_map::operator== (const region_to_value_map &other) const
159 : {
160 485247 : if (m_hash_map.elements () != other.m_hash_map.elements ())
161 : return false;
162 :
163 621374 : for (auto iter : *this)
164 : {
165 138794 : const region *reg = iter.first;
166 138794 : const svalue *sval = iter.second;
167 138794 : const svalue * const *other_slot = other.get (reg);
168 138794 : if (other_slot == nullptr)
169 58 : return false;
170 138764 : if (sval != *other_slot)
171 : return false;
172 : }
173 :
174 482580 : return true;
175 : }
176 :
177 : /* Dump this object to PP. */
178 :
179 : void
180 416 : region_to_value_map::dump_to_pp (pretty_printer *pp, bool simple,
181 : bool multiline) const
182 : {
183 416 : auto_vec<const region *> regs;
184 832 : for (iterator iter = begin (); iter != end (); ++iter)
185 416 : regs.safe_push ((*iter).first);
186 416 : regs.qsort (region::cmp_ptr_ptr);
187 416 : if (multiline)
188 416 : pp_newline (pp);
189 : else
190 0 : pp_string (pp, " {");
191 416 : unsigned i;
192 416 : const region *reg;
193 832 : FOR_EACH_VEC_ELT (regs, i, reg)
194 : {
195 416 : if (multiline)
196 416 : pp_string (pp, " ");
197 0 : else if (i > 0)
198 0 : pp_string (pp, ", ");
199 416 : reg->dump_to_pp (pp, simple);
200 416 : pp_string (pp, ": ");
201 416 : const svalue *sval = *get (reg);
202 416 : sval->dump_to_pp (pp, true);
203 416 : if (multiline)
204 416 : pp_newline (pp);
205 : }
206 416 : if (!multiline)
207 0 : pp_string (pp, "}");
208 416 : }
209 :
210 : /* Dump this object to stderr. */
211 :
212 : DEBUG_FUNCTION void
213 0 : region_to_value_map::dump (bool simple) const
214 : {
215 0 : tree_dump_pretty_printer pp (stderr);
216 0 : dump_to_pp (&pp, simple, true);
217 0 : pp_newline (&pp);
218 0 : }
219 :
220 : /* Generate a JSON value for this region_to_value_map.
221 : This is intended for debugging the analyzer rather than
222 : serialization. */
223 :
224 : std::unique_ptr<json::object>
225 4 : region_to_value_map::to_json () const
226 : {
227 4 : auto map_obj = std::make_unique<json::object> ();
228 :
229 4 : auto_vec<const region *> regs;
230 4 : for (iterator iter = begin (); iter != end (); ++iter)
231 0 : regs.safe_push ((*iter).first);
232 4 : regs.qsort (region::cmp_ptr_ptr);
233 :
234 4 : unsigned i;
235 4 : const region *reg;
236 4 : FOR_EACH_VEC_ELT (regs, i, reg)
237 : {
238 0 : label_text reg_desc = reg->get_desc ();
239 0 : const svalue *sval = *get (reg);
240 0 : map_obj->set (reg_desc.get (), sval->to_json ());
241 0 : }
242 :
243 4 : return map_obj;
244 4 : }
245 :
246 : std::unique_ptr<text_art::tree_widget>
247 4 : region_to_value_map::
248 : make_dump_widget (const text_art::dump_widget_info &dwi) const
249 : {
250 4 : if (is_empty ())
251 4 : return nullptr;
252 :
253 0 : std::unique_ptr<text_art::tree_widget> w
254 0 : (text_art::tree_widget::make (dwi, "Dynamic Extents"));
255 :
256 0 : auto_vec<const region *> regs;
257 0 : for (iterator iter = begin (); iter != end (); ++iter)
258 0 : regs.safe_push ((*iter).first);
259 0 : regs.qsort (region::cmp_ptr_ptr);
260 :
261 0 : unsigned i;
262 0 : const region *reg;
263 0 : FOR_EACH_VEC_ELT (regs, i, reg)
264 : {
265 0 : pretty_printer the_pp;
266 0 : pretty_printer * const pp = &the_pp;
267 0 : pp_format_decoder (pp) = default_tree_printer;
268 0 : const bool simple = true;
269 :
270 0 : reg->dump_to_pp (pp, simple);
271 0 : pp_string (pp, ": ");
272 0 : const svalue *sval = *get (reg);
273 0 : sval->dump_to_pp (pp, true);
274 0 : w->add_child (text_art::tree_widget::make (dwi, pp));
275 0 : }
276 0 : return w;
277 0 : }
278 :
279 : /* Attempt to merge THIS with OTHER, writing the result
280 : to OUT.
281 :
282 : For now, write (region, value) mappings that are in common between THIS
283 : and OTHER to OUT, effectively taking the intersection.
284 :
285 : Reject merger of different values. */
286 :
287 : bool
288 42550 : region_to_value_map::can_merge_with_p (const region_to_value_map &other,
289 : region_to_value_map *out) const
290 : {
291 50078 : for (auto iter : *this)
292 : {
293 9396 : const region *iter_reg = iter.first;
294 9396 : const svalue *iter_sval = iter.second;
295 9396 : const svalue * const * other_slot = other.get (iter_reg);
296 9396 : if (other_slot)
297 : {
298 9119 : if (iter_sval == *other_slot)
299 7251 : out->put (iter_reg, iter_sval);
300 : else
301 1868 : return false;
302 : }
303 : }
304 40682 : return true;
305 : }
306 :
307 : /* Purge any state involving SVAL. */
308 :
309 : void
310 30285 : region_to_value_map::purge_state_involving (const svalue *sval)
311 : {
312 30285 : auto_vec<const region *> to_purge;
313 53616 : for (auto iter : *this)
314 : {
315 23331 : const region *iter_reg = iter.first;
316 23331 : const svalue *iter_sval = iter.second;
317 23331 : if (iter_reg->involves_p (sval) || iter_sval->involves_p (sval))
318 26 : to_purge.safe_push (iter_reg);
319 : }
320 30363 : for (auto iter : to_purge)
321 26 : m_hash_map.remove (iter);
322 30285 : }
323 :
324 : // struct exception_node
325 :
326 : bool
327 11319 : exception_node::operator== (const exception_node &other) const
328 : {
329 11319 : return (m_exception_sval == other.m_exception_sval
330 11319 : && m_typeinfo_sval == other.m_typeinfo_sval
331 22638 : && m_destructor_sval == other.m_destructor_sval);
332 : }
333 :
334 : void
335 6 : exception_node::dump_to_pp (pretty_printer *pp,
336 : bool simple) const
337 : {
338 6 : pp_printf (pp, "{exception: ");
339 6 : m_exception_sval->dump_to_pp (pp, simple);
340 6 : pp_string (pp, ", typeinfo: ");
341 6 : m_typeinfo_sval->dump_to_pp (pp, simple);
342 6 : pp_string (pp, ", destructor: ");
343 6 : m_destructor_sval->dump_to_pp (pp, simple);
344 6 : pp_string (pp, "}");
345 6 : }
346 :
347 : void
348 0 : exception_node::dump (FILE *fp, bool simple) const
349 : {
350 0 : tree_dump_pretty_printer pp (fp);
351 0 : dump_to_pp (&pp, simple);
352 0 : pp_newline (&pp);
353 0 : }
354 :
355 : /* Dump a multiline representation of this model to stderr. */
356 :
357 : DEBUG_FUNCTION void
358 0 : exception_node::dump (bool simple) const
359 : {
360 0 : dump (stderr, simple);
361 0 : }
362 :
363 : DEBUG_FUNCTION void
364 0 : exception_node::dump () const
365 : {
366 0 : text_art::dump (*this);
367 0 : }
368 :
369 : std::unique_ptr<json::object>
370 0 : exception_node::to_json () const
371 : {
372 0 : auto obj = std::make_unique<json::object> ();
373 0 : obj->set ("exception", m_exception_sval->to_json ());
374 0 : obj->set ("typeinfo", m_typeinfo_sval->to_json ());
375 0 : obj->set ("destructor", m_destructor_sval->to_json ());
376 0 : return obj;
377 : }
378 :
379 : std::unique_ptr<text_art::tree_widget>
380 0 : exception_node::make_dump_widget (const text_art::dump_widget_info &dwi) const
381 : {
382 0 : using text_art::tree_widget;
383 0 : std::unique_ptr<tree_widget> w
384 0 : (tree_widget::from_fmt (dwi, nullptr, "Exception Node"));
385 :
386 0 : w->add_child (m_exception_sval->make_dump_widget (dwi, "exception"));
387 0 : w->add_child (m_typeinfo_sval->make_dump_widget (dwi, "typeinfo"));
388 0 : w->add_child (m_destructor_sval->make_dump_widget (dwi, "destructor"));
389 :
390 0 : return w;
391 : }
392 :
393 : tree
394 697 : exception_node::maybe_get_type () const
395 : {
396 697 : return m_typeinfo_sval->maybe_get_type_from_typeinfo ();
397 : }
398 :
399 : void
400 64 : exception_node::add_to_reachable_regions (reachable_regions ®s) const
401 : {
402 64 : regs.handle_sval (m_exception_sval);
403 64 : regs.handle_sval (m_typeinfo_sval);
404 64 : regs.handle_sval (m_destructor_sval);
405 64 : }
406 :
407 : /* class region_model. */
408 :
409 : /* Ctor for region_model: construct an "empty" model. */
410 :
411 421442 : region_model::region_model (region_model_manager *mgr)
412 421442 : : m_mgr (mgr), m_store (), m_current_frame (nullptr),
413 421442 : m_thrown_exceptions_stack (),
414 421442 : m_caught_exceptions_stack (),
415 421442 : m_dynamic_extents ()
416 : {
417 421442 : m_constraints = new constraint_manager (mgr);
418 421442 : }
419 :
420 : /* region_model's copy ctor. */
421 :
422 3268755 : region_model::region_model (const region_model &other)
423 3268755 : : m_mgr (other.m_mgr), m_store (other.m_store),
424 3268755 : m_constraints (new constraint_manager (*other.m_constraints)),
425 3268755 : m_current_frame (other.m_current_frame),
426 3268755 : m_thrown_exceptions_stack (other.m_thrown_exceptions_stack),
427 3268755 : m_caught_exceptions_stack (other.m_caught_exceptions_stack),
428 3268755 : m_dynamic_extents (other.m_dynamic_extents)
429 : {
430 3268755 : }
431 :
432 : /* region_model's dtor. */
433 :
434 3690197 : region_model::~region_model ()
435 : {
436 3690197 : delete m_constraints;
437 3690197 : }
438 :
439 : /* region_model's assignment operator. */
440 :
441 : region_model &
442 99055 : region_model::operator= (const region_model &other)
443 : {
444 : /* m_mgr is const. */
445 99055 : gcc_assert (m_mgr == other.m_mgr);
446 :
447 99055 : m_store = other.m_store;
448 :
449 99055 : delete m_constraints;
450 99055 : m_constraints = new constraint_manager (*other.m_constraints);
451 :
452 99055 : m_current_frame = other.m_current_frame;
453 :
454 99055 : m_thrown_exceptions_stack = other.m_thrown_exceptions_stack;
455 99055 : m_caught_exceptions_stack = other.m_caught_exceptions_stack;
456 :
457 99055 : m_dynamic_extents = other.m_dynamic_extents;
458 :
459 99055 : return *this;
460 : }
461 :
462 : /* Equality operator for region_model.
463 :
464 : Amongst other things this directly compares the stores and the constraint
465 : managers, so for this to be meaningful both this and OTHER should
466 : have been canonicalized. */
467 :
468 : bool
469 543072 : region_model::operator== (const region_model &other) const
470 : {
471 : /* We can only compare instances that use the same manager. */
472 543072 : gcc_assert (m_mgr == other.m_mgr);
473 :
474 543072 : if (m_store != other.m_store)
475 : return false;
476 :
477 444039 : if (*m_constraints != *other.m_constraints)
478 : return false;
479 :
480 439067 : if (m_current_frame != other.m_current_frame)
481 : return false;
482 :
483 439059 : if (m_thrown_exceptions_stack != other.m_thrown_exceptions_stack)
484 : return false;
485 439059 : if (m_caught_exceptions_stack != other.m_caught_exceptions_stack)
486 : return false;
487 :
488 439059 : if (m_dynamic_extents != other.m_dynamic_extents)
489 : return false;
490 :
491 438790 : gcc_checking_assert (hash () == other.hash ());
492 :
493 : return true;
494 : }
495 :
496 : /* Generate a hash value for this region_model. */
497 :
498 : hashval_t
499 1358981 : region_model::hash () const
500 : {
501 1358981 : hashval_t result = m_store.hash ();
502 1358981 : result ^= m_constraints->hash ();
503 1358981 : return result;
504 : }
505 :
506 : /* Dump a representation of this model to PP, showing the
507 : stack, the store, and any constraints.
508 : Use SIMPLE to control how svalues and regions are printed. */
509 :
510 : void
511 2126 : region_model::dump_to_pp (pretty_printer *pp, bool simple,
512 : bool multiline) const
513 : {
514 : /* Dump frame stack. */
515 2126 : pp_printf (pp, "stack depth: %i", get_stack_depth ());
516 2126 : if (multiline)
517 545 : pp_newline (pp);
518 : else
519 1581 : pp_string (pp, " {");
520 4228 : for (const frame_region *iter_frame = m_current_frame; iter_frame;
521 2102 : iter_frame = iter_frame->get_calling_frame ())
522 : {
523 2102 : if (multiline)
524 549 : pp_string (pp, " ");
525 1553 : else if (iter_frame != m_current_frame)
526 0 : pp_string (pp, ", ");
527 2102 : pp_printf (pp, "frame (index %i): ", iter_frame->get_index ());
528 2102 : iter_frame->dump_to_pp (pp, simple);
529 2102 : if (multiline)
530 549 : pp_newline (pp);
531 : }
532 2126 : if (!multiline)
533 1581 : pp_string (pp, "}");
534 :
535 : /* Dump exception stacks. */
536 2126 : if (m_thrown_exceptions_stack.size () > 0)
537 : {
538 6 : pp_printf (pp, "thrown exceptions: %i", (int)m_thrown_exceptions_stack.size ());
539 6 : if (multiline)
540 6 : pp_newline (pp);
541 : else
542 0 : pp_string (pp, " {");
543 12 : for (size_t idx = 0; idx < m_thrown_exceptions_stack.size (); ++idx)
544 : {
545 6 : if (multiline)
546 6 : pp_string (pp, " ");
547 0 : else if (idx > 0)
548 0 : pp_string (pp, ", ");
549 6 : pp_printf (pp, "exception (index %i): ", (int)idx);
550 6 : m_thrown_exceptions_stack[idx].dump_to_pp (pp, simple);
551 6 : if (multiline)
552 6 : pp_newline (pp);
553 : }
554 6 : if (!multiline)
555 0 : pp_string (pp, "}");
556 : }
557 2126 : if (m_caught_exceptions_stack.size () > 0)
558 : {
559 0 : pp_printf (pp, "caught exceptions: %i", (int)m_caught_exceptions_stack.size ());
560 0 : if (multiline)
561 0 : pp_newline (pp);
562 : else
563 0 : pp_string (pp, " {");
564 0 : for (size_t idx = 0; idx < m_caught_exceptions_stack.size (); ++idx)
565 : {
566 0 : if (multiline)
567 0 : pp_string (pp, " ");
568 0 : else if (idx > 0)
569 0 : pp_string (pp, ", ");
570 0 : pp_printf (pp, "exception (index %i): ", (int)idx);
571 0 : m_caught_exceptions_stack[idx].dump_to_pp (pp, simple);
572 0 : if (multiline)
573 0 : pp_newline (pp);
574 : }
575 0 : if (!multiline)
576 0 : pp_string (pp, "}");
577 : }
578 :
579 : /* Dump store. */
580 2126 : if (!multiline)
581 1581 : pp_string (pp, ", {");
582 2126 : m_store.dump_to_pp (pp, simple, multiline,
583 2126 : m_mgr->get_store_manager ());
584 2126 : if (!multiline)
585 1581 : pp_string (pp, "}");
586 :
587 : /* Dump constraints. */
588 2126 : pp_string (pp, "constraint_manager:");
589 2126 : if (multiline)
590 545 : pp_newline (pp);
591 : else
592 1581 : pp_string (pp, " {");
593 2126 : m_constraints->dump_to_pp (pp, multiline);
594 2126 : if (!multiline)
595 1581 : pp_string (pp, "}");
596 :
597 : /* Dump sizes of dynamic regions, if any are known. */
598 2126 : if (!m_dynamic_extents.is_empty ())
599 : {
600 416 : pp_string (pp, "dynamic_extents:");
601 416 : m_dynamic_extents.dump_to_pp (pp, simple, multiline);
602 : }
603 2126 : }
604 :
605 : /* Dump a representation of this model to FILE. */
606 :
607 : void
608 0 : region_model::dump (FILE *fp, bool simple, bool multiline) const
609 : {
610 0 : tree_dump_pretty_printer pp (fp);
611 0 : dump_to_pp (&pp, simple, multiline);
612 0 : pp_newline (&pp);
613 0 : }
614 :
615 : /* Dump a multiline representation of this model to stderr. */
616 :
617 : DEBUG_FUNCTION void
618 0 : region_model::dump (bool simple) const
619 : {
620 0 : dump (stderr, simple, true);
621 0 : }
622 :
623 : /* Dump a tree-like representation of this state to stderr. */
624 :
625 : DEBUG_FUNCTION void
626 0 : region_model::dump () const
627 : {
628 0 : text_art::dump (*this);
629 0 : }
630 :
631 : /* Dump a multiline representation of this model to stderr. */
632 :
633 : DEBUG_FUNCTION void
634 0 : region_model::debug () const
635 : {
636 0 : dump (true);
637 0 : }
638 :
639 : /* Generate a JSON value for this region_model.
640 : This is intended for debugging the analyzer rather than
641 : serialization. */
642 :
643 : std::unique_ptr<json::object>
644 4 : region_model::to_json () const
645 : {
646 4 : auto model_obj = std::make_unique<json::object> ();
647 4 : model_obj->set ("store", m_store.to_json ());
648 4 : model_obj->set ("constraints", m_constraints->to_json ());
649 4 : if (m_current_frame)
650 4 : model_obj->set ("current_frame", m_current_frame->to_json ());
651 :
652 4 : auto thrown_exceptions_arr = std::make_unique<json::array> ();
653 4 : for (auto &node : m_thrown_exceptions_stack)
654 0 : thrown_exceptions_arr->append (node.to_json ());
655 4 : model_obj->set ("thrown_exception_stack", std::move (thrown_exceptions_arr));
656 :
657 4 : auto caught_exceptions_arr = std::make_unique<json::array> ();
658 4 : for (auto &node : m_caught_exceptions_stack)
659 0 : caught_exceptions_arr->append (node.to_json ());
660 4 : model_obj->set ("caught_exception_stack", std::move (caught_exceptions_arr));
661 :
662 4 : model_obj->set ("dynamic_extents", m_dynamic_extents.to_json ());
663 8 : return model_obj;
664 4 : }
665 :
666 : std::unique_ptr<text_art::tree_widget>
667 4 : region_model::make_dump_widget (const text_art::dump_widget_info &dwi) const
668 : {
669 4 : using text_art::tree_widget;
670 4 : std::unique_ptr<tree_widget> model_widget
671 4 : (tree_widget::from_fmt (dwi, nullptr, "Region Model"));
672 :
673 4 : if (m_current_frame)
674 : {
675 0 : pretty_printer the_pp;
676 0 : pretty_printer * const pp = &the_pp;
677 0 : pp_format_decoder (pp) = default_tree_printer;
678 0 : pp_show_color (pp) = true;
679 0 : const bool simple = true;
680 :
681 0 : pp_string (pp, "Current Frame: ");
682 0 : m_current_frame->dump_to_pp (pp, simple);
683 0 : model_widget->add_child (tree_widget::make (dwi, pp));
684 0 : }
685 :
686 4 : if (m_thrown_exceptions_stack.size () > 0)
687 : {
688 0 : auto thrown_exceptions_widget
689 0 : = tree_widget::make (dwi, "Thrown Exceptions");
690 0 : for (auto &thrown_exception : m_thrown_exceptions_stack)
691 0 : thrown_exceptions_widget->add_child
692 0 : (thrown_exception.make_dump_widget (dwi));
693 0 : model_widget->add_child (std::move (thrown_exceptions_widget));
694 0 : }
695 4 : if (m_caught_exceptions_stack.size () > 0)
696 : {
697 0 : auto caught_exceptions_widget
698 0 : = tree_widget::make (dwi, "Caught Exceptions");
699 0 : for (auto &caught_exception : m_caught_exceptions_stack)
700 0 : caught_exceptions_widget->add_child
701 0 : (caught_exception.make_dump_widget (dwi));
702 0 : model_widget->add_child (std::move (caught_exceptions_widget));
703 0 : }
704 :
705 4 : model_widget->add_child
706 8 : (m_store.make_dump_widget (dwi,
707 4 : m_mgr->get_store_manager ()));
708 4 : model_widget->add_child (m_constraints->make_dump_widget (dwi));
709 4 : model_widget->add_child (m_dynamic_extents.make_dump_widget (dwi));
710 4 : return model_widget;
711 : }
712 :
713 : /* Assert that this object is valid. */
714 :
715 : void
716 1876326 : region_model::validate () const
717 : {
718 1876326 : m_store.validate ();
719 1876326 : }
720 :
721 : /* Canonicalize the store and constraints, to maximize the chance of
722 : equality between region_model instances. */
723 :
724 : void
725 902109 : region_model::canonicalize ()
726 : {
727 902109 : m_store.canonicalize (m_mgr->get_store_manager ());
728 902109 : m_constraints->canonicalize ();
729 902109 : }
730 :
731 : /* Return true if this region_model is in canonical form. */
732 :
733 : bool
734 428720 : region_model::canonicalized_p () const
735 : {
736 428720 : region_model copy (*this);
737 428720 : copy.canonicalize ();
738 428720 : return *this == copy;
739 428720 : }
740 :
741 : /* See the comment for store::loop_replay_fixup. */
742 :
743 : void
744 4656 : region_model::loop_replay_fixup (const region_model *dst_state)
745 : {
746 4656 : m_store.loop_replay_fixup (dst_state->get_store (), m_mgr);
747 4656 : }
748 :
749 : /* A subclass of pending_diagnostic for complaining about pointer
750 : subtractions involving unrelated buffers. */
751 :
752 : class undefined_ptrdiff_diagnostic
753 : : public pending_diagnostic_subclass<undefined_ptrdiff_diagnostic>
754 : {
755 : public:
756 : /* Region_creation_event subclass to give a custom wording when
757 : talking about creation of buffers for LHS and RHS of the
758 : subtraction. */
759 : class ptrdiff_region_creation_event : public region_creation_event
760 : {
761 : public:
762 56 : ptrdiff_region_creation_event (const event_loc_info &loc_info,
763 : bool is_lhs)
764 : : region_creation_event (loc_info),
765 56 : m_is_lhs (is_lhs)
766 : {
767 : }
768 :
769 112 : void print_desc (pretty_printer &pp) const final override
770 : {
771 112 : if (m_is_lhs)
772 56 : pp_string (&pp,
773 : "underlying object for left-hand side"
774 : " of subtraction created here");
775 : else
776 56 : pp_string (&pp,
777 : "underlying object for right-hand side"
778 : " of subtraction created here");
779 112 : }
780 :
781 : private:
782 : bool m_is_lhs;
783 : };
784 :
785 64 : undefined_ptrdiff_diagnostic (const gassign *assign,
786 : const svalue *sval_a,
787 : const svalue *sval_b,
788 : const region *base_reg_a,
789 : const region *base_reg_b)
790 64 : : m_assign (assign),
791 64 : m_sval_a (sval_a),
792 64 : m_sval_b (sval_b),
793 64 : m_base_reg_a (base_reg_a),
794 64 : m_base_reg_b (base_reg_b)
795 : {
796 64 : gcc_assert (m_base_reg_a != m_base_reg_b);
797 : }
798 :
799 380 : const char *get_kind () const final override
800 : {
801 380 : return "undefined_ptrdiff_diagnostic";
802 : }
803 :
804 56 : bool operator== (const undefined_ptrdiff_diagnostic &other) const
805 : {
806 56 : return (m_assign == other.m_assign
807 56 : && m_sval_a == other.m_sval_a
808 56 : && m_sval_b == other.m_sval_b
809 56 : && m_base_reg_a == other.m_base_reg_a
810 112 : && m_base_reg_b == other.m_base_reg_b);
811 : }
812 :
813 84 : int get_controlling_option () const final override
814 : {
815 84 : return OPT_Wanalyzer_undefined_behavior_ptrdiff;
816 : }
817 :
818 28 : bool emit (diagnostic_emission_context &ctxt) final override
819 : {
820 : /* CWE-469: Use of Pointer Subtraction to Determine Size. */
821 28 : ctxt.add_cwe (469);
822 28 : return ctxt.warn ("undefined behavior when subtracting pointers");
823 : }
824 :
825 56 : void add_region_creation_events (const region *reg,
826 : tree /*capacity*/,
827 : const event_loc_info &loc_info,
828 : checker_path &emission_path) final override
829 : {
830 56 : if (reg == m_base_reg_a)
831 28 : emission_path.add_event
832 28 : (std::make_unique<ptrdiff_region_creation_event> (loc_info, true));
833 28 : else if (reg == m_base_reg_b)
834 28 : emission_path.add_event
835 28 : (std::make_unique<ptrdiff_region_creation_event> (loc_info, false));
836 56 : }
837 :
838 : bool
839 56 : describe_final_event (pretty_printer &pp,
840 : const evdesc::final_event &) final override
841 : {
842 56 : pp_string (&pp,
843 : "subtraction of pointers has undefined behavior if"
844 : " they do not point into the same array object");
845 56 : return true;
846 : }
847 :
848 56 : void mark_interesting_stuff (interesting_t *interesting) final override
849 : {
850 56 : interesting->add_region_creation (m_base_reg_a);
851 56 : interesting->add_region_creation (m_base_reg_b);
852 56 : }
853 :
854 : private:
855 : const gassign *m_assign;
856 : const svalue *m_sval_a;
857 : const svalue *m_sval_b;
858 : const region *m_base_reg_a;
859 : const region *m_base_reg_b;
860 : };
861 :
862 : /* Locate the parameter with the given index within FNDECL.
863 : ARGNUM is zero based, -1 indicates the `this' argument of a method.
864 : Return the location of the FNDECL itself if there are problems. */
865 :
866 : bool
867 23 : callsite_expr::maybe_get_param_location (tree fndecl,
868 : location_t *out_loc) const
869 : {
870 23 : gcc_assert (fndecl);
871 :
872 23 : if (DECL_ARTIFICIAL (fndecl))
873 : return false;
874 :
875 23 : tree param = get_param_tree (fndecl);
876 23 : if (!param)
877 : return false;
878 :
879 22 : *out_loc = DECL_SOURCE_LOCATION (param);
880 22 : return true;
881 : }
882 :
883 : /* If this callsite_expr refers to a parameter, get the PARM_DECL from
884 : FNDECL.
885 : Return NULL_TREE on any problems. */
886 :
887 : tree
888 69 : callsite_expr::get_param_tree (tree fndecl) const
889 : {
890 69 : if (!param_p ())
891 : return NULL_TREE;
892 :
893 66 : int i;
894 66 : tree param;
895 :
896 : /* Locate param by index within DECL_ARGUMENTS (fndecl). */
897 66 : for (i = 1, param = DECL_ARGUMENTS (fndecl);
898 126 : i < param_num () && param;
899 60 : i++, param = TREE_CHAIN (param))
900 : ;
901 :
902 : return param;
903 : }
904 :
905 : class div_by_zero_diagnostic
906 : : public pending_diagnostic_subclass<div_by_zero_diagnostic>
907 : {
908 : public:
909 74 : div_by_zero_diagnostic (const gassign *assign,
910 : const region *divisor_reg)
911 74 : : m_assign (assign),
912 74 : m_divisor_reg (divisor_reg)
913 : {}
914 :
915 409 : const char *get_kind () const final override
916 : {
917 409 : return "div_by_zero_diagnostic";
918 : }
919 :
920 74 : bool operator== (const div_by_zero_diagnostic &other) const
921 : {
922 74 : return m_assign == other.m_assign;
923 : }
924 :
925 107 : int get_controlling_option () const final override
926 : {
927 107 : return OPT_Wanalyzer_div_by_zero;
928 : }
929 :
930 33 : bool emit (diagnostic_emission_context &ctxt) final override
931 : {
932 33 : return ctxt.warn ("division by zero");
933 : }
934 :
935 : bool
936 66 : describe_final_event (pretty_printer &pp,
937 : const evdesc::final_event &) final override
938 : {
939 66 : pp_printf (&pp, "division by zero");
940 66 : return true;
941 : }
942 :
943 : void
944 66 : mark_interesting_stuff (interesting_t *interest) override
945 : {
946 66 : interest->add_read_region (m_divisor_reg, "divisor zero value");
947 66 : }
948 :
949 : void
950 57 : add_function_entry_event (const exploded_edge &eedge,
951 : checker_path *emission_path,
952 : const state_transition_at_call *state_trans)
953 : override
954 : {
955 0 : class custom_function_entry_event : public function_entry_event
956 : {
957 : public:
958 57 : custom_function_entry_event (const event_loc_info &loc_info,
959 : const program_state &state,
960 : const state_transition_at_call *state_trans)
961 : : function_entry_event (loc_info,
962 : state,
963 57 : state_trans)
964 : {
965 : }
966 :
967 72 : void print_desc (pretty_printer &pp) const override
968 : {
969 72 : if (auto state_trans = get_state_transition_at_call ())
970 : {
971 4 : auto expr = state_trans->get_callsite_expr ();
972 4 : if (tree parm = expr.get_param_tree (m_effective_fndecl))
973 : {
974 4 : auto src_event_id = state_trans->get_src_event_id ();
975 4 : if (src_event_id.known_p ())
976 4 : pp_printf (&pp, "entry to %qE with zero from %@ for %qE",
977 4 : m_effective_fndecl,
978 : &src_event_id,
979 : parm);
980 : else
981 0 : pp_printf (&pp, "entry to %qE with zero for %qE",
982 0 : m_effective_fndecl, parm);
983 4 : return;
984 : }
985 : }
986 68 : return function_entry_event::print_desc (pp);
987 : }
988 : };
989 :
990 57 : const exploded_node *dst_node = eedge.m_dest;
991 57 : const program_point &dst_point = dst_node->get_point ();
992 57 : const program_state &dst_state = dst_node->get_state ();
993 57 : auto loc_info {event_loc_info_for_function_entry (dst_point, state_trans)};
994 57 : emission_path->add_event
995 57 : (std::make_unique<custom_function_entry_event> (loc_info,
996 : dst_state,
997 : state_trans));
998 57 : }
999 :
1000 : bool
1001 44 : describe_origin_of_state (pretty_printer &pp,
1002 : const evdesc::origin_of_state &) final override
1003 : {
1004 44 : pp_printf (&pp, "zero value originates here");
1005 44 : return true;
1006 : }
1007 :
1008 : bool
1009 4 : describe_call_with_state (pretty_printer &pp,
1010 : const evdesc::call_with_state &evd) final override
1011 : {
1012 4 : if (evd.m_state_trans)
1013 : {
1014 4 : callsite_expr expr = evd.m_state_trans->get_callsite_expr ();
1015 4 : if (expr.param_p ())
1016 : {
1017 4 : if (evd.m_src_event_id.known_p ())
1018 4 : pp_printf (&pp, "passing zero from %@ from %qE to %qE via parameter %i",
1019 : &evd.m_src_event_id,
1020 4 : evd.m_caller_fndecl,
1021 4 : evd.m_callee_fndecl,
1022 : expr.param_num ());
1023 : else
1024 0 : pp_printf (&pp, "passing zero from %qE to %qE via parameter %i",
1025 0 : evd.m_caller_fndecl,
1026 0 : evd.m_callee_fndecl,
1027 : expr.param_num ());
1028 4 : return true;
1029 : }
1030 : }
1031 :
1032 : return false;
1033 : }
1034 :
1035 : bool
1036 24 : describe_return_of_state (pretty_printer &pp,
1037 : const evdesc::return_of_state &evd) final override
1038 : {
1039 24 : if (evd.m_src_event_id.known_p ())
1040 24 : pp_printf (&pp, "returning zero from %@ from %qE here",
1041 : &evd.m_src_event_id,
1042 24 : evd.m_callee_fndecl);
1043 : else
1044 0 : pp_printf (&pp, "returning zero from %qE here",
1045 0 : evd.m_callee_fndecl);
1046 24 : return true;
1047 : }
1048 :
1049 : bool
1050 12 : describe_copy_of_state (pretty_printer &pp,
1051 : const evdesc::copy_of_state &evd) final override
1052 : {
1053 12 : if (evd.m_src_event_id.known_p ())
1054 12 : pp_printf (&pp, "copying zero value from %@ from %qE to %qE",
1055 : &evd.m_src_event_id,
1056 12 : evd.m_src_reg_expr, evd.m_dst_reg_expr);
1057 : else
1058 0 : pp_printf (&pp, "copying zero value from %qE to %qE",
1059 0 : evd.m_src_reg_expr, evd.m_dst_reg_expr);
1060 12 : return true;
1061 : }
1062 :
1063 : bool
1064 16 : describe_use_of_state (pretty_printer &pp,
1065 : const evdesc::use_of_state &evd) final override
1066 : {
1067 16 : if (evd.m_src_event_id.known_p ())
1068 8 : pp_printf (&pp, "using zero value from %@ from %qE",
1069 : &evd.m_src_event_id,
1070 8 : evd.m_src_reg_expr);
1071 : else
1072 8 : pp_printf (&pp, "using zero value from %qE",
1073 8 : evd.m_src_reg_expr);
1074 16 : return true;
1075 : }
1076 :
1077 : private:
1078 : const gassign *m_assign;
1079 : const region *m_divisor_reg;
1080 : };
1081 :
1082 : /* Check the pointer subtraction SVAL_A - SVAL_B at ASSIGN and add
1083 : a warning to CTXT if they're not within the same base region. */
1084 :
1085 : static void
1086 774 : check_for_invalid_ptrdiff (const gassign *assign,
1087 : region_model_context &ctxt,
1088 : const svalue *sval_a, const svalue *sval_b)
1089 : {
1090 774 : const region *base_reg_a = sval_a->maybe_get_deref_base_region ();
1091 774 : if (!base_reg_a)
1092 710 : return;
1093 158 : const region *base_reg_b = sval_b->maybe_get_deref_base_region ();
1094 158 : if (!base_reg_b)
1095 : return;
1096 :
1097 134 : if (base_reg_a == base_reg_b)
1098 : return;
1099 :
1100 64 : if (base_reg_a->get_kind () == RK_SYMBOLIC)
1101 : return;
1102 64 : if (base_reg_b->get_kind () == RK_SYMBOLIC)
1103 : return;
1104 :
1105 64 : ctxt.warn
1106 64 : (std::make_unique<undefined_ptrdiff_diagnostic> (assign,
1107 : sval_a,
1108 : sval_b,
1109 : base_reg_a,
1110 : base_reg_b));
1111 : }
1112 :
1113 : /* If ASSIGN is a stmt that can be modelled via
1114 : set_value (lhs_reg, SVALUE, CTXT)
1115 : for some SVALUE, get the SVALUE.
1116 : Otherwise return nullptr. */
1117 :
1118 : const svalue *
1119 446562 : region_model::get_gassign_result (const gassign *assign,
1120 : region_model_context *ctxt)
1121 : {
1122 446562 : tree lhs = gimple_assign_lhs (assign);
1123 :
1124 446562 : if (gimple_has_volatile_ops (assign)
1125 446562 : && !gimple_clobber_p (assign))
1126 : {
1127 116 : conjured_purge p (this, ctxt);
1128 116 : return m_mgr->get_or_create_conjured_svalue (TREE_TYPE (lhs),
1129 : assign,
1130 : get_lvalue (lhs, ctxt),
1131 : p);
1132 : }
1133 :
1134 446446 : tree rhs1 = gimple_assign_rhs1 (assign);
1135 446446 : enum tree_code op = gimple_assign_rhs_code (assign);
1136 446446 : switch (op)
1137 : {
1138 : default:
1139 : return nullptr;
1140 :
1141 44006 : case POINTER_PLUS_EXPR:
1142 44006 : {
1143 : /* e.g. "_1 = a_10(D) + 12;" */
1144 44006 : tree ptr = rhs1;
1145 44006 : tree offset = gimple_assign_rhs2 (assign);
1146 :
1147 44006 : const svalue *ptr_sval = get_rvalue (ptr, ctxt);
1148 44006 : const svalue *offset_sval = get_rvalue (offset, ctxt);
1149 : /* Quoting tree.def, "the second operand [of a POINTER_PLUS_EXPR]
1150 : is an integer of type sizetype". */
1151 44006 : offset_sval = m_mgr->get_or_create_cast (size_type_node, offset_sval);
1152 :
1153 44006 : const svalue *sval_binop
1154 44006 : = m_mgr->get_or_create_binop (TREE_TYPE (lhs), op,
1155 : ptr_sval, offset_sval);
1156 44006 : return sval_binop;
1157 : }
1158 944 : break;
1159 :
1160 944 : case POINTER_DIFF_EXPR:
1161 944 : {
1162 : /* e.g. "_1 = p_2(D) - q_3(D);". */
1163 944 : tree rhs2 = gimple_assign_rhs2 (assign);
1164 944 : const svalue *rhs1_sval = get_rvalue (rhs1, ctxt);
1165 944 : const svalue *rhs2_sval = get_rvalue (rhs2, ctxt);
1166 :
1167 : // TODO: perhaps fold to zero if they're known to be equal?
1168 :
1169 944 : if (ctxt)
1170 774 : check_for_invalid_ptrdiff (assign, *ctxt, rhs1_sval, rhs2_sval);
1171 :
1172 944 : const svalue *sval_binop
1173 944 : = m_mgr->get_or_create_binop (TREE_TYPE (lhs), op,
1174 : rhs1_sval, rhs2_sval);
1175 944 : return sval_binop;
1176 : }
1177 222379 : break;
1178 :
1179 : /* Assignments of the form
1180 : set_value (lvalue (LHS), rvalue (EXPR))
1181 : for various EXPR.
1182 : We already have the lvalue for the LHS above, as "lhs_reg". */
1183 222379 : case ADDR_EXPR: /* LHS = &RHS; */
1184 222379 : case BIT_FIELD_REF:
1185 222379 : case COMPONENT_REF: /* LHS = op0.op1; */
1186 222379 : case MEM_REF:
1187 222379 : case REAL_CST:
1188 222379 : case COMPLEX_CST:
1189 222379 : case VECTOR_CST:
1190 222379 : case INTEGER_CST:
1191 222379 : case ARRAY_REF:
1192 222379 : case SSA_NAME: /* LHS = VAR; */
1193 222379 : case VAR_DECL: /* LHS = VAR; */
1194 222379 : case PARM_DECL:/* LHS = VAR; */
1195 222379 : case REALPART_EXPR:
1196 222379 : case IMAGPART_EXPR:
1197 222379 : return get_rvalue (rhs1, ctxt);
1198 :
1199 67690 : case ABS_EXPR:
1200 67690 : case ABSU_EXPR:
1201 67690 : case CONJ_EXPR:
1202 67690 : case BIT_NOT_EXPR:
1203 67690 : case FIX_TRUNC_EXPR:
1204 67690 : case FLOAT_EXPR:
1205 67690 : case NEGATE_EXPR:
1206 67690 : case NOP_EXPR:
1207 67690 : case VIEW_CONVERT_EXPR:
1208 67690 : {
1209 : /* Unary ops. */
1210 67690 : const svalue *rhs_sval = get_rvalue (rhs1, ctxt);
1211 67690 : const svalue *sval_unaryop
1212 67690 : = m_mgr->get_or_create_unaryop (TREE_TYPE (lhs), op, rhs_sval);
1213 67690 : return sval_unaryop;
1214 : }
1215 :
1216 16520 : case EQ_EXPR:
1217 16520 : case GE_EXPR:
1218 16520 : case LE_EXPR:
1219 16520 : case NE_EXPR:
1220 16520 : case GT_EXPR:
1221 16520 : case LT_EXPR:
1222 16520 : case UNORDERED_EXPR:
1223 16520 : case ORDERED_EXPR:
1224 16520 : {
1225 16520 : tree rhs2 = gimple_assign_rhs2 (assign);
1226 :
1227 16520 : const svalue *rhs1_sval = get_rvalue (rhs1, ctxt);
1228 16520 : const svalue *rhs2_sval = get_rvalue (rhs2, ctxt);
1229 :
1230 16520 : if (TREE_TYPE (lhs) == boolean_type_node)
1231 : {
1232 : /* Consider constraints between svalues. */
1233 16373 : tristate t = eval_condition (rhs1_sval, op, rhs2_sval);
1234 16373 : if (t.is_known ())
1235 9246 : return m_mgr->get_or_create_constant_svalue
1236 9246 : (t.is_true () ? boolean_true_node : boolean_false_node);
1237 : }
1238 :
1239 : /* Otherwise, generate a symbolic binary op. */
1240 7274 : const svalue *sval_binop
1241 7274 : = m_mgr->get_or_create_binop (TREE_TYPE (lhs), op,
1242 : rhs1_sval, rhs2_sval);
1243 7274 : return sval_binop;
1244 : }
1245 78995 : break;
1246 :
1247 78995 : case PLUS_EXPR:
1248 78995 : case MINUS_EXPR:
1249 78995 : case MULT_EXPR:
1250 78995 : case MULT_HIGHPART_EXPR:
1251 78995 : case TRUNC_DIV_EXPR:
1252 78995 : case CEIL_DIV_EXPR:
1253 78995 : case FLOOR_DIV_EXPR:
1254 78995 : case ROUND_DIV_EXPR:
1255 78995 : case TRUNC_MOD_EXPR:
1256 78995 : case CEIL_MOD_EXPR:
1257 78995 : case FLOOR_MOD_EXPR:
1258 78995 : case ROUND_MOD_EXPR:
1259 78995 : case RDIV_EXPR:
1260 78995 : case EXACT_DIV_EXPR:
1261 78995 : case LSHIFT_EXPR:
1262 78995 : case RSHIFT_EXPR:
1263 78995 : case LROTATE_EXPR:
1264 78995 : case RROTATE_EXPR:
1265 78995 : case BIT_IOR_EXPR:
1266 78995 : case BIT_XOR_EXPR:
1267 78995 : case BIT_AND_EXPR:
1268 78995 : case MIN_EXPR:
1269 78995 : case MAX_EXPR:
1270 78995 : case COMPLEX_EXPR:
1271 78995 : {
1272 : /* Binary ops. */
1273 78995 : tree rhs2 = gimple_assign_rhs2 (assign);
1274 :
1275 78995 : const svalue *rhs1_sval = get_rvalue (rhs1, ctxt);
1276 78995 : const svalue *rhs2_sval = get_rvalue (rhs2, ctxt);
1277 :
1278 78995 : if (ctxt && (op == LSHIFT_EXPR || op == RSHIFT_EXPR))
1279 : {
1280 : /* "INT34-C. Do not shift an expression by a negative number of bits
1281 : or by greater than or equal to the number of bits that exist in
1282 : the operand." */
1283 13755 : if (const tree rhs2_cst = rhs2_sval->maybe_get_constant ())
1284 13459 : if (TREE_CODE (rhs2_cst) == INTEGER_CST
1285 13459 : && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
1286 : {
1287 13457 : if (tree_int_cst_sgn (rhs2_cst) < 0)
1288 : {
1289 24 : const region *rhs2_reg
1290 48 : = get_lvalue (gimple_assign_rhs2 (assign), nullptr);
1291 24 : ctxt->warn
1292 24 : (make_shift_count_negative_diagnostic (assign,
1293 : rhs2_cst,
1294 : rhs2_reg));
1295 : }
1296 13433 : else if (compare_tree_int (rhs2_cst,
1297 13433 : TYPE_PRECISION (TREE_TYPE (rhs1)))
1298 : >= 0)
1299 : {
1300 24 : const region *rhs2_reg
1301 48 : = get_lvalue (gimple_assign_rhs2 (assign), nullptr);
1302 48 : ctxt->warn (make_shift_count_overflow_diagnostic
1303 24 : (assign,
1304 24 : int (TYPE_PRECISION (TREE_TYPE (rhs1))),
1305 : rhs2_cst,
1306 : rhs2_reg));
1307 : }
1308 : }
1309 : }
1310 :
1311 78995 : if (op == TRUNC_DIV_EXPR
1312 : || op == CEIL_DIV_EXPR
1313 : || op == FLOOR_DIV_EXPR
1314 : || op == ROUND_DIV_EXPR
1315 : || op == TRUNC_MOD_EXPR
1316 : || op == CEIL_MOD_EXPR
1317 : || op == FLOOR_MOD_EXPR
1318 : || op == ROUND_MOD_EXPR
1319 : || op == RDIV_EXPR
1320 78995 : || op == EXACT_DIV_EXPR)
1321 : {
1322 1256 : value_range rhs_vr;
1323 1256 : if (rhs2_sval->maybe_get_value_range (rhs_vr))
1324 1156 : if (rhs_vr.zero_p ())
1325 : {
1326 74 : if (ctxt)
1327 : {
1328 74 : const region *rhs2_reg
1329 148 : = get_lvalue (gimple_assign_rhs2 (assign), nullptr);
1330 74 : ctxt->warn
1331 74 : (std::make_unique<div_by_zero_diagnostic> (assign,
1332 : rhs2_reg));
1333 74 : ctxt->terminate_path ();
1334 : }
1335 74 : return nullptr;
1336 : }
1337 1256 : }
1338 :
1339 78921 : const svalue *sval_binop
1340 78921 : = m_mgr->get_or_create_binop (TREE_TYPE (lhs), op,
1341 : rhs1_sval, rhs2_sval);
1342 78921 : return sval_binop;
1343 : }
1344 :
1345 : /* Vector expressions. In theory we could implement these elementwise,
1346 : but for now, simply return unknown values. */
1347 0 : case VEC_DUPLICATE_EXPR:
1348 0 : case VEC_SERIES_EXPR:
1349 0 : case VEC_COND_EXPR:
1350 0 : case VEC_PERM_EXPR:
1351 0 : case VEC_WIDEN_MULT_HI_EXPR:
1352 0 : case VEC_WIDEN_MULT_LO_EXPR:
1353 0 : case VEC_WIDEN_MULT_EVEN_EXPR:
1354 0 : case VEC_WIDEN_MULT_ODD_EXPR:
1355 0 : case VEC_UNPACK_HI_EXPR:
1356 0 : case VEC_UNPACK_LO_EXPR:
1357 0 : case VEC_UNPACK_FLOAT_HI_EXPR:
1358 0 : case VEC_UNPACK_FLOAT_LO_EXPR:
1359 0 : case VEC_UNPACK_FIX_TRUNC_HI_EXPR:
1360 0 : case VEC_UNPACK_FIX_TRUNC_LO_EXPR:
1361 0 : case VEC_PACK_TRUNC_EXPR:
1362 0 : case VEC_PACK_SAT_EXPR:
1363 0 : case VEC_PACK_FIX_TRUNC_EXPR:
1364 0 : case VEC_PACK_FLOAT_EXPR:
1365 0 : case VEC_WIDEN_LSHIFT_HI_EXPR:
1366 0 : case VEC_WIDEN_LSHIFT_LO_EXPR:
1367 0 : return m_mgr->get_or_create_unknown_svalue (TREE_TYPE (lhs));
1368 : }
1369 : }
1370 :
1371 : /* Workaround for discarding certain false positives from
1372 : -Wanalyzer-use-of-uninitialized-value
1373 : of the form:
1374 : ((A OR-IF B) OR-IF C)
1375 : and:
1376 : ((A AND-IF B) AND-IF C)
1377 : where evaluating B is redundant, but could involve simple accesses of
1378 : uninitialized locals.
1379 :
1380 : When optimization is turned on the FE can immediately fold compound
1381 : conditionals. Specifically, c_parser_condition parses this condition:
1382 : ((A OR-IF B) OR-IF C)
1383 : and calls c_fully_fold on the condition.
1384 : Within c_fully_fold, fold_truth_andor is called, which bails when
1385 : optimization is off, but if any optimization is turned on can convert the
1386 : ((A OR-IF B) OR-IF C)
1387 : into:
1388 : ((A OR B) OR_IF C)
1389 : for sufficiently simple B
1390 : i.e. the inner OR-IF becomes an OR.
1391 : At gimplification time the inner OR becomes BIT_IOR_EXPR (in gimplify_expr),
1392 : giving this for the inner condition:
1393 : tmp = A | B;
1394 : if (tmp)
1395 : thus effectively synthesizing a redundant access of B when optimization
1396 : is turned on, when compared to:
1397 : if (A) goto L1; else goto L4;
1398 : L1: if (B) goto L2; else goto L4;
1399 : L2: if (C) goto L3; else goto L4;
1400 : for the unoptimized case.
1401 :
1402 : Return true if CTXT appears to be handling such a short-circuitable stmt,
1403 : such as the def-stmt for B for the:
1404 : tmp = A | B;
1405 : case above, for the case where A is true and thus B would have been
1406 : short-circuited without optimization, using MODEL for the value of A. */
1407 :
1408 : static bool
1409 1212 : within_short_circuited_stmt_p (const region_model *model,
1410 : const gassign *assign_stmt)
1411 : {
1412 : /* We must have an assignment to a temporary of _Bool type. */
1413 1212 : tree lhs = gimple_assign_lhs (assign_stmt);
1414 1212 : if (TREE_TYPE (lhs) != boolean_type_node)
1415 : return false;
1416 40 : if (TREE_CODE (lhs) != SSA_NAME)
1417 : return false;
1418 40 : if (SSA_NAME_VAR (lhs) != NULL_TREE)
1419 : return false;
1420 :
1421 : /* The temporary bool must be used exactly once: as the second arg of
1422 : a BIT_IOR_EXPR or BIT_AND_EXPR. */
1423 40 : use_operand_p use_op;
1424 40 : gimple *use_stmt;
1425 40 : if (!single_imm_use (lhs, &use_op, &use_stmt))
1426 : return false;
1427 40 : const gassign *use_assign = dyn_cast <const gassign *> (use_stmt);
1428 40 : if (!use_assign)
1429 : return false;
1430 40 : enum tree_code op = gimple_assign_rhs_code (use_assign);
1431 40 : if (!(op == BIT_IOR_EXPR ||op == BIT_AND_EXPR))
1432 : return false;
1433 28 : if (!(gimple_assign_rhs1 (use_assign) != lhs
1434 28 : && gimple_assign_rhs2 (use_assign) == lhs))
1435 : return false;
1436 :
1437 : /* The first arg of the bitwise stmt must have a known value in MODEL
1438 : that implies that the value of the second arg doesn't matter, i.e.
1439 : 1 for bitwise or, 0 for bitwise and. */
1440 28 : tree other_arg = gimple_assign_rhs1 (use_assign);
1441 : /* Use a nullptr ctxt here to avoid generating warnings. */
1442 28 : const svalue *other_arg_sval = model->get_rvalue (other_arg, nullptr);
1443 28 : tree other_arg_cst = other_arg_sval->maybe_get_constant ();
1444 28 : if (!other_arg_cst)
1445 : return false;
1446 12 : switch (op)
1447 : {
1448 : default:
1449 : gcc_unreachable ();
1450 12 : case BIT_IOR_EXPR:
1451 12 : if (zerop (other_arg_cst))
1452 0 : return false;
1453 : break;
1454 0 : case BIT_AND_EXPR:
1455 0 : if (!zerop (other_arg_cst))
1456 : return false;
1457 : break;
1458 : }
1459 :
1460 : /* All tests passed. We appear to be in a stmt that generates a boolean
1461 : temporary with a value that won't matter. */
1462 : return true;
1463 : }
1464 :
1465 : /* Workaround for discarding certain false positives from
1466 : -Wanalyzer-use-of-uninitialized-value
1467 : seen with -ftrivial-auto-var-init=.
1468 :
1469 : -ftrivial-auto-var-init= will generate calls to IFN_DEFERRED_INIT.
1470 :
1471 : If the address of the var is taken, gimplification will give us
1472 : something like:
1473 :
1474 : _1 = .DEFERRED_INIT (4, 2, &"len"[0]);
1475 : len = _1;
1476 :
1477 : The result of DEFERRED_INIT will be an uninit value; we don't
1478 : want to emit a false positive for "len = _1;"
1479 :
1480 : Return true if ASSIGN_STMT is such a stmt. */
1481 :
1482 : static bool
1483 1200 : due_to_ifn_deferred_init_p (const gassign *assign_stmt)
1484 :
1485 : {
1486 : /* We must have an assignment to a decl from an SSA name that's the
1487 : result of a IFN_DEFERRED_INIT call. */
1488 2230 : if (gimple_assign_rhs_code (assign_stmt) != SSA_NAME)
1489 : return false;
1490 323 : tree lhs = gimple_assign_lhs (assign_stmt);
1491 323 : if (TREE_CODE (lhs) != VAR_DECL)
1492 : return false;
1493 258 : tree rhs = gimple_assign_rhs1 (assign_stmt);
1494 258 : if (TREE_CODE (rhs) != SSA_NAME)
1495 : return false;
1496 258 : const gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
1497 258 : const gcall *call = dyn_cast <const gcall *> (def_stmt);
1498 258 : if (!call)
1499 : return false;
1500 258 : if (gimple_call_internal_p (call)
1501 258 : && gimple_call_internal_fn (call) == IFN_DEFERRED_INIT)
1502 246 : return true;
1503 : return false;
1504 : }
1505 :
1506 : /* Check for SVAL being poisoned, adding a warning to CTXT.
1507 : Return SVAL, or, if a warning is added, another value, to avoid
1508 : repeatedly complaining about the same poisoned value in followup code.
1509 : SRC_REGION is a hint about where SVAL came from, and can be nullptr. */
1510 :
1511 : const svalue *
1512 3555651 : region_model::check_for_poison (const svalue *sval,
1513 : tree expr,
1514 : const region *src_region,
1515 : region_model_context *ctxt) const
1516 : {
1517 3555651 : if (!ctxt)
1518 : return sval;
1519 :
1520 1814272 : if (const poisoned_svalue *poisoned_sval = sval->dyn_cast_poisoned_svalue ())
1521 : {
1522 2811 : enum poison_kind pkind = poisoned_sval->get_poison_kind ();
1523 :
1524 : /* Ignore uninitialized uses of empty types; there's nothing
1525 : to initialize. */
1526 2811 : if (pkind == poison_kind::uninit
1527 2770 : && sval->get_type ()
1528 5472 : && is_empty_type (sval->get_type ()))
1529 : return sval;
1530 :
1531 2529 : if (pkind == poison_kind::uninit)
1532 2488 : if (const gimple *curr_stmt = ctxt->get_stmt ())
1533 1556 : if (const gassign *assign_stmt
1534 3483 : = dyn_cast <const gassign *> (curr_stmt))
1535 : {
1536 : /* Special case to avoid certain false positives. */
1537 1212 : if (within_short_circuited_stmt_p (this, assign_stmt))
1538 : return sval;
1539 :
1540 : /* Special case to avoid false positive on
1541 : -ftrivial-auto-var-init=. */
1542 1200 : if (due_to_ifn_deferred_init_p (assign_stmt))
1543 : return sval;
1544 : }
1545 :
1546 : /* If we have an SSA name for a temporary, we don't want to print
1547 : '<unknown>'.
1548 : Poisoned values are shared by type, and so we can't reconstruct
1549 : the tree other than via the def stmts, using
1550 : fixup_tree_for_diagnostic. */
1551 2271 : tree diag_arg = fixup_tree_for_diagnostic (expr);
1552 2271 : if (src_region == nullptr && pkind == poison_kind::uninit)
1553 2181 : src_region = get_region_for_poisoned_expr (expr);
1554 :
1555 : /* Can we reliably get the poisoned value from "expr"?
1556 : This is for use by poisoned_value_diagnostic::check_valid_fpath_p.
1557 : Unfortunately, we might not have a reliable value for EXPR.
1558 : Hence we only query its value now, and only use it if we get the
1559 : poisoned value back again. */
1560 2271 : tree check_expr = expr;
1561 2271 : const svalue *foo_sval = get_rvalue (expr, nullptr);
1562 2271 : if (foo_sval == sval)
1563 : check_expr = expr;
1564 : else
1565 109 : check_expr = nullptr;
1566 2271 : if (ctxt->warn (make_poisoned_value_diagnostic (diag_arg,
1567 : pkind,
1568 : src_region,
1569 : check_expr)))
1570 : {
1571 : /* We only want to report use of a poisoned value at the first
1572 : place it gets used; return an unknown value to avoid generating
1573 : a chain of followup warnings. */
1574 1382 : sval = m_mgr->get_or_create_unknown_svalue (sval->get_type ());
1575 : }
1576 :
1577 : return sval;
1578 : }
1579 :
1580 : return sval;
1581 : }
1582 :
1583 : /* Attempt to get a region for describing EXPR, the source of region of
1584 : a poisoned_svalue for use in a poisoned_value_diagnostic.
1585 : Return nullptr if there is no good region to use. */
1586 :
1587 : const region *
1588 2181 : region_model::get_region_for_poisoned_expr (tree expr) const
1589 : {
1590 2181 : if (TREE_CODE (expr) == SSA_NAME)
1591 : {
1592 1402 : tree decl = SSA_NAME_VAR (expr);
1593 1362 : if (decl && DECL_P (decl))
1594 : expr = decl;
1595 : else
1596 : return nullptr;
1597 : }
1598 2141 : return get_lvalue (expr, nullptr);
1599 : }
1600 :
1601 : /* Update this model for the ASSIGN stmt, using CTXT to report any
1602 : diagnostics. */
1603 :
1604 : void
1605 266146 : region_model::on_assignment (const gassign *assign, region_model_context *ctxt)
1606 : {
1607 266146 : tree lhs = gimple_assign_lhs (assign);
1608 266146 : tree rhs1 = gimple_assign_rhs1 (assign);
1609 :
1610 266146 : const region *lhs_reg = get_lvalue (lhs, ctxt);
1611 :
1612 : /* Any writes other than to the stack are treated
1613 : as externally visible. */
1614 266146 : if (ctxt)
1615 : {
1616 204632 : enum memory_space memspace = lhs_reg->get_memory_space ();
1617 204632 : if (memspace != MEMSPACE_STACK)
1618 13318 : ctxt->maybe_did_work ();
1619 : }
1620 :
1621 : /* Most assignments are handled by:
1622 : set_value (lhs_reg, SVALUE, CTXT)
1623 : for some SVALUE. */
1624 266146 : if (const svalue *sval = get_gassign_result (assign, ctxt))
1625 : {
1626 257320 : tree expr = get_diagnostic_tree_for_gassign (assign);
1627 257320 : check_for_poison (sval, expr, nullptr, ctxt);
1628 257320 : set_value (lhs_reg, sval, ctxt);
1629 257320 : return;
1630 : }
1631 :
1632 8826 : enum tree_code op = gimple_assign_rhs_code (assign);
1633 8826 : switch (op)
1634 : {
1635 37 : default:
1636 37 : {
1637 37 : if (0)
1638 : sorry_at (assign->location, "unhandled assignment op: %qs",
1639 : get_tree_code_name (op));
1640 37 : const svalue *unknown_sval
1641 37 : = m_mgr->get_or_create_unknown_svalue (TREE_TYPE (lhs));
1642 37 : set_value (lhs_reg, unknown_sval, ctxt);
1643 : }
1644 37 : break;
1645 :
1646 8231 : case CONSTRUCTOR:
1647 8231 : {
1648 8231 : if (TREE_CLOBBER_P (rhs1))
1649 : {
1650 : /* e.g. "x ={v} {CLOBBER};" */
1651 8067 : clobber_region (lhs_reg);
1652 : }
1653 : else
1654 : {
1655 : /* Any CONSTRUCTOR that survives to this point is either
1656 : just a zero-init of everything, or a vector. */
1657 164 : if (!CONSTRUCTOR_NO_CLEARING (rhs1))
1658 164 : zero_fill_region (lhs_reg, ctxt);
1659 164 : unsigned ix;
1660 164 : tree index;
1661 164 : tree val;
1662 326 : FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (rhs1), ix, index, val)
1663 : {
1664 162 : gcc_assert (TREE_CODE (TREE_TYPE (rhs1)) == VECTOR_TYPE);
1665 162 : if (!index)
1666 22 : index = build_int_cst (integer_type_node, ix);
1667 162 : gcc_assert (TREE_CODE (index) == INTEGER_CST);
1668 162 : const svalue *index_sval
1669 162 : = m_mgr->get_or_create_constant_svalue (index);
1670 162 : gcc_assert (index_sval);
1671 162 : const region *sub_reg
1672 162 : = m_mgr->get_element_region (lhs_reg,
1673 162 : TREE_TYPE (val),
1674 : index_sval);
1675 162 : const svalue *val_sval = get_rvalue (val, ctxt);
1676 162 : set_value (sub_reg, val_sval, ctxt);
1677 : }
1678 : }
1679 : }
1680 : break;
1681 :
1682 558 : case STRING_CST:
1683 558 : {
1684 : /* e.g. "struct s2 x = {{'A', 'B', 'C', 'D'}};". */
1685 558 : const svalue *rhs_sval = get_rvalue (rhs1, ctxt);
1686 762 : m_store.set_value (m_mgr->get_store_manager(), lhs_reg, rhs_sval,
1687 204 : ctxt ? ctxt->get_uncertainty () : nullptr,
1688 : *this);
1689 : }
1690 558 : break;
1691 : }
1692 : }
1693 :
1694 : /* Handle the pre-sm-state part of STMT, modifying this object in-place.
1695 : Write true to *OUT_UNKNOWN_SIDE_EFFECTS if the stmt has unknown
1696 : side effects. */
1697 :
1698 : void
1699 348849 : region_model::on_stmt_pre (const gimple *stmt,
1700 : bool *out_unknown_side_effects,
1701 : region_model_context *ctxt)
1702 : {
1703 348849 : switch (gimple_code (stmt))
1704 : {
1705 : case GIMPLE_COND:
1706 : case GIMPLE_EH_DISPATCH:
1707 : case GIMPLE_GOTO:
1708 : case GIMPLE_LABEL:
1709 : case GIMPLE_NOP:
1710 : case GIMPLE_PREDICT:
1711 : case GIMPLE_RESX:
1712 : case GIMPLE_SWITCH:
1713 : /* No-ops here. */
1714 : break;
1715 :
1716 266146 : case GIMPLE_ASSIGN:
1717 266146 : {
1718 266146 : const gassign *assign = as_a <const gassign *> (stmt);
1719 266146 : on_assignment (assign, ctxt);
1720 : }
1721 266146 : break;
1722 :
1723 384 : case GIMPLE_ASM:
1724 384 : {
1725 384 : const gasm *asm_stmt = as_a <const gasm *> (stmt);
1726 384 : on_asm_stmt (asm_stmt, ctxt);
1727 384 : if (ctxt)
1728 342 : ctxt->maybe_did_work ();
1729 : }
1730 : break;
1731 :
1732 78781 : case GIMPLE_CALL:
1733 78781 : {
1734 : /* Track whether we have a gcall to a function that's not recognized by
1735 : anything, for which we don't have a function body, or for which we
1736 : don't know the fndecl. */
1737 78781 : const gcall *call = as_a <const gcall *> (stmt);
1738 78781 : *out_unknown_side_effects = on_call_pre (*call, ctxt);
1739 : }
1740 78781 : break;
1741 :
1742 0 : case GIMPLE_RETURN:
1743 0 : {
1744 0 : const greturn *return_ = as_a <const greturn *> (stmt);
1745 0 : on_return (return_, ctxt);
1746 : }
1747 0 : break;
1748 :
1749 : /* We don't expect to see any other statement kinds in the analyzer. */
1750 0 : case GIMPLE_DEBUG: // should have stripped these out when building the supergraph
1751 0 : default:
1752 0 : internal_error ("unexpected gimple stmt code: %qs",
1753 0 : gimple_code_name[gimple_code (stmt)]);
1754 348849 : break;
1755 : }
1756 348849 : }
1757 :
1758 : /* Given a call CD with function attribute FORMAT_ATTR, check that the
1759 : format arg to the call is a valid null-terminated string. */
1760 :
1761 : void
1762 1055 : region_model::check_call_format_attr (const call_details &cd,
1763 : tree format_attr) const
1764 : {
1765 : /* We assume that FORMAT_ATTR has already been validated. */
1766 :
1767 : /* arg0 of the attribute should be kind of format strings
1768 : that this function expects (e.g. "printf"). */
1769 1055 : const tree arg0_tree_list = TREE_VALUE (format_attr);
1770 1055 : if (!arg0_tree_list)
1771 0 : return;
1772 :
1773 : /* arg1 of the attribute should be the 1-based parameter index
1774 : to treat as the format string. */
1775 1055 : const tree arg1_tree_list = TREE_CHAIN (arg0_tree_list);
1776 1055 : if (!arg1_tree_list)
1777 : return;
1778 1055 : const tree arg1_value = TREE_VALUE (arg1_tree_list);
1779 1055 : if (!arg1_value)
1780 : return;
1781 :
1782 1055 : unsigned format_arg_idx = TREE_INT_CST_LOW (arg1_value) - 1;
1783 1055 : if (cd.num_args () <= format_arg_idx)
1784 : return;
1785 :
1786 : /* Subclass of annotating_context that
1787 : adds a note about the format attr to any saved diagnostics. */
1788 1055 : class annotating_ctxt : public annotating_context
1789 : {
1790 : public:
1791 1055 : annotating_ctxt (const call_details &cd,
1792 : unsigned fmt_param_idx)
1793 : : annotating_context (cd.get_ctxt ()),
1794 1055 : m_cd (cd),
1795 1055 : m_fmt_param_idx (fmt_param_idx)
1796 : {
1797 : }
1798 13 : void add_annotations () final override
1799 : {
1800 0 : class reason_format_attr
1801 : : public pending_note_subclass<reason_format_attr>
1802 : {
1803 : public:
1804 13 : reason_format_attr (const call_arg_details &arg_details)
1805 13 : : m_arg_details (arg_details)
1806 : {
1807 : }
1808 :
1809 74 : const char *get_kind () const final override
1810 : {
1811 74 : return "reason_format_attr";
1812 : }
1813 :
1814 13 : void emit () const final override
1815 : {
1816 13 : inform (DECL_SOURCE_LOCATION (m_arg_details.m_called_fndecl),
1817 : "parameter %i of %qD marked as a format string"
1818 : " via %qs attribute",
1819 13 : m_arg_details.m_arg_idx + 1, m_arg_details.m_called_fndecl,
1820 : "format");
1821 13 : }
1822 :
1823 37 : bool operator== (const reason_format_attr &other) const
1824 : {
1825 37 : return m_arg_details == other.m_arg_details;
1826 : }
1827 :
1828 : private:
1829 : call_arg_details m_arg_details;
1830 : };
1831 :
1832 13 : call_arg_details arg_details (m_cd, m_fmt_param_idx);
1833 13 : add_note (std::make_unique<reason_format_attr> (arg_details));
1834 13 : }
1835 : private:
1836 : const call_details &m_cd;
1837 : unsigned m_fmt_param_idx;
1838 : };
1839 :
1840 1055 : annotating_ctxt my_ctxt (cd, format_arg_idx);
1841 1055 : call_details my_cd (cd, &my_ctxt);
1842 1055 : my_cd.check_for_null_terminated_string_arg (format_arg_idx);
1843 : }
1844 :
1845 : /* Ensure that all arguments at the call described by CD are checked
1846 : for poisoned values, by calling get_rvalue on each argument.
1847 :
1848 : Check that calls to functions with "format" attribute have valid
1849 : null-terminated strings for their format argument. */
1850 :
1851 : void
1852 50816 : region_model::check_call_args (const call_details &cd) const
1853 : {
1854 118347 : for (unsigned arg_idx = 0; arg_idx < cd.num_args (); arg_idx++)
1855 67531 : cd.get_arg_svalue (arg_idx);
1856 :
1857 : /* Handle attribute "format". */
1858 50816 : if (tree format_attr = cd.lookup_function_attribute ("format"))
1859 1055 : check_call_format_attr (cd, format_attr);
1860 50816 : }
1861 :
1862 : /* Update this model for an outcome of a call that returns a specific
1863 : integer constant.
1864 : If UNMERGEABLE, then make the result unmergeable, e.g. to prevent
1865 : the state-merger code from merging success and failure outcomes. */
1866 :
1867 : void
1868 936 : region_model::update_for_int_cst_return (const call_details &cd,
1869 : int retval,
1870 : bool unmergeable)
1871 : {
1872 936 : if (!cd.get_lhs_type ())
1873 : return;
1874 615 : if (TREE_CODE (cd.get_lhs_type ()) != INTEGER_TYPE)
1875 : return;
1876 609 : const svalue *result
1877 609 : = m_mgr->get_or_create_int_cst (cd.get_lhs_type (), retval);
1878 609 : if (unmergeable)
1879 609 : result = m_mgr->get_or_create_unmergeable (result);
1880 609 : set_value (cd.get_lhs_region (), result, cd.get_ctxt ());
1881 : }
1882 :
1883 : /* Update this model for an outcome of a call that returns zero.
1884 : If UNMERGEABLE, then make the result unmergeable, e.g. to prevent
1885 : the state-merger code from merging success and failure outcomes. */
1886 :
1887 : void
1888 290 : region_model::update_for_zero_return (const call_details &cd,
1889 : bool unmergeable)
1890 : {
1891 290 : update_for_int_cst_return (cd, 0, unmergeable);
1892 290 : }
1893 :
1894 : /* Update this model for an outcome of a call that returns a NULL
1895 : pointer.
1896 : If UNMERGEABLE, then make the result unmergeable, e.g. to prevent
1897 : the state-merger code from merging success and failure outcomes. */
1898 :
1899 : void
1900 14 : region_model::update_for_null_return (const call_details &cd, bool unmergeable)
1901 : {
1902 14 : if (!cd.get_lhs_type ())
1903 : return;
1904 2 : if (!POINTER_TYPE_P (cd.get_lhs_type ()))
1905 : return;
1906 2 : const svalue *result = m_mgr->get_or_create_null_ptr (cd.get_lhs_type ());
1907 2 : if (unmergeable)
1908 2 : result = m_mgr->get_or_create_unmergeable (result);
1909 2 : set_value (cd.get_lhs_region (), result, cd.get_ctxt ());
1910 : }
1911 :
1912 : /* Update this model for an outcome of a call that returns non-zero.
1913 : Specifically, assign an svalue to the LHS, and add a constraint that
1914 : that svalue is non-zero. */
1915 :
1916 : void
1917 136 : region_model::update_for_nonzero_return (const call_details &cd)
1918 : {
1919 136 : if (!cd.get_lhs_type ())
1920 : return;
1921 100 : if (TREE_CODE (cd.get_lhs_type ()) != INTEGER_TYPE)
1922 : return;
1923 100 : cd.set_any_lhs_with_defaults ();
1924 100 : const svalue *zero
1925 100 : = m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
1926 100 : const svalue *result
1927 100 : = get_store_value (cd.get_lhs_region (), cd.get_ctxt ());
1928 100 : add_constraint (result, NE_EXPR, zero, cd.get_ctxt ());
1929 : }
1930 :
1931 : /* Subroutine of region_model::maybe_get_copy_bounds.
1932 : The Linux kernel commonly uses
1933 : min_t([unsigned] long, VAR, sizeof(T));
1934 : to set an upper bound on the size of a copy_to_user.
1935 : Attempt to simplify such sizes by trying to get the upper bound as a
1936 : constant.
1937 : Return the simplified svalue if possible, or nullptr otherwise. */
1938 :
1939 : static const svalue *
1940 53 : maybe_simplify_upper_bound (const svalue *num_bytes_sval,
1941 : region_model_manager *mgr)
1942 : {
1943 53 : tree type = num_bytes_sval->get_type ();
1944 70 : while (const svalue *raw = num_bytes_sval->maybe_undo_cast ())
1945 : num_bytes_sval = raw;
1946 53 : if (const binop_svalue *binop_sval = num_bytes_sval->dyn_cast_binop_svalue ())
1947 38 : if (binop_sval->get_op () == MIN_EXPR)
1948 8 : if (binop_sval->get_arg1 ()->get_kind () == SK_CONSTANT)
1949 : {
1950 8 : return mgr->get_or_create_cast (type, binop_sval->get_arg1 ());
1951 : /* TODO: we might want to also capture the constraint
1952 : when recording the diagnostic, or note that we're using
1953 : the upper bound. */
1954 : }
1955 : return nullptr;
1956 : }
1957 :
1958 : /* Attempt to get an upper bound for the size of a copy when simulating a
1959 : copy function.
1960 :
1961 : NUM_BYTES_SVAL is the symbolic value for the size of the copy.
1962 : Use it if it's constant, otherwise try to simplify it. Failing
1963 : that, use the size of SRC_REG if constant.
1964 :
1965 : Return a symbolic value for an upper limit on the number of bytes
1966 : copied, or nullptr if no such value could be determined. */
1967 :
1968 : const svalue *
1969 157 : region_model::maybe_get_copy_bounds (const region *src_reg,
1970 : const svalue *num_bytes_sval)
1971 : {
1972 157 : if (num_bytes_sval->maybe_get_constant ())
1973 : return num_bytes_sval;
1974 :
1975 106 : if (const svalue *simplified
1976 53 : = maybe_simplify_upper_bound (num_bytes_sval, m_mgr))
1977 8 : num_bytes_sval = simplified;
1978 :
1979 53 : if (num_bytes_sval->maybe_get_constant ())
1980 : return num_bytes_sval;
1981 :
1982 : /* For now, try just guessing the size as the capacity of the
1983 : base region of the src.
1984 : This is a hack; we might get too large a value. */
1985 45 : const region *src_base_reg = src_reg->get_base_region ();
1986 45 : num_bytes_sval = get_capacity (src_base_reg);
1987 :
1988 45 : if (num_bytes_sval->maybe_get_constant ())
1989 11 : return num_bytes_sval;
1990 :
1991 : /* Non-constant: give up. */
1992 : return nullptr;
1993 : }
1994 :
1995 : /* Get any known_function for FNDECL for call CD.
1996 :
1997 : The call must match all assumptions made by the known_function (such as
1998 : e.g. "argument 1's type must be a pointer type").
1999 :
2000 : Return nullptr if no known_function is found, or it does not match the
2001 : assumption(s). */
2002 :
2003 : const known_function *
2004 313110 : region_model::get_known_function (tree fndecl, const call_details &cd) const
2005 : {
2006 313110 : known_function_manager *known_fn_mgr = m_mgr->get_known_function_manager ();
2007 313110 : return known_fn_mgr->get_match (fndecl, cd);
2008 : }
2009 :
2010 : /* Get any known_function for IFN, or nullptr. */
2011 :
2012 : const known_function *
2013 1442 : region_model::get_known_function (enum internal_fn ifn) const
2014 : {
2015 1442 : known_function_manager *known_fn_mgr = m_mgr->get_known_function_manager ();
2016 1442 : return known_fn_mgr->get_internal_fn (ifn);
2017 : }
2018 :
2019 : /* Get any builtin_known_function for CALL and emit any warning to CTXT
2020 : if not nullptr.
2021 :
2022 : The call must match all assumptions made by the known_function (such as
2023 : e.g. "argument 1's type must be a pointer type").
2024 :
2025 : Return nullptr if no builtin_known_function is found, or it does
2026 : not match the assumption(s).
2027 :
2028 : Internally calls get_known_function to find a known_function and cast it
2029 : to a builtin_known_function.
2030 :
2031 : For instance, calloc is a C builtin, defined in gcc/builtins.def
2032 : by the DEF_LIB_BUILTIN macro. Such builtins are recognized by the
2033 : analyzer by their name, so that even in C++ or if the user redeclares
2034 : them but mismatch their signature, they are still recognized as builtins.
2035 :
2036 : Cases when a supposed builtin is not flagged as one by the FE:
2037 :
2038 : The C++ FE does not recognize calloc as a builtin if it has not been
2039 : included from a standard header, but the C FE does. Hence in C++ if
2040 : CALL comes from a calloc and stdlib is not included,
2041 : gcc/tree.h:fndecl_built_in_p (CALL) would be false.
2042 :
2043 : In C code, a __SIZE_TYPE__ calloc (__SIZE_TYPE__, __SIZE_TYPE__) user
2044 : declaration has obviously a mismatching signature from the standard, and
2045 : its function_decl tree won't be unified by
2046 : gcc/c-decl.cc:match_builtin_function_types.
2047 :
2048 : Yet in both cases the analyzer should treat the calls as a builtin calloc
2049 : so that extra attributes unspecified by the standard but added by GCC
2050 : (e.g. sprintf attributes in gcc/builtins.def), useful for the detection of
2051 : dangerous behavior, are indeed processed.
2052 :
2053 : Therefore for those cases when a "builtin flag" is not added by the FE,
2054 : builtins' kf are derived from builtin_known_function, whose method
2055 : builtin_known_function::builtin_decl returns the builtin's
2056 : function_decl tree as defined in gcc/builtins.def, with all the extra
2057 : attributes. */
2058 :
2059 : const builtin_known_function *
2060 169778 : region_model::get_builtin_kf (const gcall &call,
2061 : region_model_context *ctxt /* = nullptr */) const
2062 : {
2063 169778 : region_model *mut_this = const_cast <region_model *> (this);
2064 169778 : tree callee_fndecl = mut_this->get_fndecl_for_call (call, ctxt);
2065 169778 : if (! callee_fndecl)
2066 : return nullptr;
2067 :
2068 169778 : call_details cd (call, mut_this, ctxt);
2069 169778 : if (const known_function *kf = get_known_function (callee_fndecl, cd))
2070 117372 : return kf->dyn_cast_builtin_kf ();
2071 :
2072 : return nullptr;
2073 : }
2074 :
2075 : /* Subclass of custom_edge_info for use by exploded_edges that represent
2076 : an exception being thrown from a call we don't have the code for. */
2077 :
2078 : class exception_thrown_from_unrecognized_call : public custom_edge_info
2079 : {
2080 : public:
2081 5605 : exception_thrown_from_unrecognized_call (const gcall &call,
2082 : tree fndecl)
2083 5605 : : m_call (call),
2084 5605 : m_fndecl (fndecl)
2085 : {
2086 : }
2087 :
2088 12 : void print (pretty_printer *pp) const final override
2089 : {
2090 12 : if (m_fndecl)
2091 12 : pp_printf (pp, "if %qD throws an exception...", m_fndecl);
2092 : else
2093 0 : pp_printf (pp, "if the called function throws an exception...");
2094 12 : };
2095 :
2096 : bool
2097 5642 : update_model (region_model *model,
2098 : const exploded_edge *,
2099 : region_model_context *ctxt) const final override
2100 : {
2101 : /* Allocate an exception and set it as the current exception. */
2102 5642 : const region *exception_reg
2103 : = model->get_or_create_region_for_heap_alloc
2104 5642 : (nullptr, /* We don't know the size of the region. */
2105 : ctxt);
2106 :
2107 5642 : region_model_manager *mgr = model->get_manager ();
2108 5642 : conjured_purge p (model, ctxt);
2109 :
2110 : /* The contents of the region are some conjured svalue. */
2111 5642 : const svalue *exception_sval
2112 11284 : = mgr->get_or_create_conjured_svalue (NULL_TREE,
2113 5642 : &m_call,
2114 : exception_reg, p, 0);
2115 5642 : model->set_value (exception_reg, exception_sval, ctxt);
2116 5642 : const svalue *exception_ptr_sval
2117 5642 : = mgr->get_ptr_svalue (ptr_type_node, exception_reg);
2118 5642 : const svalue *tinfo_sval
2119 11284 : = mgr->get_or_create_conjured_svalue (ptr_type_node,
2120 5642 : &m_call,
2121 : exception_reg, p, 1);
2122 5642 : const svalue *destructor_sval
2123 11284 : = mgr->get_or_create_conjured_svalue (ptr_type_node,
2124 5642 : &m_call,
2125 : exception_reg, p, 2);
2126 :
2127 : /* Push a new exception_node on the model's thrown exception stack. */
2128 5642 : exception_node eh_node (exception_ptr_sval, tinfo_sval, destructor_sval);
2129 5642 : model->push_thrown_exception (eh_node);
2130 :
2131 5642 : return true;
2132 : }
2133 :
2134 : void
2135 29 : add_events_to_path (checker_path *emission_path,
2136 : const exploded_edge &eedge,
2137 : pending_diagnostic &,
2138 : const state_transition *) const final override
2139 : {
2140 29 : const exploded_node *dst_node = eedge.m_dest;
2141 29 : const program_point &dst_point = dst_node->get_point ();
2142 29 : const int dst_stack_depth = dst_point.get_stack_depth ();
2143 :
2144 29 : emission_path->add_event
2145 29 : (std::make_unique<throw_from_call_to_external_fn_event>
2146 29 : (event_loc_info (m_call.location,
2147 : dst_point.get_fndecl (),
2148 29 : dst_stack_depth),
2149 : dst_node,
2150 : m_call,
2151 29 : m_fndecl));
2152 29 : }
2153 :
2154 : exploded_node *
2155 5492 : create_enode (exploded_graph &eg,
2156 : const program_point &point,
2157 : program_state &&state,
2158 : exploded_node *enode_for_diag,
2159 : region_model_context *ctxt) const final override
2160 : {
2161 5492 : exploded_node *thrown_enode
2162 5492 : = eg.get_or_create_node (point, state, enode_for_diag,
2163 : /* Don't add to worklist. */
2164 : false);
2165 5492 : if (!thrown_enode)
2166 : return nullptr;
2167 :
2168 : /* Add successor edges for thrown_enode "by hand" for the exception. */
2169 5416 : eg.unwind_from_exception (*thrown_enode,
2170 5416 : &m_call,
2171 : ctxt);
2172 5416 : return thrown_enode;
2173 : }
2174 :
2175 : private:
2176 : const gcall &m_call;
2177 : tree m_fndecl; // could be null
2178 : };
2179 :
2180 : /* Get a set of functions that are assumed to not throw exceptions. */
2181 :
2182 : static function_set
2183 5469 : get_fns_assumed_not_to_throw ()
2184 : {
2185 : // TODO: populate this list more fully
2186 5469 : static const char * const fn_names[] = {
2187 : /* This array must be kept sorted. */
2188 :
2189 : "fclose"
2190 : };
2191 5469 : const size_t count = ARRAY_SIZE (fn_names);
2192 5469 : function_set fs (fn_names, count);
2193 5469 : return fs;
2194 : }
2195 :
2196 : /* Return true if CALL could throw an exception.
2197 : FNDECL could be NULL_TREE. */
2198 :
2199 : static bool
2200 12946 : can_throw_p (const gcall &call, tree fndecl)
2201 : {
2202 12946 : if (!flag_exceptions)
2203 : return false;
2204 :
2205 : /* Compatibility flag to allow the user to assume external functions
2206 : never throw exceptions. This may be useful when using the analyzer
2207 : on C code that is compiled with -fexceptions, but for which the headers
2208 : haven't yet had "nothrow" attributes systematically added. */
2209 6156 : if (flag_analyzer_assume_nothrow)
2210 : return false;
2211 :
2212 6154 : if (gimple_call_nothrow_p (&call))
2213 : return false;
2214 :
2215 5615 : if (fndecl)
2216 : {
2217 : /* If we are checking a thunk, we want to verify whether or not the
2218 : underlying function is nothrow. */
2219 5472 : if (cgraph_node *n = cgraph_node::get (fndecl))
2220 5472 : fndecl = n->function_symbol ()->decl;
2221 :
2222 5472 : if (TREE_NOTHROW (fndecl))
2223 10 : return false;
2224 :
2225 5469 : const function_set fs = get_fns_assumed_not_to_throw ();
2226 5469 : if (fs.contains_decl_p (fndecl))
2227 : return false;
2228 : }
2229 :
2230 : return true;
2231 : }
2232 :
2233 : /* Given CALL where we don't know what code is being called
2234 : (by not having the body of FNDECL, or having NULL_TREE for FNDECL),
2235 : potentially bifurcate control flow to simulate the call throwing
2236 : an exception. */
2237 :
2238 : void
2239 18966 : region_model::check_for_throw_inside_call (const gcall &call,
2240 : tree fndecl,
2241 : region_model_context *ctxt)
2242 : {
2243 18966 : if (!ctxt)
2244 13361 : return;
2245 :
2246 : /* Could this function throw an exception?
2247 : If so, add an extra e-edge for that. */
2248 12946 : if (!can_throw_p (call, fndecl))
2249 : return;
2250 :
2251 5605 : auto throws_exception
2252 5605 : = std::make_unique<exception_thrown_from_unrecognized_call> (call, fndecl);
2253 5605 : ctxt->bifurcate (std::move (throws_exception));
2254 5605 : }
2255 :
2256 : /* A subclass of pending_diagnostic for complaining about jumps through NULL
2257 : function pointers. */
2258 :
2259 : class jump_through_null : public pending_diagnostic_subclass<jump_through_null>
2260 : {
2261 : public:
2262 16 : jump_through_null (const gcall &call)
2263 16 : : m_call (call)
2264 : {}
2265 :
2266 152 : const char *get_kind () const final override
2267 : {
2268 152 : return "jump_through_null";
2269 : }
2270 :
2271 16 : bool operator== (const jump_through_null &other) const
2272 : {
2273 16 : return &m_call == &other.m_call;
2274 : }
2275 :
2276 32 : int get_controlling_option () const final override
2277 : {
2278 32 : return OPT_Wanalyzer_jump_through_null;
2279 : }
2280 :
2281 16 : bool emit (diagnostic_emission_context &ctxt) final override
2282 : {
2283 16 : return ctxt.warn ("jump through null pointer");
2284 : }
2285 :
2286 32 : bool describe_final_event (pretty_printer &pp,
2287 : const evdesc::final_event &) final override
2288 : {
2289 32 : pp_string (&pp, "jump through null pointer here");
2290 32 : return true;
2291 : }
2292 :
2293 : private:
2294 : const gcall &m_call;
2295 : };
2296 : /* Update this model for the CALL stmt, using CTXT to report any
2297 : diagnostics - the first half.
2298 :
2299 : Updates to the region_model that should be made *before* sm-states
2300 : are updated are done here; other updates to the region_model are done
2301 : in region_model::on_call_post.
2302 :
2303 : Return true if the function call has unknown side effects (it wasn't
2304 : recognized and we don't have a body for it, or are unable to tell which
2305 : fndecl it is). */
2306 :
2307 : bool
2308 78781 : region_model::on_call_pre (const gcall &call, region_model_context *ctxt)
2309 : {
2310 78781 : call_details cd (call, this, ctxt);
2311 :
2312 : /* Special-case for IFN_DEFERRED_INIT.
2313 : We want to report uninitialized variables with -fanalyzer (treating
2314 : -ftrivial-auto-var-init= as purely a mitigation feature).
2315 : Handle IFN_DEFERRED_INIT by treating it as no-op: don't touch the
2316 : lhs of the call, so that it is still uninitialized from the point of
2317 : view of the analyzer. */
2318 78781 : if (gimple_call_internal_p (&call)
2319 78781 : && gimple_call_internal_fn (&call) == IFN_DEFERRED_INIT)
2320 : return false; /* No side effects. */
2321 :
2322 : /* Get svalues for all of the arguments at the callsite, to ensure that we
2323 : complain about any uninitialized arguments. This might lead to
2324 : duplicates if any of the handling below also looks up the svalues,
2325 : but the deduplication code should deal with that. */
2326 73705 : if (ctxt)
2327 50816 : check_call_args (cd);
2328 :
2329 73705 : tree callee_fndecl = get_fndecl_for_call (call, ctxt);
2330 :
2331 73705 : if (gimple_call_internal_p (&call))
2332 2884 : if (const known_function *kf
2333 1442 : = get_known_function (gimple_call_internal_fn (&call)))
2334 : {
2335 1408 : kf->impl_call_pre (cd);
2336 1408 : return false; /* No further side effects. */
2337 : }
2338 :
2339 72297 : if (!callee_fndecl)
2340 : {
2341 : /* Check for jump through nullptr. */
2342 523 : if (ctxt)
2343 407 : if (tree fn_ptr = gimple_call_fn (&call))
2344 : {
2345 381 : const svalue *fn_ptr_sval = get_rvalue (fn_ptr, ctxt);
2346 381 : if (fn_ptr_sval->all_zeroes_p ())
2347 : {
2348 16 : ctxt->warn
2349 16 : (std::make_unique<jump_through_null> (call));
2350 16 : ctxt->terminate_path ();
2351 16 : return true;
2352 : }
2353 : }
2354 :
2355 507 : check_for_throw_inside_call (call, NULL_TREE, ctxt);
2356 507 : cd.set_any_lhs_with_defaults ();
2357 507 : return true; /* Unknown side effects. */
2358 : }
2359 :
2360 71774 : if (const known_function *kf = get_known_function (callee_fndecl, cd))
2361 : {
2362 50979 : kf->impl_call_pre (cd);
2363 50979 : return false; /* No further side effects. */
2364 : }
2365 :
2366 20795 : cd.set_any_lhs_with_defaults ();
2367 :
2368 20795 : const int callee_fndecl_flags = flags_from_decl_or_type (callee_fndecl);
2369 20795 : if (callee_fndecl_flags & (ECF_CONST | ECF_PURE))
2370 : return false; /* No side effects. */
2371 :
2372 19251 : if (fndecl_built_in_p (callee_fndecl))
2373 : return true; /* Unknown side effects. */
2374 :
2375 18459 : if (!fndecl_has_gimple_body_p (callee_fndecl))
2376 : {
2377 18459 : check_for_throw_inside_call (call, callee_fndecl, ctxt);
2378 18459 : return true; /* Unknown side effects. */
2379 : }
2380 :
2381 : return false; /* No side effects. */
2382 : }
2383 :
2384 : /* Update this model for the CALL stmt, using CTXT to report any
2385 : diagnostics - the second half.
2386 :
2387 : Updates to the region_model that should be made *after* sm-states
2388 : are updated are done here; other updates to the region_model are done
2389 : in region_model::on_call_pre.
2390 :
2391 : If UNKNOWN_SIDE_EFFECTS is true, also call handle_unrecognized_call
2392 : to purge state. */
2393 :
2394 : void
2395 78518 : region_model::on_call_post (const gcall &call,
2396 : bool unknown_side_effects,
2397 : region_model_context *ctxt)
2398 : {
2399 78518 : if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
2400 : {
2401 71558 : call_details cd (call, this, ctxt);
2402 71558 : if (const known_function *kf = get_known_function (callee_fndecl, cd))
2403 : {
2404 50821 : kf->impl_call_post (cd);
2405 102129 : return;
2406 : }
2407 : /* Was this fndecl referenced by
2408 : __attribute__((malloc(FOO)))? */
2409 20737 : if (lookup_attribute ("*dealloc", DECL_ATTRIBUTES (callee_fndecl)))
2410 : {
2411 487 : impl_deallocation_call (cd);
2412 487 : return;
2413 : }
2414 : }
2415 :
2416 27210 : if (unknown_side_effects)
2417 : {
2418 18123 : handle_unrecognized_call (call, ctxt);
2419 18123 : if (ctxt)
2420 12356 : ctxt->maybe_did_work ();
2421 : }
2422 : }
2423 :
2424 : /* Purge state involving SVAL from this region_model, using CTXT
2425 : (if non-NULL) to purge other state in a program_state.
2426 :
2427 : For example, if we're at the def-stmt of an SSA name, then we need to
2428 : purge any state for svalues that involve that SSA name. This avoids
2429 : false positives in loops, since a symbolic value referring to the
2430 : SSA name will be referring to the previous value of that SSA name.
2431 :
2432 : For example, in:
2433 : while ((e = hashmap_iter_next(&iter))) {
2434 : struct oid2strbuf *e_strbuf = (struct oid2strbuf *)e;
2435 : free (e_strbuf->value);
2436 : }
2437 : at the def-stmt of e_8:
2438 : e_8 = hashmap_iter_next (&iter);
2439 : we should purge the "freed" state of:
2440 : INIT_VAL(CAST_REG(‘struct oid2strbuf’, (*INIT_VAL(e_8))).value)
2441 : which is the "e_strbuf->value" value from the previous iteration,
2442 : or we will erroneously report a double-free - the "e_8" within it
2443 : refers to the previous value. */
2444 :
2445 : void
2446 30285 : region_model::purge_state_involving (const svalue *sval,
2447 : region_model_context *ctxt)
2448 : {
2449 30285 : if (!sval->can_have_associated_state_p ())
2450 : return;
2451 30285 : m_store.purge_state_involving (sval, m_mgr);
2452 30285 : m_constraints->purge_state_involving (sval);
2453 30285 : m_dynamic_extents.purge_state_involving (sval);
2454 30285 : if (ctxt)
2455 17985 : ctxt->purge_state_involving (sval);
2456 : }
2457 :
2458 : /* A pending_note subclass for adding a note about an
2459 : __attribute__((access, ...)) to a diagnostic. */
2460 :
2461 : class reason_attr_access : public pending_note_subclass<reason_attr_access>
2462 : {
2463 : public:
2464 22 : reason_attr_access (tree callee_fndecl, const attr_access &access)
2465 22 : : m_callee_fndecl (callee_fndecl),
2466 22 : m_ptr_argno (access.ptrarg),
2467 22 : m_access_str (TREE_STRING_POINTER (access.to_external_string ()))
2468 : {
2469 22 : }
2470 :
2471 116 : const char *get_kind () const final override { return "reason_attr_access"; }
2472 :
2473 18 : void emit () const final override
2474 : {
2475 18 : auto_urlify_attributes sentinel;
2476 18 : inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
2477 : "parameter %i of %qD marked with attribute %qs",
2478 18 : m_ptr_argno + 1, m_callee_fndecl, m_access_str);
2479 18 : }
2480 :
2481 58 : bool operator== (const reason_attr_access &other) const
2482 : {
2483 58 : return (m_callee_fndecl == other.m_callee_fndecl
2484 22 : && m_ptr_argno == other.m_ptr_argno
2485 80 : && !strcmp (m_access_str, other.m_access_str));
2486 : }
2487 :
2488 : private:
2489 : tree m_callee_fndecl;
2490 : unsigned m_ptr_argno;
2491 : const char *m_access_str;
2492 : };
2493 :
2494 : /* Check CALL a call to external function CALLEE_FNDECL based on
2495 : any __attribute__ ((access, ....) on the latter, complaining to
2496 : CTXT about any issues.
2497 :
2498 : Currently we merely call check_region_for_write on any regions
2499 : pointed to by arguments marked with a "write_only" or "read_write"
2500 : attribute. */
2501 :
2502 : void
2503 1257 : region_model::check_function_attr_access (const gcall &call,
2504 : tree callee_fndecl,
2505 : region_model_context *ctxt,
2506 : rdwr_map &rdwr_idx) const
2507 : {
2508 1257 : gcc_assert (callee_fndecl);
2509 1257 : gcc_assert (ctxt);
2510 :
2511 1257 : tree fntype = TREE_TYPE (callee_fndecl);
2512 1257 : gcc_assert (fntype);
2513 :
2514 1257 : unsigned argno = 0;
2515 :
2516 4776 : for (tree iter = TYPE_ARG_TYPES (fntype); iter;
2517 3519 : iter = TREE_CHAIN (iter), ++argno)
2518 : {
2519 3519 : const attr_access* access = rdwr_idx.get (argno);
2520 3519 : if (!access)
2521 3241 : continue;
2522 :
2523 : /* Ignore any duplicate entry in the map for the size argument. */
2524 278 : if (access->ptrarg != argno)
2525 114 : continue;
2526 :
2527 164 : if (access->mode == access_write_only
2528 164 : || access->mode == access_read_write)
2529 : {
2530 : /* Subclass of annotating_context that
2531 : adds a note about the attr access to any saved diagnostics. */
2532 40 : class annotating_ctxt : public annotating_context
2533 : {
2534 : public:
2535 40 : annotating_ctxt (tree callee_fndecl,
2536 : const attr_access &access,
2537 : region_model_context *ctxt)
2538 : : annotating_context (ctxt),
2539 40 : m_callee_fndecl (callee_fndecl),
2540 40 : m_access (access)
2541 : {
2542 : }
2543 22 : void add_annotations () final override
2544 : {
2545 22 : add_note (std::make_unique<reason_attr_access>
2546 22 : (m_callee_fndecl, m_access));
2547 22 : }
2548 : private:
2549 : tree m_callee_fndecl;
2550 : const attr_access &m_access;
2551 : };
2552 :
2553 : /* Use this ctxt below so that any diagnostics get the
2554 : note added to them. */
2555 40 : annotating_ctxt my_ctxt (callee_fndecl, *access, ctxt);
2556 :
2557 40 : tree ptr_tree = gimple_call_arg (&call, access->ptrarg);
2558 40 : const svalue *ptr_sval = get_rvalue (ptr_tree, &my_ctxt);
2559 40 : const region *reg = deref_rvalue (ptr_sval, ptr_tree, &my_ctxt);
2560 40 : check_region_for_write (reg, nullptr, &my_ctxt);
2561 : /* We don't use the size arg for now. */
2562 : }
2563 : }
2564 1257 : }
2565 :
2566 : /* Subroutine of region_model::check_function_attr_null_terminated_string_arg,
2567 : checking one instance of __attribute__((null_terminated_string_arg)). */
2568 :
2569 : void
2570 200 : region_model::
2571 : check_one_function_attr_null_terminated_string_arg (const gcall &call,
2572 : tree callee_fndecl,
2573 : region_model_context *ctxt,
2574 : rdwr_map &rdwr_idx,
2575 : tree attr)
2576 : {
2577 200 : gcc_assert (callee_fndecl);
2578 200 : gcc_assert (ctxt);
2579 200 : gcc_assert (attr);
2580 :
2581 200 : tree arg = TREE_VALUE (attr);
2582 200 : if (!arg)
2583 76 : return;
2584 :
2585 : /* Convert from 1-based to 0-based index. */
2586 200 : unsigned int arg_idx = TREE_INT_CST_LOW (TREE_VALUE (arg)) - 1;
2587 :
2588 : /* If there's also an "access" attribute on the ptr param
2589 : for reading with a size param specified, then that size
2590 : limits the size of the possible read from the pointer. */
2591 200 : if (const attr_access* access = rdwr_idx.get (arg_idx))
2592 104 : if ((access->mode == access_read_only
2593 104 : || access->mode == access_read_write)
2594 104 : && access->sizarg != UINT_MAX)
2595 : {
2596 76 : call_details cd_checked (call, this, ctxt);
2597 76 : const svalue *limit_sval
2598 76 : = cd_checked.get_arg_svalue (access->sizarg);
2599 76 : const svalue *ptr_sval
2600 76 : = cd_checked.get_arg_svalue (arg_idx);
2601 : /* Try reading all of the bytes expressed by the size param,
2602 : but without emitting warnings (via a null context). */
2603 76 : const svalue *limited_sval
2604 76 : = read_bytes (deref_rvalue (ptr_sval, NULL_TREE, nullptr),
2605 : NULL_TREE,
2606 : limit_sval,
2607 : nullptr);
2608 76 : if (limited_sval->get_kind () == SK_POISONED)
2609 : {
2610 : /* Reading up to the truncation limit caused issues.
2611 : Assume that the string is meant to be terminated
2612 : before then, so perform a *checked* check for the
2613 : terminator. */
2614 24 : check_for_null_terminated_string_arg (cd_checked,
2615 : arg_idx);
2616 : }
2617 : else
2618 : {
2619 : /* Reading up to the truncation limit seems OK; repeat
2620 : the read, but with checking enabled. */
2621 52 : read_bytes (deref_rvalue (ptr_sval, NULL_TREE, ctxt),
2622 : NULL_TREE,
2623 : limit_sval,
2624 : ctxt);
2625 : }
2626 76 : return;
2627 : }
2628 :
2629 : /* Otherwise, we don't have an access-attribute limiting the read.
2630 : Simulate a read up to the null terminator (if any). */
2631 :
2632 124 : call_details cd (call, this, ctxt);
2633 124 : check_for_null_terminated_string_arg (cd, arg_idx);
2634 : }
2635 :
2636 : /* Check CALL a call to external function CALLEE_FNDECL for any uses
2637 : of __attribute__ ((null_terminated_string_arg)), complaining
2638 : to CTXT about any issues.
2639 :
2640 : Use RDWR_IDX for tracking uses of __attribute__ ((access, ....). */
2641 :
2642 : void
2643 1257 : region_model::
2644 : check_function_attr_null_terminated_string_arg (const gcall &call,
2645 : tree callee_fndecl,
2646 : region_model_context *ctxt,
2647 : rdwr_map &rdwr_idx)
2648 : {
2649 1257 : gcc_assert (callee_fndecl);
2650 1257 : gcc_assert (ctxt);
2651 :
2652 1257 : tree fntype = TREE_TYPE (callee_fndecl);
2653 1257 : gcc_assert (fntype);
2654 :
2655 : /* A function declaration can specify multiple attribute
2656 : null_terminated_string_arg, each with one argument. */
2657 1457 : for (tree attr = TYPE_ATTRIBUTES (fntype); attr; attr = TREE_CHAIN (attr))
2658 : {
2659 1281 : attr = lookup_attribute ("null_terminated_string_arg", attr);
2660 1281 : if (!attr)
2661 : return;
2662 :
2663 200 : check_one_function_attr_null_terminated_string_arg (call, callee_fndecl,
2664 : ctxt, rdwr_idx,
2665 : attr);
2666 : }
2667 : }
2668 :
2669 : /* Check CALL a call to external function CALLEE_FNDECL for any
2670 : function attributes, complaining to CTXT about any issues. */
2671 :
2672 : void
2673 11970 : region_model::check_function_attrs (const gcall &call,
2674 : tree callee_fndecl,
2675 : region_model_context *ctxt)
2676 : {
2677 11970 : gcc_assert (callee_fndecl);
2678 11970 : gcc_assert (ctxt);
2679 :
2680 11970 : tree fntype = TREE_TYPE (callee_fndecl);
2681 11970 : if (!fntype)
2682 10713 : return;
2683 :
2684 11970 : if (!TYPE_ATTRIBUTES (fntype))
2685 : return;
2686 :
2687 : /* Initialize a map of attribute access specifications for arguments
2688 : to the function call. */
2689 1257 : rdwr_map rdwr_idx;
2690 1257 : init_attr_rdwr_indices (&rdwr_idx, TYPE_ATTRIBUTES (fntype));
2691 :
2692 1257 : check_function_attr_access (call, callee_fndecl, ctxt, rdwr_idx);
2693 1257 : check_function_attr_null_terminated_string_arg (call, callee_fndecl,
2694 : ctxt, rdwr_idx);
2695 1257 : }
2696 :
2697 : /* Handle a call CALL to a function with unknown behavior.
2698 :
2699 : Traverse the regions in this model, determining what regions are
2700 : reachable from pointer arguments to CALL and from global variables,
2701 : recursively.
2702 :
2703 : Set all reachable regions to new unknown values and purge sm-state
2704 : from their values, and from values that point to them. */
2705 :
2706 : void
2707 18123 : region_model::handle_unrecognized_call (const gcall &call,
2708 : region_model_context *ctxt)
2709 : {
2710 18123 : tree fndecl = get_fndecl_for_call (call, ctxt);
2711 :
2712 18123 : if (fndecl && ctxt)
2713 11970 : check_function_attrs (call, fndecl, ctxt);
2714 :
2715 18123 : reachable_regions reachable_regs (this);
2716 :
2717 : /* Determine the reachable regions and their mutability. */
2718 18123 : {
2719 : /* Add globals and regions that already escaped in previous
2720 : unknown calls. */
2721 18123 : m_store.for_each_cluster (reachable_regions::init_cluster_cb,
2722 : &reachable_regs);
2723 :
2724 : /* Params that are pointers. */
2725 18123 : tree iter_param_types = NULL_TREE;
2726 18123 : if (fndecl)
2727 17621 : iter_param_types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
2728 37883 : for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (&call);
2729 : arg_idx++)
2730 : {
2731 : /* Track expected param type, where available. */
2732 19760 : tree param_type = NULL_TREE;
2733 19760 : if (iter_param_types)
2734 : {
2735 18221 : param_type = TREE_VALUE (iter_param_types);
2736 18221 : gcc_assert (param_type);
2737 18221 : iter_param_types = TREE_CHAIN (iter_param_types);
2738 : }
2739 :
2740 19760 : tree parm = gimple_call_arg (&call, arg_idx);
2741 19760 : const svalue *parm_sval = get_rvalue (parm, ctxt);
2742 19760 : reachable_regs.handle_parm (parm_sval, param_type);
2743 : }
2744 : }
2745 :
2746 18123 : uncertainty_t *uncertainty = ctxt ? ctxt->get_uncertainty () : nullptr;
2747 :
2748 : /* Purge sm-state for the svalues that were reachable,
2749 : both in non-mutable and mutable form. */
2750 46697 : for (svalue_set::iterator iter
2751 18123 : = reachable_regs.begin_reachable_svals ();
2752 46697 : iter != reachable_regs.end_reachable_svals (); ++iter)
2753 : {
2754 28574 : const svalue *sval = (*iter);
2755 28574 : if (ctxt)
2756 22225 : ctxt->on_unknown_change (sval, false);
2757 : }
2758 59628 : for (svalue_set::iterator iter
2759 18123 : = reachable_regs.begin_mutable_svals ();
2760 59628 : iter != reachable_regs.end_mutable_svals (); ++iter)
2761 : {
2762 41505 : const svalue *sval = (*iter);
2763 41505 : if (ctxt)
2764 32493 : ctxt->on_unknown_change (sval, true);
2765 41505 : if (uncertainty)
2766 31282 : uncertainty->on_mutable_sval_at_unknown_call (sval);
2767 : }
2768 :
2769 : /* Mark any clusters that have escaped. */
2770 18123 : reachable_regs.mark_escaped_clusters (ctxt);
2771 :
2772 : /* Update bindings for all clusters that have escaped, whether above,
2773 : or previously. */
2774 18123 : m_store.on_unknown_fncall (call, m_mgr->get_store_manager (),
2775 18123 : conjured_purge (this, ctxt));
2776 :
2777 : /* Purge dynamic extents from any regions that have escaped mutably:
2778 : realloc could have been called on them. */
2779 26225 : for (hash_set<const region *>::iterator
2780 18123 : iter = reachable_regs.begin_mutable_base_regs ();
2781 44348 : iter != reachable_regs.end_mutable_base_regs ();
2782 26225 : ++iter)
2783 : {
2784 26225 : const region *base_reg = (*iter);
2785 26225 : unset_dynamic_extents (base_reg);
2786 : }
2787 18123 : }
2788 :
2789 : /* Traverse the regions in this model, determining what regions are
2790 : reachable from the store and populating *OUT.
2791 :
2792 : If EXTRA_SVAL is non-NULL, treat it as an additional "root"
2793 : for reachability (for handling return values from functions when
2794 : analyzing return of the only function on the stack).
2795 :
2796 : If UNCERTAINTY is non-NULL, treat any svalues that were recorded
2797 : within it as being maybe-bound as additional "roots" for reachability.
2798 :
2799 : Find svalues that haven't leaked. */
2800 :
2801 : void
2802 1048792 : region_model::get_reachable_svalues (svalue_set *out,
2803 : const svalue *extra_sval,
2804 : const uncertainty_t *uncertainty)
2805 : {
2806 1048792 : reachable_regions reachable_regs (this);
2807 :
2808 : /* Add globals and regions that already escaped in previous
2809 : unknown calls. */
2810 1048792 : m_store.for_each_cluster (reachable_regions::init_cluster_cb,
2811 : &reachable_regs);
2812 :
2813 1048792 : if (extra_sval)
2814 5425 : reachable_regs.handle_sval (extra_sval);
2815 :
2816 1048792 : if (uncertainty)
2817 482018 : for (uncertainty_t::iterator iter
2818 466813 : = uncertainty->begin_maybe_bound_svals ();
2819 948831 : iter != uncertainty->end_maybe_bound_svals (); ++iter)
2820 15205 : reachable_regs.handle_sval (*iter);
2821 :
2822 : /* Get regions for locals that have explicitly bound values. */
2823 9913423 : for (store::cluster_map_t::iterator iter = m_store.begin ();
2824 9913423 : iter != m_store.end (); ++iter)
2825 : {
2826 8864631 : const region *base_reg = (*iter).first;
2827 8864631 : if (const region *parent = base_reg->get_parent_region ())
2828 8864631 : if (parent->get_kind () == RK_FRAME)
2829 5863285 : reachable_regs.add (base_reg, false);
2830 : }
2831 :
2832 : /* Populate *OUT based on the values that were reachable. */
2833 1048792 : for (svalue_set::iterator iter
2834 1048792 : = reachable_regs.begin_reachable_svals ();
2835 10572528 : iter != reachable_regs.end_reachable_svals (); ++iter)
2836 9523736 : out->add (*iter);
2837 1048792 : }
2838 :
2839 : /* Update this model for the RETURN_STMT, using CTXT to report any
2840 : diagnostics. */
2841 :
2842 : void
2843 0 : region_model::on_return (const greturn *return_stmt, region_model_context *ctxt)
2844 : {
2845 0 : tree callee = get_current_function ()->decl;
2846 0 : tree lhs = DECL_RESULT (callee);
2847 0 : tree rhs = gimple_return_retval (return_stmt);
2848 :
2849 0 : if (lhs && rhs)
2850 : {
2851 0 : const svalue *sval = get_rvalue (rhs, ctxt);
2852 0 : const region *ret_reg = get_lvalue (lhs, ctxt);
2853 0 : set_value (ret_reg, sval, ctxt);
2854 : }
2855 0 : }
2856 :
2857 : /* Implementation of region_model::get_lvalue; the latter adds type-checking.
2858 :
2859 : Get the id of the region for PV within this region_model,
2860 : emitting any diagnostics to CTXT. */
2861 :
2862 : const region *
2863 2708761 : region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt) const
2864 : {
2865 2708761 : tree expr = pv.m_tree;
2866 :
2867 2708761 : gcc_assert (expr);
2868 :
2869 2708761 : switch (TREE_CODE (expr))
2870 : {
2871 84 : default:
2872 84 : return m_mgr->get_region_for_unexpected_tree_code (ctxt, expr,
2873 84 : dump_location_t ());
2874 :
2875 28310 : case ARRAY_REF:
2876 28310 : {
2877 28310 : tree array = TREE_OPERAND (expr, 0);
2878 28310 : tree index = TREE_OPERAND (expr, 1);
2879 :
2880 28310 : const region *array_reg = get_lvalue (array, ctxt);
2881 28310 : const svalue *index_sval = get_rvalue (index, ctxt);
2882 28310 : return m_mgr->get_element_region (array_reg,
2883 28310 : TREE_TYPE (TREE_TYPE (array)),
2884 28310 : index_sval);
2885 : }
2886 189 : break;
2887 :
2888 189 : case BIT_FIELD_REF:
2889 189 : {
2890 189 : tree inner_expr = TREE_OPERAND (expr, 0);
2891 189 : const region *inner_reg = get_lvalue (inner_expr, ctxt);
2892 189 : tree num_bits = TREE_OPERAND (expr, 1);
2893 189 : tree first_bit_offset = TREE_OPERAND (expr, 2);
2894 189 : gcc_assert (TREE_CODE (num_bits) == INTEGER_CST);
2895 189 : gcc_assert (TREE_CODE (first_bit_offset) == INTEGER_CST);
2896 189 : bit_range bits (TREE_INT_CST_LOW (first_bit_offset),
2897 189 : TREE_INT_CST_LOW (num_bits));
2898 189 : return m_mgr->get_bit_range (inner_reg, TREE_TYPE (expr), bits);
2899 : }
2900 82398 : break;
2901 :
2902 82398 : case MEM_REF:
2903 82398 : {
2904 82398 : tree ptr = TREE_OPERAND (expr, 0);
2905 82398 : tree offset = TREE_OPERAND (expr, 1);
2906 82398 : const svalue *ptr_sval = get_rvalue (ptr, ctxt);
2907 82398 : const svalue *offset_sval = get_rvalue (offset, ctxt);
2908 82398 : const region *star_ptr = deref_rvalue (ptr_sval, ptr, ctxt);
2909 82398 : return m_mgr->get_offset_region (star_ptr,
2910 82398 : TREE_TYPE (expr),
2911 82398 : offset_sval);
2912 : }
2913 930912 : break;
2914 :
2915 930912 : case FUNCTION_DECL:
2916 930912 : return m_mgr->get_region_for_fndecl (expr);
2917 :
2918 343 : case LABEL_DECL:
2919 343 : return m_mgr->get_region_for_label (expr);
2920 :
2921 169030 : case VAR_DECL:
2922 : /* Handle globals. */
2923 169030 : if (is_global_var (expr))
2924 55834 : return m_mgr->get_region_for_global (expr);
2925 :
2926 : /* Fall through. */
2927 :
2928 1536443 : case SSA_NAME:
2929 1536443 : case PARM_DECL:
2930 1536443 : case RESULT_DECL:
2931 1536443 : {
2932 1536443 : gcc_assert (TREE_CODE (expr) == SSA_NAME
2933 : || TREE_CODE (expr) == PARM_DECL
2934 : || VAR_P (expr)
2935 : || TREE_CODE (expr) == RESULT_DECL);
2936 :
2937 1536443 : int stack_index = pv.m_stack_depth;
2938 1536443 : const frame_region *frame = get_frame_at_index (stack_index);
2939 1536443 : gcc_assert (frame);
2940 1536443 : return frame->get_region_for_local (m_mgr, expr, ctxt);
2941 : }
2942 :
2943 58493 : case COMPONENT_REF:
2944 58493 : {
2945 : /* obj.field */
2946 58493 : tree obj = TREE_OPERAND (expr, 0);
2947 58493 : tree field = TREE_OPERAND (expr, 1);
2948 58493 : const region *obj_reg = get_lvalue (obj, ctxt);
2949 58493 : return m_mgr->get_field_region (obj_reg, field);
2950 : }
2951 15755 : break;
2952 :
2953 15755 : case STRING_CST:
2954 15755 : return m_mgr->get_region_for_string (expr);
2955 : }
2956 : }
2957 :
2958 : /* Assert that SRC_TYPE can be converted to DST_TYPE as a no-op. */
2959 :
2960 : static void
2961 6015193 : assert_compat_types (tree src_type, tree dst_type)
2962 : {
2963 6015193 : if (src_type && dst_type && !VOID_TYPE_P (dst_type))
2964 : {
2965 : #if CHECKING_P
2966 6014808 : if (!(useless_type_conversion_p (src_type, dst_type)))
2967 0 : internal_error ("incompatible types: %qT and %qT", src_type, dst_type);
2968 : #endif
2969 : }
2970 6015193 : }
2971 :
2972 : /* Return true if SRC_TYPE can be converted to DST_TYPE as a no-op. */
2973 :
2974 : bool
2975 14943 : compat_types_p (tree src_type, tree dst_type)
2976 : {
2977 14943 : if (src_type && dst_type && !VOID_TYPE_P (dst_type))
2978 14943 : if (!(useless_type_conversion_p (src_type, dst_type)))
2979 : return false;
2980 : return true;
2981 : }
2982 :
2983 : /* Get the region for PV within this region_model,
2984 : emitting any diagnostics to CTXT. */
2985 :
2986 : const region *
2987 2708761 : region_model::get_lvalue (path_var pv, region_model_context *ctxt) const
2988 : {
2989 2708761 : if (pv.m_tree == NULL_TREE)
2990 : return nullptr;
2991 :
2992 2708761 : const region *result_reg = get_lvalue_1 (pv, ctxt);
2993 2708761 : assert_compat_types (result_reg->get_type (), TREE_TYPE (pv.m_tree));
2994 2708761 : return result_reg;
2995 : }
2996 :
2997 : /* Get the region for EXPR within this region_model (assuming the most
2998 : recent stack frame if it's a local). */
2999 :
3000 : const region *
3001 1678925 : region_model::get_lvalue (tree expr, region_model_context *ctxt) const
3002 : {
3003 1678925 : return get_lvalue (path_var (expr, get_stack_depth () - 1), ctxt);
3004 : }
3005 :
3006 : /* Implementation of region_model::get_rvalue; the latter adds type-checking.
3007 :
3008 : Get the value of PV within this region_model,
3009 : emitting any diagnostics to CTXT. */
3010 :
3011 : const svalue *
3012 3291878 : region_model::get_rvalue_1 (path_var pv, region_model_context *ctxt) const
3013 : {
3014 3291878 : gcc_assert (pv.m_tree);
3015 :
3016 3291878 : switch (TREE_CODE (pv.m_tree))
3017 : {
3018 281 : default:
3019 281 : return m_mgr->get_or_create_unknown_svalue (TREE_TYPE (pv.m_tree));
3020 :
3021 1005758 : case ADDR_EXPR:
3022 1005758 : {
3023 : /* "&EXPR". */
3024 1005758 : tree expr = pv.m_tree;
3025 1005758 : tree op0 = TREE_OPERAND (expr, 0);
3026 1005758 : const region *expr_reg = get_lvalue (op0, ctxt);
3027 1005758 : return m_mgr->get_ptr_svalue (TREE_TYPE (expr), expr_reg);
3028 : }
3029 130 : break;
3030 :
3031 130 : case BIT_FIELD_REF:
3032 130 : {
3033 130 : tree expr = pv.m_tree;
3034 130 : tree op0 = TREE_OPERAND (expr, 0);
3035 130 : const region *reg = get_lvalue (op0, ctxt);
3036 130 : tree num_bits = TREE_OPERAND (expr, 1);
3037 130 : tree first_bit_offset = TREE_OPERAND (expr, 2);
3038 130 : gcc_assert (TREE_CODE (num_bits) == INTEGER_CST);
3039 130 : gcc_assert (TREE_CODE (first_bit_offset) == INTEGER_CST);
3040 130 : bit_range bits (TREE_INT_CST_LOW (first_bit_offset),
3041 130 : TREE_INT_CST_LOW (num_bits));
3042 130 : return get_rvalue_for_bits (TREE_TYPE (expr), reg, bits, ctxt);
3043 : }
3044 :
3045 36433 : case VAR_DECL:
3046 36433 : if (DECL_HARD_REGISTER (pv.m_tree))
3047 : {
3048 : /* If it has a hard register, it doesn't have a memory region
3049 : and can't be referred to as an lvalue. */
3050 43 : return m_mgr->get_or_create_unknown_svalue (TREE_TYPE (pv.m_tree));
3051 : }
3052 : /* Fall through. */
3053 975769 : case PARM_DECL:
3054 975769 : case SSA_NAME:
3055 975769 : case RESULT_DECL:
3056 975769 : case ARRAY_REF:
3057 975769 : {
3058 975769 : const region *reg = get_lvalue (pv, ctxt);
3059 975769 : return get_store_value (reg, ctxt);
3060 : }
3061 :
3062 174 : case REALPART_EXPR:
3063 174 : case IMAGPART_EXPR:
3064 174 : case VIEW_CONVERT_EXPR:
3065 174 : {
3066 174 : tree expr = pv.m_tree;
3067 174 : tree arg = TREE_OPERAND (expr, 0);
3068 174 : const svalue *arg_sval = get_rvalue (arg, ctxt);
3069 174 : const svalue *sval_unaryop
3070 174 : = m_mgr->get_or_create_unaryop (TREE_TYPE (expr), TREE_CODE (expr),
3071 : arg_sval);
3072 174 : return sval_unaryop;
3073 1255441 : };
3074 :
3075 1255441 : case INTEGER_CST:
3076 1255441 : case REAL_CST:
3077 1255441 : case COMPLEX_CST:
3078 1255441 : case VECTOR_CST:
3079 1255441 : case STRING_CST:
3080 1255441 : case RAW_DATA_CST:
3081 1255441 : return m_mgr->get_or_create_constant_svalue (pv.m_tree);
3082 :
3083 41 : case POINTER_PLUS_EXPR:
3084 41 : {
3085 41 : tree expr = pv.m_tree;
3086 41 : tree ptr = TREE_OPERAND (expr, 0);
3087 41 : tree offset = TREE_OPERAND (expr, 1);
3088 41 : const svalue *ptr_sval = get_rvalue (ptr, ctxt);
3089 41 : const svalue *offset_sval = get_rvalue (offset, ctxt);
3090 41 : const svalue *sval_binop
3091 41 : = m_mgr->get_or_create_binop (TREE_TYPE (expr), POINTER_PLUS_EXPR,
3092 : ptr_sval, offset_sval);
3093 41 : return sval_binop;
3094 : }
3095 :
3096 : /* Binary ops. */
3097 94 : case PLUS_EXPR:
3098 94 : case MULT_EXPR:
3099 94 : case BIT_AND_EXPR:
3100 94 : case BIT_IOR_EXPR:
3101 94 : case BIT_XOR_EXPR:
3102 94 : {
3103 94 : tree expr = pv.m_tree;
3104 94 : tree arg0 = TREE_OPERAND (expr, 0);
3105 94 : tree arg1 = TREE_OPERAND (expr, 1);
3106 94 : const svalue *arg0_sval = get_rvalue (arg0, ctxt);
3107 94 : const svalue *arg1_sval = get_rvalue (arg1, ctxt);
3108 94 : const svalue *sval_binop
3109 94 : = m_mgr->get_or_create_binop (TREE_TYPE (expr), TREE_CODE (expr),
3110 : arg0_sval, arg1_sval);
3111 94 : return sval_binop;
3112 : }
3113 :
3114 54027 : case COMPONENT_REF:
3115 54027 : case MEM_REF:
3116 54027 : {
3117 54027 : const region *ref_reg = get_lvalue (pv, ctxt);
3118 54027 : return get_store_value (ref_reg, ctxt);
3119 : }
3120 120 : case OBJ_TYPE_REF:
3121 120 : {
3122 120 : tree expr = OBJ_TYPE_REF_EXPR (pv.m_tree);
3123 120 : return get_rvalue (expr, ctxt);
3124 : }
3125 : }
3126 : }
3127 :
3128 : /* Get the value of PV within this region_model,
3129 : emitting any diagnostics to CTXT. */
3130 :
3131 : const svalue *
3132 3329053 : region_model::get_rvalue (path_var pv, region_model_context *ctxt) const
3133 : {
3134 3329053 : if (pv.m_tree == NULL_TREE)
3135 : return nullptr;
3136 :
3137 3291878 : const svalue *result_sval = get_rvalue_1 (pv, ctxt);
3138 :
3139 3291878 : assert_compat_types (result_sval->get_type (), TREE_TYPE (pv.m_tree));
3140 :
3141 3291878 : result_sval = check_for_poison (result_sval, pv.m_tree, nullptr, ctxt);
3142 :
3143 3291878 : return result_sval;
3144 : }
3145 :
3146 : /* Get the value of EXPR within this region_model (assuming the most
3147 : recent stack frame if it's a local). */
3148 :
3149 : const svalue *
3150 3327326 : region_model::get_rvalue (tree expr, region_model_context *ctxt) const
3151 : {
3152 3327326 : return get_rvalue (path_var (expr, get_stack_depth () - 1), ctxt);
3153 : }
3154 :
3155 : /* Return true if this model is on a path with "main" as the entrypoint
3156 : (as opposed to one in which we're merely analyzing a subset of the
3157 : path through the code). */
3158 :
3159 : bool
3160 281552 : region_model::called_from_main_p () const
3161 : {
3162 281552 : if (!m_current_frame)
3163 : return false;
3164 : /* Determine if the oldest stack frame in this model is for "main". */
3165 275100 : const frame_region *frame0 = get_frame_at_index (0);
3166 275100 : gcc_assert (frame0);
3167 275100 : return id_equal (DECL_NAME (frame0->get_function ().decl), "main");
3168 : }
3169 :
3170 : /* Subroutine of region_model::get_store_value for when REG is (or is within)
3171 : a global variable that hasn't been touched since the start of this path
3172 : (or was implicitly touched due to a call to an unknown function). */
3173 :
3174 : const svalue *
3175 290821 : region_model::get_initial_value_for_global (const region *reg) const
3176 : {
3177 : /* Get the decl that REG is for (or is within). */
3178 290821 : const decl_region *base_reg
3179 290821 : = reg->get_base_region ()->dyn_cast_decl_region ();
3180 290821 : gcc_assert (base_reg);
3181 290821 : tree decl = base_reg->get_decl ();
3182 :
3183 : /* Special-case: to avoid having to explicitly update all previously
3184 : untracked globals when calling an unknown fn, they implicitly have
3185 : an unknown value if an unknown call has occurred, unless this is
3186 : static to-this-TU and hasn't escaped. Globals that have escaped
3187 : are explicitly tracked, so we shouldn't hit this case for them. */
3188 290821 : if (m_store.called_unknown_fn_p ()
3189 71041 : && TREE_PUBLIC (decl)
3190 308461 : && !TREE_READONLY (decl))
3191 9325 : return m_mgr->get_or_create_unknown_svalue (reg->get_type ());
3192 :
3193 : /* If we are on a path from the entrypoint from "main" and we have a
3194 : global decl defined in this TU that hasn't been touched yet, then
3195 : the initial value of REG can be taken from the initialization value
3196 : of the decl. */
3197 281496 : if (called_from_main_p () || TREE_READONLY (decl))
3198 72017 : return reg->get_initial_value_at_main (m_mgr);
3199 :
3200 : /* Otherwise, return INIT_VAL(REG). */
3201 209479 : return m_mgr->get_or_create_initial_value (reg);
3202 : }
3203 :
3204 : /* Get a value for REG, looking it up in the store, or otherwise falling
3205 : back to "initial" or "unknown" values.
3206 : Use CTXT to report any warnings associated with reading from REG. */
3207 :
3208 : const svalue *
3209 4467198 : region_model::get_store_value (const region *reg,
3210 : region_model_context *ctxt) const
3211 : {
3212 : /* Getting the value of an empty region gives an unknown_svalue. */
3213 4467198 : if (reg->empty_p ())
3214 52 : return m_mgr->get_or_create_unknown_svalue (reg->get_type ());
3215 :
3216 4467146 : bool check_poisoned = true;
3217 4467146 : if (check_region_for_read (reg, ctxt))
3218 436 : check_poisoned = false;
3219 :
3220 : /* Special-case: handle var_decls in the constant pool. */
3221 4467146 : if (const decl_region *decl_reg = reg->dyn_cast_decl_region ())
3222 3663968 : if (const svalue *sval = decl_reg->maybe_get_constant_value (m_mgr))
3223 : return sval;
3224 :
3225 4467130 : const svalue *sval
3226 4467130 : = m_store.get_any_binding (m_mgr->get_store_manager (), reg);
3227 4467130 : if (sval)
3228 : {
3229 1232630 : if (reg->get_type ())
3230 1230358 : sval = m_mgr->get_or_create_cast (reg->get_type (), sval);
3231 : return sval;
3232 : }
3233 :
3234 : /* Special-case: read at a constant index within a STRING_CST. */
3235 3234500 : if (const offset_region *offset_reg = reg->dyn_cast_offset_region ())
3236 157647 : if (tree byte_offset_cst
3237 157647 : = offset_reg->get_byte_offset ()->maybe_get_constant ())
3238 32663 : if (const string_region *str_reg
3239 32663 : = reg->get_parent_region ()->dyn_cast_string_region ())
3240 : {
3241 205 : tree string_cst = str_reg->get_string_cst ();
3242 410 : if (const svalue *char_sval
3243 205 : = m_mgr->maybe_get_char_from_string_cst (string_cst,
3244 : byte_offset_cst))
3245 201 : return m_mgr->get_or_create_cast (reg->get_type (), char_sval);
3246 : }
3247 :
3248 : /* Special-case: read the initial char of a STRING_CST. */
3249 3234299 : if (const cast_region *cast_reg = reg->dyn_cast_cast_region ())
3250 6180 : if (const string_region *str_reg
3251 3090 : = cast_reg->get_parent_region ()->dyn_cast_string_region ())
3252 : {
3253 197 : tree string_cst = str_reg->get_string_cst ();
3254 197 : tree byte_offset_cst = integer_zero_node;
3255 394 : if (const svalue *char_sval
3256 197 : = m_mgr->maybe_get_char_from_string_cst (string_cst,
3257 : byte_offset_cst))
3258 197 : return m_mgr->get_or_create_cast (reg->get_type (), char_sval);
3259 : }
3260 :
3261 : /* Otherwise we implicitly have the initial value of the region
3262 : (if the cluster had been touched, binding_cluster::get_any_binding,
3263 : would have returned UNKNOWN, and we would already have returned
3264 : that above). */
3265 :
3266 : /* Handle globals. */
3267 3234102 : if (reg->get_base_region ()->get_parent_region ()->get_kind ()
3268 : == RK_GLOBALS)
3269 290821 : return get_initial_value_for_global (reg);
3270 :
3271 2943281 : return m_mgr->get_or_create_initial_value (reg, check_poisoned);
3272 : }
3273 :
3274 : /* Return false if REG does not exist, true if it may do.
3275 : This is for detecting regions within the stack that don't exist anymore
3276 : after frames are popped. */
3277 :
3278 : bool
3279 2754289 : region_model::region_exists_p (const region *reg) const
3280 : {
3281 : /* If within a stack frame, check that the stack frame is live. */
3282 2754289 : if (const frame_region *enclosing_frame = reg->maybe_get_frame_region ())
3283 : {
3284 : /* Check that the current frame is the enclosing frame, or is called
3285 : by it. */
3286 2827709 : for (const frame_region *iter_frame = get_current_frame (); iter_frame;
3287 672805 : iter_frame = iter_frame->get_calling_frame ())
3288 2808802 : if (iter_frame == enclosing_frame)
3289 : return true;
3290 : return false;
3291 : }
3292 :
3293 : return true;
3294 : }
3295 :
3296 : /* Get a region for referencing PTR_SVAL, creating a region if need be, and
3297 : potentially generating warnings via CTXT.
3298 : PTR_SVAL must be of pointer type.
3299 : PTR_TREE if non-NULL can be used when emitting diagnostics. */
3300 :
3301 : const region *
3302 144812 : region_model::deref_rvalue (const svalue *ptr_sval, tree ptr_tree,
3303 : region_model_context *ctxt,
3304 : bool add_nonnull_constraint) const
3305 : {
3306 144812 : gcc_assert (ptr_sval);
3307 144812 : gcc_assert (POINTER_TYPE_P (ptr_sval->get_type ()));
3308 :
3309 : /* If we're dereferencing PTR_SVAL, assume that it is non-NULL; add this
3310 : as a constraint. This suppresses false positives from
3311 : -Wanalyzer-null-dereference for the case where we later have an
3312 : if (PTR_SVAL) that would occur if we considered the false branch
3313 : and transitioned the malloc state machine from start->null. */
3314 144812 : if (add_nonnull_constraint)
3315 : {
3316 136599 : tree null_ptr_cst = build_int_cst (ptr_sval->get_type (), 0);
3317 136599 : const svalue *null_ptr
3318 136599 : = m_mgr->get_or_create_constant_svalue (null_ptr_cst);
3319 136599 : m_constraints->add_constraint (ptr_sval, NE_EXPR, null_ptr);
3320 : }
3321 :
3322 144812 : switch (ptr_sval->get_kind ())
3323 : {
3324 : default:
3325 : break;
3326 :
3327 59715 : case SK_REGION:
3328 59715 : {
3329 59715 : const region_svalue *region_sval
3330 59715 : = as_a <const region_svalue *> (ptr_sval);
3331 59715 : return region_sval->get_pointee ();
3332 : }
3333 :
3334 25286 : case SK_BINOP:
3335 25286 : {
3336 25286 : const binop_svalue *binop_sval
3337 25286 : = as_a <const binop_svalue *> (ptr_sval);
3338 25286 : switch (binop_sval->get_op ())
3339 : {
3340 25286 : case POINTER_PLUS_EXPR:
3341 25286 : {
3342 : /* If we have a symbolic value expressing pointer arithmetic,
3343 : try to convert it to a suitable region. */
3344 25286 : const region *parent_region
3345 25286 : = deref_rvalue (binop_sval->get_arg0 (), NULL_TREE, ctxt);
3346 25286 : const svalue *offset = binop_sval->get_arg1 ();
3347 25286 : tree type= TREE_TYPE (ptr_sval->get_type ());
3348 25286 : return m_mgr->get_offset_region (parent_region, type, offset);
3349 : }
3350 : default:
3351 : break;
3352 : }
3353 : }
3354 : break;
3355 :
3356 2678 : case SK_POISONED:
3357 2678 : {
3358 2678 : if (ctxt)
3359 : {
3360 624 : tree ptr = get_representative_tree (ptr_sval);
3361 : /* If we can't get a representative tree for PTR_SVAL
3362 : (e.g. if it hasn't been bound into the store), then
3363 : fall back on PTR_TREE, if non-NULL. */
3364 624 : if (!ptr)
3365 624 : ptr = ptr_tree;
3366 624 : if (ptr)
3367 : {
3368 0 : const poisoned_svalue *poisoned_sval
3369 0 : = as_a <const poisoned_svalue *> (ptr_sval);
3370 0 : enum poison_kind pkind = poisoned_sval->get_poison_kind ();
3371 0 : ctxt->warn (make_poisoned_value_diagnostic
3372 0 : (ptr, pkind, nullptr, nullptr));
3373 : }
3374 : }
3375 : }
3376 : break;
3377 : }
3378 :
3379 59811 : return m_mgr->get_symbolic_region (ptr_sval);
3380 : }
3381 :
3382 : /* Attempt to get BITS within any value of REG, as TYPE.
3383 : In particular, extract values from compound_svalues for the case
3384 : where there's a concrete binding at BITS.
3385 : Return an unknown svalue if we can't handle the given case.
3386 : Use CTXT to report any warnings associated with reading from REG. */
3387 :
3388 : const svalue *
3389 130 : region_model::get_rvalue_for_bits (tree type,
3390 : const region *reg,
3391 : const bit_range &bits,
3392 : region_model_context *ctxt) const
3393 : {
3394 130 : const svalue *sval = get_store_value (reg, ctxt);
3395 130 : return m_mgr->get_or_create_bits_within (type, bits, sval);
3396 : }
3397 :
3398 : /* Use CTXT to warn If DEST_REG is a region that shouldn't be written to. */
3399 :
3400 : void
3401 290868 : region_model::check_for_writable_region (const region* dest_reg,
3402 : region_model_context *ctxt) const
3403 : {
3404 : /* Fail gracefully if CTXT is nullptr. */
3405 290868 : if (!ctxt)
3406 : return;
3407 :
3408 290868 : const region *base_reg = dest_reg->get_base_region ();
3409 290868 : switch (base_reg->get_kind ())
3410 : {
3411 : default:
3412 : break;
3413 9 : case RK_FUNCTION:
3414 9 : {
3415 9 : const function_region *func_reg = as_a <const function_region *> (base_reg);
3416 9 : tree fndecl = func_reg->get_fndecl ();
3417 9 : ctxt->warn (make_write_to_const_diagnostic (func_reg, fndecl));
3418 : }
3419 9 : break;
3420 4 : case RK_LABEL:
3421 4 : {
3422 4 : const label_region *label_reg = as_a <const label_region *> (base_reg);
3423 4 : tree label = label_reg->get_label ();
3424 4 : ctxt->warn (make_write_to_const_diagnostic (label_reg, label));
3425 : }
3426 4 : break;
3427 272093 : case RK_DECL:
3428 272093 : {
3429 272093 : const decl_region *decl_reg = as_a <const decl_region *> (base_reg);
3430 272093 : tree decl = decl_reg->get_decl ();
3431 : /* Warn about writes to const globals.
3432 : Don't warn for writes to const locals, and params in particular,
3433 : since we would warn in push_frame when setting them up (e.g the
3434 : "this" param is "T* const"). */
3435 272093 : if (TREE_READONLY (decl)
3436 272093 : && is_global_var (decl))
3437 20 : ctxt->warn (make_write_to_const_diagnostic (dest_reg, decl));
3438 : }
3439 : break;
3440 51 : case RK_STRING:
3441 51 : ctxt->warn (make_write_to_string_literal_diagnostic (dest_reg));
3442 51 : break;
3443 : }
3444 : }
3445 :
3446 : /* Get the capacity of REG in bytes. */
3447 :
3448 : const svalue *
3449 909678 : region_model::get_capacity (const region *reg) const
3450 : {
3451 909693 : switch (reg->get_kind ())
3452 : {
3453 : default:
3454 : break;
3455 840048 : case RK_DECL:
3456 840048 : {
3457 840048 : const decl_region *decl_reg = as_a <const decl_region *> (reg);
3458 840048 : tree decl = decl_reg->get_decl ();
3459 840048 : if (TREE_CODE (decl) == SSA_NAME)
3460 : {
3461 740742 : tree type = TREE_TYPE (decl);
3462 740742 : tree size = TYPE_SIZE (type);
3463 740742 : return get_rvalue (size, nullptr);
3464 : }
3465 : else
3466 : {
3467 99306 : tree size = decl_init_size (decl, false);
3468 99306 : if (size)
3469 99139 : return get_rvalue (size, nullptr);
3470 : }
3471 : }
3472 : break;
3473 15 : case RK_SIZED:
3474 : /* Look through sized regions to get at the capacity
3475 : of the underlying regions. */
3476 15 : return get_capacity (reg->get_parent_region ());
3477 535 : case RK_STRING:
3478 535 : {
3479 : /* "Capacity" here means "size". */
3480 535 : const string_region *string_reg = as_a <const string_region *> (reg);
3481 535 : tree string_cst = string_reg->get_string_cst ();
3482 535 : return m_mgr->get_or_create_int_cst (size_type_node,
3483 535 : TREE_STRING_LENGTH (string_cst));
3484 : }
3485 69262 : break;
3486 : }
3487 :
3488 69262 : if (const svalue *recorded = get_dynamic_extents (reg))
3489 : return recorded;
3490 :
3491 56644 : return m_mgr->get_or_create_unknown_svalue (sizetype);
3492 : }
3493 :
3494 : /* If CTXT is non-NULL, use it to warn about any problems accessing REG,
3495 : using DIR to determine if this access is a read or write.
3496 : Return TRUE if an OOB access was detected.
3497 : If SVAL_HINT is non-NULL, use it as a hint in diagnostics
3498 : about the value that would be written to REG. */
3499 :
3500 : bool
3501 4858364 : region_model::check_region_access (const region *reg,
3502 : enum access_direction dir,
3503 : const svalue *sval_hint,
3504 : region_model_context *ctxt) const
3505 : {
3506 : /* Fail gracefully if CTXT is NULL. */
3507 4858364 : if (!ctxt)
3508 : return false;
3509 :
3510 897624 : bool oob_access_detected = false;
3511 897624 : check_region_for_taint (reg, dir, ctxt);
3512 897624 : if (!check_region_bounds (reg, dir, sval_hint, ctxt))
3513 779 : oob_access_detected = true;
3514 :
3515 897624 : switch (dir)
3516 : {
3517 0 : default:
3518 0 : gcc_unreachable ();
3519 : case access_direction::read:
3520 : /* Currently a no-op. */
3521 : break;
3522 290868 : case access_direction::write:
3523 290868 : check_for_writable_region (reg, ctxt);
3524 290868 : break;
3525 : }
3526 : return oob_access_detected;
3527 : }
3528 :
3529 : /* If CTXT is non-NULL, use it to warn about any problems writing to REG. */
3530 :
3531 : void
3532 391218 : region_model::check_region_for_write (const region *dest_reg,
3533 : const svalue *sval_hint,
3534 : region_model_context *ctxt) const
3535 : {
3536 391218 : check_region_access (dest_reg, access_direction::write, sval_hint, ctxt);
3537 391218 : }
3538 :
3539 : /* If CTXT is non-NULL, use it to warn about any problems reading from REG.
3540 : Returns TRUE if an OOB read was detected. */
3541 :
3542 : bool
3543 4467146 : region_model::check_region_for_read (const region *src_reg,
3544 : region_model_context *ctxt) const
3545 : {
3546 4467146 : return check_region_access (src_reg, access_direction::read, nullptr, ctxt);
3547 : }
3548 :
3549 : /* Concrete subclass for casts of pointers that lead to trailing bytes. */
3550 :
3551 : class dubious_allocation_size
3552 : : public pending_diagnostic_subclass<dubious_allocation_size>
3553 : {
3554 : public:
3555 111 : dubious_allocation_size (const region *lhs, const region *rhs,
3556 : const svalue *capacity_sval, tree expr,
3557 : const gimple *stmt)
3558 111 : : m_lhs (lhs), m_rhs (rhs),
3559 111 : m_capacity_sval (capacity_sval), m_expr (expr),
3560 111 : m_stmt (stmt),
3561 111 : m_has_allocation_event (false)
3562 : {
3563 111 : gcc_assert (m_capacity_sval);
3564 : }
3565 :
3566 1186 : const char *get_kind () const final override
3567 : {
3568 1186 : return "dubious_allocation_size";
3569 : }
3570 :
3571 111 : bool operator== (const dubious_allocation_size &other) const
3572 : {
3573 111 : return (m_stmt == other.m_stmt
3574 111 : && pending_diagnostic::same_tree_p (m_expr, other.m_expr));
3575 : }
3576 :
3577 222 : int get_controlling_option () const final override
3578 : {
3579 222 : return OPT_Wanalyzer_allocation_size;
3580 : }
3581 :
3582 111 : bool emit (diagnostic_emission_context &ctxt) final override
3583 : {
3584 111 : ctxt.add_cwe (131);
3585 :
3586 111 : return ctxt.warn ("allocated buffer size is not a multiple"
3587 111 : " of the pointee's size");
3588 : }
3589 :
3590 : bool
3591 222 : describe_final_event (pretty_printer &pp,
3592 : const evdesc::final_event &) final override
3593 : {
3594 222 : tree pointee_type = TREE_TYPE (m_lhs->get_type ());
3595 222 : if (m_has_allocation_event)
3596 : {
3597 214 : pp_printf (&pp,
3598 : "assigned to %qT here;"
3599 : " %<sizeof (%T)%> is %qE",
3600 214 : m_lhs->get_type (), pointee_type,
3601 : size_in_bytes (pointee_type));
3602 214 : return true;
3603 : }
3604 : /* Fallback: Typically, we should always see an allocation_event
3605 : before. */
3606 8 : if (m_expr)
3607 : {
3608 8 : if (TREE_CODE (m_expr) == INTEGER_CST)
3609 : {
3610 8 : pp_printf (&pp,
3611 : "allocated %E bytes and assigned to"
3612 : " %qT here; %<sizeof (%T)%> is %qE",
3613 8 : m_expr, m_lhs->get_type (), pointee_type,
3614 : size_in_bytes (pointee_type));
3615 8 : return true;
3616 : }
3617 : else
3618 : {
3619 0 : pp_printf (&pp,
3620 : "allocated %qE bytes and assigned to"
3621 : " %qT here; %<sizeof (%T)%> is %qE",
3622 0 : m_expr, m_lhs->get_type (), pointee_type,
3623 : size_in_bytes (pointee_type));
3624 0 : return true;
3625 : }
3626 : }
3627 :
3628 0 : pp_printf (&pp,
3629 : "allocated and assigned to %qT here;"
3630 : " %<sizeof (%T)%> is %qE",
3631 0 : m_lhs->get_type (), pointee_type,
3632 : size_in_bytes (pointee_type));
3633 0 : return true;
3634 : }
3635 :
3636 : void
3637 107 : add_region_creation_events (const region *,
3638 : tree capacity,
3639 : const event_loc_info &loc_info,
3640 : checker_path &emission_path) final override
3641 : {
3642 107 : emission_path.add_event
3643 107 : (std::make_unique<region_creation_event_allocation_size>
3644 107 : (capacity, loc_info));
3645 :
3646 107 : m_has_allocation_event = true;
3647 107 : }
3648 :
3649 222 : void mark_interesting_stuff (interesting_t *interest) final override
3650 : {
3651 222 : interest->add_region_creation (m_rhs);
3652 222 : }
3653 :
3654 : void
3655 0 : maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
3656 : const final override
3657 : {
3658 0 : auto &props = result_obj.get_or_create_properties ();
3659 : #define PROPERTY_PREFIX "gcc/analyzer/dubious_allocation_size/"
3660 0 : props.set (PROPERTY_PREFIX "lhs", m_lhs->to_json ());
3661 0 : props.set (PROPERTY_PREFIX "rhs", m_rhs->to_json ());
3662 0 : props.set (PROPERTY_PREFIX "capacity_sval", m_capacity_sval->to_json ());
3663 : #undef PROPERTY_PREFIX
3664 0 : }
3665 :
3666 : private:
3667 : const region *m_lhs;
3668 : const region *m_rhs;
3669 : const svalue *m_capacity_sval;
3670 : const tree m_expr;
3671 : const gimple *m_stmt;
3672 : bool m_has_allocation_event;
3673 : };
3674 :
3675 : /* Return true on dubious allocation sizes for constant sizes. */
3676 :
3677 : static bool
3678 2037 : capacity_compatible_with_type (tree cst, tree pointee_size_tree,
3679 : bool is_struct)
3680 : {
3681 2037 : gcc_assert (TREE_CODE (cst) == INTEGER_CST);
3682 2037 : gcc_assert (TREE_CODE (pointee_size_tree) == INTEGER_CST);
3683 :
3684 2037 : unsigned HOST_WIDE_INT pointee_size = TREE_INT_CST_LOW (pointee_size_tree);
3685 2037 : unsigned HOST_WIDE_INT alloc_size = TREE_INT_CST_LOW (cst);
3686 :
3687 2037 : if (is_struct)
3688 722 : return alloc_size == 0 || alloc_size >= pointee_size;
3689 1315 : return alloc_size % pointee_size == 0;
3690 : }
3691 :
3692 : static bool
3693 394 : capacity_compatible_with_type (tree cst, tree pointee_size_tree)
3694 : {
3695 0 : return capacity_compatible_with_type (cst, pointee_size_tree, false);
3696 : }
3697 :
3698 : /* Checks whether SVAL could be a multiple of SIZE_CST.
3699 :
3700 : It works by visiting all svalues inside SVAL until it reaches
3701 : atomic nodes. From those, it goes back up again and adds each
3702 : node that is not a multiple of SIZE_CST to the RESULT_SET. */
3703 :
3704 6780 : class size_visitor : public visitor
3705 : {
3706 : public:
3707 3390 : size_visitor (tree size_cst, const svalue *root_sval, constraint_manager *cm)
3708 3390 : : m_size_cst (size_cst), m_root_sval (root_sval), m_cm (cm)
3709 : {
3710 3390 : m_root_sval->accept (this);
3711 3390 : }
3712 :
3713 3390 : bool is_dubious_capacity ()
3714 : {
3715 3390 : return result_set.contains (m_root_sval);
3716 : }
3717 :
3718 410 : void visit_constant_svalue (const constant_svalue *sval) final override
3719 : {
3720 410 : check_constant (sval->get_constant (), sval);
3721 410 : }
3722 :
3723 250 : void visit_unaryop_svalue (const unaryop_svalue *sval) final override
3724 : {
3725 250 : if (CONVERT_EXPR_CODE_P (sval->get_op ())
3726 291 : && result_set.contains (sval->get_arg ()))
3727 105 : result_set.add (sval);
3728 250 : }
3729 :
3730 406 : void visit_binop_svalue (const binop_svalue *sval) final override
3731 : {
3732 406 : const svalue *arg0 = sval->get_arg0 ();
3733 406 : const svalue *arg1 = sval->get_arg1 ();
3734 :
3735 406 : switch (sval->get_op ())
3736 : {
3737 288 : case MULT_EXPR:
3738 288 : if (result_set.contains (arg0) && result_set.contains (arg1))
3739 24 : result_set.add (sval);
3740 : break;
3741 90 : case PLUS_EXPR:
3742 90 : case MINUS_EXPR:
3743 90 : if (result_set.contains (arg0) || result_set.contains (arg1))
3744 28 : result_set.add (sval);
3745 : break;
3746 : default:
3747 : break;
3748 : }
3749 406 : }
3750 :
3751 0 : void visit_unmergeable_svalue (const unmergeable_svalue *sval) final override
3752 : {
3753 0 : if (result_set.contains (sval->get_arg ()))
3754 0 : result_set.add (sval);
3755 0 : }
3756 :
3757 12 : void visit_widening_svalue (const widening_svalue *sval) final override
3758 : {
3759 12 : const svalue *base = sval->get_base_svalue ();
3760 12 : const svalue *iter = sval->get_iter_svalue ();
3761 :
3762 12 : if (result_set.contains (base) || result_set.contains (iter))
3763 8 : result_set.add (sval);
3764 12 : }
3765 :
3766 303 : void visit_initial_svalue (const initial_svalue *sval) final override
3767 : {
3768 303 : equiv_class_id id = equiv_class_id::null ();
3769 303 : if (m_cm->get_equiv_class_by_svalue (sval, &id))
3770 : {
3771 75 : if (tree cst = id.get_obj (*m_cm).get_any_constant ())
3772 0 : check_constant (cst, sval);
3773 : }
3774 228 : else if (!m_cm->sval_constrained_p (sval))
3775 : {
3776 174 : result_set.add (sval);
3777 : }
3778 303 : }
3779 :
3780 30 : void visit_conjured_svalue (const conjured_svalue *sval) final override
3781 : {
3782 30 : equiv_class_id id = equiv_class_id::null ();
3783 30 : if (m_cm->get_equiv_class_by_svalue (sval, &id))
3784 13 : if (tree cst = id.get_obj (*m_cm).get_any_constant ())
3785 8 : check_constant (cst, sval);
3786 30 : }
3787 :
3788 : private:
3789 418 : void check_constant (tree cst, const svalue *sval)
3790 : {
3791 418 : switch (TREE_CODE (cst))
3792 : {
3793 : default:
3794 : /* Assume all unhandled operands are compatible. */
3795 : break;
3796 394 : case INTEGER_CST:
3797 394 : if (!capacity_compatible_with_type (cst, m_size_cst))
3798 68 : result_set.add (sval);
3799 : break;
3800 : }
3801 418 : }
3802 :
3803 : tree m_size_cst;
3804 : const svalue *m_root_sval;
3805 : constraint_manager *m_cm;
3806 : svalue_set result_set; /* Used as a mapping of svalue*->bool. */
3807 : };
3808 :
3809 : /* Return true if SIZE_CST is a power of 2, and we have
3810 : CAPACITY_SVAL == ((X | (Y - 1) ) + 1), since it is then a multiple
3811 : of SIZE_CST, as used by Linux kernel's round_up macro. */
3812 :
3813 : static bool
3814 3394 : is_round_up (tree size_cst,
3815 : const svalue *capacity_sval)
3816 : {
3817 3394 : if (!integer_pow2p (size_cst))
3818 : return false;
3819 3394 : const binop_svalue *binop_sval = capacity_sval->dyn_cast_binop_svalue ();
3820 3394 : if (!binop_sval)
3821 : return false;
3822 272 : if (binop_sval->get_op () != PLUS_EXPR)
3823 : return false;
3824 70 : tree rhs_cst = binop_sval->get_arg1 ()->maybe_get_constant ();
3825 70 : if (!rhs_cst)
3826 : return false;
3827 70 : if (!integer_onep (rhs_cst))
3828 : return false;
3829 :
3830 : /* We have CAPACITY_SVAL == (LHS + 1) for some LHS expression. */
3831 :
3832 4 : const binop_svalue *lhs_binop_sval
3833 4 : = binop_sval->get_arg0 ()->dyn_cast_binop_svalue ();
3834 4 : if (!lhs_binop_sval)
3835 : return false;
3836 4 : if (lhs_binop_sval->get_op () != BIT_IOR_EXPR)
3837 : return false;
3838 :
3839 4 : tree inner_rhs_cst = lhs_binop_sval->get_arg1 ()->maybe_get_constant ();
3840 4 : if (!inner_rhs_cst)
3841 : return false;
3842 :
3843 4 : if (wi::to_widest (inner_rhs_cst) + 1 != wi::to_widest (size_cst))
3844 : return false;
3845 : return true;
3846 : }
3847 :
3848 : /* Return true if CAPACITY_SVAL is known to be a multiple of SIZE_CST. */
3849 :
3850 : static bool
3851 3394 : is_multiple_p (tree size_cst,
3852 : const svalue *capacity_sval)
3853 : {
3854 3450 : if (const svalue *sval = capacity_sval->maybe_undo_cast ())
3855 : return is_multiple_p (size_cst, sval);
3856 :
3857 3394 : if (is_round_up (size_cst, capacity_sval))
3858 : return true;
3859 :
3860 : return false;
3861 : }
3862 :
3863 : /* Return true if we should emit a dubious_allocation_size warning
3864 : on assigning a region of capacity CAPACITY_SVAL bytes to a pointer
3865 : of type with size SIZE_CST, where CM expresses known constraints. */
3866 :
3867 : static bool
3868 3394 : is_dubious_capacity (tree size_cst,
3869 : const svalue *capacity_sval,
3870 : constraint_manager *cm)
3871 : {
3872 3394 : if (is_multiple_p (size_cst, capacity_sval))
3873 : return false;
3874 3390 : size_visitor v (size_cst, capacity_sval, cm);
3875 3390 : return v.is_dubious_capacity ();
3876 3390 : }
3877 :
3878 :
3879 : /* Return true if a struct or union either uses the inheritance pattern,
3880 : where the first field is a base struct, or the flexible array member
3881 : pattern, where the last field is an array without a specified size. */
3882 :
3883 : static bool
3884 4581 : struct_or_union_with_inheritance_p (tree struc)
3885 : {
3886 4581 : tree iter = TYPE_FIELDS (struc);
3887 4581 : if (iter == NULL_TREE)
3888 : return false;
3889 4573 : if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (iter)))
3890 : return true;
3891 :
3892 : tree last_field;
3893 101564 : while (iter != NULL_TREE)
3894 : {
3895 97395 : last_field = iter;
3896 97395 : iter = DECL_CHAIN (iter);
3897 : }
3898 :
3899 4169 : if (last_field != NULL_TREE
3900 4169 : && TREE_CODE (TREE_TYPE (last_field)) == ARRAY_TYPE)
3901 35 : return true;
3902 :
3903 : return false;
3904 : }
3905 :
3906 : /* Return true if the lhs and rhs of an assignment have different types. */
3907 :
3908 : static bool
3909 205598 : is_any_cast_p (const gimple *stmt)
3910 : {
3911 205598 : if (const gassign *assign = dyn_cast <const gassign *> (stmt))
3912 159910 : return gimple_assign_cast_p (assign)
3913 293803 : || !pending_diagnostic::same_tree_p (
3914 133893 : TREE_TYPE (gimple_assign_lhs (assign)),
3915 133893 : TREE_TYPE (gimple_assign_rhs1 (assign)));
3916 45688 : else if (const gcall *call = dyn_cast <const gcall *> (stmt))
3917 : {
3918 45280 : tree lhs = gimple_call_lhs (call);
3919 78281 : return lhs != NULL_TREE && !pending_diagnostic::same_tree_p (
3920 33001 : TREE_TYPE (gimple_call_lhs (call)),
3921 : gimple_call_return_type (call));
3922 : }
3923 :
3924 : return false;
3925 : }
3926 :
3927 : /* On pointer assignments, check whether the buffer size of
3928 : RHS_SVAL is compatible with the type of the LHS_REG.
3929 : Use a non-null CTXT to report allocation size warnings. */
3930 :
3931 : void
3932 389514 : region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval,
3933 : region_model_context *ctxt) const
3934 : {
3935 389514 : if (!ctxt || ctxt->get_stmt () == nullptr)
3936 381470 : return;
3937 : /* Only report warnings on assignments that actually change the type. */
3938 205598 : if (!is_any_cast_p (ctxt->get_stmt ()))
3939 : return;
3940 :
3941 66564 : tree pointer_type = lhs_reg->get_type ();
3942 66564 : if (pointer_type == NULL_TREE || !POINTER_TYPE_P (pointer_type))
3943 : return;
3944 :
3945 20372 : tree pointee_type = TREE_TYPE (pointer_type);
3946 : /* Make sure that the type on the left-hand size actually has a size. */
3947 20372 : if (pointee_type == NULL_TREE || VOID_TYPE_P (pointee_type)
3948 39943 : || TYPE_SIZE_UNIT (pointee_type) == NULL_TREE)
3949 : return;
3950 :
3951 : /* Bail out early on function pointers. */
3952 19471 : if (TREE_CODE (pointee_type) == FUNCTION_TYPE)
3953 : return;
3954 :
3955 : /* Bail out early on pointers to structs where we can
3956 : not deduce whether the buffer size is compatible. */
3957 19183 : bool is_struct = RECORD_OR_UNION_TYPE_P (pointee_type);
3958 19183 : if (is_struct && struct_or_union_with_inheritance_p (pointee_type))
3959 : return;
3960 :
3961 18744 : tree pointee_size_tree = size_in_bytes (pointee_type);
3962 : /* We give up if the type size is not known at compile-time or the
3963 : type size is always compatible regardless of the buffer size. */
3964 18744 : if (TREE_CODE (pointee_size_tree) != INTEGER_CST
3965 18657 : || integer_zerop (pointee_size_tree)
3966 37388 : || integer_onep (pointee_size_tree))
3967 : return;
3968 :
3969 8044 : const region *rhs_reg = deref_rvalue (rhs_sval, NULL_TREE, ctxt, false);
3970 8044 : const svalue *capacity = get_capacity (rhs_reg);
3971 8044 : switch (capacity->get_kind ())
3972 : {
3973 1643 : case svalue_kind::SK_CONSTANT:
3974 1643 : {
3975 1643 : const constant_svalue *cst_cap_sval
3976 1643 : = as_a <const constant_svalue *> (capacity);
3977 1643 : tree cst_cap = cst_cap_sval->get_constant ();
3978 1643 : if (TREE_CODE (cst_cap) == INTEGER_CST
3979 1643 : && !capacity_compatible_with_type (cst_cap, pointee_size_tree,
3980 : is_struct))
3981 63 : ctxt->warn
3982 126 : (std::make_unique <dubious_allocation_size> (lhs_reg, rhs_reg,
3983 : capacity, cst_cap,
3984 126 : ctxt->get_stmt ()));
3985 : }
3986 1643 : break;
3987 6401 : default:
3988 6401 : {
3989 6401 : if (!is_struct)
3990 : {
3991 3394 : if (is_dubious_capacity (pointee_size_tree,
3992 : capacity,
3993 3394 : m_constraints))
3994 : {
3995 48 : tree expr = get_representative_tree (capacity);
3996 48 : ctxt->warn
3997 96 : (std::make_unique <dubious_allocation_size> (lhs_reg,
3998 : rhs_reg,
3999 : capacity, expr,
4000 96 : ctxt->get_stmt ()));
4001 : }
4002 : }
4003 : break;
4004 : }
4005 : }
4006 : }
4007 :
4008 : /* Set the value of the region given by LHS_REG to the value given
4009 : by RHS_SVAL.
4010 : Use CTXT to report any warnings associated with writing to LHS_REG. */
4011 :
4012 : void
4013 389534 : region_model::set_value (const region *lhs_reg, const svalue *rhs_sval,
4014 : region_model_context *ctxt)
4015 : {
4016 389534 : gcc_assert (lhs_reg);
4017 389534 : gcc_assert (rhs_sval);
4018 :
4019 : /* Setting the value of an empty region is a no-op. */
4020 389534 : if (lhs_reg->empty_p ())
4021 : return;
4022 :
4023 389514 : check_region_size (lhs_reg, rhs_sval, ctxt);
4024 :
4025 389514 : check_region_for_write (lhs_reg, rhs_sval, ctxt);
4026 :
4027 679420 : m_store.set_value (m_mgr->get_store_manager(), lhs_reg, rhs_sval,
4028 289906 : ctxt ? ctxt->get_uncertainty () : nullptr,
4029 : *this);
4030 : }
4031 :
4032 : /* Set the value of the region given by LHS to the value given by RHS. */
4033 :
4034 : void
4035 84 : region_model::set_value (tree lhs, tree rhs, region_model_context *ctxt)
4036 : {
4037 84 : const region *lhs_reg = get_lvalue (lhs, ctxt);
4038 84 : const svalue *rhs_sval = get_rvalue (rhs, ctxt);
4039 84 : gcc_assert (lhs_reg);
4040 84 : gcc_assert (rhs_sval);
4041 84 : set_value (lhs_reg, rhs_sval, ctxt);
4042 84 : }
4043 :
4044 : /* Issue a note specifying that a particular function parameter is expected
4045 : to be a valid null-terminated string. */
4046 :
4047 : static void
4048 152 : inform_about_expected_null_terminated_string_arg (const call_arg_details &ad)
4049 : {
4050 : // TODO: ideally we'd underline the param here
4051 152 : inform (DECL_SOURCE_LOCATION (ad.m_called_fndecl),
4052 : "argument %d of %qD must be a pointer to a null-terminated string",
4053 152 : ad.m_arg_idx + 1, ad.m_called_fndecl);
4054 152 : }
4055 :
4056 : /* A binding of a specific svalue at a concrete byte range. */
4057 :
4058 : struct fragment
4059 : {
4060 3851 : fragment ()
4061 3851 : : m_byte_range (0, 0), m_sval (nullptr)
4062 : {
4063 3851 : }
4064 :
4065 1033 : fragment (const byte_range &bytes, const svalue *sval)
4066 1033 : : m_byte_range (bytes), m_sval (sval)
4067 : {
4068 : }
4069 :
4070 1977 : static int cmp_ptrs (const void *p1, const void *p2)
4071 : {
4072 1977 : const fragment *f1 = (const fragment *)p1;
4073 1977 : const fragment *f2 = (const fragment *)p2;
4074 1977 : return byte_range::cmp (f1->m_byte_range, f2->m_byte_range);
4075 : }
4076 :
4077 : void
4078 2 : dump_to_pp (pretty_printer *pp) const
4079 : {
4080 2 : pp_string (pp, "fragment(");
4081 2 : m_byte_range.dump_to_pp (pp);
4082 2 : pp_string (pp, ", sval: ");
4083 2 : if (m_sval)
4084 2 : m_sval->dump_to_pp (pp, true);
4085 : else
4086 0 : pp_string (pp, "nullptr");
4087 2 : pp_string (pp, ")");
4088 2 : }
4089 :
4090 : byte_range m_byte_range;
4091 : const svalue *m_sval;
4092 : };
4093 :
4094 : /* Determine if there is a zero terminator somewhere in the
4095 : part of STRING_CST covered by BYTES (where BYTES is relative to the
4096 : start of the constant).
4097 :
4098 : Return a tristate:
4099 : - true if there definitely is a zero byte, writing to *OUT_BYTES_READ
4100 : the number of bytes from that would be read, including the zero byte.
4101 : - false if there definitely isn't a zero byte
4102 : - unknown if we don't know. */
4103 :
4104 : static tristate
4105 463 : string_cst_has_null_terminator (tree string_cst,
4106 : const byte_range &bytes,
4107 : byte_offset_t *out_bytes_read)
4108 : {
4109 463 : gcc_assert (bytes.m_start_byte_offset >= 0);
4110 :
4111 : /* If we're beyond the string_cst, reads are unsuccessful. */
4112 463 : if (tree cst_size = get_string_cst_size (string_cst))
4113 463 : if (TREE_CODE (cst_size) == INTEGER_CST)
4114 463 : if (bytes.m_start_byte_offset >= TREE_INT_CST_LOW (cst_size))
4115 0 : return tristate::unknown ();
4116 :
4117 : /* Assume all bytes after TREE_STRING_LENGTH are zero. This handles
4118 : the case where an array is initialized with a string_cst that isn't
4119 : as long as the array, where the remaining elements are
4120 : empty-initialized and thus zeroed. */
4121 463 : if (bytes.m_start_byte_offset >= TREE_STRING_LENGTH (string_cst))
4122 : {
4123 2 : *out_bytes_read = 1;
4124 2 : return tristate (true);
4125 : }
4126 :
4127 : /* Look for the first 0 byte within STRING_CST
4128 : from START_READ_OFFSET onwards. */
4129 461 : const byte_offset_t num_bytes_to_search
4130 922 : = std::min<byte_offset_t> ((TREE_STRING_LENGTH (string_cst)
4131 461 : - bytes.m_start_byte_offset),
4132 461 : bytes.m_size_in_bytes);
4133 461 : const char *start = (TREE_STRING_POINTER (string_cst)
4134 461 : + bytes.m_start_byte_offset.slow ());
4135 461 : if (num_bytes_to_search >= 0)
4136 461 : if (const void *p = memchr (start, 0, bytes.m_size_in_bytes.slow ()))
4137 : {
4138 332 : *out_bytes_read = (const char *)p - start + 1;
4139 332 : return tristate (true);
4140 : }
4141 :
4142 129 : *out_bytes_read = bytes.m_size_in_bytes;
4143 129 : return tristate (false);
4144 : }
4145 :
4146 : static tristate
4147 : svalue_byte_range_has_null_terminator (const svalue *sval,
4148 : const byte_range &bytes,
4149 : byte_offset_t *out_bytes_read,
4150 : logger *logger);
4151 :
4152 : /* Determine if there is a zero terminator somewhere in the
4153 : part of SVAL covered by BYTES (where BYTES is relative to the svalue).
4154 :
4155 : Return a tristate:
4156 : - true if there definitely is a zero byte, writing to *OUT_BYTES_READ
4157 : the number of bytes from that would be read, including the zero byte.
4158 : - false if there definitely isn't a zero byte
4159 : - unknown if we don't know.
4160 :
4161 : Use LOGGER (if non-null) for any logging. */
4162 :
4163 : static tristate
4164 849 : svalue_byte_range_has_null_terminator_1 (const svalue *sval,
4165 : const byte_range &bytes,
4166 : byte_offset_t *out_bytes_read,
4167 : logger *logger)
4168 : {
4169 849 : if (bytes.m_start_byte_offset == 0
4170 849 : && sval->all_zeroes_p ())
4171 : {
4172 : /* The initial byte of an all-zeroes SVAL is a zero byte. */
4173 21 : *out_bytes_read = 1;
4174 21 : return tristate (true);
4175 : }
4176 :
4177 828 : switch (sval->get_kind ())
4178 : {
4179 341 : case SK_CONSTANT:
4180 341 : {
4181 341 : tree cst
4182 341 : = as_a <const constant_svalue *> (sval)->get_constant ();
4183 341 : switch (TREE_CODE (cst))
4184 : {
4185 326 : case STRING_CST:
4186 326 : return string_cst_has_null_terminator (cst, bytes, out_bytes_read);
4187 15 : case INTEGER_CST:
4188 15 : if (bytes.m_start_byte_offset == 0
4189 15 : && integer_onep (TYPE_SIZE_UNIT (TREE_TYPE (cst))))
4190 : {
4191 : /* Model accesses to the initial byte of a 1-byte
4192 : INTEGER_CST. */
4193 13 : *out_bytes_read = 1;
4194 13 : if (zerop (cst))
4195 0 : return tristate (true);
4196 : else
4197 13 : return tristate (false);
4198 : }
4199 : /* Treat any other access to an INTEGER_CST as unknown. */
4200 2 : return tristate::TS_UNKNOWN;
4201 :
4202 : default:
4203 : break;
4204 : }
4205 : }
4206 : break;
4207 :
4208 158 : case SK_INITIAL:
4209 158 : {
4210 158 : const initial_svalue *initial_sval = (const initial_svalue *)sval;
4211 158 : const region *reg = initial_sval->get_region ();
4212 158 : if (const string_region *string_reg = reg->dyn_cast_string_region ())
4213 : {
4214 137 : tree string_cst = string_reg->get_string_cst ();
4215 137 : return string_cst_has_null_terminator (string_cst,
4216 : bytes,
4217 137 : out_bytes_read);
4218 : }
4219 21 : return tristate::TS_UNKNOWN;
4220 : }
4221 74 : break;
4222 :
4223 74 : case SK_BITS_WITHIN:
4224 74 : {
4225 74 : const bits_within_svalue *bits_within_sval
4226 : = (const bits_within_svalue *)sval;
4227 74 : byte_range bytes_within_inner (0, 0);
4228 74 : if (bits_within_sval->get_bits ().as_byte_range (&bytes_within_inner))
4229 : {
4230 : /* Consider e.g. looking for null terminator of
4231 : bytes 2-4 of BITS_WITHIN(bytes 10-15 of inner_sval)
4232 :
4233 : This is equivalent to looking within bytes 12-14 of
4234 : inner_sval. */
4235 74 : const byte_offset_t start_byte_relative_to_inner
4236 74 : = (bytes.m_start_byte_offset
4237 74 : + bytes_within_inner.m_start_byte_offset);
4238 74 : const byte_offset_t next_byte_relative_to_inner
4239 74 : = (bytes.get_next_byte_offset ()
4240 74 : + bytes_within_inner.m_start_byte_offset);
4241 74 : if (next_byte_relative_to_inner > start_byte_relative_to_inner)
4242 : {
4243 74 : const byte_range relative_to_inner
4244 : (start_byte_relative_to_inner,
4245 74 : next_byte_relative_to_inner - start_byte_relative_to_inner);
4246 74 : const svalue *inner_sval
4247 74 : = bits_within_sval->get_inner_svalue ();
4248 74 : return svalue_byte_range_has_null_terminator (inner_sval,
4249 : relative_to_inner,
4250 : out_bytes_read,
4251 : logger);
4252 : }
4253 : }
4254 : }
4255 0 : break;
4256 :
4257 : default:
4258 : // TODO: it may be possible to handle other cases here.
4259 : break;
4260 : }
4261 255 : return tristate::TS_UNKNOWN;
4262 : }
4263 :
4264 : /* Like svalue_byte_range_has_null_terminator_1, but add logging. */
4265 :
4266 : static tristate
4267 849 : svalue_byte_range_has_null_terminator (const svalue *sval,
4268 : const byte_range &bytes,
4269 : byte_offset_t *out_bytes_read,
4270 : logger *logger)
4271 : {
4272 849 : LOG_SCOPE (logger);
4273 849 : if (logger)
4274 : {
4275 1 : pretty_printer *pp = logger->get_printer ();
4276 1 : logger->start_log_line ();
4277 1 : bytes.dump_to_pp (pp);
4278 1 : logger->log_partial (" of sval: ");
4279 1 : sval->dump_to_pp (pp, true);
4280 1 : logger->end_log_line ();
4281 : }
4282 849 : tristate ts
4283 849 : = svalue_byte_range_has_null_terminator_1 (sval, bytes,
4284 : out_bytes_read, logger);
4285 849 : if (logger)
4286 : {
4287 1 : pretty_printer *pp = logger->get_printer ();
4288 1 : logger->start_log_line ();
4289 1 : pp_printf (pp, "has null terminator: %s", ts.as_string ());
4290 1 : if (ts.is_true ())
4291 : {
4292 1 : pp_string (pp, "; bytes read: ");
4293 1 : pp_wide_int (pp, *out_bytes_read, SIGNED);
4294 : }
4295 1 : logger->end_log_line ();
4296 : }
4297 1698 : return ts;
4298 849 : }
4299 :
4300 : /* A frozen copy of a single base region's binding_cluster within a store,
4301 : optimized for traversal of the concrete parts in byte order.
4302 : This only captures concrete bindings, and is an implementation detail
4303 : of region_model::scan_for_null_terminator. */
4304 :
4305 3709 : class iterable_cluster
4306 : {
4307 : public:
4308 3709 : iterable_cluster (const binding_cluster *cluster)
4309 3709 : {
4310 3709 : if (!cluster)
4311 : return;
4312 3217 : for (auto iter : cluster->get_map ().get_concrete_bindings ())
4313 : {
4314 1033 : const bit_range &bits = iter.first;
4315 1033 : const svalue *sval = iter.second;
4316 :
4317 1033 : byte_range fragment_bytes (0, 0);
4318 1033 : if (bits.as_byte_range (&fragment_bytes))
4319 1033 : m_fragments.safe_push (fragment (fragment_bytes, sval));
4320 : }
4321 2308 : for (auto iter : cluster->get_map ().get_symbolic_bindings ())
4322 124 : m_symbolic_bindings.safe_push (iter);
4323 2184 : m_fragments.qsort (fragment::cmp_ptrs);
4324 : }
4325 :
4326 : bool
4327 3851 : get_fragment_for_byte (byte_offset_t byte, fragment *out_frag) const
4328 : {
4329 : /* TODO: binary search rather than linear. */
4330 3851 : unsigned iter_idx;
4331 4085 : for (iter_idx = 0; iter_idx < m_fragments.length (); iter_idx++)
4332 : {
4333 1009 : if (m_fragments[iter_idx].m_byte_range.contains_p (byte))
4334 : {
4335 775 : *out_frag = m_fragments[iter_idx];
4336 775 : return true;
4337 : }
4338 : }
4339 : return false;
4340 : }
4341 :
4342 3076 : bool has_symbolic_bindings_p () const
4343 : {
4344 6152 : return !m_symbolic_bindings.is_empty ();
4345 : }
4346 :
4347 2 : void dump_to_pp (pretty_printer *pp) const
4348 : {
4349 2 : pp_string (pp, "iterable_cluster (fragments: [");
4350 5 : for (auto const &iter : &m_fragments)
4351 : {
4352 2 : if (&iter != m_fragments.begin ())
4353 0 : pp_string (pp, ", ");
4354 1 : iter.dump_to_pp (pp);
4355 : }
4356 2 : pp_printf (pp, "], symbolic bindings: [");
4357 2 : for (auto const &iter : m_symbolic_bindings)
4358 : {
4359 0 : if (&iter != m_symbolic_bindings.begin ())
4360 0 : pp_string (pp, ", ");
4361 0 : iter.m_region->dump_to_pp (pp, true);
4362 : }
4363 2 : pp_string (pp, "])");
4364 2 : }
4365 :
4366 : private:
4367 : auto_vec<fragment> m_fragments;
4368 : auto_vec<binding_map::symbolic_binding> m_symbolic_bindings;
4369 : };
4370 :
4371 : /* Simulate reading the bytes at BYTES from BASE_REG.
4372 : Complain to CTXT about any issues with the read e.g. out-of-bounds. */
4373 :
4374 : const svalue *
4375 8165 : region_model::get_store_bytes (const region *base_reg,
4376 : const byte_range &bytes,
4377 : region_model_context *ctxt) const
4378 : {
4379 : /* Shortcut reading all of a string_region. */
4380 8165 : if (bytes.get_start_byte_offset () == 0)
4381 7938 : if (const string_region *string_reg = base_reg->dyn_cast_string_region ())
4382 4712 : if (bytes.m_size_in_bytes
4383 4712 : == TREE_STRING_LENGTH (string_reg->get_string_cst ()))
4384 4712 : return m_mgr->get_or_create_initial_value (base_reg);
4385 :
4386 3453 : const svalue *index_sval
4387 3453 : = m_mgr->get_or_create_int_cst (size_type_node,
4388 3453 : bytes.get_start_byte_offset ());
4389 3453 : const region *offset_reg = m_mgr->get_offset_region (base_reg,
4390 : NULL_TREE,
4391 : index_sval);
4392 3453 : const svalue *byte_size_sval
4393 3453 : = m_mgr->get_or_create_int_cst (size_type_node, bytes.m_size_in_bytes);
4394 3453 : const region *read_reg = m_mgr->get_sized_region (offset_reg,
4395 : NULL_TREE,
4396 : byte_size_sval);
4397 :
4398 : /* Simulate reading those bytes from the store. */
4399 3453 : const svalue *sval = get_store_value (read_reg, ctxt);
4400 3453 : return sval;
4401 : }
4402 :
4403 : static tree
4404 2826 : get_tree_for_byte_offset (tree ptr_expr, byte_offset_t byte_offset)
4405 : {
4406 2826 : gcc_assert (ptr_expr);
4407 2826 : tree ptype = build_pointer_type_for_mode (char_type_node, ptr_mode, true);
4408 2826 : return fold_build2 (MEM_REF,
4409 : char_type_node,
4410 : ptr_expr, wide_int_to_tree (ptype, byte_offset));
4411 : }
4412 :
4413 : /* Simulate a series of reads of REG until we find a 0 byte
4414 : (equivalent to calling strlen).
4415 :
4416 : Complain to CTXT and return NULL if:
4417 : - the buffer pointed to isn't null-terminated
4418 : - the buffer pointed to has any uninitialized bytes before any 0-terminator
4419 : - any of the reads aren't within the bounds of the underlying base region
4420 :
4421 : Otherwise, return a svalue for the number of bytes read (strlen + 1),
4422 : and, if OUT_SVAL is non-NULL, write to *OUT_SVAL with an svalue
4423 : representing the content of REG up to and including the terminator.
4424 :
4425 : Algorithm
4426 : =========
4427 :
4428 : Get offset for first byte to read.
4429 : Find the binding (if any) that contains it.
4430 : Find the size in bits of that binding.
4431 : Round to the nearest byte (which way???)
4432 : Or maybe give up if we have a partial binding there.
4433 : Get the svalue from the binding.
4434 : Determine the strlen (if any) of that svalue.
4435 : Does it have a 0-terminator within it?
4436 : If so, we have a partial read up to and including that terminator
4437 : Read those bytes from the store; add to the result in the correct place.
4438 : Finish
4439 : If not, we have a full read of that svalue
4440 : Read those bytes from the store; add to the result in the correct place.
4441 : Update read/write offsets
4442 : Continue
4443 : If unknown:
4444 : Result is unknown
4445 : Finish
4446 : */
4447 :
4448 : const svalue *
4449 8540 : region_model::scan_for_null_terminator_1 (const region *reg,
4450 : tree expr,
4451 : const svalue **out_sval,
4452 : region_model_context *ctxt) const
4453 : {
4454 8540 : logger *logger = ctxt ? ctxt->get_logger () : nullptr;
4455 :
4456 8540 : region_offset offset = reg->get_offset (m_mgr);
4457 8540 : if (offset.symbolic_p ())
4458 : {
4459 115 : if (out_sval)
4460 0 : *out_sval = get_store_value (reg, nullptr);
4461 115 : if (logger)
4462 0 : logger->log ("offset is symbolic");
4463 115 : return m_mgr->get_or_create_unknown_svalue (size_type_node);
4464 : }
4465 8425 : byte_offset_t src_byte_offset;
4466 8425 : if (!offset.get_concrete_byte_offset (&src_byte_offset))
4467 : {
4468 0 : if (out_sval)
4469 0 : *out_sval = get_store_value (reg, nullptr);
4470 0 : if (logger)
4471 0 : logger->log ("can't get concrete byte offset");
4472 0 : return m_mgr->get_or_create_unknown_svalue (size_type_node);
4473 : }
4474 8425 : const byte_offset_t initial_src_byte_offset = src_byte_offset;
4475 8425 : byte_offset_t dst_byte_offset = 0;
4476 :
4477 8425 : const region *base_reg = reg->get_base_region ();
4478 :
4479 8425 : if (const string_region *str_reg = base_reg->dyn_cast_string_region ())
4480 : {
4481 4718 : tree string_cst = str_reg->get_string_cst ();
4482 4720 : if (src_byte_offset >= 0
4483 4717 : && src_byte_offset < TREE_STRING_LENGTH (string_cst)
4484 9434 : && wi::fits_shwi_p (src_byte_offset))
4485 : {
4486 4716 : HOST_WIDE_INT str_byte_offset = src_byte_offset.to_shwi ();
4487 4716 : const char *effective_start
4488 4716 : = TREE_STRING_POINTER (string_cst) + str_byte_offset;
4489 4716 : size_t effective_len
4490 4716 : = TREE_STRING_LENGTH (string_cst) - str_byte_offset;
4491 4716 : if (const void *p = memchr (effective_start, 0, effective_len))
4492 : {
4493 4716 : size_t num_bytes_read
4494 4716 : = (const char *)p - effective_start + 1;
4495 : /* Simulate the read. */
4496 4716 : byte_range bytes_to_read (0, num_bytes_read);
4497 4716 : const svalue *sval = get_store_bytes (reg, bytes_to_read, ctxt);
4498 4716 : if (out_sval)
4499 834 : *out_sval = sval;
4500 4716 : if (logger)
4501 0 : logger->log ("using string_cst");
4502 4716 : return m_mgr->get_or_create_int_cst (size_type_node,
4503 4716 : num_bytes_read);
4504 : }
4505 : }
4506 : }
4507 3709 : const binding_cluster *cluster = m_store.get_cluster (base_reg);
4508 3709 : iterable_cluster c (cluster);
4509 3709 : if (logger)
4510 : {
4511 2 : pretty_printer *pp = logger->get_printer ();
4512 2 : logger->start_log_line ();
4513 2 : c.dump_to_pp (pp);
4514 2 : logger->end_log_line ();
4515 : }
4516 :
4517 3709 : concrete_binding_map result;
4518 :
4519 3993 : while (1)
4520 : {
4521 3851 : fragment f;
4522 3851 : if (c.get_fragment_for_byte (src_byte_offset, &f))
4523 : {
4524 775 : if (logger)
4525 : {
4526 1 : logger->start_log_line ();
4527 1 : pretty_printer *pp = logger->get_printer ();
4528 1 : pp_printf (pp, "src_byte_offset: ");
4529 1 : pp_wide_int (pp, src_byte_offset, SIGNED);
4530 1 : pp_string (pp, ": ");
4531 1 : f.dump_to_pp (pp);
4532 1 : logger->end_log_line ();
4533 : }
4534 775 : gcc_assert (f.m_byte_range.contains_p (src_byte_offset));
4535 : /* src_byte_offset and f.m_byte_range are both expressed relative to
4536 : the base region.
4537 : Convert to a byte_range relative to the svalue. */
4538 775 : const byte_range bytes_relative_to_svalue
4539 775 : (src_byte_offset - f.m_byte_range.get_start_byte_offset (),
4540 775 : f.m_byte_range.get_next_byte_offset () - src_byte_offset);
4541 775 : byte_offset_t fragment_bytes_read;
4542 775 : tristate is_terminated
4543 775 : = svalue_byte_range_has_null_terminator (f.m_sval,
4544 : bytes_relative_to_svalue,
4545 : &fragment_bytes_read,
4546 : logger);
4547 775 : if (is_terminated.is_unknown ())
4548 : {
4549 278 : if (out_sval)
4550 2 : *out_sval = get_store_value (reg, nullptr);
4551 633 : return m_mgr->get_or_create_unknown_svalue (size_type_node);
4552 : }
4553 :
4554 : /* Simulate reading those bytes from the store. */
4555 497 : byte_range bytes_to_read (src_byte_offset, fragment_bytes_read);
4556 497 : const svalue *sval = get_store_bytes (base_reg, bytes_to_read, ctxt);
4557 497 : check_for_poison (sval, expr, nullptr, ctxt);
4558 :
4559 497 : if (out_sval)
4560 : {
4561 9 : byte_range bytes_to_write (dst_byte_offset, fragment_bytes_read);
4562 9 : result.insert (bytes_to_write, sval);
4563 : }
4564 :
4565 497 : src_byte_offset += fragment_bytes_read;
4566 497 : dst_byte_offset += fragment_bytes_read;
4567 :
4568 497 : if (is_terminated.is_true ())
4569 : {
4570 355 : if (out_sval)
4571 6 : *out_sval = m_mgr->get_or_create_compound_svalue (NULL_TREE,
4572 : std::move (result));
4573 355 : if (logger)
4574 1 : logger->log ("got terminator");
4575 355 : return m_mgr->get_or_create_int_cst (size_type_node,
4576 355 : dst_byte_offset);
4577 : }
4578 : }
4579 : else
4580 : break;
4581 142 : }
4582 :
4583 : /* No binding for this base_region, or no binding at src_byte_offset
4584 : (or a symbolic binding). */
4585 :
4586 3076 : if (c.has_symbolic_bindings_p ())
4587 : {
4588 124 : if (out_sval)
4589 40 : *out_sval = get_store_value (reg, nullptr);
4590 124 : if (logger)
4591 0 : logger->log ("got symbolic binding");
4592 124 : return m_mgr->get_or_create_unknown_svalue (size_type_node);
4593 : }
4594 :
4595 : /* TODO: the various special-cases seen in
4596 : region_model::get_store_value. */
4597 :
4598 : /* Simulate reading from this byte, then give up. */
4599 2952 : byte_range bytes_to_read (src_byte_offset, 1);
4600 2952 : const svalue *sval = get_store_bytes (base_reg, bytes_to_read, ctxt);
4601 2952 : tree byte_expr
4602 : = (expr
4603 5778 : ? get_tree_for_byte_offset (expr,
4604 : src_byte_offset - initial_src_byte_offset)
4605 : : NULL_TREE);
4606 2952 : check_for_poison (sval, byte_expr, nullptr, ctxt);
4607 2952 : if (base_reg->can_have_initial_svalue_p ())
4608 : {
4609 2744 : if (out_sval)
4610 276 : *out_sval = get_store_value (reg, nullptr);
4611 2744 : return m_mgr->get_or_create_unknown_svalue (size_type_node);
4612 : }
4613 : else
4614 : return nullptr;
4615 7418 : }
4616 :
4617 : /* Like region_model::scan_for_null_terminator_1, but add logging. */
4618 :
4619 : const svalue *
4620 8540 : region_model::scan_for_null_terminator (const region *reg,
4621 : tree expr,
4622 : const svalue **out_sval,
4623 : region_model_context *ctxt) const
4624 : {
4625 8540 : logger *logger = ctxt ? ctxt->get_logger () : nullptr;
4626 8540 : LOG_SCOPE (logger);
4627 8540 : if (logger)
4628 : {
4629 2 : pretty_printer *pp = logger->get_printer ();
4630 2 : logger->start_log_line ();
4631 2 : logger->log_partial ("region: ");
4632 2 : reg->dump_to_pp (pp, true);
4633 2 : logger->end_log_line ();
4634 : }
4635 8540 : if (out_sval)
4636 1165 : *out_sval = nullptr;
4637 8540 : const svalue *sval = scan_for_null_terminator_1 (reg, expr, out_sval, ctxt);
4638 8540 : if (sval && out_sval)
4639 1158 : gcc_assert (*out_sval);
4640 8540 : if (logger)
4641 : {
4642 2 : pretty_printer *pp = logger->get_printer ();
4643 2 : logger->start_log_line ();
4644 2 : logger->log_partial ("length result: ");
4645 2 : if (sval)
4646 1 : sval->dump_to_pp (pp, true);
4647 : else
4648 1 : pp_printf (pp, "NULL");
4649 2 : logger->end_log_line ();
4650 2 : if (out_sval)
4651 : {
4652 2 : logger->start_log_line ();
4653 2 : logger->log_partial ("content result: ");
4654 2 : if (*out_sval)
4655 1 : (*out_sval)->dump_to_pp (pp, true);
4656 : else
4657 1 : pp_printf (pp, "NULL");
4658 2 : logger->end_log_line ();
4659 : }
4660 : }
4661 17080 : return sval;
4662 8540 : }
4663 :
4664 : /* Check that argument ARG_IDX (0-based) to the call described by CD
4665 : is a pointer to a valid null-terminated string.
4666 :
4667 : Simulate scanning through the buffer, reading until we find a 0 byte
4668 : (equivalent to calling strlen).
4669 :
4670 : Complain and return nullptr if:
4671 : - the buffer pointed to isn't null-terminated
4672 : - the buffer pointed to has any uninitialized bytes before any 0-terminator
4673 : - any of the reads aren't within the bounds of the underlying base region
4674 :
4675 : Otherwise, return a svalue for strlen of the buffer (*not* including
4676 : the null terminator).
4677 :
4678 : TODO: we should also complain if:
4679 : - the pointer is NULL (or could be). */
4680 :
4681 : const svalue *
4682 209 : region_model::check_for_null_terminated_string_arg (const call_details &cd,
4683 : unsigned arg_idx) const
4684 : {
4685 209 : return check_for_null_terminated_string_arg (cd,
4686 : arg_idx,
4687 : false, /* include_terminator */
4688 209 : nullptr); // out_sval
4689 : }
4690 :
4691 :
4692 : /* Check that argument ARG_IDX (0-based) to the call described by CD
4693 : is a pointer to a valid null-terminated string.
4694 :
4695 : Simulate scanning through the buffer, reading until we find a 0 byte
4696 : (equivalent to calling strlen).
4697 :
4698 : Complain and return nullptr if:
4699 : - the buffer pointed to isn't null-terminated
4700 : - the buffer pointed to has any uninitialized bytes before any 0-terminator
4701 : - any of the reads aren't within the bounds of the underlying base region
4702 :
4703 : Otherwise, return a svalue. This will be the number of bytes read
4704 : (including the null terminator) if INCLUDE_TERMINATOR is true, or strlen
4705 : of the buffer (not including the null terminator) if it is false.
4706 :
4707 : Also, when returning an svalue, if OUT_SVAL is non-nullptr, write to
4708 : *OUT_SVAL with an svalue representing the content of the buffer up to
4709 : and including the terminator.
4710 :
4711 : TODO: we should also complain if:
4712 : - the pointer is NULL (or could be). */
4713 :
4714 : const svalue *
4715 8069 : region_model::check_for_null_terminated_string_arg (const call_details &cd,
4716 : unsigned arg_idx,
4717 : bool include_terminator,
4718 : const svalue **out_sval) const
4719 : {
4720 0 : class null_terminator_check_event : public custom_event
4721 : {
4722 : public:
4723 164 : null_terminator_check_event (const event_loc_info &loc_info,
4724 : const call_arg_details &arg_details)
4725 : : custom_event (loc_info),
4726 164 : m_arg_details (arg_details)
4727 : {
4728 : }
4729 :
4730 310 : void print_desc (pretty_printer &pp) const final override
4731 : {
4732 310 : if (m_arg_details.m_arg_expr)
4733 310 : pp_printf (&pp,
4734 : "while looking for null terminator"
4735 : " for argument %i (%qE) of %qD...",
4736 310 : m_arg_details.m_arg_idx + 1,
4737 : m_arg_details.m_arg_expr,
4738 310 : m_arg_details.m_called_fndecl);
4739 : else
4740 0 : pp_printf (&pp,
4741 : "while looking for null terminator"
4742 : " for argument %i of %qD...",
4743 0 : m_arg_details.m_arg_idx + 1,
4744 0 : m_arg_details.m_called_fndecl);
4745 310 : }
4746 :
4747 : private:
4748 : const call_arg_details m_arg_details;
4749 : };
4750 :
4751 0 : class null_terminator_check_decl_note
4752 : : public pending_note_subclass<null_terminator_check_decl_note>
4753 : {
4754 : public:
4755 164 : null_terminator_check_decl_note (const call_arg_details &arg_details)
4756 164 : : m_arg_details (arg_details)
4757 : {
4758 : }
4759 :
4760 1300 : const char *get_kind () const final override
4761 : {
4762 1300 : return "null_terminator_check_decl_note";
4763 : }
4764 :
4765 152 : void emit () const final override
4766 : {
4767 152 : inform_about_expected_null_terminated_string_arg (m_arg_details);
4768 152 : }
4769 :
4770 650 : bool operator== (const null_terminator_check_decl_note &other) const
4771 : {
4772 650 : return m_arg_details == other.m_arg_details;
4773 : }
4774 :
4775 : private:
4776 : const call_arg_details m_arg_details;
4777 : };
4778 :
4779 : /* Subclass of decorated_region_model_context that
4780 : adds the above event and note to any saved diagnostics. */
4781 8069 : class annotating_ctxt : public annotating_context
4782 : {
4783 : public:
4784 8069 : annotating_ctxt (const call_details &cd,
4785 : unsigned arg_idx)
4786 : : annotating_context (cd.get_ctxt ()),
4787 8069 : m_cd (cd),
4788 8069 : m_arg_idx (arg_idx)
4789 : {
4790 : }
4791 164 : void add_annotations () final override
4792 : {
4793 164 : call_arg_details arg_details (m_cd, m_arg_idx);
4794 328 : event_loc_info loc_info (m_cd.get_location (),
4795 164 : m_cd.get_model ()->get_current_function ()->decl,
4796 328 : m_cd.get_model ()->get_stack_depth ());
4797 :
4798 164 : add_event
4799 164 : (std::make_unique<null_terminator_check_event> (loc_info,
4800 : arg_details));
4801 164 : add_note
4802 164 : (std::make_unique <null_terminator_check_decl_note> (arg_details));
4803 164 : }
4804 : private:
4805 : const call_details &m_cd;
4806 : unsigned m_arg_idx;
4807 : };
4808 :
4809 : /* Use this ctxt below so that any diagnostics that get added
4810 : get annotated. */
4811 8069 : annotating_ctxt my_ctxt (cd, arg_idx);
4812 :
4813 8069 : const svalue *arg_sval = cd.get_arg_svalue (arg_idx);
4814 8069 : const region *buf_reg
4815 8069 : = deref_rvalue (arg_sval, cd.get_arg_tree (arg_idx), &my_ctxt);
4816 :
4817 16138 : if (const svalue *num_bytes_read_sval
4818 8069 : = scan_for_null_terminator (buf_reg,
4819 : cd.get_arg_tree (arg_idx),
4820 : out_sval,
4821 : &my_ctxt))
4822 : {
4823 7899 : if (out_sval)
4824 1158 : gcc_assert (*out_sval);
4825 7899 : if (include_terminator)
4826 : return num_bytes_read_sval;
4827 : else
4828 : {
4829 : /* strlen is (bytes_read - 1). */
4830 6741 : const svalue *one = m_mgr->get_or_create_int_cst (size_type_node, 1);
4831 6741 : return m_mgr->get_or_create_binop (size_type_node,
4832 : MINUS_EXPR,
4833 : num_bytes_read_sval,
4834 6741 : one);
4835 : }
4836 : }
4837 : else
4838 : return nullptr;
4839 : }
4840 :
4841 : /* Remove all bindings overlapping REG within the store. */
4842 :
4843 : void
4844 8067 : region_model::clobber_region (const region *reg)
4845 : {
4846 8067 : m_store.clobber_region (m_mgr->get_store_manager(), reg);
4847 8067 : }
4848 :
4849 : /* Remove any bindings for REG within the store. */
4850 :
4851 : void
4852 231799 : region_model::purge_region (const region *reg)
4853 : {
4854 231799 : m_store.purge_region (m_mgr->get_store_manager(), reg);
4855 231799 : }
4856 :
4857 : /* Fill REG with SVAL.
4858 : Use CTXT to report any warnings associated with the write
4859 : (e.g. out-of-bounds). */
4860 :
4861 : void
4862 746 : region_model::fill_region (const region *reg,
4863 : const svalue *sval,
4864 : region_model_context *ctxt)
4865 : {
4866 746 : check_region_for_write (reg, nullptr, ctxt);
4867 746 : m_store.fill_region (m_mgr->get_store_manager(), reg, sval);
4868 746 : }
4869 :
4870 : /* Zero-fill REG.
4871 : Use CTXT to report any warnings associated with the write
4872 : (e.g. out-of-bounds). */
4873 :
4874 : void
4875 861 : region_model::zero_fill_region (const region *reg,
4876 : region_model_context *ctxt)
4877 : {
4878 861 : check_region_for_write (reg, nullptr, ctxt);
4879 861 : m_store.zero_fill_region (m_mgr->get_store_manager(), reg);
4880 861 : }
4881 :
4882 : /* Copy NUM_BYTES_SVAL of SVAL to DEST_REG.
4883 : Use CTXT to report any warnings associated with the copy
4884 : (e.g. out-of-bounds writes). */
4885 :
4886 : void
4887 2300 : region_model::write_bytes (const region *dest_reg,
4888 : const svalue *num_bytes_sval,
4889 : const svalue *sval,
4890 : region_model_context *ctxt)
4891 : {
4892 2300 : const region *sized_dest_reg
4893 2300 : = m_mgr->get_sized_region (dest_reg, NULL_TREE, num_bytes_sval);
4894 2300 : set_value (sized_dest_reg, sval, ctxt);
4895 2300 : }
4896 :
4897 : /* Read NUM_BYTES_SVAL from SRC_REG.
4898 : Use CTXT to report any warnings associated with the copy
4899 : (e.g. out-of-bounds reads, copying of uninitialized values, etc). */
4900 :
4901 : const svalue *
4902 1270 : region_model::read_bytes (const region *src_reg,
4903 : tree src_ptr_expr,
4904 : const svalue *num_bytes_sval,
4905 : region_model_context *ctxt) const
4906 : {
4907 1270 : if (num_bytes_sval->get_kind () == SK_UNKNOWN)
4908 224 : return m_mgr->get_or_create_unknown_svalue (NULL_TREE);
4909 1046 : const region *sized_src_reg
4910 1046 : = m_mgr->get_sized_region (src_reg, NULL_TREE, num_bytes_sval);
4911 1046 : const svalue *src_contents_sval = get_store_value (sized_src_reg, ctxt);
4912 1046 : check_for_poison (src_contents_sval, src_ptr_expr,
4913 : sized_src_reg, ctxt);
4914 1046 : return src_contents_sval;
4915 : }
4916 :
4917 : /* Copy NUM_BYTES_SVAL bytes from SRC_REG to DEST_REG.
4918 : Use CTXT to report any warnings associated with the copy
4919 : (e.g. out-of-bounds reads/writes, copying of uninitialized values,
4920 : etc). */
4921 :
4922 : void
4923 646 : region_model::copy_bytes (const region *dest_reg,
4924 : const region *src_reg,
4925 : tree src_ptr_expr,
4926 : const svalue *num_bytes_sval,
4927 : region_model_context *ctxt)
4928 : {
4929 646 : const svalue *data_sval
4930 646 : = read_bytes (src_reg, src_ptr_expr, num_bytes_sval, ctxt);
4931 646 : write_bytes (dest_reg, num_bytes_sval, data_sval, ctxt);
4932 646 : }
4933 :
4934 : /* Mark REG as having unknown content. */
4935 :
4936 : void
4937 309 : region_model::mark_region_as_unknown (const region *reg,
4938 : uncertainty_t *uncertainty)
4939 : {
4940 309 : svalue_set maybe_live_values;
4941 309 : m_store.mark_region_as_unknown (m_mgr->get_store_manager(), reg,
4942 : uncertainty, &maybe_live_values);
4943 309 : m_store.on_maybe_live_values (*m_mgr->get_store_manager (),
4944 : maybe_live_values);
4945 309 : }
4946 :
4947 : /* Determine what is known about the condition "LHS_SVAL OP RHS_SVAL" within
4948 : this model. */
4949 :
4950 : tristate
4951 231396 : region_model::eval_condition (const svalue *lhs,
4952 : enum tree_code op,
4953 : const svalue *rhs) const
4954 : {
4955 231396 : gcc_assert (lhs);
4956 231396 : gcc_assert (rhs);
4957 :
4958 : /* For now, make no attempt to capture constraints on floating-point
4959 : values. */
4960 231396 : if ((lhs->get_type () && FLOAT_TYPE_P (lhs->get_type ()))
4961 400116 : || (rhs->get_type () && FLOAT_TYPE_P (rhs->get_type ())))
4962 72 : return tristate::unknown ();
4963 :
4964 : /* See what we know based on the values. */
4965 :
4966 : /* Unwrap any unmergeable values. */
4967 231324 : lhs = lhs->unwrap_any_unmergeable ();
4968 231324 : rhs = rhs->unwrap_any_unmergeable ();
4969 :
4970 231324 : if (lhs == rhs)
4971 : {
4972 : /* If we have the same svalue, then we have equality
4973 : (apart from NaN-handling).
4974 : TODO: should this definitely be the case for poisoned values? */
4975 : /* Poisoned and unknown values are "unknowable". */
4976 22566 : if (lhs->get_kind () == SK_POISONED
4977 22566 : || lhs->get_kind () == SK_UNKNOWN)
4978 9720 : return tristate::TS_UNKNOWN;
4979 :
4980 12846 : switch (op)
4981 : {
4982 9584 : case EQ_EXPR:
4983 9584 : case GE_EXPR:
4984 9584 : case LE_EXPR:
4985 9584 : return tristate::TS_TRUE;
4986 :
4987 3262 : case NE_EXPR:
4988 3262 : case GT_EXPR:
4989 3262 : case LT_EXPR:
4990 3262 : return tristate::TS_FALSE;
4991 :
4992 : default:
4993 : /* For other ops, use the logic below. */
4994 : break;
4995 : }
4996 : }
4997 :
4998 : /* If we have a pair of region_svalues, compare them. */
4999 208758 : if (const region_svalue *lhs_ptr = lhs->dyn_cast_region_svalue ())
5000 24558 : if (const region_svalue *rhs_ptr = rhs->dyn_cast_region_svalue ())
5001 : {
5002 922 : tristate res = region_svalue::eval_condition (lhs_ptr, op, rhs_ptr,
5003 : *this);
5004 922 : if (res.is_known ())
5005 632 : return res;
5006 : /* Otherwise, only known through constraints. */
5007 : }
5008 :
5009 208126 : if (const constant_svalue *cst_lhs = lhs->dyn_cast_constant_svalue ())
5010 : {
5011 : /* If we have a pair of constants, compare them. */
5012 54401 : if (const constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
5013 16206 : return constant_svalue::eval_condition (cst_lhs, op, cst_rhs);
5014 : else
5015 : {
5016 : /* When we have one constant, put it on the RHS. */
5017 38195 : std::swap (lhs, rhs);
5018 38195 : op = swap_tree_comparison (op);
5019 : }
5020 : }
5021 191920 : gcc_assert (lhs->get_kind () != SK_CONSTANT);
5022 :
5023 : /* Handle comparison against zero. */
5024 191920 : if (const constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
5025 161452 : if (zerop (cst_rhs->get_constant ()))
5026 : {
5027 102223 : if (const region_svalue *ptr = lhs->dyn_cast_region_svalue ())
5028 : {
5029 : /* A region_svalue is a non-NULL pointer, except in certain
5030 : special cases (see the comment for region::non_null_p). */
5031 23374 : const region *pointee = ptr->get_pointee ();
5032 23374 : if (pointee->non_null_p ())
5033 : {
5034 12758 : switch (op)
5035 : {
5036 0 : default:
5037 0 : gcc_unreachable ();
5038 :
5039 322 : case EQ_EXPR:
5040 322 : case GE_EXPR:
5041 322 : case LE_EXPR:
5042 322 : return tristate::TS_FALSE;
5043 :
5044 12436 : case NE_EXPR:
5045 12436 : case GT_EXPR:
5046 12436 : case LT_EXPR:
5047 12436 : return tristate::TS_TRUE;
5048 : }
5049 : }
5050 : }
5051 78849 : else if (const binop_svalue *binop = lhs->dyn_cast_binop_svalue ())
5052 : {
5053 : /* Treat offsets from a non-NULL pointer as being non-NULL. This
5054 : isn't strictly true, in that eventually ptr++ will wrap
5055 : around and be NULL, but it won't occur in practise and thus
5056 : can be used to suppress effectively false positives that we
5057 : shouldn't warn for. */
5058 21320 : if (binop->get_op () == POINTER_PLUS_EXPR)
5059 : {
5060 13199 : tristate lhs_ts = eval_condition (binop->get_arg0 (), op, rhs);
5061 13199 : if (lhs_ts.is_known ())
5062 12480 : return lhs_ts;
5063 : }
5064 : }
5065 115058 : else if (const unaryop_svalue *unaryop
5066 57529 : = lhs->dyn_cast_unaryop_svalue ())
5067 : {
5068 3409 : if (unaryop->get_op () == NEGATE_EXPR)
5069 : {
5070 : /* e.g. "-X <= 0" is equivalent to X >= 0". */
5071 51 : tristate lhs_ts = eval_condition (unaryop->get_arg (),
5072 : swap_tree_comparison (op),
5073 : rhs);
5074 51 : if (lhs_ts.is_known ())
5075 48 : return lhs_ts;
5076 : }
5077 : }
5078 : }
5079 :
5080 : /* Handle rejection of equality for comparisons of the initial values of
5081 : "external" values (such as params) with the address of locals. */
5082 166634 : if (const initial_svalue *init_lhs = lhs->dyn_cast_initial_svalue ())
5083 40131 : if (const region_svalue *rhs_ptr = rhs->dyn_cast_region_svalue ())
5084 : {
5085 271 : tristate res = compare_initial_and_pointer (init_lhs, rhs_ptr);
5086 271 : if (res.is_known ())
5087 72 : return res;
5088 : }
5089 166562 : if (const initial_svalue *init_rhs = rhs->dyn_cast_initial_svalue ())
5090 5254 : if (const region_svalue *lhs_ptr = lhs->dyn_cast_region_svalue ())
5091 : {
5092 166 : tristate res = compare_initial_and_pointer (init_rhs, lhs_ptr);
5093 166 : if (res.is_known ())
5094 0 : return res;
5095 : }
5096 :
5097 166562 : if (const widening_svalue *widen_lhs = lhs->dyn_cast_widening_svalue ())
5098 5194 : if (tree rhs_cst = rhs->maybe_get_constant ())
5099 : {
5100 2814 : tristate res = widen_lhs->eval_condition_without_cm (op, rhs_cst);
5101 2814 : if (res.is_known ())
5102 69 : return res;
5103 : }
5104 :
5105 : /* Handle comparisons between two svalues with more than one operand. */
5106 166493 : if (const binop_svalue *binop = lhs->dyn_cast_binop_svalue ())
5107 : {
5108 27774 : switch (op)
5109 : {
5110 : default:
5111 : break;
5112 3837 : case EQ_EXPR:
5113 3837 : {
5114 : /* TODO: binops can be equal even if they are not structurally
5115 : equal in case of commutative operators. */
5116 3837 : tristate res = structural_equality (lhs, rhs);
5117 3837 : if (res.is_true ())
5118 44 : return res;
5119 : }
5120 3793 : break;
5121 1120 : case LE_EXPR:
5122 1120 : {
5123 1120 : tristate res = structural_equality (lhs, rhs);
5124 1120 : if (res.is_true ())
5125 0 : return res;
5126 : }
5127 1120 : break;
5128 7238 : case GE_EXPR:
5129 7238 : {
5130 7238 : tristate res = structural_equality (lhs, rhs);
5131 7238 : if (res.is_true ())
5132 46 : return res;
5133 7192 : res = symbolic_greater_than (binop, rhs);
5134 7192 : if (res.is_true ())
5135 56 : return res;
5136 : }
5137 : break;
5138 8888 : case GT_EXPR:
5139 8888 : {
5140 8888 : tristate res = symbolic_greater_than (binop, rhs);
5141 8888 : if (res.is_true ())
5142 167 : return res;
5143 : }
5144 8721 : break;
5145 : }
5146 : }
5147 :
5148 : /* Try range_op, but avoid cases where we have been sloppy about types. */
5149 166180 : if (lhs->get_type ()
5150 114233 : && rhs->get_type ()
5151 274718 : && range_compatible_p (lhs->get_type (), rhs->get_type ()))
5152 : {
5153 101774 : value_range lhs_vr, rhs_vr;
5154 101774 : if (lhs->maybe_get_value_range (lhs_vr))
5155 46408 : if (rhs->maybe_get_value_range (rhs_vr))
5156 : {
5157 45834 : range_op_handler handler (op);
5158 45834 : if (handler)
5159 : {
5160 45834 : int_range_max out;
5161 45834 : if (handler.fold_range (out, boolean_type_node, lhs_vr, rhs_vr))
5162 : {
5163 45834 : if (out.zero_p ())
5164 183 : return tristate::TS_FALSE;
5165 45651 : if (!out.contains_zero_p ())
5166 164 : return tristate::TS_TRUE;
5167 : }
5168 45834 : }
5169 : }
5170 101774 : }
5171 :
5172 : /* Attempt to unwrap cast if there is one, and the types match. */
5173 165833 : tree lhs_type = lhs->get_type ();
5174 165833 : tree rhs_type = rhs->get_type ();
5175 165833 : if (lhs_type && rhs_type)
5176 : {
5177 108191 : const unaryop_svalue *lhs_un_op = dyn_cast <const unaryop_svalue *> (lhs);
5178 108191 : const unaryop_svalue *rhs_un_op = dyn_cast <const unaryop_svalue *> (rhs);
5179 4478 : if (lhs_un_op && CONVERT_EXPR_CODE_P (lhs_un_op->get_op ())
5180 4273 : && rhs_un_op && CONVERT_EXPR_CODE_P (rhs_un_op->get_op ())
5181 108524 : && lhs_type == rhs_type)
5182 : {
5183 333 : tristate res = eval_condition (lhs_un_op->get_arg (),
5184 : op,
5185 : rhs_un_op->get_arg ());
5186 333 : if (res.is_known ())
5187 0 : return res;
5188 : }
5189 4145 : else if (lhs_un_op && CONVERT_EXPR_CODE_P (lhs_un_op->get_op ())
5190 111798 : && lhs_type == rhs_type)
5191 : {
5192 3212 : tristate res = eval_condition (lhs_un_op->get_arg (), op, rhs);
5193 3212 : if (res.is_known ())
5194 56 : return res;
5195 : }
5196 2420 : else if (rhs_un_op && CONVERT_EXPR_CODE_P (rhs_un_op->get_op ())
5197 107066 : && lhs_type == rhs_type)
5198 : {
5199 1557 : tristate res = eval_condition (lhs, op, rhs_un_op->get_arg ());
5200 1557 : if (res.is_known ())
5201 0 : return res;
5202 : }
5203 : }
5204 :
5205 : /* Otherwise, try constraints.
5206 : Cast to const to ensure we don't change the constraint_manager as we
5207 : do this (e.g. by creating equivalence classes). */
5208 165777 : const constraint_manager *constraints = m_constraints;
5209 165777 : return constraints->eval_condition (lhs, op, rhs);
5210 : }
5211 :
5212 : /* Subroutine of region_model::eval_condition, for rejecting
5213 : equality of INIT_VAL(PARM) with &LOCAL. */
5214 :
5215 : tristate
5216 437 : region_model::compare_initial_and_pointer (const initial_svalue *init,
5217 : const region_svalue *ptr) const
5218 : {
5219 437 : const region *pointee = ptr->get_pointee ();
5220 :
5221 : /* If we have a pointer to something within a stack frame, it can't be the
5222 : initial value of a param. */
5223 437 : if (pointee->maybe_get_frame_region ())
5224 72 : if (init->initial_value_of_param_p ())
5225 72 : return tristate::TS_FALSE;
5226 :
5227 365 : return tristate::TS_UNKNOWN;
5228 : }
5229 :
5230 : /* Return true if SVAL is definitely positive. */
5231 :
5232 : static bool
5233 14557 : is_positive_svalue (const svalue *sval)
5234 : {
5235 14557 : if (tree cst = sval->maybe_get_constant ())
5236 14285 : return !zerop (cst) && get_range_pos_neg (cst) == 1;
5237 272 : tree type = sval->get_type ();
5238 272 : if (!type)
5239 : return false;
5240 : /* Consider a binary operation size_t + int. The analyzer wraps the int in
5241 : an unaryop_svalue, converting it to a size_t, but in the dynamic execution
5242 : the result is smaller than the first operand. Thus, we have to look if
5243 : the argument of the unaryop_svalue is also positive. */
5244 215 : if (const unaryop_svalue *un_op = dyn_cast <const unaryop_svalue *> (sval))
5245 10 : return CONVERT_EXPR_CODE_P (un_op->get_op ()) && TYPE_UNSIGNED (type)
5246 18 : && is_positive_svalue (un_op->get_arg ());
5247 205 : return TYPE_UNSIGNED (type);
5248 : }
5249 :
5250 : /* Return true if A is definitely larger than B.
5251 :
5252 : Limitation: does not account for integer overflows and does not try to
5253 : return false, so it can not be used negated. */
5254 :
5255 : tristate
5256 16080 : region_model::symbolic_greater_than (const binop_svalue *bin_a,
5257 : const svalue *b) const
5258 : {
5259 16080 : if (bin_a->get_op () == PLUS_EXPR || bin_a->get_op () == MULT_EXPR)
5260 : {
5261 : /* Eliminate the right-hand side of both svalues. */
5262 14589 : if (const binop_svalue *bin_b = dyn_cast <const binop_svalue *> (b))
5263 2570 : if (bin_a->get_op () == bin_b->get_op ()
5264 1438 : && eval_condition (bin_a->get_arg1 (),
5265 : GT_EXPR,
5266 1438 : bin_b->get_arg1 ()).is_true ()
5267 4008 : && eval_condition (bin_a->get_arg0 (),
5268 : GE_EXPR,
5269 63 : bin_b->get_arg0 ()).is_true ())
5270 40 : return tristate (tristate::TS_TRUE);
5271 :
5272 : /* Otherwise, try to remove a positive offset or factor from BIN_A. */
5273 14549 : if (is_positive_svalue (bin_a->get_arg1 ())
5274 14549 : && eval_condition (bin_a->get_arg0 (),
5275 13833 : GE_EXPR, b).is_true ())
5276 183 : return tristate (tristate::TS_TRUE);
5277 : }
5278 15857 : return tristate::unknown ();
5279 : }
5280 :
5281 : /* Return true if A and B are equal structurally.
5282 :
5283 : Structural equality means that A and B are equal if the svalues A and B have
5284 : the same nodes at the same positions in the tree and the leafs are equal.
5285 : Equality for conjured_svalues and initial_svalues is determined by comparing
5286 : the pointers while constants are compared by value. That behavior is useful
5287 : to check for binaryop_svlaues that evaluate to the same concrete value but
5288 : might use one operand with a different type but the same constant value.
5289 :
5290 : For example,
5291 : binop_svalue (mult_expr,
5292 : initial_svalue (‘size_t’, decl_region (..., 'some_var')),
5293 : constant_svalue (‘size_t’, 4))
5294 : and
5295 : binop_svalue (mult_expr,
5296 : initial_svalue (‘size_t’, decl_region (..., 'some_var'),
5297 : constant_svalue (‘sizetype’, 4))
5298 : are structurally equal. A concrete C code example, where this occurs, can
5299 : be found in test7 of out-of-bounds-5.c. */
5300 :
5301 : tristate
5302 15065 : region_model::structural_equality (const svalue *a, const svalue *b) const
5303 : {
5304 : /* If A and B are referentially equal, they are also structurally equal. */
5305 15065 : if (a == b)
5306 431 : return tristate (tristate::TS_TRUE);
5307 :
5308 14634 : switch (a->get_kind ())
5309 : {
5310 1257 : default:
5311 1257 : return tristate::unknown ();
5312 : /* SK_CONJURED and SK_INITIAL are already handled
5313 : by the referential equality above. */
5314 1055 : case SK_CONSTANT:
5315 1055 : {
5316 1055 : tree a_cst = a->maybe_get_constant ();
5317 1055 : tree b_cst = b->maybe_get_constant ();
5318 1055 : if (a_cst && b_cst)
5319 1809 : return tristate (tree_int_cst_equal (a_cst, b_cst));
5320 : }
5321 126 : return tristate (tristate::TS_FALSE);
5322 9 : case SK_UNARYOP:
5323 9 : {
5324 9 : const unaryop_svalue *un_a = as_a <const unaryop_svalue *> (a);
5325 9 : if (const unaryop_svalue *un_b = dyn_cast <const unaryop_svalue *> (b))
5326 8 : return tristate (pending_diagnostic::same_tree_p (un_a->get_type (),
5327 : un_b->get_type ())
5328 8 : && un_a->get_op () == un_b->get_op ()
5329 : && structural_equality (un_a->get_arg (),
5330 16 : un_b->get_arg ()));
5331 : }
5332 1 : return tristate (tristate::TS_FALSE);
5333 12313 : case SK_BINOP:
5334 12313 : {
5335 12313 : const binop_svalue *bin_a = as_a <const binop_svalue *> (a);
5336 12313 : if (const binop_svalue *bin_b = dyn_cast <const binop_svalue *> (b))
5337 2377 : return tristate (bin_a->get_op () == bin_b->get_op ()
5338 : && structural_equality (bin_a->get_arg0 (),
5339 2862 : bin_b->get_arg0 ())
5340 : && structural_equality (bin_a->get_arg1 (),
5341 2862 : bin_b->get_arg1 ()));
5342 : }
5343 10882 : return tristate (tristate::TS_FALSE);
5344 : }
5345 : }
5346 :
5347 : /* Handle various constraints of the form:
5348 : LHS: ((bool)INNER_LHS INNER_OP INNER_RHS))
5349 : OP : == or !=
5350 : RHS: zero
5351 : and (with a cast):
5352 : LHS: CAST([long]int, ((bool)INNER_LHS INNER_OP INNER_RHS))
5353 : OP : == or !=
5354 : RHS: zero
5355 : by adding constraints for INNER_LHS INNEROP INNER_RHS.
5356 :
5357 : Return true if this function can fully handle the constraint; if
5358 : so, add the implied constraint(s) and write true to *OUT if they
5359 : are consistent with existing constraints, or write false to *OUT
5360 : if they contradicts existing constraints.
5361 :
5362 : Return false for cases that this function doeesn't know how to handle.
5363 :
5364 : For example, if we're checking a stored conditional, we'll have
5365 : something like:
5366 : LHS: CAST(long int, (&HEAP_ALLOCATED_REGION(8)!=(int *)0B))
5367 : OP : NE_EXPR
5368 : RHS: zero
5369 : which this function can turn into an add_constraint of:
5370 : (&HEAP_ALLOCATED_REGION(8) != (int *)0B)
5371 :
5372 : Similarly, optimized && and || conditionals lead to e.g.
5373 : if (p && q)
5374 : becoming gimple like this:
5375 : _1 = p_6 == 0B;
5376 : _2 = q_8 == 0B
5377 : _3 = _1 | _2
5378 : On the "_3 is false" branch we can have constraints of the form:
5379 : ((&HEAP_ALLOCATED_REGION(8)!=(int *)0B)
5380 : | (&HEAP_ALLOCATED_REGION(10)!=(int *)0B))
5381 : == 0
5382 : which implies that both _1 and _2 are false,
5383 : which this function can turn into a pair of add_constraints of
5384 : (&HEAP_ALLOCATED_REGION(8)!=(int *)0B)
5385 : and:
5386 : (&HEAP_ALLOCATED_REGION(10)!=(int *)0B). */
5387 :
5388 : bool
5389 58095 : region_model::add_constraints_from_binop (const svalue *outer_lhs,
5390 : enum tree_code outer_op,
5391 : const svalue *outer_rhs,
5392 : bool *out,
5393 : region_model_context *ctxt)
5394 : {
5395 60426 : while (const svalue *cast = outer_lhs->maybe_undo_cast ())
5396 : outer_lhs = cast;
5397 58095 : const binop_svalue *binop_sval = outer_lhs->dyn_cast_binop_svalue ();
5398 58095 : if (!binop_sval)
5399 : return false;
5400 8583 : if (!outer_rhs->all_zeroes_p ())
5401 : return false;
5402 :
5403 5928 : const svalue *inner_lhs = binop_sval->get_arg0 ();
5404 5928 : enum tree_code inner_op = binop_sval->get_op ();
5405 5928 : const svalue *inner_rhs = binop_sval->get_arg1 ();
5406 :
5407 5928 : if (outer_op != NE_EXPR && outer_op != EQ_EXPR)
5408 : return false;
5409 :
5410 : /* We have either
5411 : - "OUTER_LHS != false" (i.e. OUTER is true), or
5412 : - "OUTER_LHS == false" (i.e. OUTER is false). */
5413 5248 : bool is_true = outer_op == NE_EXPR;
5414 :
5415 5248 : switch (inner_op)
5416 : {
5417 : default:
5418 : return false;
5419 :
5420 2890 : case EQ_EXPR:
5421 2890 : case NE_EXPR:
5422 2890 : case GE_EXPR:
5423 2890 : case GT_EXPR:
5424 2890 : case LE_EXPR:
5425 2890 : case LT_EXPR:
5426 2890 : {
5427 : /* ...and "(inner_lhs OP inner_rhs) == 0"
5428 : then (inner_lhs OP inner_rhs) must have the same
5429 : logical value as LHS. */
5430 2890 : if (!is_true)
5431 1367 : inner_op = invert_tree_comparison (inner_op, false /* honor_nans */);
5432 2890 : *out = add_constraint (inner_lhs, inner_op, inner_rhs, ctxt);
5433 2890 : return true;
5434 : }
5435 913 : break;
5436 :
5437 913 : case BIT_AND_EXPR:
5438 913 : if (is_true)
5439 : {
5440 : /* ...and "(inner_lhs & inner_rhs) != 0"
5441 : then both inner_lhs and inner_rhs must be true. */
5442 457 : const svalue *false_sval
5443 457 : = m_mgr->get_or_create_constant_svalue (boolean_false_node);
5444 457 : bool sat1 = add_constraint (inner_lhs, NE_EXPR, false_sval, ctxt);
5445 457 : bool sat2 = add_constraint (inner_rhs, NE_EXPR, false_sval, ctxt);
5446 457 : *out = sat1 && sat2;
5447 457 : return true;
5448 : }
5449 : return false;
5450 :
5451 644 : case BIT_IOR_EXPR:
5452 644 : if (!is_true)
5453 : {
5454 : /* ...and "(inner_lhs | inner_rhs) == 0"
5455 : i.e. "(inner_lhs | inner_rhs)" is false
5456 : then both inner_lhs and inner_rhs must be false. */
5457 362 : const svalue *false_sval
5458 362 : = m_mgr->get_or_create_constant_svalue (boolean_false_node);
5459 362 : bool sat1 = add_constraint (inner_lhs, EQ_EXPR, false_sval, ctxt);
5460 362 : bool sat2 = add_constraint (inner_rhs, EQ_EXPR, false_sval, ctxt);
5461 362 : *out = sat1 && sat2;
5462 362 : return true;
5463 : }
5464 : return false;
5465 : }
5466 : }
5467 :
5468 : /* Attempt to add the constraint "LHS OP RHS" to this region_model.
5469 : If it is consistent with existing constraints, add it, and return true.
5470 : Return false if it contradicts existing constraints.
5471 : Use CTXT for reporting any diagnostics associated with the accesses. */
5472 :
5473 : bool
5474 78759 : region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
5475 : region_model_context *ctxt)
5476 : {
5477 : /* For now, make no attempt to capture constraints on floating-point
5478 : values. */
5479 78759 : if (FLOAT_TYPE_P (TREE_TYPE (lhs)) || FLOAT_TYPE_P (TREE_TYPE (rhs)))
5480 : return true;
5481 :
5482 78389 : const svalue *lhs_sval = get_rvalue (lhs, ctxt);
5483 78389 : const svalue *rhs_sval = get_rvalue (rhs, ctxt);
5484 :
5485 78389 : return add_constraint (lhs_sval, op, rhs_sval, ctxt);
5486 : }
5487 :
5488 : static bool
5489 17092 : unusable_in_infinite_loop_constraint_p (const svalue *sval)
5490 : {
5491 17092 : if (sval->get_kind () == SK_WIDENING)
5492 0 : return true;
5493 : return false;
5494 : }
5495 :
5496 : /* Attempt to add the constraint "LHS OP RHS" to this region_model.
5497 : If it is consistent with existing constraints, add it, and return true.
5498 : Return false if it contradicts existing constraints.
5499 : Use CTXT for reporting any diagnostics associated with the accesses. */
5500 :
5501 : bool
5502 88698 : region_model::add_constraint (const svalue *lhs,
5503 : enum tree_code op,
5504 : const svalue *rhs,
5505 : region_model_context *ctxt)
5506 : {
5507 88698 : const bool checking_for_infinite_loop
5508 88698 : = ctxt ? ctxt->checking_for_infinite_loop_p () : false;
5509 :
5510 8673 : if (checking_for_infinite_loop)
5511 : {
5512 17092 : if (unusable_in_infinite_loop_constraint_p (lhs)
5513 88698 : || unusable_in_infinite_loop_constraint_p (rhs))
5514 : {
5515 257 : gcc_assert (ctxt);
5516 257 : ctxt->on_unusable_in_infinite_loop ();
5517 257 : return false;
5518 : }
5519 : }
5520 :
5521 88441 : tristate t_cond = eval_condition (lhs, op, rhs);
5522 :
5523 : /* If we already have the condition, do nothing. */
5524 88441 : if (t_cond.is_true ())
5525 : return true;
5526 :
5527 : /* Reject a constraint that would contradict existing knowledge, as
5528 : unsatisfiable. */
5529 71475 : if (t_cond.is_false ())
5530 : return false;
5531 :
5532 61675 : if (checking_for_infinite_loop)
5533 : {
5534 : /* Here, we don't have a definite true/false value, so bail out
5535 : when checking for infinite loops. */
5536 3580 : gcc_assert (ctxt);
5537 3580 : ctxt->on_unusable_in_infinite_loop ();
5538 3580 : return false;
5539 : }
5540 :
5541 58095 : bool out;
5542 58095 : if (add_constraints_from_binop (lhs, op, rhs, &out, ctxt))
5543 3709 : return out;
5544 :
5545 : /* Attempt to store the constraint. */
5546 54386 : if (!m_constraints->add_constraint (lhs, op, rhs))
5547 : return false;
5548 :
5549 : /* Notify the context, if any. This exists so that the state machines
5550 : in a program_state can be notified about the condition, and so can
5551 : set sm-state for e.g. unchecked->checked, both for cfg-edges, and
5552 : when synthesizing constraints as above. */
5553 54282 : if (ctxt)
5554 35870 : ctxt->on_condition (lhs, op, rhs);
5555 :
5556 : /* If we have ®ION == NULL, then drop dynamic extents for REGION (for
5557 : the case where REGION is heap-allocated and thus could be NULL). */
5558 54282 : if (tree rhs_cst = rhs->maybe_get_constant ())
5559 44904 : if (op == EQ_EXPR && zerop (rhs_cst))
5560 13374 : if (const region_svalue *region_sval = lhs->dyn_cast_region_svalue ())
5561 1895 : unset_dynamic_extents (region_sval->get_pointee ());
5562 :
5563 : return true;
5564 : }
5565 :
5566 : /* As above, but when returning false, if OUT is non-NULL, write a
5567 : new rejected_constraint to *OUT. */
5568 :
5569 : bool
5570 77615 : region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
5571 : region_model_context *ctxt,
5572 : std::unique_ptr<rejected_constraint> *out)
5573 : {
5574 77615 : bool sat = add_constraint (lhs, op, rhs, ctxt);
5575 77615 : if (!sat && out)
5576 : {
5577 2194 : const svalue *lhs_sval = get_rvalue (lhs, nullptr);
5578 2194 : const svalue *rhs_sval = get_rvalue (rhs, nullptr);
5579 4388 : *out = std::make_unique <rejected_op_constraint> (*this,
5580 2194 : lhs_sval, op, rhs_sval);
5581 : }
5582 77615 : return sat;
5583 : }
5584 :
5585 : /* Determine what is known about the condition "LHS OP RHS" within
5586 : this model.
5587 : Use CTXT for reporting any diagnostics associated with the accesses. */
5588 :
5589 : tristate
5590 37336 : region_model::eval_condition (tree lhs,
5591 : enum tree_code op,
5592 : tree rhs,
5593 : region_model_context *ctxt) const
5594 : {
5595 : /* For now, make no attempt to model constraints on floating-point
5596 : values. */
5597 37336 : if (FLOAT_TYPE_P (TREE_TYPE (lhs)) || FLOAT_TYPE_P (TREE_TYPE (rhs)))
5598 16 : return tristate::unknown ();
5599 :
5600 37320 : return eval_condition (get_rvalue (lhs, ctxt), op, get_rvalue (rhs, ctxt));
5601 : }
5602 :
5603 : /* Implementation of region_model::get_representative_path_var.
5604 : Attempt to return a path_var that represents SVAL, or return NULL_TREE.
5605 : Use VISITED to prevent infinite mutual recursion with the overload for
5606 : regions. */
5607 :
5608 : path_var
5609 13227 : region_model::get_representative_path_var_1 (const svalue *sval,
5610 : svalue_set *visited,
5611 : logger *logger) const
5612 : {
5613 13227 : gcc_assert (sval);
5614 :
5615 : /* Prevent infinite recursion. */
5616 13227 : if (visited->contains (sval))
5617 : {
5618 14 : if (sval->get_kind () == SK_CONSTANT)
5619 14 : return path_var (sval->maybe_get_constant (), 0);
5620 : else
5621 0 : return path_var (NULL_TREE, 0);
5622 : }
5623 13213 : visited->add (sval);
5624 :
5625 : /* Handle casts by recursion into get_representative_path_var. */
5626 13213 : if (const svalue *cast_sval = sval->maybe_undo_cast ())
5627 : {
5628 402 : path_var result = get_representative_path_var (cast_sval, visited,
5629 : logger);
5630 402 : tree orig_type = sval->get_type ();
5631 : /* If necessary, wrap the result in a cast. */
5632 402 : if (result.m_tree && orig_type)
5633 332 : result.m_tree = build1 (NOP_EXPR, orig_type, result.m_tree);
5634 402 : return result;
5635 : }
5636 :
5637 12811 : auto_vec<path_var> pvs;
5638 12811 : m_store.get_representative_path_vars (this, visited, sval, logger, &pvs);
5639 :
5640 12811 : if (tree cst = sval->maybe_get_constant ())
5641 1918 : pvs.safe_push (path_var (cst, 0));
5642 :
5643 : /* Handle string literals and various other pointers. */
5644 12811 : if (const region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
5645 : {
5646 4470 : const region *reg = ptr_sval->get_pointee ();
5647 4470 : if (path_var pv = get_representative_path_var (reg, visited, logger))
5648 30 : return path_var (build1 (ADDR_EXPR,
5649 : sval->get_type (),
5650 : pv.m_tree),
5651 30 : pv.m_stack_depth);
5652 : }
5653 :
5654 : /* If we have a sub_svalue, look for ways to represent the parent. */
5655 12781 : if (const sub_svalue *sub_sval = sval->dyn_cast_sub_svalue ())
5656 : {
5657 370 : const svalue *parent_sval = sub_sval->get_parent ();
5658 370 : const region *subreg = sub_sval->get_subregion ();
5659 740 : if (path_var parent_pv
5660 370 : = get_representative_path_var (parent_sval, visited, logger))
5661 153 : if (const field_region *field_reg = subreg->dyn_cast_field_region ())
5662 111 : return path_var (build3 (COMPONENT_REF,
5663 : sval->get_type (),
5664 : parent_pv.m_tree,
5665 : field_reg->get_field (),
5666 : NULL_TREE),
5667 111 : parent_pv.m_stack_depth);
5668 : }
5669 :
5670 : /* Handle binops. */
5671 12670 : if (const binop_svalue *binop_sval = sval->dyn_cast_binop_svalue ())
5672 534 : if (path_var lhs_pv
5673 534 : = get_representative_path_var (binop_sval->get_arg0 (), visited,
5674 534 : logger))
5675 468 : if (path_var rhs_pv
5676 468 : = get_representative_path_var (binop_sval->get_arg1 (), visited,
5677 468 : logger))
5678 439 : return path_var (build2 (binop_sval->get_op (),
5679 : sval->get_type (),
5680 : lhs_pv.m_tree, rhs_pv.m_tree),
5681 439 : lhs_pv.m_stack_depth);
5682 :
5683 12231 : if (pvs.length () < 1)
5684 2189 : return path_var (NULL_TREE, 0);
5685 :
5686 10042 : pvs.qsort (readability_comparator);
5687 10042 : return pvs[0];
5688 12811 : }
5689 :
5690 : /* Attempt to return a path_var that represents SVAL, or return NULL_TREE.
5691 : Use VISITED to prevent infinite mutual recursion with the overload for
5692 : regions
5693 :
5694 : This function defers to get_representative_path_var_1 to do the work;
5695 : it adds verification that get_representative_path_var_1 returned a tree
5696 : of the correct type. */
5697 :
5698 : path_var
5699 18655 : region_model::get_representative_path_var (const svalue *sval,
5700 : svalue_set *visited,
5701 : logger *logger) const
5702 : {
5703 18655 : if (sval == nullptr)
5704 5428 : return path_var (NULL_TREE, 0);
5705 :
5706 13227 : LOG_SCOPE (logger);
5707 13227 : if (logger)
5708 : {
5709 0 : logger->start_log_line ();
5710 0 : logger->log_partial ("sval: ");
5711 0 : sval->dump_to_pp (logger->get_printer (), true);
5712 0 : logger->end_log_line ();
5713 : }
5714 :
5715 13227 : tree orig_type = sval->get_type ();
5716 :
5717 13227 : path_var result = get_representative_path_var_1 (sval, visited, logger);
5718 :
5719 : /* Verify that the result has the same type as SVAL, if any. */
5720 13227 : if (result.m_tree && orig_type)
5721 10880 : gcc_assert (TREE_TYPE (result.m_tree) == orig_type);
5722 :
5723 13227 : if (logger)
5724 : {
5725 0 : logger->start_log_line ();
5726 0 : logger->log_partial ("sval: ");
5727 0 : sval->dump_to_pp (logger->get_printer (), true);
5728 0 : logger->end_log_line ();
5729 :
5730 0 : if (result.m_tree)
5731 0 : logger->log ("tree: %qE", result.m_tree);
5732 : else
5733 0 : logger->log ("tree: NULL");
5734 : }
5735 :
5736 13227 : return result;
5737 13227 : }
5738 :
5739 : /* Attempt to return a tree that represents SVAL, or return NULL_TREE.
5740 :
5741 : Strip off any top-level cast, to avoid messages like
5742 : double-free of '(void *)ptr'
5743 : from analyzer diagnostics. */
5744 :
5745 : tree
5746 14819 : region_model::get_representative_tree (const svalue *sval, logger *logger) const
5747 : {
5748 14819 : svalue_set visited;
5749 14819 : tree expr = get_representative_path_var (sval, &visited, logger).m_tree;
5750 :
5751 : /* Strip off any top-level cast. */
5752 14819 : if (expr && TREE_CODE (expr) == NOP_EXPR)
5753 572 : expr = TREE_OPERAND (expr, 0);
5754 :
5755 14819 : return fixup_tree_for_diagnostic (expr);
5756 14819 : }
5757 :
5758 : tree
5759 838 : region_model::get_representative_tree (const region *reg, logger *logger) const
5760 : {
5761 838 : svalue_set visited;
5762 838 : tree expr = get_representative_path_var (reg, &visited, logger).m_tree;
5763 :
5764 : /* Strip off any top-level cast. */
5765 838 : if (expr && TREE_CODE (expr) == NOP_EXPR)
5766 1 : expr = TREE_OPERAND (expr, 0);
5767 :
5768 838 : return fixup_tree_for_diagnostic (expr);
5769 838 : }
5770 :
5771 : /* Implementation of region_model::get_representative_path_var.
5772 :
5773 : Attempt to return a path_var that represents REG, or return
5774 : the NULL path_var.
5775 : For example, a region for a field of a local would be a path_var
5776 : wrapping a COMPONENT_REF.
5777 : Use VISITED to prevent infinite mutual recursion with the overload for
5778 : svalues. */
5779 :
5780 : path_var
5781 16679 : region_model::get_representative_path_var_1 (const region *reg,
5782 : svalue_set *visited,
5783 : logger *logger) const
5784 : {
5785 16679 : switch (reg->get_kind ())
5786 : {
5787 0 : default:
5788 0 : gcc_unreachable ();
5789 :
5790 0 : case RK_FRAME:
5791 0 : case RK_GLOBALS:
5792 0 : case RK_CODE:
5793 0 : case RK_HEAP:
5794 0 : case RK_STACK:
5795 0 : case RK_THREAD_LOCAL:
5796 0 : case RK_ROOT:
5797 : /* Regions that represent memory spaces are not expressible as trees. */
5798 0 : return path_var (NULL_TREE, 0);
5799 :
5800 1 : case RK_FUNCTION:
5801 1 : {
5802 1 : const function_region *function_reg
5803 1 : = as_a <const function_region *> (reg);
5804 1 : return path_var (function_reg->get_fndecl (), 0);
5805 : }
5806 1 : case RK_LABEL:
5807 1 : {
5808 1 : const label_region *label_reg = as_a <const label_region *> (reg);
5809 1 : return path_var (label_reg->get_label (), 0);
5810 : }
5811 :
5812 225 : case RK_SYMBOLIC:
5813 225 : {
5814 225 : const symbolic_region *symbolic_reg
5815 225 : = as_a <const symbolic_region *> (reg);
5816 225 : const svalue *pointer = symbolic_reg->get_pointer ();
5817 225 : path_var pointer_pv = get_representative_path_var (pointer, visited,
5818 : logger);
5819 225 : if (!pointer_pv)
5820 16 : return path_var (NULL_TREE, 0);
5821 209 : tree offset = build_int_cst (pointer->get_type (), 0);
5822 209 : return path_var (build2 (MEM_REF,
5823 : reg->get_type (),
5824 : pointer_pv.m_tree,
5825 : offset),
5826 209 : pointer_pv.m_stack_depth);
5827 : }
5828 10195 : case RK_DECL:
5829 10195 : {
5830 10195 : const decl_region *decl_reg = as_a <const decl_region *> (reg);
5831 10195 : return path_var (decl_reg->get_decl (), decl_reg->get_stack_depth ());
5832 : }
5833 1373 : case RK_FIELD:
5834 1373 : {
5835 1373 : const field_region *field_reg = as_a <const field_region *> (reg);
5836 1373 : path_var parent_pv
5837 1373 : = get_representative_path_var (reg->get_parent_region (), visited,
5838 : logger);
5839 1373 : if (!parent_pv)
5840 37 : return path_var (NULL_TREE, 0);
5841 1336 : return path_var (build3 (COMPONENT_REF,
5842 : reg->get_type (),
5843 : parent_pv.m_tree,
5844 : field_reg->get_field (),
5845 : NULL_TREE),
5846 1336 : parent_pv.m_stack_depth);
5847 : }
5848 :
5849 150 : case RK_ELEMENT:
5850 150 : {
5851 150 : const element_region *element_reg
5852 150 : = as_a <const element_region *> (reg);
5853 150 : path_var parent_pv
5854 150 : = get_representative_path_var (reg->get_parent_region (), visited,
5855 : logger);
5856 150 : if (!parent_pv)
5857 0 : return path_var (NULL_TREE, 0);
5858 150 : path_var index_pv
5859 150 : = get_representative_path_var (element_reg->get_index (), visited,
5860 : logger);
5861 150 : if (!index_pv)
5862 0 : return path_var (NULL_TREE, 0);
5863 150 : return path_var (build4 (ARRAY_REF,
5864 : reg->get_type (),
5865 : parent_pv.m_tree, index_pv.m_tree,
5866 : NULL_TREE, NULL_TREE),
5867 150 : parent_pv.m_stack_depth);
5868 : }
5869 :
5870 42 : case RK_OFFSET:
5871 42 : {
5872 42 : const offset_region *offset_reg
5873 42 : = as_a <const offset_region *> (reg);
5874 42 : path_var parent_pv
5875 42 : = get_representative_path_var (reg->get_parent_region (), visited,
5876 : logger);
5877 42 : if (!parent_pv)
5878 0 : return path_var (NULL_TREE, 0);
5879 42 : path_var offset_pv
5880 42 : = get_representative_path_var (offset_reg->get_byte_offset (),
5881 : visited, logger);
5882 42 : if (!offset_pv || TREE_CODE (offset_pv.m_tree) != INTEGER_CST)
5883 42 : return path_var (NULL_TREE, 0);
5884 0 : tree addr_parent = build1 (ADDR_EXPR,
5885 : build_pointer_type (reg->get_type ()),
5886 : parent_pv.m_tree);
5887 0 : tree ptype = build_pointer_type_for_mode (char_type_node, ptr_mode,
5888 : true);
5889 0 : return path_var (build2 (MEM_REF, reg->get_type (), addr_parent,
5890 : fold_convert (ptype, offset_pv.m_tree)),
5891 0 : parent_pv.m_stack_depth);
5892 : }
5893 :
5894 46 : case RK_SIZED:
5895 46 : return path_var (NULL_TREE, 0);
5896 :
5897 17 : case RK_CAST:
5898 17 : {
5899 17 : path_var parent_pv
5900 17 : = get_representative_path_var (reg->get_parent_region (), visited,
5901 : logger);
5902 17 : if (!parent_pv)
5903 1 : return path_var (NULL_TREE, 0);
5904 16 : return path_var (build1 (NOP_EXPR,
5905 : reg->get_type (),
5906 : parent_pv.m_tree),
5907 16 : parent_pv.m_stack_depth);
5908 : }
5909 :
5910 4615 : case RK_HEAP_ALLOCATED:
5911 4615 : case RK_ALLOCA:
5912 : /* No good way to express heap-allocated/alloca regions as trees. */
5913 4615 : return path_var (NULL_TREE, 0);
5914 :
5915 10 : case RK_STRING:
5916 10 : {
5917 10 : const string_region *string_reg = as_a <const string_region *> (reg);
5918 10 : return path_var (string_reg->get_string_cst (), 0);
5919 : }
5920 :
5921 4 : case RK_VAR_ARG:
5922 4 : case RK_ERRNO:
5923 4 : case RK_UNKNOWN:
5924 4 : case RK_PRIVATE:
5925 4 : return path_var (NULL_TREE, 0);
5926 : }
5927 : }
5928 :
5929 : /* Attempt to return a path_var that represents REG, or return
5930 : the NULL path_var.
5931 : For example, a region for a field of a local would be a path_var
5932 : wrapping a COMPONENT_REF.
5933 : Use VISITED to prevent infinite mutual recursion with the overload for
5934 : svalues.
5935 :
5936 : This function defers to get_representative_path_var_1 to do the work;
5937 : it adds verification that get_representative_path_var_1 returned a tree
5938 : of the correct type. */
5939 :
5940 : path_var
5941 16679 : region_model::get_representative_path_var (const region *reg,
5942 : svalue_set *visited,
5943 : logger *logger) const
5944 : {
5945 16679 : LOG_SCOPE (logger);
5946 16679 : if (logger)
5947 : {
5948 0 : logger->start_log_line ();
5949 0 : logger->log_partial ("reg: ");
5950 0 : reg->dump_to_pp (logger->get_printer (), true);
5951 0 : logger->end_log_line ();
5952 : }
5953 :
5954 16679 : path_var result = get_representative_path_var_1 (reg, visited, logger);
5955 :
5956 : /* Verify that the result has the same type as REG, if any. */
5957 16679 : if (result.m_tree && reg->get_type ())
5958 11917 : gcc_assert (TREE_TYPE (result.m_tree) == reg->get_type ());
5959 :
5960 16679 : if (logger)
5961 : {
5962 0 : logger->start_log_line ();
5963 0 : logger->log_partial ("reg: ");
5964 0 : reg->dump_to_pp (logger->get_printer (), true);
5965 0 : logger->end_log_line ();
5966 :
5967 0 : if (result.m_tree)
5968 0 : logger->log ("tree: %qE", result.m_tree);
5969 : else
5970 0 : logger->log ("tree: NULL");
5971 : }
5972 :
5973 33358 : return result;
5974 16679 : }
5975 :
5976 : /* Push a new frame_region on to the stack region.
5977 : Populate the frame_region with child regions for the function call's
5978 : parameters, using values from the arguments at the callsite in the
5979 : caller's frame. */
5980 :
5981 : void
5982 15590 : region_model::update_for_gcall (const gcall &call_stmt,
5983 : region_model_context *ctxt,
5984 : function *callee)
5985 : {
5986 : /* Build a vec of argument svalues, using the current top
5987 : frame for resolving tree expressions. */
5988 15590 : auto_vec<const svalue *> arg_svals (gimple_call_num_args (&call_stmt));
5989 :
5990 49188 : for (unsigned i = 0; i < gimple_call_num_args (&call_stmt); i++)
5991 : {
5992 18008 : tree arg = gimple_call_arg (&call_stmt, i);
5993 18008 : arg_svals.quick_push (get_rvalue (arg, ctxt));
5994 : }
5995 :
5996 15590 : if(!callee)
5997 : {
5998 : /* Get the function * from the gcall. */
5999 0 : tree fn_decl = get_fndecl_for_call (call_stmt, ctxt);
6000 0 : callee = DECL_STRUCT_FUNCTION (fn_decl);
6001 : }
6002 :
6003 0 : gcc_assert (callee);
6004 15590 : push_frame (*callee, &call_stmt, &arg_svals, ctxt);
6005 15590 : }
6006 :
6007 : /* Pop the top-most frame_region from the stack, and copy the return
6008 : region's values (if any) into the region for the lvalue of the LHS of
6009 : the call (if any). */
6010 :
6011 : void
6012 11964 : region_model::update_for_return_gcall (const gcall &call_stmt,
6013 : region_model_context *ctxt)
6014 : {
6015 : /* Get the lvalue for the result of the call, passing it to pop_frame,
6016 : so that pop_frame can determine the region with respect to the
6017 : *caller* frame. */
6018 11964 : tree lhs = gimple_call_lhs (&call_stmt);
6019 11964 : pop_frame (lhs, nullptr, ctxt, &call_stmt);
6020 11964 : }
6021 :
6022 : /* Attempt to use R to replay SUMMARY into this object.
6023 : Return true if it is possible. */
6024 :
6025 : bool
6026 1664 : region_model::replay_call_summary (call_summary_replay &r,
6027 : const region_model &summary)
6028 : {
6029 1664 : gcc_assert (summary.get_stack_depth () == 1);
6030 :
6031 1664 : m_store.replay_call_summary (r, summary.m_store);
6032 :
6033 1664 : if (r.get_ctxt ())
6034 1542 : r.get_ctxt ()->maybe_did_work ();
6035 :
6036 1664 : if (!m_constraints->replay_call_summary (r, *summary.m_constraints))
6037 : return false;
6038 :
6039 3020 : for (auto kv : summary.m_dynamic_extents)
6040 : {
6041 1479 : const region *summary_reg = kv.first;
6042 1479 : const region *caller_reg = r.convert_region_from_summary (summary_reg);
6043 1479 : if (!caller_reg)
6044 2 : continue;
6045 1477 : const svalue *summary_sval = kv.second;
6046 1477 : const svalue *caller_sval = r.convert_svalue_from_summary (summary_sval);
6047 1477 : if (!caller_sval)
6048 0 : continue;
6049 1477 : m_dynamic_extents.put (caller_reg, caller_sval);
6050 : }
6051 :
6052 1541 : return true;
6053 : }
6054 :
6055 : /* For use with push_frame when handling a top-level call within the analysis.
6056 : PARAM has a defined but unknown initial value.
6057 : Anything it points to has escaped, since the calling context "knows"
6058 : the pointer, and thus calls to unknown functions could read/write into
6059 : the region.
6060 : If NONNULL is true, then assume that PARAM must be non-NULL. */
6061 :
6062 : void
6063 23454 : region_model::on_top_level_param (tree param,
6064 : bool nonnull,
6065 : region_model_context *ctxt)
6066 : {
6067 23454 : if (POINTER_TYPE_P (TREE_TYPE (param)))
6068 : {
6069 11437 : const region *param_reg = get_lvalue (param, ctxt);
6070 11437 : const svalue *init_ptr_sval
6071 11437 : = m_mgr->get_or_create_initial_value (param_reg);
6072 11437 : const region *pointee_reg = m_mgr->get_symbolic_region (init_ptr_sval);
6073 11437 : store_manager *store_mgr = m_mgr->get_store_manager ();
6074 11437 : m_store.mark_as_escaped (*store_mgr, pointee_reg);
6075 11437 : if (nonnull)
6076 : {
6077 1085 : const svalue *null_ptr_sval
6078 1085 : = m_mgr->get_or_create_null_ptr (TREE_TYPE (param));
6079 1085 : add_constraint (init_ptr_sval, NE_EXPR, null_ptr_sval, ctxt);
6080 : }
6081 : }
6082 23454 : }
6083 :
6084 : /* Update this region_model to reflect pushing a frame onto the stack
6085 : for a call to FUN.
6086 :
6087 : If CALL_STMT is non-NULL, this is for the interprocedural case where
6088 : we already have an execution path into the caller. It can be NULL for
6089 : top-level entrypoints into the analysis, or in selftests.
6090 :
6091 : If ARG_SVALS is non-NULL, use it to populate the parameters
6092 : in the new frame.
6093 : Otherwise, the params have their initial_svalues.
6094 :
6095 : Return the frame_region for the new frame. */
6096 :
6097 : const region *
6098 41197 : region_model::push_frame (const function &fun,
6099 : const gcall *call_stmt,
6100 : const vec<const svalue *> *arg_svals,
6101 : region_model_context *ctxt)
6102 : {
6103 41197 : tree fndecl = fun.decl;
6104 41197 : if (arg_svals)
6105 : {
6106 : /* If the result of the callee is DECL_BY_REFERENCE, then
6107 : we'll need to store a reference to the caller's lhs of
6108 : CALL_STMT within callee's result.
6109 : If so, determine the region of CALL_STMT's lhs within
6110 : the caller's frame before updating m_current_frame. */
6111 15590 : const region *caller_return_by_reference_reg = nullptr;
6112 15590 : if (tree result = DECL_RESULT (fndecl))
6113 15590 : if (DECL_BY_REFERENCE (result))
6114 : {
6115 55 : gcc_assert (call_stmt);
6116 55 : tree lhs = gimple_call_lhs (call_stmt);
6117 55 : gcc_assert (lhs);
6118 55 : caller_return_by_reference_reg = get_lvalue (lhs, ctxt);
6119 : }
6120 :
6121 : /* Update m_current_frame. */
6122 15590 : m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
6123 :
6124 : /* Arguments supplied from a caller frame. */
6125 15590 : unsigned idx = 0;
6126 33122 : for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
6127 17532 : iter_parm = DECL_CHAIN (iter_parm), ++idx)
6128 : {
6129 : /* If there's a mismatching declaration, the call stmt might
6130 : not have enough args. Handle this case by leaving the
6131 : rest of the params as uninitialized. */
6132 17536 : if (idx >= arg_svals->length ())
6133 : break;
6134 17532 : tree parm_lval = iter_parm;
6135 17532 : if (tree parm_default_ssa = get_ssa_default_def (fun, iter_parm))
6136 16183 : parm_lval = parm_default_ssa;
6137 17532 : const region *parm_reg = get_lvalue (parm_lval, ctxt);
6138 17532 : const svalue *arg_sval = (*arg_svals)[idx];
6139 17532 : set_value (parm_reg, arg_sval, ctxt);
6140 : }
6141 :
6142 : /* Handle any variadic args. */
6143 16066 : unsigned va_arg_idx = 0;
6144 16066 : for (; idx < arg_svals->length (); idx++, va_arg_idx++)
6145 : {
6146 476 : const svalue *arg_sval = (*arg_svals)[idx];
6147 476 : const region *var_arg_reg
6148 476 : = m_mgr->get_var_arg_region (m_current_frame,
6149 : va_arg_idx);
6150 476 : set_value (var_arg_reg, arg_sval, ctxt);
6151 : }
6152 :
6153 : /* If the result of the callee is DECL_BY_REFERENCE, then above
6154 : we should have determined the region within the
6155 : caller's frame that the callee will be writing back to.
6156 : Use this now to initialize the reference in callee's frame. */
6157 15590 : if (tree result = DECL_RESULT (fndecl))
6158 15590 : if (DECL_BY_REFERENCE (result))
6159 : {
6160 : /* Get reference to the caller lhs. */
6161 55 : gcc_assert (caller_return_by_reference_reg);
6162 55 : const svalue *ref_sval
6163 55 : = m_mgr->get_ptr_svalue (TREE_TYPE (result),
6164 : caller_return_by_reference_reg);
6165 :
6166 : /* Get region for default val of DECL_RESULT within the
6167 : callee. */
6168 55 : if (tree result_default_ssa = get_ssa_default_def (fun, result))
6169 : {
6170 52 : const region *callee_result_reg
6171 52 : = get_lvalue (result_default_ssa, ctxt);
6172 :
6173 : /* Set the callee's reference to refer to the caller's lhs. */
6174 52 : set_value (callee_result_reg, ref_sval, ctxt);
6175 : }
6176 : }
6177 : }
6178 : else
6179 : {
6180 : /* Otherwise we have a top-level call within the analysis. The params
6181 : have defined but unknown initial values.
6182 : Anything they point to has escaped. */
6183 :
6184 : /* Update m_current_frame. */
6185 25607 : m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
6186 :
6187 : /* Handle "__attribute__((nonnull))". */
6188 25607 : tree fntype = TREE_TYPE (fndecl);
6189 25607 : bitmap nonnull_args = get_nonnull_args (fntype);
6190 :
6191 25607 : unsigned parm_idx = 0;
6192 49061 : for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
6193 23454 : iter_parm = DECL_CHAIN (iter_parm))
6194 : {
6195 23454 : bool non_null = (nonnull_args
6196 23454 : ? (bitmap_empty_p (nonnull_args)
6197 1454 : || bitmap_bit_p (nonnull_args, parm_idx))
6198 23454 : : false);
6199 23454 : if (tree parm_default_ssa = get_ssa_default_def (fun, iter_parm))
6200 20097 : on_top_level_param (parm_default_ssa, non_null, ctxt);
6201 : else
6202 3357 : on_top_level_param (iter_parm, non_null, ctxt);
6203 23454 : parm_idx++;
6204 : }
6205 :
6206 25607 : BITMAP_FREE (nonnull_args);
6207 : }
6208 :
6209 41197 : return m_current_frame;
6210 : }
6211 :
6212 : /* Get the function of the top-most frame in this region_model's stack.
6213 : There must be such a frame. */
6214 :
6215 : const function *
6216 1123 : region_model::get_current_function () const
6217 : {
6218 1123 : const frame_region *frame = get_current_frame ();
6219 1123 : gcc_assert (frame);
6220 1123 : return &frame->get_function ();
6221 : }
6222 :
6223 : /* Custom region_model_context for the assignment to the result
6224 : at a call statement when popping a frame (PR analyzer/106203). */
6225 :
6226 : class caller_context : public region_model_context_decorator
6227 : {
6228 : public:
6229 5723 : caller_context (region_model_context *inner,
6230 : const gcall *call_stmt,
6231 : const frame_region &caller_frame)
6232 : : region_model_context_decorator (inner),
6233 5723 : m_call_stmt (call_stmt),
6234 5723 : m_caller_frame (caller_frame)
6235 : {}
6236 :
6237 : pending_location
6238 9 : get_pending_location_for_diag () const override
6239 : {
6240 9 : pending_location ploc
6241 9 : = region_model_context_decorator::get_pending_location_for_diag ();
6242 :
6243 9 : ploc.m_event_loc_info
6244 9 : = event_loc_info (m_call_stmt->location,
6245 9 : m_caller_frame.get_fndecl (),
6246 9 : m_caller_frame.get_stack_depth ());
6247 :
6248 9 : return ploc;
6249 : }
6250 :
6251 11455 : const gimple *get_stmt () const override
6252 : {
6253 11455 : return m_call_stmt;
6254 : };
6255 :
6256 : private:
6257 : const gcall *m_call_stmt;
6258 : const frame_region &m_caller_frame;
6259 : };
6260 :
6261 :
6262 : /* Pop the topmost frame_region from this region_model's stack;
6263 :
6264 : If RESULT_LVALUE is non-null, copy any return value from the frame
6265 : into the corresponding region (evaluated with respect to the *caller*
6266 : frame, rather than the called frame).
6267 : If OUT_RESULT is non-null, copy any return value from the frame
6268 : into *OUT_RESULT.
6269 :
6270 : If non-null, use CALL_STMT as the location when complaining about
6271 : assignment of the return value to RESULT_LVALUE.
6272 :
6273 : If EVAL_RETURN_SVALUE is false, then don't evaluate the return value.
6274 : This is for use when unwinding frames e.g. due to longjmp, to suppress
6275 : erroneously reporting uninitialized return values.
6276 :
6277 : Purge the frame region and all its descendent regions.
6278 : Convert any pointers that point into such regions into
6279 : poison_kind::popped_stack svalues. */
6280 :
6281 : void
6282 31098 : region_model::pop_frame (tree result_lvalue,
6283 : const svalue **out_result,
6284 : region_model_context *ctxt,
6285 : const gcall *call_stmt,
6286 : bool eval_return_svalue)
6287 : {
6288 31098 : gcc_assert (m_current_frame);
6289 :
6290 31098 : const region_model pre_popped_model = *this;
6291 31098 : const frame_region *frame_reg = m_current_frame;
6292 :
6293 : /* Notify state machines. */
6294 31098 : if (ctxt)
6295 27806 : ctxt->on_pop_frame (frame_reg);
6296 :
6297 : /* Evaluate the result, within the callee frame. */
6298 31098 : tree fndecl = m_current_frame->get_function ().decl;
6299 31098 : tree result = DECL_RESULT (fndecl);
6300 31098 : const svalue *retval = nullptr;
6301 31098 : if (result
6302 31090 : && TREE_TYPE (result) != void_type_node
6303 45085 : && eval_return_svalue)
6304 : {
6305 11619 : retval = get_rvalue (result, ctxt);
6306 11619 : if (out_result)
6307 5425 : *out_result = retval;
6308 : }
6309 :
6310 : /* Pop the frame. */
6311 31098 : m_current_frame = m_current_frame->get_calling_frame ();
6312 :
6313 31098 : if (result_lvalue
6314 31098 : && retval
6315 : /* Don't write back for DECL_BY_REFERENCE; the writes
6316 : should have happened within the callee already. */
6317 31098 : && !DECL_BY_REFERENCE (result))
6318 : {
6319 5723 : gcc_assert (eval_return_svalue);
6320 :
6321 : /* Compute result_dst_reg using RESULT_LVALUE *after* popping
6322 : the frame, but before poisoning pointers into the old frame. */
6323 5723 : const region *result_dst_reg = get_lvalue (result_lvalue, ctxt);
6324 :
6325 : /* Assign retval to result_dst_reg, using caller_context
6326 : to set the call_stmt and the popped_frame for any diagnostics
6327 : due to the assignment. */
6328 5723 : gcc_assert (m_current_frame);
6329 5723 : caller_context caller_ctxt (ctxt, call_stmt, *m_current_frame);
6330 11446 : set_value (result_dst_reg, retval, call_stmt ? &caller_ctxt : ctxt);
6331 : }
6332 :
6333 31098 : unbind_region_and_descendents (frame_reg,poison_kind::popped_stack);
6334 :
6335 31098 : if (auto chan = g->get_channels ().analyzer_events_channel.get_if_active ())
6336 : {
6337 237 : gcc::topics::analyzer_events::on_frame_popped msg
6338 237 : {this, &pre_popped_model, retval, ctxt};
6339 237 : chan->publish (msg);
6340 : }
6341 31098 : }
6342 :
6343 : /* Get the number of frames in this region_model's stack. */
6344 :
6345 : int
6346 5875758 : region_model::get_stack_depth () const
6347 : {
6348 5875758 : const frame_region *frame = get_current_frame ();
6349 5875758 : if (frame)
6350 5857784 : return frame->get_stack_depth ();
6351 : else
6352 : return 0;
6353 : }
6354 :
6355 : /* Get the frame_region with the given index within the stack.
6356 : The frame_region must exist. */
6357 :
6358 : const frame_region *
6359 1811582 : region_model::get_frame_at_index (int index) const
6360 : {
6361 1811582 : const frame_region *frame = get_current_frame ();
6362 1811582 : gcc_assert (frame);
6363 1811582 : gcc_assert (index >= 0);
6364 1811582 : gcc_assert (index <= frame->get_index ());
6365 2122576 : while (index != frame->get_index ())
6366 : {
6367 310994 : frame = frame->get_calling_frame ();
6368 310994 : gcc_assert (frame);
6369 : }
6370 1811582 : return frame;
6371 : }
6372 :
6373 : /* Unbind svalues for any regions in REG and below.
6374 : Find any pointers to such regions; convert them to
6375 : poisoned values of kind PKIND.
6376 : Also purge any dynamic extents. */
6377 :
6378 : void
6379 42052 : region_model::unbind_region_and_descendents (const region *reg,
6380 : enum poison_kind pkind)
6381 : {
6382 : /* Gather a set of base regions to be unbound. */
6383 42052 : hash_set<const region *> base_regs;
6384 244980 : for (store::cluster_map_t::iterator iter = m_store.begin ();
6385 244980 : iter != m_store.end (); ++iter)
6386 : {
6387 202928 : const region *iter_base_reg = (*iter).first;
6388 202928 : if (iter_base_reg->descendent_of_p (reg))
6389 41195 : base_regs.add (iter_base_reg);
6390 : }
6391 83247 : for (hash_set<const region *>::iterator iter = base_regs.begin ();
6392 83247 : iter != base_regs.end (); ++iter)
6393 41195 : m_store.purge_cluster (*iter);
6394 :
6395 : /* Find any pointers to REG or its descendents; convert to poisoned. */
6396 42052 : poison_any_pointers_to_descendents (reg, pkind);
6397 :
6398 : /* Purge dynamic extents of any base regions in REG and below
6399 : (e.g. VLAs and alloca stack regions). */
6400 103963 : for (auto iter : m_dynamic_extents)
6401 : {
6402 19859 : const region *iter_reg = iter.first;
6403 19859 : if (iter_reg->descendent_of_p (reg))
6404 6310 : unset_dynamic_extents (iter_reg);
6405 : }
6406 42052 : }
6407 :
6408 : /* Find any pointers to REG or its descendents; convert them to
6409 : poisoned values of kind PKIND. */
6410 :
6411 : void
6412 42052 : region_model::poison_any_pointers_to_descendents (const region *reg,
6413 : enum poison_kind pkind)
6414 : {
6415 203785 : for (const auto &cluster_iter : m_store)
6416 : {
6417 161733 : binding_cluster *cluster = cluster_iter.second;
6418 161733 : for (auto iter = cluster->begin ();
6419 324301 : iter != cluster->end ();
6420 162568 : ++iter)
6421 : {
6422 162568 : auto bp = *iter;
6423 162568 : const svalue *sval = bp.m_sval;
6424 162568 : if (const region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
6425 : {
6426 42218 : const region *ptr_dst = ptr_sval->get_pointee ();
6427 : /* Poison ptrs to descendents of REG, but not to REG itself,
6428 : otherwise double-free detection doesn't work (since sm-state
6429 : for "free" is stored on the original ptr svalue). */
6430 42218 : if (ptr_dst->descendent_of_p (reg)
6431 42218 : && ptr_dst != reg)
6432 : {
6433 286 : const svalue *new_sval
6434 286 : = m_mgr->get_or_create_poisoned_svalue (pkind,
6435 : sval->get_type ());
6436 286 : cluster->get_map ().overwrite (iter, new_sval);
6437 : }
6438 : }
6439 : }
6440 : }
6441 42052 : }
6442 :
6443 : /* Attempt to merge THIS with OTHER_MODEL, writing the result
6444 : to OUT_MODEL. Use POINT to distinguish values created as a
6445 : result of merging. */
6446 :
6447 : bool
6448 149580 : region_model::can_merge_with_p (const region_model &other_model,
6449 : const program_point &point,
6450 : region_model *out_model,
6451 : const extrinsic_state *ext_state,
6452 : const program_state *state_a,
6453 : const program_state *state_b) const
6454 : {
6455 149580 : gcc_assert (out_model);
6456 149580 : gcc_assert (m_mgr == other_model.m_mgr);
6457 149580 : gcc_assert (m_mgr == out_model->m_mgr);
6458 :
6459 149580 : if (m_current_frame != other_model.m_current_frame)
6460 : return false;
6461 149580 : out_model->m_current_frame = m_current_frame;
6462 :
6463 149580 : model_merger m (this, &other_model, point, out_model,
6464 149580 : ext_state, state_a, state_b);
6465 :
6466 149580 : if (!store::can_merge_p (&m_store, &other_model.m_store,
6467 149580 : &out_model->m_store, m_mgr->get_store_manager (),
6468 : &m))
6469 : return false;
6470 :
6471 42550 : if (!m_dynamic_extents.can_merge_with_p (other_model.m_dynamic_extents,
6472 : &out_model->m_dynamic_extents))
6473 : return false;
6474 :
6475 : /* Merge constraints. */
6476 40682 : constraint_manager::merge (*m_constraints,
6477 40682 : *other_model.m_constraints,
6478 : out_model->m_constraints);
6479 :
6480 41410 : for (auto iter : m.m_svals_changing_meaning)
6481 728 : out_model->m_constraints->purge_state_involving (iter);
6482 :
6483 40682 : if (m_thrown_exceptions_stack != other_model.m_thrown_exceptions_stack)
6484 : return false;
6485 40653 : out_model->m_thrown_exceptions_stack = m_thrown_exceptions_stack;
6486 :
6487 40653 : if (m_caught_exceptions_stack != other_model.m_caught_exceptions_stack)
6488 : return false;
6489 40653 : out_model->m_caught_exceptions_stack = m_caught_exceptions_stack;
6490 :
6491 40653 : return true;
6492 149580 : }
6493 :
6494 : /* Recover the vtable OBJ's vptr (for OBJ_TYPE) actually points to, plus the
6495 : byte offset into it, so callers can recover the most-derived type from the
6496 : vtable's DECL_CONTEXT and BINFO.
6497 :
6498 : Only recognizes the shape we model for a vptr store, "vptr_field =
6499 : &vtable_decl + offset", i.e. a POINTER_PLUS_EXPR binop_svalue of a
6500 : region_svalue for the _ZTV* decl and a constant offset. The offset is
6501 : nonzero when this vptr slot belongs to a non-primary base's own sub-vtable
6502 : group within the same decl; we return it via OUT for callers that need to
6503 : index into the vtable (e.g. gimple_get_virt_method_for_vtable). */
6504 :
6505 : tree
6506 1962 : region_model::get_vtable_from_obj (tree obj, tree obj_type,
6507 : region_model_manager *mgr,
6508 : region_model_context *ctxt,
6509 : unsigned HOST_WIDE_INT *out) const
6510 : {
6511 1962 : if (!obj_type)
6512 : return NULL_TREE;
6513 1962 : tree vfield = TYPE_VFIELD (obj_type);
6514 1962 : if (!vfield)
6515 : return NULL_TREE;
6516 :
6517 1962 : const svalue *obj_sval = get_rvalue (obj, ctxt);
6518 1962 : const region *obj_reg = deref_rvalue (obj_sval, obj, ctxt);
6519 1962 : const region *vptr_reg = mgr->get_field_region (obj_reg, vfield);
6520 :
6521 1962 : const svalue *vptr_sval = get_store_value (vptr_reg, ctxt);
6522 1962 : while (const svalue *cast = vptr_sval->maybe_undo_cast ())
6523 : vptr_sval = cast;
6524 :
6525 1962 : const binop_svalue *b = vptr_sval->dyn_cast_binop_svalue ();
6526 1962 : if (!b || b->get_op () != POINTER_PLUS_EXPR)
6527 : return NULL_TREE;
6528 :
6529 261 : const svalue *offset_sval = b->get_arg1 ();
6530 261 : tree offset_const = offset_sval->maybe_get_constant ();
6531 261 : if (!offset_const || TREE_CODE (offset_const) != INTEGER_CST)
6532 : return NULL_TREE;
6533 261 : if (out)
6534 261 : *out = tree_to_uhwi (offset_const);
6535 :
6536 261 : vptr_sval = b->get_arg0 ();
6537 261 : const region_svalue *vptr = vptr_sval->dyn_cast_region_svalue ();
6538 : /* Give up if we have a conjured vptr. */
6539 261 : if (!vptr)
6540 : return NULL_TREE;
6541 :
6542 261 : tree vtable = vptr->get_pointee ()->maybe_get_decl ();
6543 261 : return vtable;
6544 : }
6545 :
6546 : /* Attempt to get the fndecl for a virtual call via OBJ_TYPE_REF, or
6547 : NULL_TREE if it can't be resolved.
6548 :
6549 : A virtual call's callee is a GIMPLE OBJ_TYPE_REF:
6550 : OBJ_TYPE_REF(EXPR; (TYPE)OBJECT->TOKEN)
6551 : EXPR is the function pointer actually loaded and called; OBJECT, TYPE and
6552 : TOKEN are devirtualization metadata, not needed to perform the call itself.
6553 : OBJECT is the "this" pointer, TYPE its static type, TOKEN the vtable slot
6554 : index. We ignore EXPR and instead resolve TOKEN against OBJECT's modeled
6555 : dynamic type rather than its static TYPE.
6556 :
6557 : Reads the value bound to the object's vptr field (OBJ_TYPE_REF_OBJECT's
6558 : vfield).
6559 : If that value has the form "&vtable_decl + constant" (a region_svalue for a
6560 : _ZTV* decl plus a byte offset), recover the vtable decl and offset and use
6561 : gimple_get_virt_method_for_vtable, together with OBJ_TYPE_REF_TOKEN, to look
6562 : up the concrete fndecl in the vtable's initializer.
6563 :
6564 : Relies on the store having bound the vptr field to the _ZTV* instance, so no
6565 : separate modeling of the object's dynamic type is needed. */
6566 :
6567 : tree
6568 1863 : region_model::get_fndecl_for_virtual_call (const_tree obj_type_ref,
6569 : region_model_context *ctxt)
6570 : {
6571 1863 : tree obj = OBJ_TYPE_REF_OBJECT (obj_type_ref);
6572 1863 : tree obj_type = obj_type_ref_class (obj_type_ref);
6573 :
6574 1863 : unsigned HOST_WIDE_INT offset;
6575 1863 : tree vtable = get_vtable_from_obj (obj, obj_type, m_mgr, ctxt, &offset);
6576 1863 : if (!vtable)
6577 : return NULL_TREE;
6578 :
6579 165 : unsigned HOST_WIDE_INT token
6580 165 : = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (obj_type_ref));
6581 165 : bool can_refer;
6582 165 : tree vptr_fn
6583 165 : = gimple_get_virt_method_for_vtable (token, vtable, offset, &can_refer);
6584 165 : if (!vptr_fn || !can_refer)
6585 : return NULL_TREE;
6586 :
6587 165 : if (cgraph_node *node = cgraph_node::get_create (vptr_fn))
6588 165 : if (const cgraph_node *ultimate = node->ultimate_alias_target ())
6589 165 : return ultimate->decl;
6590 :
6591 : return NULL_TREE;
6592 : }
6593 :
6594 : /* Attempt to get the fndecl used at CALL, if known, or NULL_TREE
6595 : otherwise. */
6596 :
6597 : tree
6598 981212 : region_model::get_fndecl_for_call (const gcall &call,
6599 : region_model_context *ctxt)
6600 : {
6601 981212 : tree fn_ptr = gimple_call_fn (&call);
6602 981212 : if (fn_ptr == NULL_TREE)
6603 : return NULL_TREE;
6604 :
6605 : /* Handle OBJ_TYPE_REF so that we can try to find the definition for a virtual
6606 : call and treat it like any other call. */
6607 937824 : if (TREE_CODE (fn_ptr) == OBJ_TYPE_REF)
6608 1863 : return get_fndecl_for_virtual_call (fn_ptr, ctxt);
6609 :
6610 935961 : const svalue *fn_ptr_sval = get_rvalue (fn_ptr, ctxt);
6611 1871922 : if (const region_svalue *fn_ptr_ptr
6612 935961 : = fn_ptr_sval->dyn_cast_region_svalue ())
6613 : {
6614 931369 : const region *reg = fn_ptr_ptr->get_pointee ();
6615 931369 : if (const function_region *fn_reg = reg->dyn_cast_function_region ())
6616 : {
6617 931313 : tree fn_decl = fn_reg->get_fndecl ();
6618 931313 : cgraph_node *node = cgraph_node::get (fn_decl);
6619 931313 : if (!node)
6620 : return NULL_TREE;
6621 931313 : const cgraph_node *ultimate_node = node->ultimate_alias_target ();
6622 931313 : if (ultimate_node)
6623 931313 : return ultimate_node->decl;
6624 : }
6625 : }
6626 :
6627 : return NULL_TREE;
6628 : }
6629 :
6630 : /* Would be much simpler to use a lambda here, if it were supported. */
6631 :
6632 : struct append_regions_cb_data
6633 : {
6634 : const region_model *model;
6635 : auto_vec<const decl_region *> *out;
6636 : };
6637 :
6638 : /* Populate *OUT with all decl_regions in the current
6639 : frame that have clusters within the store. */
6640 :
6641 : void
6642 432126 : region_model::
6643 : get_regions_for_current_frame (auto_vec<const decl_region *> *out) const
6644 : {
6645 432126 : append_regions_cb_data data;
6646 432126 : data.model = this;
6647 432126 : data.out = out;
6648 432126 : m_store.for_each_cluster (append_regions_cb, &data);
6649 432126 : }
6650 :
6651 : /* Implementation detail of get_regions_for_current_frame. */
6652 :
6653 : void
6654 3269034 : region_model::append_regions_cb (const region *base_reg,
6655 : append_regions_cb_data *cb_data)
6656 : {
6657 3269034 : if (base_reg->get_parent_region () != cb_data->model->m_current_frame)
6658 : return;
6659 1819005 : if (const decl_region *decl_reg = base_reg->dyn_cast_decl_region ())
6660 1800671 : cb_data->out->safe_push (decl_reg);
6661 : }
6662 :
6663 :
6664 : /* Abstract class for diagnostics related to the use of
6665 : floating-point arithmetic where precision is needed. */
6666 :
6667 25 : class imprecise_floating_point_arithmetic : public pending_diagnostic
6668 : {
6669 : public:
6670 50 : int get_controlling_option () const final override
6671 : {
6672 50 : return OPT_Wanalyzer_imprecise_fp_arithmetic;
6673 : }
6674 : };
6675 :
6676 : /* Concrete diagnostic to complain about uses of floating-point arithmetic
6677 : in the size argument of malloc etc. */
6678 :
6679 : class float_as_size_arg : public imprecise_floating_point_arithmetic
6680 : {
6681 : public:
6682 25 : float_as_size_arg (tree arg) : m_arg (arg)
6683 : {}
6684 :
6685 305 : const char *get_kind () const final override
6686 : {
6687 305 : return "float_as_size_arg_diagnostic";
6688 : }
6689 :
6690 25 : bool subclass_equal_p (const pending_diagnostic &other) const final override
6691 : {
6692 25 : return same_tree_p (m_arg, ((const float_as_size_arg &) other).m_arg);
6693 : }
6694 :
6695 25 : bool emit (diagnostic_emission_context &ctxt) final override
6696 : {
6697 25 : bool warned = ctxt.warn ("use of floating-point arithmetic here might"
6698 : " yield unexpected results");
6699 25 : if (warned)
6700 25 : inform (ctxt.get_location (),
6701 : "only use operands of an integer type"
6702 : " inside the size argument");
6703 25 : return warned;
6704 : }
6705 :
6706 : bool
6707 50 : describe_final_event (pretty_printer &pp,
6708 : const evdesc::final_event &) final override
6709 : {
6710 50 : if (m_arg)
6711 50 : pp_printf (&pp,
6712 : "operand %qE is of type %qT",
6713 50 : m_arg, TREE_TYPE (m_arg));
6714 : else
6715 0 : pp_printf (&pp,
6716 : "at least one operand of the size argument is"
6717 : " of a floating-point type");
6718 50 : return true;
6719 : }
6720 :
6721 : private:
6722 : tree m_arg;
6723 : };
6724 :
6725 : /* Visitor to find uses of floating-point variables/constants in an svalue. */
6726 :
6727 : class contains_floating_point_visitor : public visitor
6728 : {
6729 : public:
6730 7952 : contains_floating_point_visitor (const svalue *root_sval) : m_result (nullptr)
6731 : {
6732 7952 : root_sval->accept (this);
6733 : }
6734 :
6735 7952 : const svalue *get_svalue_to_report ()
6736 : {
6737 7952 : return m_result;
6738 : }
6739 :
6740 7696 : void visit_constant_svalue (const constant_svalue *sval) final override
6741 : {
6742 : /* At the point the analyzer runs, constant integer operands in a floating
6743 : point expression are already implicitly converted to floating-points.
6744 : Thus, we do prefer to report non-constants such that the diagnostic
6745 : always reports a floating-point operand. */
6746 7696 : tree type = sval->get_type ();
6747 7696 : if (type && FLOAT_TYPE_P (type) && !m_result)
6748 9 : m_result = sval;
6749 7696 : }
6750 :
6751 506 : void visit_conjured_svalue (const conjured_svalue *sval) final override
6752 : {
6753 506 : tree type = sval->get_type ();
6754 506 : if (type && FLOAT_TYPE_P (type))
6755 0 : m_result = sval;
6756 506 : }
6757 :
6758 993 : void visit_initial_svalue (const initial_svalue *sval) final override
6759 : {
6760 993 : tree type = sval->get_type ();
6761 993 : if (type && FLOAT_TYPE_P (type))
6762 16 : m_result = sval;
6763 993 : }
6764 :
6765 : private:
6766 : /* Non-null if at least one floating-point operand was found. */
6767 : const svalue *m_result;
6768 : };
6769 :
6770 : /* May complain about uses of floating-point operands in SIZE_IN_BYTES. */
6771 :
6772 : void
6773 7952 : region_model::check_dynamic_size_for_floats (const svalue *size_in_bytes,
6774 : region_model_context *ctxt) const
6775 : {
6776 7952 : gcc_assert (ctxt);
6777 :
6778 7952 : contains_floating_point_visitor v (size_in_bytes);
6779 7952 : if (const svalue *float_sval = v.get_svalue_to_report ())
6780 : {
6781 25 : tree diag_arg = get_representative_tree (float_sval);
6782 25 : ctxt->warn (std::make_unique<float_as_size_arg> (diag_arg));
6783 : }
6784 7952 : }
6785 :
6786 : /* Return a region describing a heap-allocated block of memory.
6787 : Use CTXT to complain about tainted sizes.
6788 :
6789 : Reuse an existing heap_allocated_region if it's not being referenced by
6790 : this region_model; otherwise create a new one.
6791 :
6792 : Optionally (update_state_machine) transitions the pointer pointing to the
6793 : heap_allocated_region from start to assumed non-null. */
6794 :
6795 : const region *
6796 19196 : region_model::get_or_create_region_for_heap_alloc (const svalue *size_in_bytes,
6797 : region_model_context *ctxt,
6798 : bool update_state_machine,
6799 : const call_details *cd)
6800 : {
6801 : /* Determine which regions are referenced in this region_model, so that
6802 : we can reuse an existing heap_allocated_region if it's not in use on
6803 : this path. */
6804 19196 : auto_bitmap base_regs_in_use;
6805 19196 : get_referenced_base_regions (base_regs_in_use);
6806 :
6807 : /* Don't reuse regions that are marked as TOUCHED. */
6808 115385 : for (store::cluster_map_t::iterator iter = m_store.begin ();
6809 115385 : iter != m_store.end (); ++iter)
6810 96189 : if ((*iter).second->touched_p ())
6811 : {
6812 9896 : const region *base_reg = (*iter).first;
6813 9896 : bitmap_set_bit (base_regs_in_use, base_reg->get_id ());
6814 : }
6815 :
6816 19196 : const region *reg
6817 19196 : = m_mgr->get_or_create_region_for_heap_alloc (base_regs_in_use);
6818 19196 : if (size_in_bytes)
6819 13520 : if (compat_types_p (size_in_bytes->get_type (), size_type_node))
6820 13520 : set_dynamic_extents (reg, size_in_bytes, ctxt);
6821 :
6822 19196 : if (update_state_machine && cd)
6823 : {
6824 0 : const svalue *ptr_sval
6825 0 : = m_mgr->get_ptr_svalue (cd->get_lhs_type (), reg);
6826 0 : transition_ptr_sval_non_null (ctxt, ptr_sval);
6827 : }
6828 :
6829 19196 : return reg;
6830 19196 : }
6831 :
6832 : /* Populate OUT_IDS with the set of IDs of those base regions which are
6833 : reachable in this region_model. */
6834 :
6835 : void
6836 21133 : region_model::get_referenced_base_regions (auto_bitmap &out_ids) const
6837 : {
6838 21133 : reachable_regions reachable_regs (const_cast<region_model *> (this));
6839 21133 : m_store.for_each_cluster (reachable_regions::init_cluster_cb,
6840 : &reachable_regs);
6841 : /* Get regions for locals that have explicitly bound values. */
6842 148530 : for (store::cluster_map_t::iterator iter = m_store.begin ();
6843 148530 : iter != m_store.end (); ++iter)
6844 : {
6845 127397 : const region *base_reg = (*iter).first;
6846 127397 : if (const region *parent = base_reg->get_parent_region ())
6847 127397 : if (parent->get_kind () == RK_FRAME)
6848 81314 : reachable_regs.add (base_reg, false);
6849 : }
6850 :
6851 21137 : for (auto &eh_node : m_thrown_exceptions_stack)
6852 4 : eh_node.add_to_reachable_regions (reachable_regs);
6853 21193 : for (auto &eh_node : m_caught_exceptions_stack)
6854 60 : eh_node.add_to_reachable_regions (reachable_regs);
6855 :
6856 :
6857 21133 : bitmap_clear (out_ids);
6858 152672 : for (auto iter_reg : reachable_regs)
6859 131539 : bitmap_set_bit (out_ids, iter_reg->get_id ());
6860 21133 : }
6861 :
6862 : /* Return a new region describing a block of memory allocated within the
6863 : current frame.
6864 : Use CTXT to complain about tainted sizes. */
6865 :
6866 : const region *
6867 529 : region_model::create_region_for_alloca (const svalue *size_in_bytes,
6868 : region_model_context *ctxt)
6869 : {
6870 529 : const region *reg = m_mgr->create_region_for_alloca (m_current_frame);
6871 529 : if (compat_types_p (size_in_bytes->get_type (), size_type_node))
6872 528 : set_dynamic_extents (reg, size_in_bytes, ctxt);
6873 529 : return reg;
6874 : }
6875 :
6876 : /* Record that the size of REG is SIZE_IN_BYTES.
6877 : Use CTXT to complain about tainted sizes. */
6878 :
6879 : void
6880 14554 : region_model::set_dynamic_extents (const region *reg,
6881 : const svalue *size_in_bytes,
6882 : region_model_context *ctxt)
6883 : {
6884 14554 : assert_compat_types (size_in_bytes->get_type (), size_type_node);
6885 14554 : if (ctxt)
6886 : {
6887 7952 : check_dynamic_size_for_taint (reg->get_memory_space (), size_in_bytes,
6888 : ctxt);
6889 7952 : check_dynamic_size_for_floats (size_in_bytes, ctxt);
6890 : }
6891 14554 : m_dynamic_extents.put (reg, size_in_bytes);
6892 14554 : }
6893 :
6894 : /* Get the recording of REG in bytes, or nullptr if no dynamic size was
6895 : recorded. */
6896 :
6897 : const svalue *
6898 71348 : region_model::get_dynamic_extents (const region *reg) const
6899 : {
6900 71348 : if (const svalue * const *slot = m_dynamic_extents.get (reg))
6901 13814 : return *slot;
6902 : return nullptr;
6903 : }
6904 :
6905 : /* Unset any recorded dynamic size of REG. */
6906 :
6907 : void
6908 52054 : region_model::unset_dynamic_extents (const region *reg)
6909 : {
6910 52054 : m_dynamic_extents.remove (reg);
6911 52054 : }
6912 :
6913 : /* A subclass of pending_diagnostic for complaining about uninitialized data
6914 : being copied across a trust boundary to an untrusted output
6915 : (e.g. copy_to_user infoleaks in the Linux kernel). */
6916 :
6917 : class exposure_through_uninit_copy
6918 : : public pending_diagnostic_subclass<exposure_through_uninit_copy>
6919 : {
6920 : public:
6921 25 : exposure_through_uninit_copy (const region *src_region,
6922 : const region *dest_region,
6923 : const svalue *copied_sval)
6924 25 : : m_src_region (src_region),
6925 25 : m_dest_region (dest_region),
6926 25 : m_copied_sval (copied_sval)
6927 : {
6928 25 : gcc_assert (m_copied_sval->get_kind () == SK_POISONED
6929 : || m_copied_sval->get_kind () == SK_COMPOUND);
6930 25 : }
6931 :
6932 294 : const char *get_kind () const final override
6933 : {
6934 294 : return "exposure_through_uninit_copy";
6935 : }
6936 :
6937 25 : bool operator== (const exposure_through_uninit_copy &other) const
6938 : {
6939 25 : return (m_src_region == other.m_src_region
6940 25 : && m_dest_region == other.m_dest_region
6941 50 : && m_copied_sval == other.m_copied_sval);
6942 : }
6943 :
6944 50 : int get_controlling_option () const final override
6945 : {
6946 50 : return OPT_Wanalyzer_exposure_through_uninit_copy;
6947 : }
6948 :
6949 25 : bool emit (diagnostic_emission_context &ctxt) final override
6950 : {
6951 : /* CWE-200: Exposure of Sensitive Information to an Unauthorized Actor. */
6952 25 : ctxt.add_cwe (200);
6953 50 : enum memory_space mem_space = get_src_memory_space ();
6954 25 : bool warned;
6955 25 : switch (mem_space)
6956 : {
6957 0 : default:
6958 0 : warned = ctxt.warn ("potential exposure of sensitive information"
6959 : " by copying uninitialized data"
6960 : " across trust boundary");
6961 0 : break;
6962 25 : case MEMSPACE_STACK:
6963 25 : warned = ctxt.warn ("potential exposure of sensitive information"
6964 : " by copying uninitialized data from stack"
6965 : " across trust boundary");
6966 25 : break;
6967 0 : case MEMSPACE_HEAP:
6968 0 : warned = ctxt.warn ("potential exposure of sensitive information"
6969 : " by copying uninitialized data from heap"
6970 : " across trust boundary");
6971 0 : break;
6972 : }
6973 25 : if (warned)
6974 : {
6975 25 : const location_t loc = ctxt.get_location ();
6976 25 : inform_number_of_uninit_bits (loc);
6977 25 : complain_about_uninit_ranges (loc);
6978 :
6979 25 : if (mem_space == MEMSPACE_STACK)
6980 25 : maybe_emit_fixit_hint ();
6981 : }
6982 25 : return warned;
6983 : }
6984 :
6985 : bool
6986 50 : describe_final_event (pretty_printer &pp,
6987 : const evdesc::final_event &) final override
6988 : {
6989 100 : enum memory_space mem_space = get_src_memory_space ();
6990 50 : switch (mem_space)
6991 : {
6992 0 : default:
6993 0 : pp_string (&pp, "uninitialized data copied here");
6994 0 : return true;
6995 :
6996 50 : case MEMSPACE_STACK:
6997 50 : pp_string (&pp, "uninitialized data copied from stack here");
6998 50 : return true;
6999 :
7000 0 : case MEMSPACE_HEAP:
7001 0 : pp_string (&pp, "uninitialized data copied from heap here");
7002 0 : return true;
7003 : }
7004 : }
7005 :
7006 50 : void mark_interesting_stuff (interesting_t *interest) final override
7007 : {
7008 50 : if (m_src_region)
7009 50 : interest->add_region_creation (m_src_region);
7010 50 : }
7011 :
7012 : void
7013 0 : maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
7014 : const final override
7015 : {
7016 0 : auto &props = result_obj.get_or_create_properties ();
7017 : #define PROPERTY_PREFIX "gcc/-Wanalyzer-exposure-through-uninit-copy/"
7018 0 : props.set (PROPERTY_PREFIX "src_region", m_src_region->to_json ());
7019 0 : props.set (PROPERTY_PREFIX "dest_region", m_dest_region->to_json ());
7020 0 : props.set (PROPERTY_PREFIX "copied_sval", m_copied_sval->to_json ());
7021 : #undef PROPERTY_PREFIX
7022 0 : }
7023 :
7024 : private:
7025 75 : enum memory_space get_src_memory_space () const
7026 : {
7027 75 : return m_src_region ? m_src_region->get_memory_space () : MEMSPACE_UNKNOWN;
7028 : }
7029 :
7030 25 : bit_size_t calc_num_uninit_bits () const
7031 : {
7032 25 : switch (m_copied_sval->get_kind ())
7033 : {
7034 0 : default:
7035 0 : gcc_unreachable ();
7036 4 : break;
7037 4 : case SK_POISONED:
7038 4 : {
7039 4 : const poisoned_svalue *poisoned_sval
7040 4 : = as_a <const poisoned_svalue *> (m_copied_sval);
7041 4 : gcc_assert (poisoned_sval->get_poison_kind () == poison_kind::uninit);
7042 :
7043 : /* Give up if don't have type information. */
7044 4 : if (m_copied_sval->get_type () == NULL_TREE)
7045 0 : return 0;
7046 :
7047 4 : bit_size_t size_in_bits;
7048 4 : if (int_size_in_bits (m_copied_sval->get_type (), &size_in_bits))
7049 4 : return size_in_bits;
7050 :
7051 : /* Give up if we can't get the size of the type. */
7052 0 : return 0;
7053 : }
7054 21 : break;
7055 21 : case SK_COMPOUND:
7056 21 : {
7057 21 : const compound_svalue *compound_sval
7058 21 : = as_a <const compound_svalue *> (m_copied_sval);
7059 21 : bit_size_t result = 0;
7060 : /* Find keys for uninit svals. */
7061 82 : for (auto iter : compound_sval->get_concrete_bindings ())
7062 : {
7063 61 : const svalue *sval = iter.second;
7064 122 : if (const poisoned_svalue *psval
7065 61 : = sval->dyn_cast_poisoned_svalue ())
7066 24 : if (psval->get_poison_kind () == poison_kind::uninit)
7067 : {
7068 24 : const bit_range &bits = iter.first;
7069 24 : result += bits.m_size_in_bits;
7070 : }
7071 : }
7072 21 : return result;
7073 : }
7074 : }
7075 : }
7076 :
7077 25 : void inform_number_of_uninit_bits (location_t loc) const
7078 : {
7079 25 : bit_size_t num_uninit_bits = calc_num_uninit_bits ();
7080 25 : if (num_uninit_bits <= 0)
7081 0 : return;
7082 25 : if (num_uninit_bits % BITS_PER_UNIT == 0)
7083 : {
7084 : /* Express in bytes. */
7085 25 : byte_size_t num_uninit_bytes = num_uninit_bits / BITS_PER_UNIT;
7086 25 : if (num_uninit_bytes == 1)
7087 3 : inform (loc, "1 byte is uninitialized");
7088 : else
7089 22 : inform (loc,
7090 : "%wu bytes are uninitialized", num_uninit_bytes.to_uhwi ());
7091 : }
7092 : else
7093 : {
7094 : /* Express in bits. */
7095 0 : if (num_uninit_bits == 1)
7096 0 : inform (loc, "1 bit is uninitialized");
7097 : else
7098 0 : inform (loc,
7099 : "%wu bits are uninitialized", num_uninit_bits.to_uhwi ());
7100 : }
7101 : }
7102 :
7103 25 : void complain_about_uninit_ranges (location_t loc) const
7104 : {
7105 50 : if (const compound_svalue *compound_sval
7106 25 : = m_copied_sval->dyn_cast_compound_svalue ())
7107 : {
7108 : /* Find keys for uninit svals. */
7109 21 : auto_vec<bit_range> uninit_bit_ranges;
7110 82 : for (auto iter : compound_sval->get_concrete_bindings ())
7111 : {
7112 61 : const svalue *sval = iter.second;
7113 122 : if (const poisoned_svalue *psval
7114 61 : = sval->dyn_cast_poisoned_svalue ())
7115 24 : if (psval->get_poison_kind () == poison_kind::uninit)
7116 24 : uninit_bit_ranges.safe_push (iter.first);
7117 : }
7118 :
7119 21 : std::unique_ptr<record_layout> layout;
7120 :
7121 21 : tree type = m_copied_sval->get_type ();
7122 21 : if (type && TREE_CODE (type) == RECORD_TYPE)
7123 : {
7124 17 : layout = std::make_unique<record_layout> (type);
7125 :
7126 17 : if (0)
7127 : layout->dump ();
7128 : }
7129 :
7130 21 : unsigned i;
7131 21 : bit_range *bits;
7132 45 : FOR_EACH_VEC_ELT (uninit_bit_ranges, i, bits)
7133 : {
7134 24 : bit_offset_t start_bit = bits->get_start_bit_offset ();
7135 24 : bit_offset_t next_bit = bits->get_next_bit_offset ();
7136 24 : complain_about_uninit_range (loc, start_bit, next_bit,
7137 24 : layout.get ());
7138 : }
7139 21 : }
7140 25 : }
7141 :
7142 24 : void complain_about_uninit_range (location_t loc,
7143 : bit_offset_t start_bit,
7144 : bit_offset_t next_bit,
7145 : const record_layout *layout) const
7146 : {
7147 24 : if (layout)
7148 : {
7149 75 : while (start_bit < next_bit)
7150 : {
7151 165 : if (const record_layout::item *item
7152 55 : = layout->get_item_at (start_bit))
7153 : {
7154 55 : gcc_assert (start_bit >= item->get_start_bit_offset ());
7155 55 : gcc_assert (start_bit < item->get_next_bit_offset ());
7156 55 : if (item->get_start_bit_offset () == start_bit
7157 108 : && item->get_next_bit_offset () <= next_bit)
7158 53 : complain_about_fully_uninit_item (*item);
7159 : else
7160 2 : complain_about_partially_uninit_item (*item);
7161 55 : start_bit = item->get_next_bit_offset ();
7162 55 : continue;
7163 : }
7164 : else
7165 : break;
7166 : }
7167 : }
7168 :
7169 24 : if (start_bit >= next_bit)
7170 : return;
7171 :
7172 4 : if (start_bit % 8 == 0 && next_bit % 8 == 0)
7173 : {
7174 : /* Express in bytes. */
7175 4 : byte_offset_t start_byte = start_bit / 8;
7176 4 : byte_offset_t last_byte = (next_bit / 8) - 1;
7177 4 : if (last_byte == start_byte)
7178 0 : inform (loc,
7179 : "byte %wu is uninitialized",
7180 : start_byte.to_uhwi ());
7181 : else
7182 4 : inform (loc,
7183 : "bytes %wu - %wu are uninitialized",
7184 : start_byte.to_uhwi (),
7185 : last_byte.to_uhwi ());
7186 : }
7187 : else
7188 : {
7189 : /* Express in bits. */
7190 0 : bit_offset_t last_bit = next_bit - 1;
7191 0 : if (last_bit == start_bit)
7192 0 : inform (loc,
7193 : "bit %wu is uninitialized",
7194 : start_bit.to_uhwi ());
7195 : else
7196 0 : inform (loc,
7197 : "bits %wu - %wu are uninitialized",
7198 : start_bit.to_uhwi (),
7199 : last_bit.to_uhwi ());
7200 : }
7201 : }
7202 :
7203 : static void
7204 53 : complain_about_fully_uninit_item (const record_layout::item &item)
7205 : {
7206 53 : const_tree field = item.m_field;
7207 53 : bit_size_t num_bits = item.m_bit_range.m_size_in_bits;
7208 53 : if (item.m_is_padding)
7209 : {
7210 11 : if (num_bits % 8 == 0)
7211 : {
7212 : /* Express in bytes. */
7213 9 : byte_size_t num_bytes = num_bits / BITS_PER_UNIT;
7214 9 : if (num_bytes == 1)
7215 2 : inform (DECL_SOURCE_LOCATION (field),
7216 : "padding after field %qD is uninitialized (1 byte)",
7217 : field);
7218 : else
7219 7 : inform (DECL_SOURCE_LOCATION (field),
7220 : "padding after field %qD is uninitialized (%wu bytes)",
7221 : field, num_bytes.to_uhwi ());
7222 : }
7223 : else
7224 : {
7225 : /* Express in bits. */
7226 2 : if (num_bits == 1)
7227 0 : inform (DECL_SOURCE_LOCATION (field),
7228 : "padding after field %qD is uninitialized (1 bit)",
7229 : field);
7230 : else
7231 2 : inform (DECL_SOURCE_LOCATION (field),
7232 : "padding after field %qD is uninitialized (%wu bits)",
7233 : field, num_bits.to_uhwi ());
7234 : }
7235 : }
7236 : else
7237 : {
7238 42 : if (num_bits % 8 == 0)
7239 : {
7240 : /* Express in bytes. */
7241 32 : byte_size_t num_bytes = num_bits / BITS_PER_UNIT;
7242 32 : if (num_bytes == 1)
7243 1 : inform (DECL_SOURCE_LOCATION (field),
7244 : "field %qD is uninitialized (1 byte)", field);
7245 : else
7246 31 : inform (DECL_SOURCE_LOCATION (field),
7247 : "field %qD is uninitialized (%wu bytes)",
7248 : field, num_bytes.to_uhwi ());
7249 : }
7250 : else
7251 : {
7252 : /* Express in bits. */
7253 10 : if (num_bits == 1)
7254 9 : inform (DECL_SOURCE_LOCATION (field),
7255 : "field %qD is uninitialized (1 bit)", field);
7256 : else
7257 1 : inform (DECL_SOURCE_LOCATION (field),
7258 : "field %qD is uninitialized (%wu bits)",
7259 : field, num_bits.to_uhwi ());
7260 : }
7261 : }
7262 53 : }
7263 :
7264 : static void
7265 2 : complain_about_partially_uninit_item (const record_layout::item &item)
7266 : {
7267 2 : const_tree field = item.m_field;
7268 2 : if (item.m_is_padding)
7269 0 : inform (DECL_SOURCE_LOCATION (field),
7270 : "padding after field %qD is partially uninitialized",
7271 : field);
7272 : else
7273 2 : inform (DECL_SOURCE_LOCATION (field),
7274 : "field %qD is partially uninitialized",
7275 : field);
7276 : /* TODO: ideally we'd describe what parts are uninitialized. */
7277 2 : }
7278 :
7279 25 : void maybe_emit_fixit_hint () const
7280 : {
7281 25 : if (tree decl = m_src_region->maybe_get_decl ())
7282 : {
7283 25 : gcc_rich_location hint_richloc (DECL_SOURCE_LOCATION (decl));
7284 25 : hint_richloc.add_fixit_insert_after (" = {0}");
7285 25 : inform (&hint_richloc,
7286 : "suggest forcing zero-initialization by"
7287 : " providing a %<{0}%> initializer");
7288 25 : }
7289 25 : }
7290 :
7291 : private:
7292 : const region *m_src_region;
7293 : const region *m_dest_region;
7294 : const svalue *m_copied_sval;
7295 : };
7296 :
7297 : /* Return true if any part of SVAL is uninitialized. */
7298 :
7299 : static bool
7300 80 : contains_uninit_p (const svalue *sval)
7301 : {
7302 80 : switch (sval->get_kind ())
7303 : {
7304 : default:
7305 : return false;
7306 4 : case SK_POISONED:
7307 4 : {
7308 4 : const poisoned_svalue *psval
7309 4 : = as_a <const poisoned_svalue *> (sval);
7310 4 : return psval->get_poison_kind () == poison_kind::uninit;
7311 : }
7312 43 : case SK_COMPOUND:
7313 43 : {
7314 43 : const compound_svalue *compound_sval
7315 43 : = as_a <const compound_svalue *> (sval);
7316 :
7317 141 : for (auto iter = compound_sval->begin ();
7318 141 : iter != compound_sval->end (); ++iter)
7319 : {
7320 119 : const svalue *inner_sval = iter->second;
7321 238 : if (const poisoned_svalue *psval
7322 119 : = inner_sval->dyn_cast_poisoned_svalue ())
7323 21 : if (psval->get_poison_kind () == poison_kind::uninit)
7324 80 : return true;
7325 : }
7326 :
7327 : return false;
7328 : }
7329 : }
7330 : }
7331 :
7332 : /* Function for use by plugins when simulating writing data through a
7333 : pointer to an "untrusted" region DST_REG (and thus crossing a security
7334 : boundary), such as copying data to user space in an OS kernel.
7335 :
7336 : Check that COPIED_SVAL is fully initialized. If not, complain about
7337 : an infoleak to CTXT.
7338 :
7339 : SRC_REG can be nullptr; if non-NULL it is used as a hint in the diagnostic
7340 : as to where COPIED_SVAL came from. */
7341 :
7342 : void
7343 80 : region_model::maybe_complain_about_infoleak (const region *dst_reg,
7344 : const svalue *copied_sval,
7345 : const region *src_reg,
7346 : region_model_context *ctxt)
7347 : {
7348 : /* Check for exposure. */
7349 80 : if (contains_uninit_p (copied_sval))
7350 25 : ctxt->warn
7351 25 : (std::make_unique<exposure_through_uninit_copy> (src_reg,
7352 : dst_reg,
7353 : copied_sval));
7354 80 : }
7355 :
7356 : /* Set errno to a positive symbolic int, as if some error has occurred. */
7357 :
7358 : void
7359 537 : region_model::set_errno (const call_details &cd)
7360 : {
7361 537 : const region *errno_reg = m_mgr->get_errno_region ();
7362 537 : conjured_purge p (this, cd.get_ctxt ());
7363 537 : const svalue *new_errno_sval
7364 537 : = m_mgr->get_or_create_conjured_svalue (integer_type_node,
7365 537 : &cd.get_call_stmt (),
7366 : errno_reg, p);
7367 537 : const svalue *zero
7368 537 : = m_mgr->get_or_create_int_cst (integer_type_node, 0);
7369 537 : add_constraint (new_errno_sval, GT_EXPR, zero, cd.get_ctxt ());
7370 537 : set_value (errno_reg, new_errno_sval, cd.get_ctxt ());
7371 537 : }
7372 :
7373 : // class region_model_context
7374 :
7375 : bool
7376 4155 : region_model_context::
7377 : warn (std::unique_ptr<pending_diagnostic> d,
7378 : std::unique_ptr<pending_location::fixer_for_epath> ploc_fixer)
7379 : {
7380 4155 : pending_location ploc (get_pending_location_for_diag ());
7381 4155 : ploc.m_fixer_for_epath = std::move (ploc_fixer);
7382 4155 : return warn_at (std::move (d), std::move (ploc));
7383 4155 : }
7384 :
7385 : /* class noop_region_model_context : public region_model_context. */
7386 :
7387 : void
7388 0 : noop_region_model_context::add_note (std::unique_ptr<pending_note>)
7389 : {
7390 0 : }
7391 :
7392 : void
7393 0 : noop_region_model_context::add_event (std::unique_ptr<checker_event>)
7394 : {
7395 0 : }
7396 :
7397 : void
7398 78 : noop_region_model_context::bifurcate (std::unique_ptr<custom_edge_info>)
7399 : {
7400 78 : }
7401 :
7402 : void
7403 0 : noop_region_model_context::terminate_path ()
7404 : {
7405 0 : }
7406 :
7407 : /* class region_model_context_decorator : public region_model_context. */
7408 :
7409 : void
7410 172 : region_model_context_decorator::add_event (std::unique_ptr<checker_event> event)
7411 : {
7412 172 : if (m_inner)
7413 172 : m_inner->add_event (std::move (event));
7414 172 : }
7415 :
7416 : /* struct model_merger. */
7417 :
7418 : /* Dump a multiline representation of this merger to PP. */
7419 :
7420 : void
7421 0 : model_merger::dump_to_pp (pretty_printer *pp, bool simple) const
7422 : {
7423 0 : pp_string (pp, "model A:");
7424 0 : pp_newline (pp);
7425 0 : m_model_a->dump_to_pp (pp, simple, true);
7426 0 : pp_newline (pp);
7427 :
7428 0 : pp_string (pp, "model B:");
7429 0 : pp_newline (pp);
7430 0 : m_model_b->dump_to_pp (pp, simple, true);
7431 0 : pp_newline (pp);
7432 :
7433 0 : pp_string (pp, "merged model:");
7434 0 : pp_newline (pp);
7435 0 : m_merged_model->dump_to_pp (pp, simple, true);
7436 0 : pp_newline (pp);
7437 0 : }
7438 :
7439 : /* Dump a multiline representation of this merger to FILE. */
7440 :
7441 : void
7442 0 : model_merger::dump (FILE *fp, bool simple) const
7443 : {
7444 0 : tree_dump_pretty_printer pp (fp);
7445 0 : dump_to_pp (&pp, simple);
7446 0 : }
7447 :
7448 : /* Dump a multiline representation of this merger to stderr. */
7449 :
7450 : DEBUG_FUNCTION void
7451 0 : model_merger::dump (bool simple) const
7452 : {
7453 0 : dump (stderr, simple);
7454 0 : }
7455 :
7456 : /* Return true if it's OK to merge SVAL with other svalues. */
7457 :
7458 : bool
7459 560726 : model_merger::mergeable_svalue_p (const svalue *sval) const
7460 : {
7461 560726 : if (m_ext_state)
7462 : {
7463 : /* Reject merging svalues that have non-purgeable sm-state,
7464 : to avoid falsely reporting memory leaks by merging them
7465 : with something else. For example, given a local var "p",
7466 : reject the merger of a:
7467 : store_a mapping "p" to a malloc-ed ptr
7468 : with:
7469 : store_b mapping "p" to a NULL ptr. */
7470 560678 : if (m_state_a)
7471 560678 : if (!m_state_a->can_purge_p (*m_ext_state, sval))
7472 : return false;
7473 558842 : if (m_state_b)
7474 558842 : if (!m_state_b->can_purge_p (*m_ext_state, sval))
7475 : return false;
7476 : }
7477 : return true;
7478 : }
7479 :
7480 : /* Mark WIDENING_SVAL as changing meaning during the merge. */
7481 :
7482 : void
7483 843 : model_merger::on_widening_reuse (const widening_svalue *widening_sval)
7484 : {
7485 843 : m_svals_changing_meaning.add (widening_sval);
7486 843 : }
7487 :
7488 : } // namespace ana
7489 :
7490 : /* Dump RMODEL fully to stderr (i.e. without summarization). */
7491 :
7492 : DEBUG_FUNCTION void
7493 0 : debug (const region_model &rmodel)
7494 : {
7495 0 : rmodel.dump (false);
7496 0 : }
7497 :
7498 : /* class rejected_op_constraint : public rejected_constraint. */
7499 :
7500 : void
7501 4 : rejected_op_constraint::dump_to_pp (pretty_printer *pp) const
7502 : {
7503 4 : region_model m (m_model);
7504 4 : m_lhs->dump_to_pp (pp, true);
7505 4 : pp_printf (pp, " %s ", op_symbol_code (m_op));
7506 4 : m_rhs->dump_to_pp (pp, true);
7507 4 : }
7508 :
7509 : /* class rejected_default_case : public rejected_constraint. */
7510 :
7511 : void
7512 0 : rejected_default_case::dump_to_pp (pretty_printer *pp) const
7513 : {
7514 0 : pp_string (pp, "implicit default for enum");
7515 0 : }
7516 :
7517 : /* class rejected_ranges_constraint : public rejected_constraint. */
7518 :
7519 : void
7520 0 : rejected_ranges_constraint::dump_to_pp (pretty_printer *pp) const
7521 : {
7522 0 : region_model m (m_model);
7523 0 : const svalue *sval = m.get_rvalue (m_expr, nullptr);
7524 0 : sval->dump_to_pp (pp, true);
7525 0 : pp_string (pp, " in ");
7526 0 : m_ranges->dump_to_pp (pp, true);
7527 0 : }
7528 :
7529 : /* class engine. */
7530 :
7531 : /* engine's ctor. */
7532 :
7533 3523 : engine::engine (region_model_manager &mgr,
7534 : const supergraph *sg)
7535 3523 : : m_mgr (mgr),
7536 3523 : m_sg (sg)
7537 : {
7538 3523 : }
7539 :
7540 : /* Dump the managed objects by class to LOGGER, and the per-class totals. */
7541 :
7542 : void
7543 5 : engine::log_stats (logger *logger) const
7544 : {
7545 5 : m_mgr.log_stats (logger, true);
7546 5 : }
7547 :
7548 : namespace ana {
7549 :
7550 : #if CHECKING_P
7551 :
7552 : namespace selftest {
7553 :
7554 : /* Build a constant tree of the given type from STR. */
7555 :
7556 : static tree
7557 64 : build_real_cst_from_string (tree type, const char *str)
7558 : {
7559 64 : REAL_VALUE_TYPE real;
7560 64 : real_from_string (&real, str);
7561 64 : return build_real (type, real);
7562 : }
7563 :
7564 : /* Append various "interesting" constants to OUT (e.g. NaN). */
7565 :
7566 : static void
7567 8 : append_interesting_constants (auto_vec<tree> *out)
7568 : {
7569 8 : out->safe_push (integer_zero_node);
7570 8 : out->safe_push (build_int_cst (integer_type_node, 42));
7571 8 : out->safe_push (build_int_cst (unsigned_type_node, 0));
7572 8 : out->safe_push (build_int_cst (unsigned_type_node, 42));
7573 8 : out->safe_push (build_real_cst_from_string (float_type_node, "QNaN"));
7574 8 : out->safe_push (build_real_cst_from_string (float_type_node, "-QNaN"));
7575 8 : out->safe_push (build_real_cst_from_string (float_type_node, "SNaN"));
7576 8 : out->safe_push (build_real_cst_from_string (float_type_node, "-SNaN"));
7577 8 : out->safe_push (build_real_cst_from_string (float_type_node, "0.0"));
7578 8 : out->safe_push (build_real_cst_from_string (float_type_node, "-0.0"));
7579 8 : out->safe_push (build_real_cst_from_string (float_type_node, "Inf"));
7580 8 : out->safe_push (build_real_cst_from_string (float_type_node, "-Inf"));
7581 8 : }
7582 :
7583 : /* Verify that tree_cmp is a well-behaved comparator for qsort, even
7584 : if the underlying constants aren't comparable. */
7585 :
7586 : static void
7587 4 : test_tree_cmp_on_constants ()
7588 : {
7589 4 : auto_vec<tree> csts;
7590 4 : append_interesting_constants (&csts);
7591 :
7592 : /* Try sorting every triple. */
7593 4 : const unsigned num = csts.length ();
7594 52 : for (unsigned i = 0; i < num; i++)
7595 624 : for (unsigned j = 0; j < num; j++)
7596 7488 : for (unsigned k = 0; k < num; k++)
7597 : {
7598 6912 : auto_vec<tree> v (3);
7599 6912 : v.quick_push (csts[i]);
7600 6912 : v.quick_push (csts[j]);
7601 6912 : v.quick_push (csts[k]);
7602 6912 : v.qsort (tree_cmp);
7603 6912 : }
7604 4 : }
7605 :
7606 : /* Implementation detail of the ASSERT_CONDITION_* macros. */
7607 :
7608 : void
7609 8 : assert_condition (const location &loc,
7610 : region_model &model,
7611 : const svalue *lhs, tree_code op, const svalue *rhs,
7612 : tristate expected)
7613 : {
7614 8 : tristate actual = model.eval_condition (lhs, op, rhs);
7615 8 : ASSERT_EQ_AT (loc, actual, expected);
7616 8 : }
7617 :
7618 : /* Implementation detail of the ASSERT_CONDITION_* macros. */
7619 :
7620 : void
7621 3084 : assert_condition (const location &loc,
7622 : region_model &model,
7623 : tree lhs, tree_code op, tree rhs,
7624 : tristate expected)
7625 : {
7626 3084 : tristate actual = model.eval_condition (lhs, op, rhs, nullptr);
7627 3084 : ASSERT_EQ_AT (loc, actual, expected);
7628 3084 : }
7629 :
7630 : /* Implementation detail of ASSERT_DUMP_TREE_EQ. */
7631 :
7632 : static void
7633 20 : assert_dump_tree_eq (const location &loc, tree t, const char *expected)
7634 : {
7635 20 : auto_fix_quotes sentinel;
7636 20 : pretty_printer pp;
7637 20 : pp_format_decoder (&pp) = default_tree_printer;
7638 20 : dump_tree (&pp, t);
7639 20 : ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected);
7640 20 : }
7641 :
7642 : /* Assert that dump_tree (T) is EXPECTED. */
7643 :
7644 : #define ASSERT_DUMP_TREE_EQ(T, EXPECTED) \
7645 : SELFTEST_BEGIN_STMT \
7646 : assert_dump_tree_eq ((SELFTEST_LOCATION), (T), (EXPECTED)); \
7647 : SELFTEST_END_STMT
7648 :
7649 : /* Implementation detail of ASSERT_DUMP_EQ. */
7650 :
7651 : static void
7652 8 : assert_dump_eq (const location &loc,
7653 : const region_model &model,
7654 : bool summarize,
7655 : const char *expected)
7656 : {
7657 8 : auto_fix_quotes sentinel;
7658 8 : pretty_printer pp;
7659 8 : pp_format_decoder (&pp) = default_tree_printer;
7660 :
7661 8 : model.dump_to_pp (&pp, summarize, true);
7662 8 : ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected);
7663 8 : }
7664 :
7665 : /* Assert that MODEL.dump_to_pp (SUMMARIZE) is EXPECTED. */
7666 :
7667 : #define ASSERT_DUMP_EQ(MODEL, SUMMARIZE, EXPECTED) \
7668 : SELFTEST_BEGIN_STMT \
7669 : assert_dump_eq ((SELFTEST_LOCATION), (MODEL), (SUMMARIZE), (EXPECTED)); \
7670 : SELFTEST_END_STMT
7671 :
7672 : /* Smoketest for region_model::dump_to_pp. */
7673 :
7674 : static void
7675 4 : test_dump ()
7676 : {
7677 4 : region_model_manager mgr;
7678 4 : region_model model (&mgr);
7679 :
7680 4 : ASSERT_DUMP_EQ (model, false,
7681 : "stack depth: 0\n"
7682 : "m_called_unknown_fn: FALSE\n"
7683 : "constraint_manager:\n"
7684 : " equiv classes:\n"
7685 : " constraints:\n");
7686 4 : ASSERT_DUMP_EQ (model, true,
7687 : "stack depth: 0\n"
7688 : "m_called_unknown_fn: FALSE\n"
7689 : "constraint_manager:\n"
7690 : " equiv classes:\n"
7691 : " constraints:\n");
7692 :
7693 4 : text_art::ascii_theme theme;
7694 4 : pretty_printer pp;
7695 4 : dump_to_pp (model, &theme, &pp);
7696 4 : ASSERT_STREQ ("Region Model\n"
7697 : "`- Store\n"
7698 : " `- m_called_unknown_fn: false\n",
7699 : pp_formatted_text (&pp));
7700 4 : }
7701 :
7702 : /* Helper function for selftests. Create a struct or union type named NAME,
7703 : with the fields given by the FIELD_DECLS in FIELDS.
7704 : If IS_STRUCT is true create a RECORD_TYPE (aka a struct), otherwise
7705 : create a UNION_TYPE. */
7706 :
7707 : static tree
7708 16 : make_test_compound_type (const char *name, bool is_struct,
7709 : const auto_vec<tree> *fields)
7710 : {
7711 16 : tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
7712 16 : TYPE_NAME (t) = get_identifier (name);
7713 16 : TYPE_SIZE (t) = 0;
7714 :
7715 16 : tree fieldlist = NULL_TREE;
7716 16 : int i;
7717 16 : tree field;
7718 48 : FOR_EACH_VEC_ELT (*fields, i, field)
7719 : {
7720 32 : gcc_assert (TREE_CODE (field) == FIELD_DECL);
7721 32 : DECL_CONTEXT (field) = t;
7722 32 : fieldlist = chainon (field, fieldlist);
7723 : }
7724 16 : fieldlist = nreverse (fieldlist);
7725 16 : TYPE_FIELDS (t) = fieldlist;
7726 :
7727 16 : layout_type (t);
7728 16 : return t;
7729 : }
7730 :
7731 : /* Selftest fixture for creating the type "struct coord {int x; int y; };". */
7732 :
7733 : struct coord_test
7734 : {
7735 16 : coord_test ()
7736 : {
7737 16 : auto_vec<tree> fields;
7738 16 : m_x_field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
7739 : get_identifier ("x"), integer_type_node);
7740 16 : fields.safe_push (m_x_field);
7741 16 : m_y_field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
7742 : get_identifier ("y"), integer_type_node);
7743 16 : fields.safe_push (m_y_field);
7744 16 : m_coord_type = make_test_compound_type ("coord", true, &fields);
7745 16 : }
7746 :
7747 : tree m_x_field;
7748 : tree m_y_field;
7749 : tree m_coord_type;
7750 : };
7751 :
7752 : /* Verify usage of a struct. */
7753 :
7754 : static void
7755 4 : test_struct ()
7756 : {
7757 4 : coord_test ct;
7758 :
7759 4 : tree c = build_global_decl ("c", ct.m_coord_type);
7760 4 : tree c_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
7761 : c, ct.m_x_field, NULL_TREE);
7762 4 : tree c_y = build3 (COMPONENT_REF, TREE_TYPE (ct.m_y_field),
7763 : c, ct.m_y_field, NULL_TREE);
7764 :
7765 4 : tree int_17 = build_int_cst (integer_type_node, 17);
7766 4 : tree int_m3 = build_int_cst (integer_type_node, -3);
7767 :
7768 4 : region_model_manager mgr;
7769 4 : region_model model (&mgr);
7770 : /* Set fields in order y, then x. */
7771 4 : model.set_value (c_y, int_m3, nullptr);
7772 4 : model.set_value (c_x, int_17, nullptr);
7773 :
7774 : /* Verify get_offset for "c.x". */
7775 4 : {
7776 4 : const region *c_x_reg = model.get_lvalue (c_x, nullptr);
7777 4 : region_offset offset = c_x_reg->get_offset (&mgr);
7778 4 : ASSERT_EQ (offset.get_base_region (), model.get_lvalue (c, nullptr));
7779 4 : ASSERT_EQ (offset.get_bit_offset (), 0);
7780 : }
7781 :
7782 : /* Verify get_offset for "c.y". */
7783 4 : {
7784 4 : const region *c_y_reg = model.get_lvalue (c_y, nullptr);
7785 4 : region_offset offset = c_y_reg->get_offset (&mgr);
7786 4 : ASSERT_EQ (offset.get_base_region (), model.get_lvalue (c, nullptr));
7787 4 : ASSERT_EQ (offset.get_bit_offset (), INT_TYPE_SIZE);
7788 : }
7789 :
7790 : /* Check iteration order of binding_cluster (and thus of binding_map). */
7791 4 : {
7792 4 : std::vector<binding_map::binding_pair> vec;
7793 4 : auto cluster
7794 4 : = model.get_store ()->get_cluster (model.get_lvalue (c, nullptr));
7795 16 : for (auto iter : *cluster)
7796 8 : vec.push_back (iter);
7797 4 : ASSERT_EQ (vec.size (), 2);
7798 : /* we should get them back in ascending order in memory (x then y). */
7799 : /* x */
7800 4 : ASSERT_EQ (vec[0].m_key->dyn_cast_concrete_binding ()->get_bit_range (),
7801 : bit_range (0, INT_TYPE_SIZE));
7802 4 : ASSERT_TRUE (tree_int_cst_equal(vec[0].m_sval->maybe_get_constant (),
7803 : int_17));
7804 : /* y */
7805 4 : ASSERT_EQ (vec[1].m_key->dyn_cast_concrete_binding ()->get_bit_range (),
7806 : bit_range (INT_TYPE_SIZE, INT_TYPE_SIZE));
7807 4 : ASSERT_TRUE (tree_int_cst_equal(vec[1].m_sval->maybe_get_constant (),
7808 : int_m3));
7809 4 : }
7810 4 : }
7811 :
7812 : /* Verify usage of an array element. */
7813 :
7814 : static void
7815 4 : test_array_1 ()
7816 : {
7817 4 : tree tlen = size_int (10);
7818 4 : tree arr_type = build_array_type (char_type_node, build_index_type (tlen));
7819 :
7820 4 : tree a = build_global_decl ("a", arr_type);
7821 :
7822 4 : region_model_manager mgr;
7823 4 : region_model model (&mgr);
7824 4 : tree int_0 = integer_zero_node;
7825 4 : tree a_0 = build4 (ARRAY_REF, char_type_node,
7826 : a, int_0, NULL_TREE, NULL_TREE);
7827 4 : tree char_A = build_int_cst (char_type_node, 'A');
7828 4 : model.set_value (a_0, char_A, nullptr);
7829 4 : }
7830 :
7831 : /* Verify that region_model::get_representative_tree works as expected. */
7832 :
7833 : static void
7834 4 : test_get_representative_tree ()
7835 : {
7836 4 : region_model_manager mgr;
7837 :
7838 : /* STRING_CST. */
7839 4 : {
7840 4 : tree string_cst = build_string (4, "foo");
7841 4 : region_model m (&mgr);
7842 4 : const svalue *str_sval = m.get_rvalue (string_cst, nullptr);
7843 4 : tree rep = m.get_representative_tree (str_sval);
7844 4 : ASSERT_EQ (rep, string_cst);
7845 4 : }
7846 :
7847 : /* String literal. */
7848 4 : {
7849 4 : tree string_cst_ptr = build_string_literal (4, "foo");
7850 4 : region_model m (&mgr);
7851 4 : const svalue *str_sval = m.get_rvalue (string_cst_ptr, nullptr);
7852 4 : tree rep = m.get_representative_tree (str_sval);
7853 4 : ASSERT_DUMP_TREE_EQ (rep, "&\"foo\"[0]");
7854 4 : }
7855 :
7856 : /* Value of an element within an array. */
7857 4 : {
7858 4 : tree tlen = size_int (10);
7859 4 : tree arr_type = build_array_type (char_type_node, build_index_type (tlen));
7860 4 : tree a = build_global_decl ("a", arr_type);
7861 4 : placeholder_svalue test_sval (mgr.alloc_symbol_id (),
7862 4 : char_type_node, "test value");
7863 :
7864 : /* Value of a[3]. */
7865 4 : {
7866 4 : test_region_model_context ctxt;
7867 4 : region_model model (&mgr);
7868 4 : tree int_3 = build_int_cst (integer_type_node, 3);
7869 4 : tree a_3 = build4 (ARRAY_REF, char_type_node,
7870 : a, int_3, NULL_TREE, NULL_TREE);
7871 4 : const region *a_3_reg = model.get_lvalue (a_3, &ctxt);
7872 4 : model.set_value (a_3_reg, &test_sval, &ctxt);
7873 4 : tree rep = model.get_representative_tree (&test_sval);
7874 4 : ASSERT_DUMP_TREE_EQ (rep, "a[3]");
7875 4 : }
7876 :
7877 : /* Value of a[0]. */
7878 4 : {
7879 4 : test_region_model_context ctxt;
7880 4 : region_model model (&mgr);
7881 4 : tree idx = integer_zero_node;
7882 4 : tree a_0 = build4 (ARRAY_REF, char_type_node,
7883 : a, idx, NULL_TREE, NULL_TREE);
7884 4 : const region *a_0_reg = model.get_lvalue (a_0, &ctxt);
7885 4 : model.set_value (a_0_reg, &test_sval, &ctxt);
7886 4 : tree rep = model.get_representative_tree (&test_sval);
7887 4 : ASSERT_DUMP_TREE_EQ (rep, "a[0]");
7888 4 : }
7889 4 : }
7890 :
7891 : /* Value of a field within a struct. */
7892 4 : {
7893 4 : coord_test ct;
7894 :
7895 4 : tree c = build_global_decl ("c", ct.m_coord_type);
7896 4 : tree c_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
7897 : c, ct.m_x_field, NULL_TREE);
7898 4 : tree c_y = build3 (COMPONENT_REF, TREE_TYPE (ct.m_y_field),
7899 : c, ct.m_y_field, NULL_TREE);
7900 :
7901 4 : test_region_model_context ctxt;
7902 :
7903 : /* Value of initial field. */
7904 4 : {
7905 4 : region_model m (&mgr);
7906 4 : const region *c_x_reg = m.get_lvalue (c_x, &ctxt);
7907 4 : placeholder_svalue test_sval_x (mgr.alloc_symbol_id (),
7908 4 : integer_type_node, "test x val");
7909 4 : m.set_value (c_x_reg, &test_sval_x, &ctxt);
7910 4 : tree rep = m.get_representative_tree (&test_sval_x);
7911 4 : ASSERT_DUMP_TREE_EQ (rep, "c.x");
7912 4 : }
7913 :
7914 : /* Value of non-initial field. */
7915 4 : {
7916 4 : region_model m (&mgr);
7917 4 : const region *c_y_reg = m.get_lvalue (c_y, &ctxt);
7918 4 : placeholder_svalue test_sval_y (mgr.alloc_symbol_id (),
7919 4 : integer_type_node, "test y val");
7920 4 : m.set_value (c_y_reg, &test_sval_y, &ctxt);
7921 4 : tree rep = m.get_representative_tree (&test_sval_y);
7922 4 : ASSERT_DUMP_TREE_EQ (rep, "c.y");
7923 4 : }
7924 4 : }
7925 4 : }
7926 :
7927 : /* Verify that calling region_model::get_rvalue repeatedly on the same
7928 : tree constant retrieves the same svalue *. */
7929 :
7930 : static void
7931 4 : test_unique_constants ()
7932 : {
7933 4 : tree int_0 = integer_zero_node;
7934 4 : tree int_42 = build_int_cst (integer_type_node, 42);
7935 :
7936 4 : test_region_model_context ctxt;
7937 4 : region_model_manager mgr;
7938 4 : region_model model (&mgr);
7939 4 : ASSERT_EQ (model.get_rvalue (int_0, &ctxt), model.get_rvalue (int_0, &ctxt));
7940 4 : ASSERT_EQ (model.get_rvalue (int_42, &ctxt),
7941 : model.get_rvalue (int_42, &ctxt));
7942 4 : ASSERT_NE (model.get_rvalue (int_0, &ctxt), model.get_rvalue (int_42, &ctxt));
7943 4 : ASSERT_EQ (ctxt.get_num_diagnostics (), 0);
7944 :
7945 : /* A "(const int)42" will be a different tree from "(int)42)"... */
7946 4 : tree const_int_type_node
7947 4 : = build_qualified_type (integer_type_node, TYPE_QUAL_CONST);
7948 4 : tree const_int_42 = build_int_cst (const_int_type_node, 42);
7949 4 : ASSERT_NE (int_42, const_int_42);
7950 : /* It should have a different const_svalue. */
7951 4 : const svalue *int_42_sval = model.get_rvalue (int_42, &ctxt);
7952 4 : const svalue *const_int_42_sval = model.get_rvalue (const_int_42, &ctxt);
7953 4 : ASSERT_NE (int_42_sval, const_int_42_sval);
7954 : /* But they should compare as equal. */
7955 4 : ASSERT_CONDITION_TRUE (model, int_42_sval, EQ_EXPR, const_int_42_sval);
7956 4 : ASSERT_CONDITION_FALSE (model, int_42_sval, NE_EXPR, const_int_42_sval);
7957 4 : }
7958 :
7959 : /* Verify that each type gets its own singleton unknown_svalue within a
7960 : region_model_manager, and that NULL_TREE gets its own singleton. */
7961 :
7962 : static void
7963 4 : test_unique_unknowns ()
7964 : {
7965 4 : region_model_manager mgr;
7966 4 : const svalue *unknown_int
7967 4 : = mgr.get_or_create_unknown_svalue (integer_type_node);
7968 : /* Repeated calls with the same type should get the same "unknown"
7969 : svalue. */
7970 4 : const svalue *unknown_int_2
7971 4 : = mgr.get_or_create_unknown_svalue (integer_type_node);
7972 4 : ASSERT_EQ (unknown_int, unknown_int_2);
7973 :
7974 : /* Different types (or the NULL type) should have different
7975 : unknown_svalues. */
7976 4 : const svalue *unknown_NULL_type = mgr.get_or_create_unknown_svalue (nullptr);
7977 4 : ASSERT_NE (unknown_NULL_type, unknown_int);
7978 :
7979 : /* Repeated calls with NULL for the type should get the same "unknown"
7980 : svalue. */
7981 4 : const svalue *unknown_NULL_type_2 = mgr.get_or_create_unknown_svalue (nullptr);
7982 4 : ASSERT_EQ (unknown_NULL_type, unknown_NULL_type_2);
7983 4 : }
7984 :
7985 : /* Verify that initial_svalue are handled as expected. */
7986 :
7987 : static void
7988 4 : test_initial_svalue_folding ()
7989 : {
7990 4 : region_model_manager mgr;
7991 4 : tree x = build_global_decl ("x", integer_type_node);
7992 4 : tree y = build_global_decl ("y", integer_type_node);
7993 :
7994 4 : test_region_model_context ctxt;
7995 4 : region_model model (&mgr);
7996 4 : const svalue *x_init = model.get_rvalue (x, &ctxt);
7997 4 : const svalue *y_init = model.get_rvalue (y, &ctxt);
7998 4 : ASSERT_NE (x_init, y_init);
7999 4 : const region *x_reg = model.get_lvalue (x, &ctxt);
8000 4 : ASSERT_EQ (x_init, mgr.get_or_create_initial_value (x_reg));
8001 :
8002 4 : }
8003 :
8004 : /* Verify that unary ops are folded as expected. */
8005 :
8006 : static void
8007 4 : test_unaryop_svalue_folding ()
8008 : {
8009 4 : region_model_manager mgr;
8010 4 : tree x = build_global_decl ("x", integer_type_node);
8011 4 : tree y = build_global_decl ("y", integer_type_node);
8012 :
8013 4 : test_region_model_context ctxt;
8014 4 : region_model model (&mgr);
8015 4 : const svalue *x_init = model.get_rvalue (x, &ctxt);
8016 4 : const svalue *y_init = model.get_rvalue (y, &ctxt);
8017 4 : const region *x_reg = model.get_lvalue (x, &ctxt);
8018 4 : ASSERT_EQ (x_init, mgr.get_or_create_initial_value (x_reg));
8019 :
8020 : /* "(int)x" -> "x". */
8021 4 : ASSERT_EQ (x_init, mgr.get_or_create_cast (integer_type_node, x_init));
8022 :
8023 : /* "(void *)x" -> something other than "x". */
8024 4 : ASSERT_NE (x_init, mgr.get_or_create_cast (ptr_type_node, x_init));
8025 :
8026 : /* "!(x == y)" -> "x != y". */
8027 4 : ASSERT_EQ (mgr.get_or_create_unaryop
8028 : (boolean_type_node, TRUTH_NOT_EXPR,
8029 : mgr.get_or_create_binop (boolean_type_node, EQ_EXPR,
8030 : x_init, y_init)),
8031 : mgr.get_or_create_binop (boolean_type_node, NE_EXPR,
8032 : x_init, y_init));
8033 : /* "!(x > y)" -> "x <= y". */
8034 4 : ASSERT_EQ (mgr.get_or_create_unaryop
8035 : (boolean_type_node, TRUTH_NOT_EXPR,
8036 : mgr.get_or_create_binop (boolean_type_node, GT_EXPR,
8037 : x_init, y_init)),
8038 : mgr.get_or_create_binop (boolean_type_node, LE_EXPR,
8039 : x_init, y_init));
8040 4 : }
8041 :
8042 : /* Verify that binops on constant svalues are folded. */
8043 :
8044 : static void
8045 4 : test_binop_svalue_folding ()
8046 : {
8047 : #define NUM_CSTS 10
8048 4 : tree cst_int[NUM_CSTS];
8049 4 : region_model_manager mgr;
8050 4 : const svalue *cst_sval[NUM_CSTS];
8051 48 : for (int i = 0; i < NUM_CSTS; i++)
8052 : {
8053 40 : cst_int[i] = build_int_cst (integer_type_node, i);
8054 40 : cst_sval[i] = mgr.get_or_create_constant_svalue (cst_int[i]);
8055 40 : ASSERT_EQ (cst_sval[i]->get_kind (), SK_CONSTANT);
8056 40 : ASSERT_EQ (cst_sval[i]->maybe_get_constant (), cst_int[i]);
8057 : }
8058 :
8059 44 : for (int i = 0; i < NUM_CSTS; i++)
8060 440 : for (int j = 0; j < NUM_CSTS; j++)
8061 : {
8062 400 : if (i != j)
8063 360 : ASSERT_NE (cst_sval[i], cst_sval[j]);
8064 400 : if (i + j < NUM_CSTS)
8065 : {
8066 220 : const svalue *sum
8067 220 : = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR,
8068 : cst_sval[i], cst_sval[j]);
8069 220 : ASSERT_EQ (sum, cst_sval[i + j]);
8070 : }
8071 400 : if (i - j >= 0)
8072 : {
8073 220 : const svalue *difference
8074 220 : = mgr.get_or_create_binop (integer_type_node, MINUS_EXPR,
8075 : cst_sval[i], cst_sval[j]);
8076 220 : ASSERT_EQ (difference, cst_sval[i - j]);
8077 : }
8078 400 : if (i * j < NUM_CSTS)
8079 : {
8080 168 : const svalue *product
8081 168 : = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
8082 : cst_sval[i], cst_sval[j]);
8083 168 : ASSERT_EQ (product, cst_sval[i * j]);
8084 : }
8085 400 : const svalue *eq = mgr.get_or_create_binop (integer_type_node, EQ_EXPR,
8086 : cst_sval[i], cst_sval[j]);
8087 400 : ASSERT_EQ (eq, i == j ? cst_sval[1] : cst_sval [0]);
8088 400 : const svalue *neq = mgr.get_or_create_binop (integer_type_node, NE_EXPR,
8089 : cst_sval[i], cst_sval[j]);
8090 400 : ASSERT_EQ (neq, i != j ? cst_sval[1] : cst_sval [0]);
8091 : // etc
8092 : }
8093 :
8094 4 : tree x = build_global_decl ("x", integer_type_node);
8095 :
8096 4 : test_region_model_context ctxt;
8097 4 : region_model model (&mgr);
8098 4 : const svalue *x_init = model.get_rvalue (x, &ctxt);
8099 :
8100 : /* PLUS_EXPR folding. */
8101 4 : const svalue *x_init_plus_zero
8102 4 : = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR,
8103 : x_init, cst_sval[0]);
8104 4 : ASSERT_EQ (x_init_plus_zero, x_init);
8105 4 : const svalue *zero_plus_x_init
8106 4 : = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR,
8107 : cst_sval[0], x_init);
8108 4 : ASSERT_EQ (zero_plus_x_init, x_init);
8109 :
8110 : /* MULT_EXPR folding. */
8111 4 : const svalue *x_init_times_zero
8112 4 : = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
8113 : x_init, cst_sval[0]);
8114 4 : ASSERT_EQ (x_init_times_zero, cst_sval[0]);
8115 4 : const svalue *zero_times_x_init
8116 4 : = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
8117 : cst_sval[0], x_init);
8118 4 : ASSERT_EQ (zero_times_x_init, cst_sval[0]);
8119 :
8120 4 : const svalue *x_init_times_one
8121 4 : = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
8122 : x_init, cst_sval[1]);
8123 4 : ASSERT_EQ (x_init_times_one, x_init);
8124 4 : const svalue *one_times_x_init
8125 4 : = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
8126 : cst_sval[1], x_init);
8127 4 : ASSERT_EQ (one_times_x_init, x_init);
8128 :
8129 : // etc
8130 : // TODO: do we want to use the match-and-simplify DSL for this?
8131 :
8132 : /* Verify that binops put any constants on the RHS. */
8133 4 : const svalue *four_times_x_init
8134 4 : = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
8135 : cst_sval[4], x_init);
8136 4 : const svalue *x_init_times_four
8137 4 : = mgr.get_or_create_binop (integer_type_node, MULT_EXPR,
8138 : x_init, cst_sval[4]);
8139 4 : ASSERT_EQ (four_times_x_init, x_init_times_four);
8140 4 : const binop_svalue *binop = four_times_x_init->dyn_cast_binop_svalue ();
8141 4 : ASSERT_EQ (binop->get_op (), MULT_EXPR);
8142 4 : ASSERT_EQ (binop->get_arg0 (), x_init);
8143 4 : ASSERT_EQ (binop->get_arg1 (), cst_sval[4]);
8144 :
8145 : /* Verify that ((x + 1) + 1) == (x + 2). */
8146 4 : const svalue *x_init_plus_one
8147 4 : = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR,
8148 : x_init, cst_sval[1]);
8149 4 : const svalue *x_init_plus_two
8150 4 : = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR,
8151 : x_init, cst_sval[2]);
8152 4 : const svalue *x_init_plus_one_plus_one
8153 4 : = mgr.get_or_create_binop (integer_type_node, PLUS_EXPR,
8154 : x_init_plus_one, cst_sval[1]);
8155 4 : ASSERT_EQ (x_init_plus_one_plus_one, x_init_plus_two);
8156 :
8157 : /* Verify various binops on booleans. */
8158 4 : {
8159 4 : const svalue *sval_true = mgr.get_or_create_int_cst (boolean_type_node, 1);
8160 4 : const svalue *sval_false = mgr.get_or_create_int_cst (boolean_type_node, 0);
8161 4 : const svalue *sval_unknown
8162 4 : = mgr.get_or_create_unknown_svalue (boolean_type_node);
8163 4 : const placeholder_svalue sval_placeholder (mgr.alloc_symbol_id (),
8164 4 : boolean_type_node, "v");
8165 12 : for (auto op : {BIT_IOR_EXPR, TRUTH_OR_EXPR})
8166 : {
8167 8 : ASSERT_EQ (mgr.get_or_create_binop (boolean_type_node, op,
8168 : sval_true, sval_unknown),
8169 : sval_true);
8170 8 : ASSERT_EQ (mgr.get_or_create_binop (boolean_type_node, op,
8171 : sval_false, sval_unknown),
8172 : sval_unknown);
8173 8 : ASSERT_EQ (mgr.get_or_create_binop (boolean_type_node, op,
8174 : sval_false, &sval_placeholder),
8175 : &sval_placeholder);
8176 : }
8177 12 : for (auto op : {BIT_AND_EXPR, TRUTH_AND_EXPR})
8178 : {
8179 8 : ASSERT_EQ (mgr.get_or_create_binop (boolean_type_node, op,
8180 : sval_false, sval_unknown),
8181 : sval_false);
8182 8 : ASSERT_EQ (mgr.get_or_create_binop (boolean_type_node, op,
8183 : sval_true, sval_unknown),
8184 : sval_unknown);
8185 8 : ASSERT_EQ (mgr.get_or_create_binop (boolean_type_node, op,
8186 : sval_true, &sval_placeholder),
8187 : &sval_placeholder);
8188 : }
8189 4 : }
8190 4 : }
8191 :
8192 : /* Verify that sub_svalues are folded as expected. */
8193 :
8194 : static void
8195 4 : test_sub_svalue_folding ()
8196 : {
8197 4 : coord_test ct;
8198 4 : tree c = build_global_decl ("c", ct.m_coord_type);
8199 4 : tree c_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
8200 : c, ct.m_x_field, NULL_TREE);
8201 :
8202 4 : region_model_manager mgr;
8203 4 : region_model model (&mgr);
8204 4 : test_region_model_context ctxt;
8205 4 : const region *c_x_reg = model.get_lvalue (c_x, &ctxt);
8206 :
8207 : /* Verify that sub_svalue of "unknown" simply
8208 : yields an unknown. */
8209 :
8210 4 : const svalue *unknown = mgr.get_or_create_unknown_svalue (ct.m_coord_type);
8211 4 : const svalue *sub = mgr.get_or_create_sub_svalue (TREE_TYPE (ct.m_x_field),
8212 : unknown, c_x_reg);
8213 4 : ASSERT_EQ (sub->get_kind (), SK_UNKNOWN);
8214 4 : ASSERT_EQ (sub->get_type (), TREE_TYPE (ct.m_x_field));
8215 4 : }
8216 :
8217 : /* Get BIT within VAL as a symbolic value within MGR. */
8218 :
8219 : static const svalue *
8220 256 : get_bit (region_model_manager *mgr,
8221 : bit_offset_t bit,
8222 : unsigned HOST_WIDE_INT val)
8223 : {
8224 256 : const svalue *inner_svalue
8225 256 : = mgr->get_or_create_int_cst (unsigned_type_node, val);
8226 256 : return mgr->get_or_create_bits_within (boolean_type_node,
8227 256 : bit_range (bit, 1),
8228 256 : inner_svalue);
8229 : }
8230 :
8231 : /* Verify that bits_within_svalues are folded as expected. */
8232 :
8233 : static void
8234 4 : test_bits_within_svalue_folding ()
8235 : {
8236 4 : region_model_manager mgr;
8237 :
8238 4 : const svalue *zero = mgr.get_or_create_int_cst (boolean_type_node, 0);
8239 4 : const svalue *one = mgr.get_or_create_int_cst (boolean_type_node, 1);
8240 :
8241 4 : {
8242 4 : const unsigned val = 0x0000;
8243 68 : for (unsigned bit = 0; bit < 16; bit++)
8244 64 : ASSERT_EQ (get_bit (&mgr, bit, val), zero);
8245 : }
8246 :
8247 4 : {
8248 4 : const unsigned val = 0x0001;
8249 4 : ASSERT_EQ (get_bit (&mgr, 0, val), one);
8250 64 : for (unsigned bit = 1; bit < 16; bit++)
8251 60 : ASSERT_EQ (get_bit (&mgr, bit, val), zero);
8252 : }
8253 :
8254 4 : {
8255 4 : const unsigned val = 0x8000;
8256 64 : for (unsigned bit = 0; bit < 15; bit++)
8257 60 : ASSERT_EQ (get_bit (&mgr, bit, val), zero);
8258 4 : ASSERT_EQ (get_bit (&mgr, 15, val), one);
8259 : }
8260 :
8261 4 : {
8262 4 : const unsigned val = 0xFFFF;
8263 68 : for (unsigned bit = 0; bit < 16; bit++)
8264 64 : ASSERT_EQ (get_bit (&mgr, bit, val), one);
8265 : }
8266 4 : }
8267 :
8268 : /* Test that region::descendent_of_p works as expected. */
8269 :
8270 : static void
8271 4 : test_descendent_of_p ()
8272 : {
8273 4 : region_model_manager mgr;
8274 4 : const region *stack = mgr.get_stack_region ();
8275 4 : const region *heap = mgr.get_heap_region ();
8276 4 : const region *code = mgr.get_code_region ();
8277 4 : const region *globals = mgr.get_globals_region ();
8278 :
8279 : /* descendent_of_p should return true when used on the region itself. */
8280 4 : ASSERT_TRUE (stack->descendent_of_p (stack));
8281 4 : ASSERT_FALSE (stack->descendent_of_p (heap));
8282 4 : ASSERT_FALSE (stack->descendent_of_p (code));
8283 4 : ASSERT_FALSE (stack->descendent_of_p (globals));
8284 :
8285 4 : tree x = build_global_decl ("x", integer_type_node);
8286 4 : const region *x_reg = mgr.get_region_for_global (x);
8287 4 : ASSERT_TRUE (x_reg->descendent_of_p (globals));
8288 :
8289 : /* A cast_region should be a descendent of the original region. */
8290 4 : const region *cast_reg = mgr.get_cast_region (x_reg, ptr_type_node);
8291 4 : ASSERT_TRUE (cast_reg->descendent_of_p (x_reg));
8292 4 : }
8293 :
8294 : /* Verify that bit_range_region works as expected. */
8295 :
8296 : static void
8297 4 : test_bit_range_regions ()
8298 : {
8299 4 : tree x = build_global_decl ("x", integer_type_node);
8300 4 : region_model_manager mgr;
8301 4 : const region *x_reg = mgr.get_region_for_global (x);
8302 4 : const region *byte0
8303 4 : = mgr.get_bit_range (x_reg, char_type_node, bit_range (0, 8));
8304 4 : const region *byte1
8305 4 : = mgr.get_bit_range (x_reg, char_type_node, bit_range (8, 8));
8306 4 : ASSERT_TRUE (byte0->descendent_of_p (x_reg));
8307 4 : ASSERT_TRUE (byte1->descendent_of_p (x_reg));
8308 4 : ASSERT_NE (byte0, byte1);
8309 4 : }
8310 :
8311 : /* Verify that simple assignments work as expected. */
8312 :
8313 : static void
8314 4 : test_assignment ()
8315 : {
8316 4 : tree int_0 = integer_zero_node;
8317 4 : tree x = build_global_decl ("x", integer_type_node);
8318 4 : tree y = build_global_decl ("y", integer_type_node);
8319 :
8320 : /* "x == 0", then use of y, then "y = 0;". */
8321 4 : region_model_manager mgr;
8322 4 : region_model model (&mgr);
8323 4 : ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
8324 4 : ASSERT_CONDITION_UNKNOWN (model, y, EQ_EXPR, int_0);
8325 4 : model.set_value (model.get_lvalue (y, nullptr),
8326 : model.get_rvalue (int_0, nullptr),
8327 : nullptr);
8328 4 : ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, int_0);
8329 4 : ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, x);
8330 4 : }
8331 :
8332 : /* Verify that compound assignments work as expected. */
8333 :
8334 : static void
8335 4 : test_compound_assignment ()
8336 : {
8337 4 : coord_test ct;
8338 :
8339 4 : tree c = build_global_decl ("c", ct.m_coord_type);
8340 4 : tree c_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
8341 : c, ct.m_x_field, NULL_TREE);
8342 4 : tree c_y = build3 (COMPONENT_REF, TREE_TYPE (ct.m_y_field),
8343 : c, ct.m_y_field, NULL_TREE);
8344 4 : tree d = build_global_decl ("d", ct.m_coord_type);
8345 4 : tree d_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
8346 : d, ct.m_x_field, NULL_TREE);
8347 4 : tree d_y = build3 (COMPONENT_REF, TREE_TYPE (ct.m_y_field),
8348 : d, ct.m_y_field, NULL_TREE);
8349 :
8350 4 : tree int_17 = build_int_cst (integer_type_node, 17);
8351 4 : tree int_m3 = build_int_cst (integer_type_node, -3);
8352 :
8353 4 : region_model_manager mgr;
8354 4 : region_model model (&mgr);
8355 4 : model.set_value (c_x, int_17, nullptr);
8356 4 : model.set_value (c_y, int_m3, nullptr);
8357 :
8358 : /* Copy c to d. */
8359 4 : const svalue *sval = model.get_rvalue (c, nullptr);
8360 4 : model.set_value (model.get_lvalue (d, nullptr), sval, nullptr);
8361 :
8362 : /* Check that the fields have the same svalues. */
8363 4 : ASSERT_EQ (model.get_rvalue (c_x, nullptr), model.get_rvalue (d_x, nullptr));
8364 4 : ASSERT_EQ (model.get_rvalue (c_y, nullptr), model.get_rvalue (d_y, nullptr));
8365 4 : }
8366 :
8367 : /* Verify the details of pushing and popping stack frames. */
8368 :
8369 : static void
8370 4 : test_stack_frames ()
8371 : {
8372 4 : tree int_42 = build_int_cst (integer_type_node, 42);
8373 4 : tree int_10 = build_int_cst (integer_type_node, 10);
8374 4 : tree int_5 = build_int_cst (integer_type_node, 5);
8375 4 : tree int_0 = integer_zero_node;
8376 :
8377 4 : auto_vec <tree> param_types;
8378 4 : tree parent_fndecl = make_fndecl (integer_type_node,
8379 : "parent_fn",
8380 : param_types);
8381 4 : allocate_struct_function (parent_fndecl, true);
8382 :
8383 4 : tree child_fndecl = make_fndecl (integer_type_node,
8384 : "child_fn",
8385 : param_types);
8386 4 : allocate_struct_function (child_fndecl, true);
8387 :
8388 : /* "a" and "b" in the parent frame. */
8389 4 : tree a = build_decl (UNKNOWN_LOCATION, PARM_DECL,
8390 : get_identifier ("a"),
8391 : integer_type_node);
8392 4 : DECL_CONTEXT (a) = parent_fndecl;
8393 4 : tree b = build_decl (UNKNOWN_LOCATION, PARM_DECL,
8394 : get_identifier ("b"),
8395 : integer_type_node);
8396 4 : DECL_CONTEXT (b) = parent_fndecl;
8397 : /* "x" and "y" in a child frame. */
8398 4 : tree x = build_decl (UNKNOWN_LOCATION, PARM_DECL,
8399 : get_identifier ("x"),
8400 : integer_type_node);
8401 4 : DECL_CONTEXT (x) = child_fndecl;
8402 4 : tree y = build_decl (UNKNOWN_LOCATION, PARM_DECL,
8403 : get_identifier ("y"),
8404 : integer_type_node);
8405 4 : DECL_CONTEXT (y) = child_fndecl;
8406 :
8407 : /* "p" global. */
8408 4 : tree p = build_global_decl ("p", ptr_type_node);
8409 :
8410 : /* "q" global. */
8411 4 : tree q = build_global_decl ("q", ptr_type_node);
8412 :
8413 4 : region_model_manager mgr;
8414 4 : test_region_model_context ctxt;
8415 4 : region_model model (&mgr);
8416 :
8417 : /* Push stack frame for "parent_fn". */
8418 4 : const region *parent_frame_reg
8419 4 : = model.push_frame (*DECL_STRUCT_FUNCTION (parent_fndecl),
8420 : nullptr, nullptr, &ctxt);
8421 4 : ASSERT_EQ (model.get_current_frame (), parent_frame_reg);
8422 4 : ASSERT_TRUE (model.region_exists_p (parent_frame_reg));
8423 4 : const region *a_in_parent_reg = model.get_lvalue (a, &ctxt);
8424 4 : model.set_value (a_in_parent_reg,
8425 : model.get_rvalue (int_42, &ctxt),
8426 : &ctxt);
8427 4 : ASSERT_EQ (a_in_parent_reg->maybe_get_frame_region (), parent_frame_reg);
8428 :
8429 4 : model.add_constraint (b, LT_EXPR, int_10, &ctxt);
8430 4 : ASSERT_EQ (model.eval_condition (b, LT_EXPR, int_10, &ctxt),
8431 : tristate (tristate::TS_TRUE));
8432 :
8433 : /* Push stack frame for "child_fn". */
8434 4 : const region *child_frame_reg
8435 4 : = model.push_frame (*DECL_STRUCT_FUNCTION (child_fndecl),
8436 : nullptr, nullptr, &ctxt);
8437 4 : ASSERT_EQ (model.get_current_frame (), child_frame_reg);
8438 4 : ASSERT_TRUE (model.region_exists_p (child_frame_reg));
8439 4 : const region *x_in_child_reg = model.get_lvalue (x, &ctxt);
8440 4 : model.set_value (x_in_child_reg,
8441 : model.get_rvalue (int_0, &ctxt),
8442 : &ctxt);
8443 4 : ASSERT_EQ (x_in_child_reg->maybe_get_frame_region (), child_frame_reg);
8444 :
8445 4 : model.add_constraint (y, NE_EXPR, int_5, &ctxt);
8446 4 : ASSERT_EQ (model.eval_condition (y, NE_EXPR, int_5, &ctxt),
8447 : tristate (tristate::TS_TRUE));
8448 :
8449 : /* Point a global pointer at a local in the child frame: p = &x. */
8450 4 : const region *p_in_globals_reg = model.get_lvalue (p, &ctxt);
8451 4 : model.set_value (p_in_globals_reg,
8452 : mgr.get_ptr_svalue (ptr_type_node, x_in_child_reg),
8453 : &ctxt);
8454 4 : ASSERT_EQ (p_in_globals_reg->maybe_get_frame_region (), nullptr);
8455 :
8456 : /* Point another global pointer at p: q = &p. */
8457 4 : const region *q_in_globals_reg = model.get_lvalue (q, &ctxt);
8458 4 : model.set_value (q_in_globals_reg,
8459 : mgr.get_ptr_svalue (ptr_type_node, p_in_globals_reg),
8460 : &ctxt);
8461 :
8462 : /* Test region::descendent_of_p. */
8463 4 : ASSERT_TRUE (child_frame_reg->descendent_of_p (child_frame_reg));
8464 4 : ASSERT_TRUE (x_in_child_reg->descendent_of_p (child_frame_reg));
8465 4 : ASSERT_FALSE (a_in_parent_reg->descendent_of_p (child_frame_reg));
8466 :
8467 : /* Pop the "child_fn" frame from the stack. */
8468 4 : model.pop_frame (nullptr, nullptr, &ctxt, nullptr);
8469 4 : ASSERT_FALSE (model.region_exists_p (child_frame_reg));
8470 4 : ASSERT_TRUE (model.region_exists_p (parent_frame_reg));
8471 :
8472 : /* Verify that p (which was pointing at the local "x" in the popped
8473 : frame) has been poisoned. */
8474 4 : const svalue *new_p_sval = model.get_rvalue (p, nullptr);
8475 4 : ASSERT_EQ (new_p_sval->get_kind (), SK_POISONED);
8476 4 : ASSERT_EQ (new_p_sval->dyn_cast_poisoned_svalue ()->get_poison_kind (),
8477 : poison_kind::popped_stack);
8478 :
8479 : /* Verify that q still points to p, in spite of the region
8480 : renumbering. */
8481 4 : const svalue *new_q_sval = model.get_rvalue (q, &ctxt);
8482 4 : ASSERT_EQ (new_q_sval->get_kind (), SK_REGION);
8483 4 : ASSERT_EQ (new_q_sval->maybe_get_region (),
8484 : model.get_lvalue (p, &ctxt));
8485 :
8486 : /* Verify that top of stack has been updated. */
8487 4 : ASSERT_EQ (model.get_current_frame (), parent_frame_reg);
8488 :
8489 : /* Verify locals in parent frame. */
8490 : /* Verify "a" still has its value. */
8491 4 : const svalue *new_a_sval = model.get_rvalue (a, &ctxt);
8492 4 : ASSERT_EQ (new_a_sval->get_kind (), SK_CONSTANT);
8493 4 : ASSERT_EQ (new_a_sval->dyn_cast_constant_svalue ()->get_constant (),
8494 : int_42);
8495 : /* Verify "b" still has its constraint. */
8496 4 : ASSERT_EQ (model.eval_condition (b, LT_EXPR, int_10, &ctxt),
8497 : tristate (tristate::TS_TRUE));
8498 4 : }
8499 :
8500 : /* Verify that get_representative_path_var works as expected, that
8501 : we can map from regions to parms and back within a recursive call
8502 : stack. */
8503 :
8504 : static void
8505 4 : test_get_representative_path_var ()
8506 : {
8507 4 : auto_vec <tree> param_types;
8508 4 : tree fndecl = make_fndecl (integer_type_node,
8509 : "factorial",
8510 : param_types);
8511 4 : allocate_struct_function (fndecl, true);
8512 :
8513 : /* Parm "n". */
8514 4 : tree n = build_decl (UNKNOWN_LOCATION, PARM_DECL,
8515 : get_identifier ("n"),
8516 : integer_type_node);
8517 4 : DECL_CONTEXT (n) = fndecl;
8518 :
8519 4 : region_model_manager mgr;
8520 4 : test_region_model_context ctxt;
8521 4 : region_model model (&mgr);
8522 :
8523 : /* Push 5 stack frames for "factorial", each with a param */
8524 4 : auto_vec<const region *> parm_regs;
8525 4 : auto_vec<const svalue *> parm_svals;
8526 24 : for (int depth = 0; depth < 5; depth++)
8527 : {
8528 20 : const region *frame_n_reg
8529 20 : = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl),
8530 : nullptr, nullptr, &ctxt);
8531 20 : const region *parm_n_reg = model.get_lvalue (path_var (n, depth), &ctxt);
8532 20 : parm_regs.safe_push (parm_n_reg);
8533 :
8534 20 : ASSERT_EQ (parm_n_reg->get_parent_region (), frame_n_reg);
8535 20 : const svalue *sval_n = mgr.get_or_create_initial_value (parm_n_reg);
8536 20 : parm_svals.safe_push (sval_n);
8537 : }
8538 :
8539 : /* Verify that we can recognize that the regions are the parms,
8540 : at every depth. */
8541 24 : for (int depth = 0; depth < 5; depth++)
8542 : {
8543 20 : {
8544 20 : svalue_set visited;
8545 40 : ASSERT_EQ (model.get_representative_path_var (parm_regs[depth],
8546 : &visited,
8547 : nullptr),
8548 : path_var (n, depth + 1));
8549 20 : }
8550 : /* ...and that we can lookup lvalues for locals for all frames,
8551 : not just the top. */
8552 20 : ASSERT_EQ (model.get_lvalue (path_var (n, depth), nullptr),
8553 : parm_regs[depth]);
8554 : /* ...and that we can locate the svalues. */
8555 20 : {
8556 20 : svalue_set visited;
8557 40 : ASSERT_EQ (model.get_representative_path_var (parm_svals[depth],
8558 : &visited,
8559 : nullptr),
8560 : path_var (n, depth + 1));
8561 20 : }
8562 : }
8563 4 : }
8564 :
8565 : /* Ensure that region_model::operator== works as expected. */
8566 :
8567 : static void
8568 4 : test_equality_1 ()
8569 : {
8570 4 : tree int_42 = build_int_cst (integer_type_node, 42);
8571 4 : tree int_17 = build_int_cst (integer_type_node, 17);
8572 :
8573 : /* Verify that "empty" region_model instances are equal to each other. */
8574 4 : region_model_manager mgr;
8575 4 : region_model model0 (&mgr);
8576 4 : region_model model1 (&mgr);
8577 4 : ASSERT_EQ (model0, model1);
8578 :
8579 : /* Verify that setting state in model1 makes the models non-equal. */
8580 4 : tree x = build_global_decl ("x", integer_type_node);
8581 4 : model0.set_value (x, int_42, nullptr);
8582 4 : ASSERT_EQ (model0.get_rvalue (x, nullptr)->maybe_get_constant (), int_42);
8583 4 : ASSERT_NE (model0, model1);
8584 :
8585 : /* Verify the copy-ctor. */
8586 4 : region_model model2 (model0);
8587 4 : ASSERT_EQ (model0, model2);
8588 4 : ASSERT_EQ (model2.get_rvalue (x, nullptr)->maybe_get_constant (), int_42);
8589 4 : ASSERT_NE (model1, model2);
8590 :
8591 : /* Verify that models obtained from copy-ctor are independently editable
8592 : w/o affecting the original model. */
8593 4 : model2.set_value (x, int_17, nullptr);
8594 4 : ASSERT_NE (model0, model2);
8595 4 : ASSERT_EQ (model2.get_rvalue (x, nullptr)->maybe_get_constant (), int_17);
8596 4 : ASSERT_EQ (model0.get_rvalue (x, nullptr)->maybe_get_constant (), int_42);
8597 4 : }
8598 :
8599 : /* Verify that region models for
8600 : x = 42; y = 113;
8601 : and
8602 : y = 113; x = 42;
8603 : are equal. */
8604 :
8605 : static void
8606 4 : test_canonicalization_2 ()
8607 : {
8608 4 : tree int_42 = build_int_cst (integer_type_node, 42);
8609 4 : tree int_113 = build_int_cst (integer_type_node, 113);
8610 4 : tree x = build_global_decl ("x", integer_type_node);
8611 4 : tree y = build_global_decl ("y", integer_type_node);
8612 :
8613 4 : region_model_manager mgr;
8614 4 : region_model model0 (&mgr);
8615 4 : model0.set_value (model0.get_lvalue (x, nullptr),
8616 : model0.get_rvalue (int_42, nullptr),
8617 : nullptr);
8618 4 : model0.set_value (model0.get_lvalue (y, nullptr),
8619 : model0.get_rvalue (int_113, nullptr),
8620 : nullptr);
8621 :
8622 4 : region_model model1 (&mgr);
8623 4 : model1.set_value (model1.get_lvalue (y, nullptr),
8624 : model1.get_rvalue (int_113, nullptr),
8625 : nullptr);
8626 4 : model1.set_value (model1.get_lvalue (x, nullptr),
8627 : model1.get_rvalue (int_42, nullptr),
8628 : nullptr);
8629 :
8630 4 : ASSERT_EQ (model0, model1);
8631 4 : }
8632 :
8633 : /* Verify that constraints for
8634 : x > 3 && y > 42
8635 : and
8636 : y > 42 && x > 3
8637 : are equal after canonicalization. */
8638 :
8639 : static void
8640 4 : test_canonicalization_3 ()
8641 : {
8642 4 : tree int_3 = build_int_cst (integer_type_node, 3);
8643 4 : tree int_42 = build_int_cst (integer_type_node, 42);
8644 4 : tree x = build_global_decl ("x", integer_type_node);
8645 4 : tree y = build_global_decl ("y", integer_type_node);
8646 :
8647 4 : region_model_manager mgr;
8648 4 : region_model model0 (&mgr);
8649 4 : model0.add_constraint (x, GT_EXPR, int_3, nullptr);
8650 4 : model0.add_constraint (y, GT_EXPR, int_42, nullptr);
8651 :
8652 4 : region_model model1 (&mgr);
8653 4 : model1.add_constraint (y, GT_EXPR, int_42, nullptr);
8654 4 : model1.add_constraint (x, GT_EXPR, int_3, nullptr);
8655 :
8656 4 : model0.canonicalize ();
8657 4 : model1.canonicalize ();
8658 4 : ASSERT_EQ (model0, model1);
8659 4 : }
8660 :
8661 : /* Verify that we can canonicalize a model containing NaN and other real
8662 : constants. */
8663 :
8664 : static void
8665 4 : test_canonicalization_4 ()
8666 : {
8667 4 : auto_vec<tree> csts;
8668 4 : append_interesting_constants (&csts);
8669 :
8670 4 : region_model_manager mgr;
8671 4 : region_model model (&mgr);
8672 :
8673 60 : for (tree cst : csts)
8674 48 : model.get_rvalue (cst, nullptr);
8675 :
8676 4 : model.canonicalize ();
8677 4 : }
8678 :
8679 : /* Assert that if we have two region_model instances
8680 : with values VAL_A and VAL_B for EXPR that they are
8681 : mergeable. Write the merged model to *OUT_MERGED_MODEL,
8682 : and the merged svalue ptr to *OUT_MERGED_SVALUE.
8683 : If VAL_A or VAL_B are nullptr_TREE, don't populate EXPR
8684 : for that region_model. */
8685 :
8686 : static void
8687 20 : assert_region_models_merge (tree expr, tree val_a, tree val_b,
8688 : region_model *out_merged_model,
8689 : const svalue **out_merged_svalue)
8690 : {
8691 20 : region_model_manager *mgr = out_merged_model->get_manager ();
8692 20 : program_point point (program_point::origin (*mgr));
8693 20 : test_region_model_context ctxt;
8694 20 : region_model model0 (mgr);
8695 20 : region_model model1 (mgr);
8696 20 : if (val_a)
8697 16 : model0.set_value (model0.get_lvalue (expr, &ctxt),
8698 : model0.get_rvalue (val_a, &ctxt),
8699 : &ctxt);
8700 20 : if (val_b)
8701 16 : model1.set_value (model1.get_lvalue (expr, &ctxt),
8702 : model1.get_rvalue (val_b, &ctxt),
8703 : &ctxt);
8704 :
8705 : /* They should be mergeable. */
8706 20 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, out_merged_model));
8707 20 : *out_merged_svalue = out_merged_model->get_rvalue (expr, &ctxt);
8708 20 : }
8709 :
8710 : /* Verify that we can merge region_model instances. */
8711 :
8712 : static void
8713 4 : test_state_merging ()
8714 : {
8715 4 : tree int_42 = build_int_cst (integer_type_node, 42);
8716 4 : tree int_113 = build_int_cst (integer_type_node, 113);
8717 4 : tree x = build_global_decl ("x", integer_type_node);
8718 4 : tree y = build_global_decl ("y", integer_type_node);
8719 4 : tree z = build_global_decl ("z", integer_type_node);
8720 4 : tree p = build_global_decl ("p", ptr_type_node);
8721 :
8722 4 : tree addr_of_y = build1 (ADDR_EXPR, ptr_type_node, y);
8723 4 : tree addr_of_z = build1 (ADDR_EXPR, ptr_type_node, z);
8724 :
8725 4 : auto_vec <tree> param_types;
8726 4 : tree test_fndecl = make_fndecl (integer_type_node, "test_fn", param_types);
8727 4 : allocate_struct_function (test_fndecl, true);
8728 :
8729 : /* Param "a". */
8730 4 : tree a = build_decl (UNKNOWN_LOCATION, PARM_DECL,
8731 : get_identifier ("a"),
8732 : integer_type_node);
8733 4 : DECL_CONTEXT (a) = test_fndecl;
8734 4 : tree addr_of_a = build1 (ADDR_EXPR, ptr_type_node, a);
8735 :
8736 : /* Param "q", a pointer. */
8737 4 : tree q = build_decl (UNKNOWN_LOCATION, PARM_DECL,
8738 : get_identifier ("q"),
8739 : ptr_type_node);
8740 4 : DECL_CONTEXT (q) = test_fndecl;
8741 :
8742 4 : region_model_manager mgr;
8743 4 : program_point point (program_point::origin (mgr));
8744 :
8745 4 : {
8746 4 : region_model model0 (&mgr);
8747 4 : region_model model1 (&mgr);
8748 4 : region_model merged (&mgr);
8749 : /* Verify empty models can be merged. */
8750 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
8751 4 : ASSERT_EQ (model0, merged);
8752 4 : }
8753 :
8754 : /* Verify that we can merge two contradictory constraints on the
8755 : value for a global. */
8756 : /* TODO: verify that the merged model doesn't have a value for
8757 : the global */
8758 4 : {
8759 4 : region_model model0 (&mgr);
8760 4 : region_model model1 (&mgr);
8761 4 : region_model merged (&mgr);
8762 4 : test_region_model_context ctxt;
8763 4 : model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
8764 4 : model1.add_constraint (x, EQ_EXPR, int_113, &ctxt);
8765 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
8766 4 : ASSERT_NE (model0, merged);
8767 4 : ASSERT_NE (model1, merged);
8768 4 : }
8769 :
8770 : /* Verify handling of a PARM_DECL. */
8771 4 : {
8772 4 : test_region_model_context ctxt;
8773 4 : region_model model0 (&mgr);
8774 4 : region_model model1 (&mgr);
8775 4 : ASSERT_EQ (model0.get_stack_depth (), 0);
8776 4 : model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
8777 : nullptr, nullptr, &ctxt);
8778 4 : ASSERT_EQ (model0.get_stack_depth (), 1);
8779 4 : model1.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
8780 : nullptr, nullptr, &ctxt);
8781 :
8782 4 : placeholder_svalue test_sval (mgr.alloc_symbol_id (),
8783 4 : integer_type_node, "test sval");
8784 4 : model0.set_value (model0.get_lvalue (a, &ctxt), &test_sval, &ctxt);
8785 4 : model1.set_value (model1.get_lvalue (a, &ctxt), &test_sval, &ctxt);
8786 4 : ASSERT_EQ (model0, model1);
8787 :
8788 : /* They should be mergeable, and the result should be the same. */
8789 4 : region_model merged (&mgr);
8790 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
8791 4 : ASSERT_EQ (model0, merged);
8792 : /* In particular, "a" should have the placeholder value. */
8793 4 : ASSERT_EQ (merged.get_rvalue (a, &ctxt), &test_sval);
8794 4 : }
8795 :
8796 : /* Verify handling of a global. */
8797 4 : {
8798 4 : test_region_model_context ctxt;
8799 4 : region_model model0 (&mgr);
8800 4 : region_model model1 (&mgr);
8801 :
8802 4 : placeholder_svalue test_sval (mgr.alloc_symbol_id (),
8803 4 : integer_type_node, "test sval");
8804 4 : model0.set_value (model0.get_lvalue (x, &ctxt), &test_sval, &ctxt);
8805 4 : model1.set_value (model1.get_lvalue (x, &ctxt), &test_sval, &ctxt);
8806 4 : ASSERT_EQ (model0, model1);
8807 :
8808 : /* They should be mergeable, and the result should be the same. */
8809 4 : region_model merged (&mgr);
8810 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
8811 4 : ASSERT_EQ (model0, merged);
8812 : /* In particular, "x" should have the placeholder value. */
8813 4 : ASSERT_EQ (merged.get_rvalue (x, &ctxt), &test_sval);
8814 4 : }
8815 :
8816 : /* Use global-handling to verify various combinations of values. */
8817 :
8818 : /* Two equal constant values. */
8819 4 : {
8820 4 : region_model merged (&mgr);
8821 4 : const svalue *merged_x_sval;
8822 4 : assert_region_models_merge (x, int_42, int_42, &merged, &merged_x_sval);
8823 :
8824 : /* In particular, there should be a constant value for "x". */
8825 4 : ASSERT_EQ (merged_x_sval->get_kind (), SK_CONSTANT);
8826 4 : ASSERT_EQ (merged_x_sval->dyn_cast_constant_svalue ()->get_constant (),
8827 : int_42);
8828 4 : }
8829 :
8830 : /* Two non-equal constant values. */
8831 4 : {
8832 4 : region_model merged (&mgr);
8833 4 : const svalue *merged_x_sval;
8834 4 : assert_region_models_merge (x, int_42, int_113, &merged, &merged_x_sval);
8835 :
8836 : /* In particular, there should be a "widening" value for "x". */
8837 4 : ASSERT_EQ (merged_x_sval->get_kind (), SK_WIDENING);
8838 4 : }
8839 :
8840 : /* Initial and constant. */
8841 4 : {
8842 4 : region_model merged (&mgr);
8843 4 : const svalue *merged_x_sval;
8844 4 : assert_region_models_merge (x, NULL_TREE, int_113, &merged, &merged_x_sval);
8845 :
8846 : /* In particular, there should be an unknown value for "x". */
8847 4 : ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
8848 4 : }
8849 :
8850 : /* Constant and initial. */
8851 4 : {
8852 4 : region_model merged (&mgr);
8853 4 : const svalue *merged_x_sval;
8854 4 : assert_region_models_merge (x, int_42, NULL_TREE, &merged, &merged_x_sval);
8855 :
8856 : /* In particular, there should be an unknown value for "x". */
8857 4 : ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
8858 4 : }
8859 :
8860 : /* Unknown and constant. */
8861 : // TODO
8862 :
8863 : /* Pointers: NULL and NULL. */
8864 : // TODO
8865 :
8866 : /* Pointers: NULL and non-NULL. */
8867 : // TODO
8868 :
8869 : /* Pointers: non-NULL and non-NULL: ptr to a local. */
8870 4 : {
8871 4 : region_model model0 (&mgr);
8872 4 : model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
8873 : nullptr, nullptr, nullptr);
8874 4 : model0.set_value (model0.get_lvalue (p, nullptr),
8875 : model0.get_rvalue (addr_of_a, nullptr), nullptr);
8876 :
8877 4 : region_model model1 (model0);
8878 4 : ASSERT_EQ (model0, model1);
8879 :
8880 : /* They should be mergeable, and the result should be the same. */
8881 4 : region_model merged (&mgr);
8882 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
8883 4 : ASSERT_EQ (model0, merged);
8884 4 : }
8885 :
8886 : /* Pointers: non-NULL and non-NULL: ptr to a global. */
8887 4 : {
8888 4 : region_model merged (&mgr);
8889 : /* p == &y in both input models. */
8890 4 : const svalue *merged_p_sval;
8891 4 : assert_region_models_merge (p, addr_of_y, addr_of_y, &merged,
8892 : &merged_p_sval);
8893 :
8894 : /* We should get p == &y in the merged model. */
8895 4 : ASSERT_EQ (merged_p_sval->get_kind (), SK_REGION);
8896 4 : const region_svalue *merged_p_ptr
8897 4 : = merged_p_sval->dyn_cast_region_svalue ();
8898 4 : const region *merged_p_star_reg = merged_p_ptr->get_pointee ();
8899 4 : ASSERT_EQ (merged_p_star_reg, merged.get_lvalue (y, nullptr));
8900 4 : }
8901 :
8902 : /* Pointers: non-NULL ptrs to different globals should not merge;
8903 : see e.g. gcc.dg/analyzer/torture/uninit-pr108725.c */
8904 4 : {
8905 4 : region_model merged_model (&mgr);
8906 4 : program_point point (program_point::origin (mgr));
8907 4 : test_region_model_context ctxt;
8908 : /* x == &y vs x == &z in the input models; these are actually casts
8909 : of the ptrs to "int". */
8910 4 : region_model model0 (&mgr);
8911 4 : region_model model1 (&mgr);
8912 4 : model0.set_value (model0.get_lvalue (x, &ctxt),
8913 : model0.get_rvalue (addr_of_y, &ctxt),
8914 : &ctxt);
8915 4 : model1.set_value (model1.get_lvalue (x, &ctxt),
8916 : model1.get_rvalue (addr_of_z, &ctxt),
8917 : &ctxt);
8918 : /* They should not be mergeable. */
8919 4 : ASSERT_FALSE (model0.can_merge_with_p (model1, point, &merged_model));
8920 4 : }
8921 :
8922 : /* Pointers: non-NULL and non-NULL: ptr to a heap region. */
8923 4 : {
8924 4 : test_region_model_context ctxt;
8925 4 : region_model model0 (&mgr);
8926 4 : tree size = build_int_cst (size_type_node, 1024);
8927 4 : const svalue *size_sval = mgr.get_or_create_constant_svalue (size);
8928 4 : const region *new_reg
8929 4 : = model0.get_or_create_region_for_heap_alloc (size_sval, &ctxt);
8930 4 : const svalue *ptr_sval = mgr.get_ptr_svalue (ptr_type_node, new_reg);
8931 4 : model0.set_value (model0.get_lvalue (p, &ctxt),
8932 : ptr_sval, &ctxt);
8933 :
8934 4 : region_model model1 (model0);
8935 :
8936 4 : ASSERT_EQ (model0, model1);
8937 :
8938 4 : region_model merged (&mgr);
8939 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
8940 :
8941 : /* The merged model ought to be identical. */
8942 4 : ASSERT_EQ (model0, merged);
8943 4 : }
8944 :
8945 : /* Two regions sharing the same placeholder svalue should continue sharing
8946 : it after self-merger. */
8947 4 : {
8948 4 : test_region_model_context ctxt;
8949 4 : region_model model0 (&mgr);
8950 4 : placeholder_svalue placeholder_sval (mgr.alloc_symbol_id (),
8951 4 : integer_type_node, "test");
8952 4 : model0.set_value (model0.get_lvalue (x, &ctxt),
8953 : &placeholder_sval, &ctxt);
8954 4 : model0.set_value (model0.get_lvalue (y, &ctxt), &placeholder_sval, &ctxt);
8955 4 : region_model model1 (model0);
8956 :
8957 : /* They should be mergeable, and the result should be the same. */
8958 4 : region_model merged (&mgr);
8959 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
8960 4 : ASSERT_EQ (model0, merged);
8961 :
8962 : /* In particular, we should have x == y. */
8963 4 : ASSERT_EQ (merged.eval_condition (x, EQ_EXPR, y, &ctxt),
8964 : tristate (tristate::TS_TRUE));
8965 4 : }
8966 :
8967 4 : {
8968 4 : region_model model0 (&mgr);
8969 4 : region_model model1 (&mgr);
8970 4 : test_region_model_context ctxt;
8971 4 : model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
8972 4 : model1.add_constraint (x, NE_EXPR, int_42, &ctxt);
8973 4 : region_model merged (&mgr);
8974 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
8975 4 : }
8976 :
8977 4 : {
8978 4 : region_model model0 (&mgr);
8979 4 : region_model model1 (&mgr);
8980 4 : test_region_model_context ctxt;
8981 4 : model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
8982 4 : model1.add_constraint (x, NE_EXPR, int_42, &ctxt);
8983 4 : model1.add_constraint (x, EQ_EXPR, int_113, &ctxt);
8984 4 : region_model merged (&mgr);
8985 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
8986 4 : }
8987 :
8988 : // TODO: what can't we merge? need at least one such test
8989 :
8990 : /* TODO: various things
8991 : - heap regions
8992 : - value merging:
8993 : - every combination, but in particular
8994 : - pairs of regions
8995 : */
8996 :
8997 : /* Views. */
8998 4 : {
8999 4 : test_region_model_context ctxt;
9000 4 : region_model model0 (&mgr);
9001 :
9002 4 : const region *x_reg = model0.get_lvalue (x, &ctxt);
9003 4 : const region *x_as_ptr = mgr.get_cast_region (x_reg, ptr_type_node);
9004 4 : model0.set_value (x_as_ptr, model0.get_rvalue (addr_of_y, &ctxt), &ctxt);
9005 :
9006 4 : region_model model1 (model0);
9007 4 : ASSERT_EQ (model1, model0);
9008 :
9009 : /* They should be mergeable, and the result should be the same. */
9010 4 : region_model merged (&mgr);
9011 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
9012 4 : }
9013 :
9014 : /* Verify that we can merge a model in which a local in an older stack
9015 : frame points to a local in a more recent stack frame. */
9016 4 : {
9017 4 : region_model model0 (&mgr);
9018 4 : model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
9019 : nullptr, nullptr, nullptr);
9020 4 : const region *q_in_first_frame = model0.get_lvalue (q, nullptr);
9021 :
9022 : /* Push a second frame. */
9023 4 : const region *reg_2nd_frame
9024 4 : = model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
9025 : nullptr, nullptr, nullptr);
9026 :
9027 : /* Have a pointer in the older frame point to a local in the
9028 : more recent frame. */
9029 4 : const svalue *sval_ptr = model0.get_rvalue (addr_of_a, nullptr);
9030 4 : model0.set_value (q_in_first_frame, sval_ptr, nullptr);
9031 :
9032 : /* Verify that it's pointing at the newer frame. */
9033 4 : const region *reg_pointee = sval_ptr->maybe_get_region ();
9034 4 : ASSERT_EQ (reg_pointee->get_parent_region (), reg_2nd_frame);
9035 :
9036 4 : model0.canonicalize ();
9037 :
9038 4 : region_model model1 (model0);
9039 4 : ASSERT_EQ (model0, model1);
9040 :
9041 : /* They should be mergeable, and the result should be the same
9042 : (after canonicalization, at least). */
9043 4 : region_model merged (&mgr);
9044 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
9045 4 : merged.canonicalize ();
9046 4 : ASSERT_EQ (model0, merged);
9047 4 : }
9048 :
9049 : /* Verify that we can merge a model in which a local points to a global. */
9050 4 : {
9051 4 : region_model model0 (&mgr);
9052 4 : model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
9053 : nullptr, nullptr, nullptr);
9054 4 : model0.set_value (model0.get_lvalue (q, nullptr),
9055 : model0.get_rvalue (addr_of_y, nullptr), nullptr);
9056 :
9057 4 : region_model model1 (model0);
9058 4 : ASSERT_EQ (model0, model1);
9059 :
9060 : /* They should be mergeable, and the result should be the same
9061 : (after canonicalization, at least). */
9062 4 : region_model merged (&mgr);
9063 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
9064 4 : ASSERT_EQ (model0, merged);
9065 4 : }
9066 4 : }
9067 :
9068 : /* Verify that constraints are correctly merged when merging region_model
9069 : instances. */
9070 :
9071 : static void
9072 4 : test_constraint_merging ()
9073 : {
9074 4 : tree int_0 = integer_zero_node;
9075 4 : tree int_5 = build_int_cst (integer_type_node, 5);
9076 4 : tree x = build_global_decl ("x", integer_type_node);
9077 4 : tree y = build_global_decl ("y", integer_type_node);
9078 4 : tree z = build_global_decl ("z", integer_type_node);
9079 4 : tree n = build_global_decl ("n", integer_type_node);
9080 :
9081 4 : region_model_manager mgr;
9082 4 : test_region_model_context ctxt;
9083 :
9084 : /* model0: 0 <= (x == y) < n. */
9085 4 : region_model model0 (&mgr);
9086 4 : model0.add_constraint (x, EQ_EXPR, y, &ctxt);
9087 4 : model0.add_constraint (x, GE_EXPR, int_0, nullptr);
9088 4 : model0.add_constraint (x, LT_EXPR, n, nullptr);
9089 :
9090 : /* model1: z != 5 && (0 <= x < n). */
9091 4 : region_model model1 (&mgr);
9092 4 : model1.add_constraint (z, NE_EXPR, int_5, nullptr);
9093 4 : model1.add_constraint (x, GE_EXPR, int_0, nullptr);
9094 4 : model1.add_constraint (x, LT_EXPR, n, nullptr);
9095 :
9096 : /* They should be mergeable; the merged constraints should
9097 : be: (0 <= x < n). */
9098 4 : program_point point (program_point::origin (mgr));
9099 4 : region_model merged (&mgr);
9100 4 : ASSERT_TRUE (model0.can_merge_with_p (model1, point, &merged));
9101 :
9102 4 : ASSERT_EQ (merged.eval_condition (x, GE_EXPR, int_0, &ctxt),
9103 : tristate (tristate::TS_TRUE));
9104 4 : ASSERT_EQ (merged.eval_condition (x, LT_EXPR, n, &ctxt),
9105 : tristate (tristate::TS_TRUE));
9106 :
9107 4 : ASSERT_EQ (merged.eval_condition (z, NE_EXPR, int_5, &ctxt),
9108 : tristate (tristate::TS_UNKNOWN));
9109 4 : ASSERT_EQ (merged.eval_condition (x, LT_EXPR, y, &ctxt),
9110 : tristate (tristate::TS_UNKNOWN));
9111 4 : }
9112 :
9113 : /* Verify that widening_svalue::eval_condition_without_cm works as
9114 : expected. */
9115 :
9116 : static void
9117 4 : test_widening_constraints ()
9118 : {
9119 4 : region_model_manager mgr;
9120 4 : const supernode *snode = nullptr;
9121 4 : tree int_0 = integer_zero_node;
9122 4 : tree int_m1 = build_int_cst (integer_type_node, -1);
9123 4 : tree int_1 = integer_one_node;
9124 4 : tree int_256 = build_int_cst (integer_type_node, 256);
9125 4 : test_region_model_context ctxt;
9126 4 : const svalue *int_0_sval = mgr.get_or_create_constant_svalue (int_0);
9127 4 : const svalue *int_1_sval = mgr.get_or_create_constant_svalue (int_1);
9128 4 : const svalue *w_zero_then_one_sval
9129 4 : = mgr.get_or_create_widening_svalue (integer_type_node, snode,
9130 : int_0_sval, int_1_sval);
9131 4 : const widening_svalue *w_zero_then_one
9132 4 : = w_zero_then_one_sval->dyn_cast_widening_svalue ();
9133 4 : ASSERT_EQ (w_zero_then_one->get_direction (),
9134 : widening_svalue::DIR_ASCENDING);
9135 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LT_EXPR, int_m1),
9136 : tristate::TS_FALSE);
9137 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LT_EXPR, int_0),
9138 : tristate::TS_FALSE);
9139 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LT_EXPR, int_1),
9140 : tristate::TS_UNKNOWN);
9141 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LT_EXPR, int_256),
9142 : tristate::TS_UNKNOWN);
9143 :
9144 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LE_EXPR, int_m1),
9145 : tristate::TS_FALSE);
9146 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LE_EXPR, int_0),
9147 : tristate::TS_UNKNOWN);
9148 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LE_EXPR, int_1),
9149 : tristate::TS_UNKNOWN);
9150 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (LE_EXPR, int_256),
9151 : tristate::TS_UNKNOWN);
9152 :
9153 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GT_EXPR, int_m1),
9154 : tristate::TS_TRUE);
9155 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GT_EXPR, int_0),
9156 : tristate::TS_UNKNOWN);
9157 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GT_EXPR, int_1),
9158 : tristate::TS_UNKNOWN);
9159 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GT_EXPR, int_256),
9160 : tristate::TS_UNKNOWN);
9161 :
9162 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GE_EXPR, int_m1),
9163 : tristate::TS_TRUE);
9164 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GE_EXPR, int_0),
9165 : tristate::TS_TRUE);
9166 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GE_EXPR, int_1),
9167 : tristate::TS_UNKNOWN);
9168 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (GE_EXPR, int_256),
9169 : tristate::TS_UNKNOWN);
9170 :
9171 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (EQ_EXPR, int_m1),
9172 : tristate::TS_FALSE);
9173 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (EQ_EXPR, int_0),
9174 : tristate::TS_UNKNOWN);
9175 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (EQ_EXPR, int_1),
9176 : tristate::TS_UNKNOWN);
9177 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (EQ_EXPR, int_256),
9178 : tristate::TS_UNKNOWN);
9179 :
9180 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (NE_EXPR, int_m1),
9181 : tristate::TS_TRUE);
9182 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (NE_EXPR, int_0),
9183 : tristate::TS_UNKNOWN);
9184 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (NE_EXPR, int_1),
9185 : tristate::TS_UNKNOWN);
9186 4 : ASSERT_EQ (w_zero_then_one->eval_condition_without_cm (NE_EXPR, int_256),
9187 : tristate::TS_UNKNOWN);
9188 4 : }
9189 :
9190 : /* Verify merging constraints for states simulating successive iterations
9191 : of a loop.
9192 : Simulate:
9193 : for (i = 0; i < 256; i++)
9194 : [...body...]
9195 : i.e. this gimple:.
9196 : i_15 = 0;
9197 : goto <bb 4>;
9198 :
9199 : <bb 4> :
9200 : i_11 = PHI <i_15(2), i_23(3)>
9201 : if (i_11 <= 255)
9202 : goto <bb 3>;
9203 : else
9204 : goto [AFTER LOOP]
9205 :
9206 : <bb 3> :
9207 : [LOOP BODY]
9208 : i_23 = i_11 + 1;
9209 :
9210 : and thus these ops (and resultant states):
9211 : i_11 = PHI()
9212 : {i_11: 0}
9213 : add_constraint (i_11 <= 255) [for the true edge]
9214 : {i_11: 0} [constraint was a no-op]
9215 : i_23 = i_11 + 1;
9216 : {i_22: 1}
9217 : i_11 = PHI()
9218 : {i_11: WIDENED (at phi, 0, 1)}
9219 : add_constraint (i_11 <= 255) [for the true edge]
9220 : {i_11: WIDENED (at phi, 0, 1); WIDENED <= 255}
9221 : i_23 = i_11 + 1;
9222 : {i_23: (WIDENED (at phi, 0, 1) + 1); WIDENED <= 255}
9223 : i_11 = PHI(); merge with state at phi above
9224 : {i_11: WIDENED (at phi, 0, 1); WIDENED <= 256}
9225 : [changing meaning of "WIDENED" here]
9226 : if (i_11 <= 255)
9227 : T: {i_11: WIDENED (at phi, 0, 1); WIDENED <= 255}; cache hit
9228 : F: {i_11: 256}
9229 : */
9230 :
9231 : static void
9232 4 : test_iteration_1 ()
9233 : {
9234 4 : region_model_manager mgr;
9235 4 : program_point point (program_point::origin (mgr));
9236 :
9237 4 : tree int_0 = integer_zero_node;
9238 4 : tree int_1 = integer_one_node;
9239 4 : tree int_256 = build_int_cst (integer_type_node, 256);
9240 4 : tree i = build_global_decl ("i", integer_type_node);
9241 :
9242 4 : test_region_model_context ctxt;
9243 :
9244 : /* model0: i: 0. */
9245 4 : region_model model0 (&mgr);
9246 4 : model0.set_value (i, int_0, &ctxt);
9247 :
9248 : /* model1: i: 1. */
9249 4 : region_model model1 (&mgr);
9250 4 : model1.set_value (i, int_1, &ctxt);
9251 :
9252 : /* Should merge "i" to a widened value. */
9253 4 : region_model model2 (&mgr);
9254 4 : ASSERT_TRUE (model1.can_merge_with_p (model0, point, &model2));
9255 4 : const svalue *merged_i = model2.get_rvalue (i, &ctxt);
9256 4 : ASSERT_EQ (merged_i->get_kind (), SK_WIDENING);
9257 4 : const widening_svalue *w = merged_i->dyn_cast_widening_svalue ();
9258 4 : ASSERT_EQ (w->get_direction (), widening_svalue::DIR_ASCENDING);
9259 :
9260 : /* Add constraint: i < 256 */
9261 4 : model2.add_constraint (i, LT_EXPR, int_256, &ctxt);
9262 4 : ASSERT_EQ (model2.eval_condition (i, LT_EXPR, int_256, &ctxt),
9263 : tristate (tristate::TS_TRUE));
9264 4 : ASSERT_EQ (model2.eval_condition (i, GE_EXPR, int_0, &ctxt),
9265 : tristate (tristate::TS_TRUE));
9266 :
9267 : /* Try merging with the initial state. */
9268 4 : region_model model3 (&mgr);
9269 4 : ASSERT_TRUE (model2.can_merge_with_p (model0, point, &model3));
9270 : /* Merging the merged value with the initial value should be idempotent,
9271 : so that the analysis converges. */
9272 4 : ASSERT_EQ (model3.get_rvalue (i, &ctxt), merged_i);
9273 : /* Merger of 0 and a widening value with constraint < CST
9274 : should retain the constraint, even though it was implicit
9275 : for the 0 case. */
9276 4 : ASSERT_EQ (model3.eval_condition (i, LT_EXPR, int_256, &ctxt),
9277 : tristate (tristate::TS_TRUE));
9278 : /* ...and we should have equality: the analysis should have converged. */
9279 4 : ASSERT_EQ (model3, model2);
9280 :
9281 : /* "i_23 = i_11 + 1;" */
9282 4 : region_model model4 (model3);
9283 4 : ASSERT_EQ (model4, model2);
9284 4 : model4.set_value (i, build2 (PLUS_EXPR, integer_type_node, i, int_1), &ctxt);
9285 4 : const svalue *plus_one = model4.get_rvalue (i, &ctxt);
9286 4 : ASSERT_EQ (plus_one->get_kind (), SK_BINOP);
9287 :
9288 : /* Try merging with the "i: 1" state. */
9289 4 : region_model model5 (&mgr);
9290 4 : ASSERT_TRUE (model4.can_merge_with_p (model1, point, &model5));
9291 4 : ASSERT_EQ (model5.get_rvalue (i, &ctxt), plus_one);
9292 4 : ASSERT_EQ (model5, model4);
9293 :
9294 : /* "i_11 = PHI();" merge with state at phi above.
9295 : For i, we should have a merger of WIDENING with WIDENING + 1,
9296 : and this should be WIDENING again. */
9297 4 : region_model model6 (&mgr);
9298 4 : ASSERT_TRUE (model5.can_merge_with_p (model2, point, &model6));
9299 4 : const svalue *merged_widening = model6.get_rvalue (i, &ctxt);
9300 4 : ASSERT_EQ (merged_widening->get_kind (), SK_WIDENING);
9301 4 : }
9302 :
9303 : /* Verify that if we mark a pointer to a malloc-ed region as non-NULL,
9304 : all cast pointers to that region are also known to be non-NULL. */
9305 :
9306 : static void
9307 4 : test_malloc_constraints ()
9308 : {
9309 4 : region_model_manager mgr;
9310 4 : region_model model (&mgr);
9311 4 : tree p = build_global_decl ("p", ptr_type_node);
9312 4 : tree char_star = build_pointer_type (char_type_node);
9313 4 : tree q = build_global_decl ("q", char_star);
9314 4 : tree null_ptr = build_int_cst (ptr_type_node, 0);
9315 :
9316 4 : const svalue *size_in_bytes
9317 4 : = mgr.get_or_create_unknown_svalue (size_type_node);
9318 4 : const region *reg
9319 4 : = model.get_or_create_region_for_heap_alloc (size_in_bytes, nullptr);
9320 4 : const svalue *sval = mgr.get_ptr_svalue (ptr_type_node, reg);
9321 4 : model.set_value (model.get_lvalue (p, nullptr), sval, nullptr);
9322 4 : model.set_value (q, p, nullptr);
9323 :
9324 4 : ASSERT_CONDITION_UNKNOWN (model, p, NE_EXPR, null_ptr);
9325 4 : ASSERT_CONDITION_UNKNOWN (model, p, EQ_EXPR, null_ptr);
9326 4 : ASSERT_CONDITION_UNKNOWN (model, q, NE_EXPR, null_ptr);
9327 4 : ASSERT_CONDITION_UNKNOWN (model, q, EQ_EXPR, null_ptr);
9328 :
9329 4 : model.add_constraint (p, NE_EXPR, null_ptr, nullptr);
9330 :
9331 4 : ASSERT_CONDITION_TRUE (model, p, NE_EXPR, null_ptr);
9332 4 : ASSERT_CONDITION_FALSE (model, p, EQ_EXPR, null_ptr);
9333 4 : ASSERT_CONDITION_TRUE (model, q, NE_EXPR, null_ptr);
9334 4 : ASSERT_CONDITION_FALSE (model, q, EQ_EXPR, null_ptr);
9335 4 : }
9336 :
9337 : /* Smoketest of getting and setting the value of a variable. */
9338 :
9339 : static void
9340 4 : test_var ()
9341 : {
9342 : /* "int i;" */
9343 4 : tree i = build_global_decl ("i", integer_type_node);
9344 :
9345 4 : tree int_17 = build_int_cst (integer_type_node, 17);
9346 4 : tree int_m3 = build_int_cst (integer_type_node, -3);
9347 :
9348 4 : region_model_manager mgr;
9349 4 : region_model model (&mgr);
9350 :
9351 4 : const region *i_reg = model.get_lvalue (i, nullptr);
9352 4 : ASSERT_EQ (i_reg->get_kind (), RK_DECL);
9353 :
9354 : /* Reading "i" should give a symbolic "initial value". */
9355 4 : const svalue *sval_init = model.get_rvalue (i, nullptr);
9356 4 : ASSERT_EQ (sval_init->get_kind (), SK_INITIAL);
9357 4 : ASSERT_EQ (sval_init->dyn_cast_initial_svalue ()->get_region (), i_reg);
9358 : /* ..and doing it again should give the same "initial value". */
9359 4 : ASSERT_EQ (model.get_rvalue (i, nullptr), sval_init);
9360 :
9361 : /* "i = 17;". */
9362 4 : model.set_value (i, int_17, nullptr);
9363 4 : ASSERT_EQ (model.get_rvalue (i, nullptr),
9364 : model.get_rvalue (int_17, nullptr));
9365 :
9366 : /* "i = -3;". */
9367 4 : model.set_value (i, int_m3, nullptr);
9368 4 : ASSERT_EQ (model.get_rvalue (i, nullptr),
9369 : model.get_rvalue (int_m3, nullptr));
9370 :
9371 : /* Verify get_offset for "i". */
9372 4 : {
9373 4 : region_offset offset = i_reg->get_offset (&mgr);
9374 4 : ASSERT_EQ (offset.get_base_region (), i_reg);
9375 4 : ASSERT_EQ (offset.get_bit_offset (), 0);
9376 : }
9377 4 : }
9378 :
9379 : static void
9380 4 : test_array_2 ()
9381 : {
9382 : /* "int arr[10];" */
9383 4 : tree tlen = size_int (10);
9384 4 : tree arr_type
9385 4 : = build_array_type (integer_type_node, build_index_type (tlen));
9386 4 : tree arr = build_global_decl ("arr", arr_type);
9387 :
9388 : /* "int i;" */
9389 4 : tree i = build_global_decl ("i", integer_type_node);
9390 :
9391 4 : tree int_0 = integer_zero_node;
9392 4 : tree int_1 = integer_one_node;
9393 :
9394 4 : tree arr_0 = build4 (ARRAY_REF, integer_type_node,
9395 : arr, int_0, NULL_TREE, NULL_TREE);
9396 4 : tree arr_1 = build4 (ARRAY_REF, integer_type_node,
9397 : arr, int_1, NULL_TREE, NULL_TREE);
9398 4 : tree arr_i = build4 (ARRAY_REF, integer_type_node,
9399 : arr, i, NULL_TREE, NULL_TREE);
9400 :
9401 4 : tree int_17 = build_int_cst (integer_type_node, 17);
9402 4 : tree int_42 = build_int_cst (integer_type_node, 42);
9403 4 : tree int_m3 = build_int_cst (integer_type_node, -3);
9404 :
9405 4 : region_model_manager mgr;
9406 4 : region_model model (&mgr);
9407 : /* "arr[0] = 17;". */
9408 4 : model.set_value (arr_0, int_17, nullptr);
9409 : /* "arr[1] = -3;". */
9410 4 : model.set_value (arr_1, int_m3, nullptr);
9411 :
9412 4 : ASSERT_EQ (model.get_rvalue (arr_0, nullptr),
9413 : model.get_rvalue (int_17, nullptr));
9414 4 : ASSERT_EQ (model.get_rvalue (arr_1, nullptr),
9415 : model.get_rvalue (int_m3, nullptr));
9416 :
9417 : /* Overwrite a pre-existing binding: "arr[1] = 42;". */
9418 4 : model.set_value (arr_1, int_42, nullptr);
9419 4 : ASSERT_EQ (model.get_rvalue (arr_1, nullptr),
9420 : model.get_rvalue (int_42, nullptr));
9421 :
9422 : /* Verify get_offset for "arr[0]". */
9423 4 : {
9424 4 : const region *arr_0_reg = model.get_lvalue (arr_0, nullptr);
9425 4 : region_offset offset = arr_0_reg->get_offset (&mgr);
9426 4 : ASSERT_EQ (offset.get_base_region (), model.get_lvalue (arr, nullptr));
9427 4 : ASSERT_EQ (offset.get_bit_offset (), 0);
9428 : }
9429 :
9430 : /* Verify get_offset for "arr[1]". */
9431 4 : {
9432 4 : const region *arr_1_reg = model.get_lvalue (arr_1, nullptr);
9433 4 : region_offset offset = arr_1_reg->get_offset (&mgr);
9434 4 : ASSERT_EQ (offset.get_base_region (), model.get_lvalue (arr, nullptr));
9435 4 : ASSERT_EQ (offset.get_bit_offset (), INT_TYPE_SIZE);
9436 : }
9437 :
9438 : /* Verify get_offset for "arr[i]". */
9439 4 : {
9440 4 : const region *arr_i_reg = model.get_lvalue (arr_i, nullptr);
9441 4 : region_offset offset = arr_i_reg->get_offset (&mgr);
9442 4 : ASSERT_EQ (offset.get_base_region (), model.get_lvalue (arr, nullptr));
9443 4 : const svalue *offset_sval = offset.get_symbolic_byte_offset ();
9444 4 : if (const svalue *cast = offset_sval->maybe_undo_cast ())
9445 4 : offset_sval = cast;
9446 4 : ASSERT_EQ (offset_sval->get_kind (), SK_BINOP);
9447 : }
9448 :
9449 : /* "arr[i] = i;" - this should remove the earlier bindings. */
9450 4 : model.set_value (arr_i, i, nullptr);
9451 4 : ASSERT_EQ (model.get_rvalue (arr_i, nullptr), model.get_rvalue (i, nullptr));
9452 4 : ASSERT_EQ (model.get_rvalue (arr_0, nullptr)->get_kind (), SK_UNKNOWN);
9453 :
9454 : /* "arr[0] = 17;" - this should remove the arr[i] binding. */
9455 4 : model.set_value (arr_0, int_17, nullptr);
9456 4 : ASSERT_EQ (model.get_rvalue (arr_0, nullptr),
9457 : model.get_rvalue (int_17, nullptr));
9458 4 : ASSERT_EQ (model.get_rvalue (arr_i, nullptr)->get_kind (), SK_UNKNOWN);
9459 4 : }
9460 :
9461 : /* Smoketest of dereferencing a pointer via MEM_REF. */
9462 :
9463 : static void
9464 4 : test_mem_ref ()
9465 : {
9466 : /*
9467 : x = 17;
9468 : p = &x;
9469 : *p;
9470 : */
9471 4 : tree x = build_global_decl ("x", integer_type_node);
9472 4 : tree int_star = build_pointer_type (integer_type_node);
9473 4 : tree p = build_global_decl ("p", int_star);
9474 :
9475 4 : tree int_17 = build_int_cst (integer_type_node, 17);
9476 4 : tree addr_of_x = build1 (ADDR_EXPR, int_star, x);
9477 4 : tree ptype = build_pointer_type_for_mode (char_type_node, ptr_mode, true);
9478 4 : tree offset_0 = build_int_cst (ptype, 0);
9479 4 : tree star_p = build2 (MEM_REF, integer_type_node, p, offset_0);
9480 :
9481 4 : region_model_manager mgr;
9482 4 : region_model model (&mgr);
9483 :
9484 : /* "x = 17;". */
9485 4 : model.set_value (x, int_17, nullptr);
9486 :
9487 : /* "p = &x;". */
9488 4 : model.set_value (p, addr_of_x, nullptr);
9489 :
9490 4 : const svalue *sval = model.get_rvalue (star_p, nullptr);
9491 4 : ASSERT_EQ (sval->maybe_get_constant (), int_17);
9492 4 : }
9493 :
9494 : /* Test for a POINTER_PLUS_EXPR followed by a MEM_REF.
9495 : Analogous to this code:
9496 : void test_6 (int a[10])
9497 : {
9498 : __analyzer_eval (a[3] == 42); [should be UNKNOWN]
9499 : a[3] = 42;
9500 : __analyzer_eval (a[3] == 42); [should be TRUE]
9501 : }
9502 : from data-model-1.c, which looks like this at the gimple level:
9503 : # __analyzer_eval (a[3] == 42); [should be UNKNOWN]
9504 : int *_1 = a_10(D) + 12; # POINTER_PLUS_EXPR
9505 : int _2 = *_1; # MEM_REF
9506 : _Bool _3 = _2 == 42;
9507 : int _4 = (int) _3;
9508 : __analyzer_eval (_4);
9509 :
9510 : # a[3] = 42;
9511 : int *_5 = a_10(D) + 12; # POINTER_PLUS_EXPR
9512 : *_5 = 42; # MEM_REF
9513 :
9514 : # __analyzer_eval (a[3] == 42); [should be TRUE]
9515 : int *_6 = a_10(D) + 12; # POINTER_PLUS_EXPR
9516 : int _7 = *_6; # MEM_REF
9517 : _Bool _8 = _7 == 42;
9518 : int _9 = (int) _8;
9519 : __analyzer_eval (_9); */
9520 :
9521 : static void
9522 4 : test_POINTER_PLUS_EXPR_then_MEM_REF ()
9523 : {
9524 4 : tree int_star = build_pointer_type (integer_type_node);
9525 4 : tree a = build_global_decl ("a", int_star);
9526 4 : tree offset_12 = build_int_cst (size_type_node, 12);
9527 4 : tree pointer_plus_expr = build2 (POINTER_PLUS_EXPR, int_star, a, offset_12);
9528 4 : tree ptype = build_pointer_type_for_mode (char_type_node, ptr_mode, true);
9529 4 : tree offset_0 = build_int_cst (ptype, 0);
9530 4 : tree mem_ref = build2 (MEM_REF, integer_type_node,
9531 : pointer_plus_expr, offset_0);
9532 4 : region_model_manager mgr;
9533 4 : region_model m (&mgr);
9534 :
9535 4 : tree int_42 = build_int_cst (integer_type_node, 42);
9536 4 : m.set_value (mem_ref, int_42, nullptr);
9537 4 : ASSERT_EQ (m.get_rvalue (mem_ref, nullptr)->maybe_get_constant (), int_42);
9538 4 : }
9539 :
9540 : /* Verify that malloc works. */
9541 :
9542 : static void
9543 4 : test_malloc ()
9544 : {
9545 4 : tree int_star = build_pointer_type (integer_type_node);
9546 4 : tree p = build_global_decl ("p", int_star);
9547 4 : tree n = build_global_decl ("n", integer_type_node);
9548 4 : tree n_times_4 = build2 (MULT_EXPR, size_type_node,
9549 : n, build_int_cst (size_type_node, 4));
9550 :
9551 4 : region_model_manager mgr;
9552 4 : test_region_model_context ctxt;
9553 4 : region_model model (&mgr);
9554 :
9555 : /* "p = malloc (n * 4);". */
9556 4 : const svalue *size_sval = model.get_rvalue (n_times_4, &ctxt);
9557 4 : const region *reg
9558 4 : = model.get_or_create_region_for_heap_alloc (size_sval, &ctxt);
9559 4 : const svalue *ptr = mgr.get_ptr_svalue (int_star, reg);
9560 4 : model.set_value (model.get_lvalue (p, &ctxt), ptr, &ctxt);
9561 4 : ASSERT_EQ (model.get_capacity (reg), size_sval);
9562 4 : }
9563 :
9564 : /* Verify that alloca works. */
9565 :
9566 : static void
9567 4 : test_alloca ()
9568 : {
9569 4 : auto_vec <tree> param_types;
9570 4 : tree fndecl = make_fndecl (integer_type_node,
9571 : "test_fn",
9572 : param_types);
9573 4 : allocate_struct_function (fndecl, true);
9574 :
9575 :
9576 4 : tree int_star = build_pointer_type (integer_type_node);
9577 4 : tree p = build_global_decl ("p", int_star);
9578 4 : tree n = build_global_decl ("n", integer_type_node);
9579 4 : tree n_times_4 = build2 (MULT_EXPR, size_type_node,
9580 : n, build_int_cst (size_type_node, 4));
9581 :
9582 4 : region_model_manager mgr;
9583 4 : test_region_model_context ctxt;
9584 4 : region_model model (&mgr);
9585 :
9586 : /* Push stack frame. */
9587 4 : const region *frame_reg
9588 4 : = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl),
9589 : nullptr, nullptr, &ctxt);
9590 : /* "p = alloca (n * 4);". */
9591 4 : const svalue *size_sval = model.get_rvalue (n_times_4, &ctxt);
9592 4 : const region *reg = model.create_region_for_alloca (size_sval, &ctxt);
9593 4 : ASSERT_EQ (reg->get_parent_region (), frame_reg);
9594 4 : const svalue *ptr = mgr.get_ptr_svalue (int_star, reg);
9595 4 : model.set_value (model.get_lvalue (p, &ctxt), ptr, &ctxt);
9596 4 : ASSERT_EQ (model.get_capacity (reg), size_sval);
9597 :
9598 : /* Verify that the pointers to the alloca region are replaced by
9599 : poisoned values when the frame is popped. */
9600 4 : model.pop_frame (nullptr, nullptr, &ctxt, nullptr);
9601 4 : ASSERT_EQ (model.get_rvalue (p, nullptr)->get_kind (), SK_POISONED);
9602 4 : }
9603 :
9604 : /* Verify that svalue::involves_p works. */
9605 :
9606 : static void
9607 4 : test_involves_p ()
9608 : {
9609 4 : region_model_manager mgr;
9610 4 : tree int_star = build_pointer_type (integer_type_node);
9611 4 : tree p = build_global_decl ("p", int_star);
9612 4 : tree q = build_global_decl ("q", int_star);
9613 :
9614 4 : test_region_model_context ctxt;
9615 4 : region_model model (&mgr);
9616 4 : const svalue *p_init = model.get_rvalue (p, &ctxt);
9617 4 : const svalue *q_init = model.get_rvalue (q, &ctxt);
9618 :
9619 4 : ASSERT_TRUE (p_init->involves_p (p_init));
9620 4 : ASSERT_FALSE (p_init->involves_p (q_init));
9621 :
9622 4 : const region *star_p_reg = mgr.get_symbolic_region (p_init);
9623 4 : const region *star_q_reg = mgr.get_symbolic_region (q_init);
9624 :
9625 4 : const svalue *init_star_p = mgr.get_or_create_initial_value (star_p_reg);
9626 4 : const svalue *init_star_q = mgr.get_or_create_initial_value (star_q_reg);
9627 :
9628 4 : ASSERT_TRUE (init_star_p->involves_p (p_init));
9629 4 : ASSERT_FALSE (p_init->involves_p (init_star_p));
9630 4 : ASSERT_FALSE (init_star_p->involves_p (q_init));
9631 4 : ASSERT_TRUE (init_star_q->involves_p (q_init));
9632 4 : ASSERT_FALSE (init_star_q->involves_p (p_init));
9633 4 : }
9634 :
9635 : /* Run all of the selftests within this file. */
9636 :
9637 : void
9638 4 : analyzer_region_model_cc_tests ()
9639 : {
9640 4 : test_tree_cmp_on_constants ();
9641 4 : test_dump ();
9642 4 : test_struct ();
9643 4 : test_array_1 ();
9644 4 : test_get_representative_tree ();
9645 4 : test_unique_constants ();
9646 4 : test_unique_unknowns ();
9647 4 : test_initial_svalue_folding ();
9648 4 : test_unaryop_svalue_folding ();
9649 4 : test_binop_svalue_folding ();
9650 4 : test_sub_svalue_folding ();
9651 4 : test_bits_within_svalue_folding ();
9652 4 : test_descendent_of_p ();
9653 4 : test_bit_range_regions ();
9654 4 : test_assignment ();
9655 4 : test_compound_assignment ();
9656 4 : test_stack_frames ();
9657 4 : test_get_representative_path_var ();
9658 4 : test_equality_1 ();
9659 4 : test_canonicalization_2 ();
9660 4 : test_canonicalization_3 ();
9661 4 : test_canonicalization_4 ();
9662 4 : test_state_merging ();
9663 4 : test_constraint_merging ();
9664 4 : test_widening_constraints ();
9665 4 : test_iteration_1 ();
9666 4 : test_malloc_constraints ();
9667 4 : test_var ();
9668 4 : test_array_2 ();
9669 4 : test_mem_ref ();
9670 4 : test_POINTER_PLUS_EXPR_then_MEM_REF ();
9671 4 : test_malloc ();
9672 4 : test_alloca ();
9673 4 : test_involves_p ();
9674 4 : }
9675 :
9676 : } // namespace selftest
9677 :
9678 : #endif /* CHECKING_P */
9679 :
9680 : } // namespace ana
9681 :
9682 : #endif /* #if ENABLE_ANALYZER */
|