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