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