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