libstdc++: Define __glibcxx_assert_fail for non-verbose build [PR115585]
[official-gcc.git] / gcc / analyzer / engine.cc
blobf5fad5b2e4704cd245947004a1cd28d7a59ea6eb
1 /* The analysis "engine".
2 Copyright (C) 2019-2024 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
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.
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.
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/>. */
21 #include "config.h"
22 #define INCLUDE_MEMORY
23 #define INCLUDE_VECTOR
24 #include "system.h"
25 #include "coretypes.h"
26 #include "make-unique.h"
27 #include "tree.h"
28 #include "fold-const.h"
29 #include "gcc-rich-location.h"
30 #include "diagnostic-core.h"
31 #include "diagnostic-event-id.h"
32 #include "diagnostic-path.h"
33 #include "function.h"
34 #include "pretty-print.h"
35 #include "sbitmap.h"
36 #include "bitmap.h"
37 #include "ordered-hash-map.h"
38 #include "analyzer/analyzer.h"
39 #include "analyzer/analyzer-logging.h"
40 #include "analyzer/call-string.h"
41 #include "analyzer/program-point.h"
42 #include "analyzer/store.h"
43 #include "analyzer/region-model.h"
44 #include "analyzer/constraint-manager.h"
45 #include "analyzer/sm.h"
46 #include "analyzer/pending-diagnostic.h"
47 #include "analyzer/diagnostic-manager.h"
48 #include "cfg.h"
49 #include "basic-block.h"
50 #include "gimple.h"
51 #include "gimple-iterator.h"
52 #include "gimple-pretty-print.h"
53 #include "cgraph.h"
54 #include "digraph.h"
55 #include "analyzer/supergraph.h"
56 #include "analyzer/program-state.h"
57 #include "analyzer/exploded-graph.h"
58 #include "analyzer/analysis-plan.h"
59 #include "analyzer/checker-path.h"
60 #include "analyzer/state-purge.h"
61 #include "analyzer/bar-chart.h"
62 #include "analyzer/call-info.h"
63 #include <zlib.h>
64 #include "plugin.h"
65 #include "target.h"
66 #include <memory>
67 #include "stringpool.h"
68 #include "attribs.h"
69 #include "tree-dfa.h"
70 #include "analyzer/known-function-manager.h"
71 #include "analyzer/call-summary.h"
72 #include "text-art/dump.h"
74 /* For an overview, see gcc/doc/analyzer.texi. */
76 #if ENABLE_ANALYZER
78 namespace ana {
80 /* class impl_region_model_context : public region_model_context. */
82 impl_region_model_context::
83 impl_region_model_context (exploded_graph &eg,
84 exploded_node *enode_for_diag,
85 const program_state *old_state,
86 program_state *new_state,
87 uncertainty_t *uncertainty,
88 path_context *path_ctxt,
89 const gimple *stmt,
90 stmt_finder *stmt_finder,
91 bool *out_could_have_done_work)
92 : m_eg (&eg), m_logger (eg.get_logger ()),
93 m_enode_for_diag (enode_for_diag),
94 m_old_state (old_state),
95 m_new_state (new_state),
96 m_stmt (stmt),
97 m_stmt_finder (stmt_finder),
98 m_ext_state (eg.get_ext_state ()),
99 m_uncertainty (uncertainty),
100 m_path_ctxt (path_ctxt),
101 m_out_could_have_done_work (out_could_have_done_work)
105 impl_region_model_context::
106 impl_region_model_context (program_state *state,
107 const extrinsic_state &ext_state,
108 uncertainty_t *uncertainty,
109 logger *logger)
110 : m_eg (NULL), m_logger (logger), m_enode_for_diag (NULL),
111 m_old_state (NULL),
112 m_new_state (state),
113 m_stmt (NULL),
114 m_stmt_finder (NULL),
115 m_ext_state (ext_state),
116 m_uncertainty (uncertainty),
117 m_path_ctxt (NULL),
118 m_out_could_have_done_work (nullptr)
122 bool
123 impl_region_model_context::warn (std::unique_ptr<pending_diagnostic> d,
124 const stmt_finder *custom_finder)
126 LOG_FUNC (get_logger ());
127 auto curr_stmt_finder = custom_finder ? custom_finder : m_stmt_finder;
128 if (m_stmt == NULL && curr_stmt_finder == NULL)
130 if (get_logger ())
131 get_logger ()->log ("rejecting diagnostic: no stmt");
132 return false;
134 if (m_eg)
136 bool terminate_path = d->terminate_path_p ();
137 pending_location ploc (m_enode_for_diag,
138 m_enode_for_diag->get_supernode (),
139 m_stmt,
140 curr_stmt_finder);
141 if (m_eg->get_diagnostic_manager ().add_diagnostic (ploc,
142 std::move (d)))
144 if (m_path_ctxt
145 && terminate_path
146 && flag_analyzer_suppress_followups)
147 m_path_ctxt->terminate_path ();
148 return true;
151 return false;
154 void
155 impl_region_model_context::add_note (std::unique_ptr<pending_note> pn)
157 LOG_FUNC (get_logger ());
158 if (m_eg)
159 m_eg->get_diagnostic_manager ().add_note (std::move (pn));
162 void
163 impl_region_model_context::add_event (std::unique_ptr<checker_event> event)
165 LOG_FUNC (get_logger ());
166 if (m_eg)
167 m_eg->get_diagnostic_manager ().add_event (std::move (event));
170 void
171 impl_region_model_context::on_svalue_leak (const svalue *sval)
174 for (sm_state_map *smap : m_new_state->m_checker_states)
175 smap->on_svalue_leak (sval, this);
178 void
179 impl_region_model_context::
180 on_liveness_change (const svalue_set &live_svalues,
181 const region_model *model)
183 for (sm_state_map *smap : m_new_state->m_checker_states)
184 smap->on_liveness_change (live_svalues, model, m_ext_state, this);
187 void
188 impl_region_model_context::on_unknown_change (const svalue *sval,
189 bool is_mutable)
191 if (!sval->can_have_associated_state_p ())
192 return;
193 for (sm_state_map *smap : m_new_state->m_checker_states)
194 smap->on_unknown_change (sval, is_mutable, m_ext_state);
197 void
198 impl_region_model_context::on_escaped_function (tree fndecl)
200 m_eg->on_escaped_function (fndecl);
203 uncertainty_t *
204 impl_region_model_context::get_uncertainty ()
206 return m_uncertainty;
209 /* Purge state involving SVAL. The region_model has already been purged,
210 so we only need to purge other state in the program_state:
211 the sm-state. */
213 void
214 impl_region_model_context::purge_state_involving (const svalue *sval)
216 int i;
217 sm_state_map *smap;
218 FOR_EACH_VEC_ELT (m_new_state->m_checker_states, i, smap)
219 smap->purge_state_involving (sval, m_ext_state);
222 void
223 impl_region_model_context::bifurcate (std::unique_ptr<custom_edge_info> info)
225 if (m_path_ctxt)
226 m_path_ctxt->bifurcate (std::move (info));
229 void
230 impl_region_model_context::terminate_path ()
232 if (m_path_ctxt)
233 return m_path_ctxt->terminate_path ();
236 /* struct setjmp_record. */
239 setjmp_record::cmp (const setjmp_record &rec1, const setjmp_record &rec2)
241 if (int cmp_enode = rec1.m_enode->m_index - rec2.m_enode->m_index)
242 return cmp_enode;
243 gcc_assert (&rec1 == &rec2);
244 return 0;
247 /* class setjmp_svalue : public svalue. */
249 /* Implementation of svalue::accept vfunc for setjmp_svalue. */
251 void
252 setjmp_svalue::accept (visitor *v) const
254 v->visit_setjmp_svalue (this);
257 /* Implementation of svalue::dump_to_pp vfunc for setjmp_svalue. */
259 void
260 setjmp_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
262 if (simple)
263 pp_printf (pp, "SETJMP(EN: %i)", get_enode_index ());
264 else
265 pp_printf (pp, "setjmp_svalue(EN%i)", get_enode_index ());
268 /* Implementation of svalue::print_dump_widget_label vfunc for
269 setjmp_svalue. */
271 void
272 setjmp_svalue::print_dump_widget_label (pretty_printer *pp) const
274 pp_printf (pp, "setjmp_svalue(EN: %i)", get_enode_index ());
277 /* Implementation of svalue::add_dump_widget_children vfunc for
278 setjmp_svalue. */
280 void
281 setjmp_svalue::
282 add_dump_widget_children (text_art::tree_widget &,
283 const text_art::dump_widget_info &) const
285 /* No children. */
288 /* Get the index of the stored exploded_node. */
291 setjmp_svalue::get_enode_index () const
293 return m_setjmp_record.m_enode->m_index;
296 /* Concrete implementation of sm_context, wiring it up to the rest of this
297 file. */
299 class impl_sm_context : public sm_context
301 public:
302 impl_sm_context (exploded_graph &eg,
303 int sm_idx,
304 const state_machine &sm,
305 exploded_node *enode_for_diag,
306 const program_state *old_state,
307 program_state *new_state,
308 const sm_state_map *old_smap,
309 sm_state_map *new_smap,
310 path_context *path_ctxt,
311 const stmt_finder *stmt_finder = NULL,
312 bool unknown_side_effects = false)
313 : sm_context (sm_idx, sm),
314 m_logger (eg.get_logger ()),
315 m_eg (eg), m_enode_for_diag (enode_for_diag),
316 m_old_state (old_state), m_new_state (new_state),
317 m_old_smap (old_smap), m_new_smap (new_smap),
318 m_path_ctxt (path_ctxt),
319 m_stmt_finder (stmt_finder),
320 m_unknown_side_effects (unknown_side_effects)
324 logger *get_logger () const { return m_logger.get_logger (); }
326 tree get_fndecl_for_call (const gcall *call) final override
328 impl_region_model_context old_ctxt
329 (m_eg, m_enode_for_diag, NULL, NULL, NULL/*m_enode->get_state ()*/,
330 NULL, call);
331 region_model *model = m_new_state->m_region_model;
332 return model->get_fndecl_for_call (call, &old_ctxt);
335 state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
336 tree var) final override
338 logger * const logger = get_logger ();
339 LOG_FUNC (logger);
340 /* Use NULL ctxt on this get_rvalue call to avoid triggering
341 uninitialized value warnings. */
342 const svalue *var_old_sval
343 = m_old_state->m_region_model->get_rvalue (var, NULL);
345 state_machine::state_t current
346 = m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ());
347 return current;
349 state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
350 const svalue *sval) final override
352 logger * const logger = get_logger ();
353 LOG_FUNC (logger);
354 state_machine::state_t current
355 = m_old_smap->get_state (sval, m_eg.get_ext_state ());
356 return current;
360 void set_next_state (const gimple *,
361 tree var,
362 state_machine::state_t to,
363 tree origin) final override
365 logger * const logger = get_logger ();
366 LOG_FUNC (logger);
367 const svalue *var_new_sval
368 = m_new_state->m_region_model->get_rvalue (var, NULL);
369 const svalue *origin_new_sval
370 = m_new_state->m_region_model->get_rvalue (origin, NULL);
372 /* We use the new sval here to avoid issues with uninitialized values. */
373 state_machine::state_t current
374 = m_old_smap->get_state (var_new_sval, m_eg.get_ext_state ());
375 if (logger)
376 logger->log ("%s: state transition of %qE: %s -> %s",
377 m_sm.get_name (),
378 var,
379 current->get_name (),
380 to->get_name ());
381 m_new_smap->set_state (m_new_state->m_region_model, var_new_sval,
382 to, origin_new_sval, m_eg.get_ext_state ());
385 void set_next_state (const gimple *stmt,
386 const svalue *sval,
387 state_machine::state_t to,
388 tree origin) final override
390 logger * const logger = get_logger ();
391 LOG_FUNC (logger);
392 impl_region_model_context old_ctxt
393 (m_eg, m_enode_for_diag, NULL, NULL, NULL/*m_enode->get_state ()*/,
394 NULL, stmt);
396 const svalue *origin_new_sval
397 = m_new_state->m_region_model->get_rvalue (origin, NULL);
399 state_machine::state_t current
400 = m_old_smap->get_state (sval, m_eg.get_ext_state ());
401 if (logger)
403 logger->start_log_line ();
404 logger->log_partial ("%s: state transition of ",
405 m_sm.get_name ());
406 sval->dump_to_pp (logger->get_printer (), true);
407 logger->log_partial (": %s -> %s",
408 current->get_name (),
409 to->get_name ());
410 logger->end_log_line ();
412 m_new_smap->set_state (m_new_state->m_region_model, sval,
413 to, origin_new_sval, m_eg.get_ext_state ());
416 void warn (const supernode *snode, const gimple *stmt,
417 tree var,
418 std::unique_ptr<pending_diagnostic> d) final override
420 LOG_FUNC (get_logger ());
421 gcc_assert (d);
422 const svalue *var_old_sval
423 = m_old_state->m_region_model->get_rvalue (var, NULL);
424 state_machine::state_t current
425 = (var
426 ? m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ())
427 : m_old_smap->get_global_state ());
428 bool terminate_path = d->terminate_path_p ();
429 pending_location ploc (m_enode_for_diag, snode, stmt, m_stmt_finder);
430 m_eg.get_diagnostic_manager ().add_diagnostic
431 (&m_sm, ploc,
432 var, var_old_sval, current, std::move (d));
433 if (m_path_ctxt
434 && terminate_path
435 && flag_analyzer_suppress_followups)
436 m_path_ctxt->terminate_path ();
439 void warn (const supernode *snode, const gimple *stmt,
440 const svalue *sval,
441 std::unique_ptr<pending_diagnostic> d) final override
443 LOG_FUNC (get_logger ());
444 gcc_assert (d);
445 state_machine::state_t current
446 = (sval
447 ? m_old_smap->get_state (sval, m_eg.get_ext_state ())
448 : m_old_smap->get_global_state ());
449 bool terminate_path = d->terminate_path_p ();
450 pending_location ploc (m_enode_for_diag, snode, stmt, m_stmt_finder);
451 m_eg.get_diagnostic_manager ().add_diagnostic
452 (&m_sm, ploc,
453 NULL_TREE, sval, current, std::move (d));
454 if (m_path_ctxt
455 && terminate_path
456 && flag_analyzer_suppress_followups)
457 m_path_ctxt->terminate_path ();
460 /* Hook for picking more readable trees for SSA names of temporaries,
461 so that rather than e.g.
462 "double-free of '<unknown>'"
463 we can print:
464 "double-free of 'inbuf.data'". */
466 tree get_diagnostic_tree (tree expr) final override
468 /* Only for SSA_NAMEs of temporaries; otherwise, return EXPR, as it's
469 likely to be the least surprising tree to report. */
470 if (TREE_CODE (expr) != SSA_NAME)
471 return expr;
472 if (SSA_NAME_VAR (expr) != NULL)
473 return expr;
475 gcc_assert (m_new_state);
476 const svalue *sval = m_new_state->m_region_model->get_rvalue (expr, NULL);
477 /* Find trees for all regions storing the value. */
478 if (tree t = m_new_state->m_region_model->get_representative_tree (sval))
479 return t;
480 else
481 return expr;
484 tree get_diagnostic_tree (const svalue *sval) final override
486 return m_new_state->m_region_model->get_representative_tree (sval);
489 state_machine::state_t get_global_state () const final override
491 return m_old_state->m_checker_states[m_sm_idx]->get_global_state ();
494 void set_global_state (state_machine::state_t state) final override
496 m_new_state->m_checker_states[m_sm_idx]->set_global_state (state);
499 void clear_all_per_svalue_state () final override
501 m_new_state->m_checker_states[m_sm_idx]->clear_all_per_svalue_state ();
504 void on_custom_transition (custom_transition *transition) final override
506 transition->impl_transition (&m_eg,
507 const_cast<exploded_node *> (m_enode_for_diag),
508 m_sm_idx);
511 tree is_zero_assignment (const gimple *stmt) final override
513 const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
514 if (!assign_stmt)
515 return NULL_TREE;
516 impl_region_model_context old_ctxt
517 (m_eg, m_enode_for_diag, m_old_state, m_new_state, NULL, NULL, stmt);
518 if (const svalue *sval
519 = m_new_state->m_region_model->get_gassign_result (assign_stmt,
520 &old_ctxt))
521 if (tree cst = sval->maybe_get_constant ())
522 if (::zerop(cst))
523 return gimple_assign_lhs (assign_stmt);
524 return NULL_TREE;
527 path_context *get_path_context () const final override
529 return m_path_ctxt;
532 bool unknown_side_effects_p () const final override
534 return m_unknown_side_effects;
537 const program_state *get_old_program_state () const final override
539 return m_old_state;
542 const program_state *get_new_program_state () const final override
544 return m_new_state;
547 log_user m_logger;
548 exploded_graph &m_eg;
549 exploded_node *m_enode_for_diag;
550 const program_state *m_old_state;
551 program_state *m_new_state;
552 const sm_state_map *m_old_smap;
553 sm_state_map *m_new_smap;
554 path_context *m_path_ctxt;
555 const stmt_finder *m_stmt_finder;
557 /* Are we handling an external function with unknown side effects? */
558 bool m_unknown_side_effects;
561 bool
562 impl_region_model_context::
563 get_state_map_by_name (const char *name,
564 sm_state_map **out_smap,
565 const state_machine **out_sm,
566 unsigned *out_sm_idx,
567 std::unique_ptr<sm_context> *out_sm_context)
569 if (!m_new_state)
570 return false;
572 unsigned sm_idx;
573 if (!m_ext_state.get_sm_idx_by_name (name, &sm_idx))
574 return false;
576 const state_machine *sm = &m_ext_state.get_sm (sm_idx);
577 sm_state_map *new_smap = m_new_state->m_checker_states[sm_idx];
579 *out_smap = new_smap;
580 *out_sm = sm;
581 if (out_sm_idx)
582 *out_sm_idx = sm_idx;
583 if (out_sm_context)
585 const sm_state_map *old_smap = m_old_state->m_checker_states[sm_idx];
586 *out_sm_context
587 = make_unique<impl_sm_context> (*m_eg,
588 sm_idx,
589 *sm,
590 m_enode_for_diag,
591 m_old_state,
592 m_new_state,
593 old_smap,
594 new_smap,
595 m_path_ctxt,
596 m_stmt_finder,
597 false);
599 return true;
602 /* Subclass of stmt_finder for finding the best stmt to report the leak at,
603 given the emission path. */
605 class leak_stmt_finder : public stmt_finder
607 public:
608 leak_stmt_finder (const exploded_graph &eg, tree var)
609 : m_eg (eg), m_var (var) {}
611 std::unique_ptr<stmt_finder> clone () const final override
613 return make_unique<leak_stmt_finder> (m_eg, m_var);
616 const gimple *find_stmt (const exploded_path &epath)
617 final override
619 logger * const logger = m_eg.get_logger ();
620 LOG_FUNC (logger);
622 if (m_var && TREE_CODE (m_var) == SSA_NAME)
624 /* Locate the final write to this SSA name in the path. */
625 const gimple *def_stmt = SSA_NAME_DEF_STMT (m_var);
627 int idx_of_def_stmt;
628 bool found = epath.find_stmt_backwards (def_stmt, &idx_of_def_stmt);
629 if (!found)
630 goto not_found;
632 /* What was the next write to the underlying var
633 after the SSA name was set? (if any). */
635 for (unsigned idx = idx_of_def_stmt + 1;
636 idx < epath.m_edges.length ();
637 ++idx)
639 const exploded_edge *eedge = epath.m_edges[idx];
640 if (logger)
641 logger->log ("eedge[%i]: EN %i -> EN %i",
642 idx,
643 eedge->m_src->m_index,
644 eedge->m_dest->m_index);
645 const exploded_node *dst_node = eedge->m_dest;
646 const program_point &dst_point = dst_node->get_point ();
647 const gimple *stmt = dst_point.get_stmt ();
648 if (!stmt)
649 continue;
650 if (const gassign *assign = dyn_cast <const gassign *> (stmt))
652 tree lhs = gimple_assign_lhs (assign);
653 if (TREE_CODE (lhs) == SSA_NAME
654 && SSA_NAME_VAR (lhs) == SSA_NAME_VAR (m_var))
655 return assign;
660 not_found:
662 /* Look backwards for the first statement with a location. */
663 int i;
664 const exploded_edge *eedge;
665 FOR_EACH_VEC_ELT_REVERSE (epath.m_edges, i, eedge)
667 if (logger)
668 logger->log ("eedge[%i]: EN %i -> EN %i",
670 eedge->m_src->m_index,
671 eedge->m_dest->m_index);
672 const exploded_node *dst_node = eedge->m_dest;
673 const program_point &dst_point = dst_node->get_point ();
674 const gimple *stmt = dst_point.get_stmt ();
675 if (stmt)
676 if (get_pure_location (stmt->location) != UNKNOWN_LOCATION)
677 return stmt;
680 gcc_unreachable ();
681 return NULL;
684 void update_event_loc_info (event_loc_info &) final override
686 /* No-op. */
689 private:
690 const exploded_graph &m_eg;
691 tree m_var;
694 /* A measurement of how good EXPR is for presenting to the user, so
695 that e.g. we can say prefer printing
696 "leak of 'tmp.m_ptr'"
697 over:
698 "leak of '<unknown>'". */
700 static int
701 readability (const_tree expr)
703 /* Arbitrarily-chosen "high readability" value. */
704 const int HIGH_READABILITY = 65536;
706 gcc_assert (expr);
707 switch (TREE_CODE (expr))
709 case COMPONENT_REF:
710 case MEM_REF:
711 /* Impose a slight readability penalty relative to that of
712 operand 0. */
713 return readability (TREE_OPERAND (expr, 0)) - 16;
715 case SSA_NAME:
717 if (tree var = SSA_NAME_VAR (expr))
719 if (DECL_ARTIFICIAL (var))
721 /* If we have an SSA name for an artificial var,
722 only use it if it has a debug expr associated with
723 it that fixup_tree_for_diagnostic can use. */
724 if (VAR_P (var) && DECL_HAS_DEBUG_EXPR_P (var))
725 return readability (DECL_DEBUG_EXPR (var)) - 1;
727 else
729 /* Slightly favor the underlying var over the SSA name to
730 avoid having them compare equal. */
731 return readability (var) - 1;
734 /* Avoid printing '<unknown>' for SSA names for temporaries. */
735 return -1;
737 break;
739 case PARM_DECL:
740 case VAR_DECL:
741 if (DECL_NAME (expr))
742 return HIGH_READABILITY;
743 else
744 /* We don't want to print temporaries. For example, the C FE
745 prints them as e.g. "<Uxxxx>" where "xxxx" is the low 16 bits
746 of the tree pointer (see pp_c_tree_decl_identifier). */
747 return -1;
749 case RESULT_DECL:
750 /* Printing "<return-value>" isn't ideal, but is less awful than
751 trying to print a temporary. */
752 return HIGH_READABILITY / 2;
754 case NOP_EXPR:
756 /* Impose a moderate readability penalty for casts. */
757 const int CAST_PENALTY = 32;
758 return readability (TREE_OPERAND (expr, 0)) - CAST_PENALTY;
761 case INTEGER_CST:
762 return HIGH_READABILITY;
764 default:
765 return 0;
768 return 0;
771 /* A qsort comparator for trees to sort them into most user-readable to
772 least user-readable. */
775 readability_comparator (const void *p1, const void *p2)
777 path_var pv1 = *(path_var const *)p1;
778 path_var pv2 = *(path_var const *)p2;
780 const int tree_r1 = readability (pv1.m_tree);
781 const int tree_r2 = readability (pv2.m_tree);
783 /* Favor items that are deeper on the stack and hence more recent;
784 this also favors locals over globals. */
785 const int COST_PER_FRAME = 64;
786 const int depth_r1 = pv1.m_stack_depth * COST_PER_FRAME;
787 const int depth_r2 = pv2.m_stack_depth * COST_PER_FRAME;
789 /* Combine the scores from the tree and from the stack depth.
790 This e.g. lets us have a slightly penalized cast in the most
791 recent stack frame "beat" an uncast value in an older stack frame. */
792 const int sum_r1 = tree_r1 + depth_r1;
793 const int sum_r2 = tree_r2 + depth_r2;
794 if (int cmp = sum_r2 - sum_r1)
795 return cmp;
797 /* Otherwise, more readable trees win. */
798 if (int cmp = tree_r2 - tree_r1)
799 return cmp;
801 /* Otherwise, if they have the same readability, then impose an
802 arbitrary deterministic ordering on them. */
804 if (int cmp = TREE_CODE (pv1.m_tree) - TREE_CODE (pv2.m_tree))
805 return cmp;
807 switch (TREE_CODE (pv1.m_tree))
809 default:
810 break;
811 case SSA_NAME:
812 if (int cmp = (SSA_NAME_VERSION (pv1.m_tree)
813 - SSA_NAME_VERSION (pv2.m_tree)))
814 return cmp;
815 break;
816 case PARM_DECL:
817 case VAR_DECL:
818 case RESULT_DECL:
819 if (int cmp = DECL_UID (pv1.m_tree) - DECL_UID (pv2.m_tree))
820 return cmp;
821 break;
824 /* TODO: We ought to find ways of sorting such cases. */
825 return 0;
828 /* Return true is SNODE is the EXIT node of a function, or is one
829 of the final snodes within its function.
831 Specifically, handle the final supernodes before the EXIT node,
832 for the case of clobbers that happen immediately before exiting.
833 We need a run of snodes leading to the return_p snode, where all edges are
834 intraprocedural, and every snode has just one successor.
836 We use this when suppressing leak reports at the end of "main". */
838 static bool
839 returning_from_function_p (const supernode *snode)
841 if (!snode)
842 return false;
844 unsigned count = 0;
845 const supernode *iter = snode;
846 while (true)
848 if (iter->return_p ())
849 return true;
850 if (iter->m_succs.length () != 1)
851 return false;
852 const superedge *sedge = iter->m_succs[0];
853 if (sedge->get_kind () != SUPEREDGE_CFG_EDGE)
854 return false;
855 iter = sedge->m_dest;
857 /* Impose a limit to ensure we terminate for pathological cases.
859 We only care about the final 3 nodes, due to cases like:
861 (clobber causing leak)
864 <label>:
865 return _val;
867 EXIT BB.*/
868 if (++count > 3)
869 return false;
873 /* Find the best tree for SVAL and call SM's on_leak vfunc with it.
874 If on_leak returns a pending_diagnostic, queue it up to be reported,
875 so that we potentially complain about a leak of SVAL in the given STATE. */
877 void
878 impl_region_model_context::on_state_leak (const state_machine &sm,
879 const svalue *sval,
880 state_machine::state_t state)
882 logger * const logger = get_logger ();
883 LOG_SCOPE (logger);
884 if (logger)
886 logger->start_log_line ();
887 logger->log_partial ("considering leak of ");
888 sval->dump_to_pp (logger->get_printer (), true);
889 logger->end_log_line ();
892 if (!m_eg)
893 return;
895 /* m_old_state also needs to be non-NULL so that the sm_ctxt can look
896 up the old state of SVAL. */
897 gcc_assert (m_old_state);
899 /* SVAL has leaked within the new state: it is not used by any reachable
900 regions.
901 We need to convert it back to a tree, but since it's likely no regions
902 use it, we have to find the "best" tree for it in the old_state. */
903 svalue_set visited;
904 path_var leaked_pv
905 = m_old_state->m_region_model->get_representative_path_var (sval,
906 &visited,
907 nullptr);
909 /* Strip off top-level casts */
910 if (leaked_pv.m_tree && TREE_CODE (leaked_pv.m_tree) == NOP_EXPR)
911 leaked_pv.m_tree = TREE_OPERAND (leaked_pv.m_tree, 0);
913 /* This might be NULL; the pending_diagnostic subclasses need to cope
914 with this. */
915 tree leaked_tree = leaked_pv.m_tree;
916 if (logger)
918 if (leaked_tree)
919 logger->log ("best leaked_tree: %qE", leaked_tree);
920 else
921 logger->log ("best leaked_tree: NULL");
924 leak_stmt_finder stmt_finder (*m_eg, leaked_tree);
925 gcc_assert (m_enode_for_diag);
927 /* Don't complain about leaks when returning from "main". */
928 if (returning_from_function_p (m_enode_for_diag->get_supernode ()))
930 tree fndecl = m_enode_for_diag->get_function ()->decl;
931 if (id_equal (DECL_NAME (fndecl), "main"))
933 if (logger)
934 logger->log ("not reporting leak from main");
935 return;
939 tree leaked_tree_for_diag = fixup_tree_for_diagnostic (leaked_tree);
940 std::unique_ptr<pending_diagnostic> pd = sm.on_leak (leaked_tree_for_diag);
941 if (pd)
943 pending_location ploc (m_enode_for_diag,
944 m_enode_for_diag->get_supernode (),
945 m_stmt,
946 &stmt_finder);
947 m_eg->get_diagnostic_manager ().add_diagnostic
948 (&sm, ploc,
949 leaked_tree_for_diag, sval, state, std::move (pd));
953 /* Implementation of region_model_context::on_condition vfunc.
954 Notify all state machines about the condition, which could lead to
955 state transitions. */
957 void
958 impl_region_model_context::on_condition (const svalue *lhs,
959 enum tree_code op,
960 const svalue *rhs)
962 int sm_idx;
963 sm_state_map *smap;
964 FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
966 const state_machine &sm = m_ext_state.get_sm (sm_idx);
967 impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
968 m_old_state, m_new_state,
969 m_old_state->m_checker_states[sm_idx],
970 m_new_state->m_checker_states[sm_idx],
971 m_path_ctxt);
972 sm.on_condition (&sm_ctxt,
973 (m_enode_for_diag
974 ? m_enode_for_diag->get_supernode ()
975 : NULL),
976 m_stmt,
977 lhs, op, rhs);
981 /* Implementation of region_model_context::on_bounded_ranges vfunc.
982 Notify all state machines about the ranges, which could lead to
983 state transitions. */
985 void
986 impl_region_model_context::on_bounded_ranges (const svalue &sval,
987 const bounded_ranges &ranges)
989 int sm_idx;
990 sm_state_map *smap;
991 FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
993 const state_machine &sm = m_ext_state.get_sm (sm_idx);
994 impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
995 m_old_state, m_new_state,
996 m_old_state->m_checker_states[sm_idx],
997 m_new_state->m_checker_states[sm_idx],
998 m_path_ctxt);
999 sm.on_bounded_ranges (&sm_ctxt,
1000 (m_enode_for_diag
1001 ? m_enode_for_diag->get_supernode ()
1002 : NULL),
1003 m_stmt, sval, ranges);
1007 /* Implementation of region_model_context::on_pop_frame vfunc.
1008 Notify all state machines about the frame being popped, which
1009 could lead to states being discarded. */
1011 void
1012 impl_region_model_context::on_pop_frame (const frame_region *frame_reg)
1014 int sm_idx;
1015 sm_state_map *smap;
1016 FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
1018 const state_machine &sm = m_ext_state.get_sm (sm_idx);
1019 sm.on_pop_frame (smap, frame_reg);
1023 /* Implementation of region_model_context::on_phi vfunc.
1024 Notify all state machines about the phi, which could lead to
1025 state transitions. */
1027 void
1028 impl_region_model_context::on_phi (const gphi *phi, tree rhs)
1030 int sm_idx;
1031 sm_state_map *smap;
1032 FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
1034 const state_machine &sm = m_ext_state.get_sm (sm_idx);
1035 impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
1036 m_old_state, m_new_state,
1037 m_old_state->m_checker_states[sm_idx],
1038 m_new_state->m_checker_states[sm_idx],
1039 m_path_ctxt);
1040 sm.on_phi (&sm_ctxt, m_enode_for_diag->get_supernode (), phi, rhs);
1044 /* Implementation of region_model_context::on_unexpected_tree_code vfunc.
1045 Mark the new state as being invalid for further exploration.
1046 TODO(stage1): introduce a warning for when this occurs. */
1048 void
1049 impl_region_model_context::on_unexpected_tree_code (tree t,
1050 const dump_location_t &loc)
1052 logger * const logger = get_logger ();
1053 if (logger)
1054 logger->log ("unhandled tree code: %qs in %qs at %s:%i",
1055 get_tree_code_name (TREE_CODE (t)),
1056 loc.get_impl_location ().m_function,
1057 loc.get_impl_location ().m_file,
1058 loc.get_impl_location ().m_line);
1059 if (m_new_state)
1060 m_new_state->m_valid = false;
1063 /* Implementation of region_model_context::maybe_did_work vfunc.
1064 Mark that "externally visible work" has occurred, and thus we
1065 shouldn't report an infinite loop here. */
1067 void
1068 impl_region_model_context::maybe_did_work ()
1070 if (m_out_could_have_done_work)
1071 *m_out_could_have_done_work = true;
1074 /* struct point_and_state. */
1076 /* Assert that this object is sane. */
1078 void
1079 point_and_state::validate (const extrinsic_state &ext_state) const
1081 /* Skip this in a release build. */
1082 #if !CHECKING_P
1083 return;
1084 #endif
1086 m_point.validate ();
1088 m_state.validate (ext_state);
1090 /* Verify that the callstring's model of the stack corresponds to that
1091 of the region_model. */
1092 /* They should have the same depth. */
1093 gcc_assert (m_point.get_stack_depth ()
1094 == m_state.m_region_model->get_stack_depth ());
1095 /* Check the functions in the callstring vs those in the frames
1096 at each depth. */
1097 for (const frame_region *iter_frame
1098 = m_state.m_region_model->get_current_frame ();
1099 iter_frame; iter_frame = iter_frame->get_calling_frame ())
1101 int index = iter_frame->get_index ();
1102 gcc_assert (m_point.get_function_at_depth (index)
1103 == &iter_frame->get_function ());
1107 /* Subroutine of print_enode_indices: print a run of indices from START_IDX
1108 to END_IDX to PP, using and updating *FIRST_RUN. */
1110 static void
1111 print_run (pretty_printer *pp, int start_idx, int end_idx,
1112 bool *first_run)
1114 if (!(*first_run))
1115 pp_string (pp, ", ");
1116 *first_run = false;
1117 if (start_idx == end_idx)
1118 pp_printf (pp, "EN: %i", start_idx);
1119 else
1120 pp_printf (pp, "EN: %i-%i", start_idx, end_idx);
1123 /* Print the indices within ENODES to PP, collecting them as
1124 runs/singletons e.g. "EN: 4-7, EN: 20-23, EN: 42". */
1126 static void
1127 print_enode_indices (pretty_printer *pp,
1128 const auto_vec<exploded_node *> &enodes)
1130 int cur_start_idx = -1;
1131 int cur_finish_idx = -1;
1132 bool first_run = true;
1133 unsigned i;
1134 exploded_node *enode;
1135 FOR_EACH_VEC_ELT (enodes, i, enode)
1137 if (cur_start_idx == -1)
1139 gcc_assert (cur_finish_idx == -1);
1140 cur_start_idx = cur_finish_idx = enode->m_index;
1142 else
1144 if (enode->m_index == cur_finish_idx + 1)
1145 /* Continuation of a run. */
1146 cur_finish_idx = enode->m_index;
1147 else
1149 /* Finish existing run, start a new one. */
1150 gcc_assert (cur_start_idx >= 0);
1151 gcc_assert (cur_finish_idx >= 0);
1152 print_run (pp, cur_start_idx, cur_finish_idx,
1153 &first_run);
1154 cur_start_idx = cur_finish_idx = enode->m_index;
1158 /* Finish any existing run. */
1159 if (cur_start_idx >= 0)
1161 gcc_assert (cur_finish_idx >= 0);
1162 print_run (pp, cur_start_idx, cur_finish_idx,
1163 &first_run);
1167 /* struct eg_traits::dump_args_t. */
1169 /* The <FILENAME>.eg.dot output can quickly become unwieldy if we show
1170 full details for all enodes (both in terms of CPU time to render it,
1171 and in terms of being meaningful to a human viewing it).
1173 If we show just the IDs then the resulting graph is usually viewable,
1174 but then we have to keep switching back and forth between the .dot
1175 view and other dumps.
1177 This function implements a heuristic for showing detail at the enodes
1178 that (we hope) matter, and just the ID at other enodes, fixing the CPU
1179 usage of the .dot viewer, and drawing the attention of the viewer
1180 to these enodes.
1182 Return true if ENODE should be shown in detail in .dot output.
1183 Return false if no detail should be shown for ENODE. */
1185 bool
1186 eg_traits::dump_args_t::show_enode_details_p (const exploded_node &enode) const
1188 /* If the number of exploded nodes isn't too large, we may as well show
1189 all enodes in full detail in the .dot output. */
1190 if (m_eg.m_nodes.length ()
1191 <= (unsigned) param_analyzer_max_enodes_for_full_dump)
1192 return true;
1194 /* Otherwise, assume that what's most interesting are state explosions,
1195 and thus the places where this happened.
1196 Expand enodes at program points where we hit the per-enode limit, so we
1197 can investigate what exploded. */
1198 const per_program_point_data *per_point_data
1199 = m_eg.get_per_program_point_data (enode.get_point ());
1200 return per_point_data->m_excess_enodes > 0;
1203 /* class exploded_node : public dnode<eg_traits>. */
1205 const char *
1206 exploded_node::status_to_str (enum status s)
1208 switch (s)
1210 default: gcc_unreachable ();
1211 case STATUS_WORKLIST: return "WORKLIST";
1212 case STATUS_PROCESSED: return "PROCESSED";
1213 case STATUS_MERGER: return "MERGER";
1214 case STATUS_BULK_MERGED: return "BULK_MERGED";
1218 /* exploded_node's ctor. */
1220 exploded_node::exploded_node (const point_and_state &ps,
1221 int index)
1222 : m_ps (ps), m_status (STATUS_WORKLIST), m_index (index),
1223 m_num_processed_stmts (0)
1225 gcc_checking_assert (ps.get_state ().m_region_model->canonicalized_p ());
1228 /* Get the stmt that was processed in this enode at index IDX.
1229 IDX is an index within the stmts processed at this enode, rather
1230 than within those of the supernode. */
1232 const gimple *
1233 exploded_node::get_processed_stmt (unsigned idx) const
1235 gcc_assert (idx < m_num_processed_stmts);
1236 const program_point &point = get_point ();
1237 gcc_assert (point.get_kind () == PK_BEFORE_STMT);
1238 const supernode *snode = get_supernode ();
1239 const unsigned int point_stmt_idx = point.get_stmt_idx ();
1240 const unsigned int idx_within_snode = point_stmt_idx + idx;
1241 const gimple *stmt = snode->m_stmts[idx_within_snode];
1242 return stmt;
1245 /* For use by dump_dot, get a value for the .dot "fillcolor" attribute.
1246 Colorize by sm-state, to make it easier to see how sm-state propagates
1247 through the exploded_graph. */
1249 const char *
1250 exploded_node::get_dot_fillcolor () const
1252 const program_state &state = get_state ();
1254 /* We want to be able to easily distinguish the no-sm-state case,
1255 and to be able to distinguish cases where there's a single state
1256 from each other.
1258 Sum the sm_states, and use the result to choose from a table,
1259 modulo table-size, special-casing the "no sm-state" case. */
1260 int total_sm_state = 0;
1261 int i;
1262 sm_state_map *smap;
1263 FOR_EACH_VEC_ELT (state.m_checker_states, i, smap)
1265 for (sm_state_map::iterator_t iter = smap->begin ();
1266 iter != smap->end ();
1267 ++iter)
1268 total_sm_state += (*iter).second.m_state->get_id ();
1269 total_sm_state += smap->get_global_state ()->get_id ();
1272 if (total_sm_state > 0)
1274 /* An arbitrarily-picked collection of light colors. */
1275 const char * const colors[]
1276 = {"azure", "coral", "cornsilk", "lightblue", "yellow",
1277 "honeydew", "lightpink", "lightsalmon", "palegreen1",
1278 "wheat", "seashell"};
1279 const int num_colors = ARRAY_SIZE (colors);
1280 return colors[total_sm_state % num_colors];
1282 else
1283 /* No sm-state. */
1284 return "lightgrey";
1287 /* Implementation of dnode::dump_dot vfunc for exploded_node. */
1289 void
1290 exploded_node::dump_dot (graphviz_out *gv, const dump_args_t &args) const
1292 pretty_printer *pp = gv->get_pp ();
1294 dump_dot_id (pp);
1295 pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
1296 get_dot_fillcolor ());
1297 pp_write_text_to_stream (pp);
1299 pp_printf (pp, "EN: %i", m_index);
1300 if (m_status == STATUS_MERGER)
1301 pp_string (pp, " (merger)");
1302 else if (m_status == STATUS_BULK_MERGED)
1303 pp_string (pp, " (bulk merged)");
1304 pp_newline (pp);
1306 if (args.show_enode_details_p (*this))
1308 format f (true);
1309 m_ps.get_point ().print (pp, f);
1310 pp_newline (pp);
1312 const extrinsic_state &ext_state = args.m_eg.get_ext_state ();
1313 const program_state &state = m_ps.get_state ();
1314 state.dump_to_pp (ext_state, false, true, pp);
1315 pp_newline (pp);
1317 dump_processed_stmts (pp);
1320 dump_saved_diagnostics (pp);
1322 args.dump_extra_info (this, pp);
1324 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
1326 pp_string (pp, "\"];\n\n");
1328 /* It can be hard to locate the saved diagnostics as text within the
1329 enode nodes, so add extra nodes to the graph for each saved_diagnostic,
1330 highlighted in red.
1331 Compare with dump_saved_diagnostics. */
1333 unsigned i;
1334 const saved_diagnostic *sd;
1335 FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
1337 sd->dump_as_dot_node (pp);
1339 /* Add edge connecting this enode to the saved_diagnostic. */
1340 dump_dot_id (pp);
1341 pp_string (pp, " -> ");
1342 sd->dump_dot_id (pp);
1343 pp_string (pp, " [style=\"dotted\" arrowhead=\"none\"];");
1344 pp_newline (pp);
1348 pp_flush (pp);
1351 /* Show any stmts that were processed within this enode,
1352 and their index within the supernode. */
1353 void
1354 exploded_node::dump_processed_stmts (pretty_printer *pp) const
1356 if (m_num_processed_stmts > 0)
1358 const program_point &point = get_point ();
1359 gcc_assert (point.get_kind () == PK_BEFORE_STMT);
1360 const supernode *snode = get_supernode ();
1361 const unsigned int point_stmt_idx = point.get_stmt_idx ();
1363 pp_printf (pp, "stmts: %i", m_num_processed_stmts);
1364 pp_newline (pp);
1365 for (unsigned i = 0; i < m_num_processed_stmts; i++)
1367 const unsigned int idx_within_snode = point_stmt_idx + i;
1368 const gimple *stmt = snode->m_stmts[idx_within_snode];
1369 pp_printf (pp, " %i: ", idx_within_snode);
1370 pp_gimple_stmt_1 (pp, stmt, 0, (dump_flags_t)0);
1371 pp_newline (pp);
1376 /* Dump any saved_diagnostics at this enode to PP. */
1378 void
1379 exploded_node::dump_saved_diagnostics (pretty_printer *pp) const
1381 unsigned i;
1382 const saved_diagnostic *sd;
1383 FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
1385 pp_printf (pp, "DIAGNOSTIC: %s (sd: %i)",
1386 sd->m_d->get_kind (), sd->get_index ());
1387 pp_newline (pp);
1391 /* Dump this to PP in a form suitable for use as an id in .dot output. */
1393 void
1394 exploded_node::dump_dot_id (pretty_printer *pp) const
1396 pp_printf (pp, "exploded_node_%i", m_index);
1399 /* Dump a multiline representation of this node to PP. */
1401 void
1402 exploded_node::dump_to_pp (pretty_printer *pp,
1403 const extrinsic_state &ext_state) const
1405 pp_printf (pp, "EN: %i", m_index);
1406 pp_newline (pp);
1408 format f (true);
1409 m_ps.get_point ().print (pp, f);
1410 pp_newline (pp);
1412 m_ps.get_state ().dump_to_pp (ext_state, false, true, pp);
1413 pp_newline (pp);
1416 /* Dump a multiline representation of this node to FILE. */
1418 void
1419 exploded_node::dump (FILE *fp,
1420 const extrinsic_state &ext_state) const
1422 pretty_printer pp;
1423 pp_format_decoder (&pp) = default_tree_printer;
1424 pp_show_color (&pp) = pp_show_color (global_dc->printer);
1425 pp.set_output_stream (fp);
1426 dump_to_pp (&pp, ext_state);
1427 pp_flush (&pp);
1430 /* Dump a multiline representation of this node to stderr. */
1432 DEBUG_FUNCTION void
1433 exploded_node::dump (const extrinsic_state &ext_state) const
1435 dump (stderr, ext_state);
1438 /* Return a new json::object of the form
1439 {"point" : object for program_point,
1440 "state" : object for program_state,
1441 "status" : str,
1442 "idx" : int,
1443 "processed_stmts" : int}. */
1445 json::object *
1446 exploded_node::to_json (const extrinsic_state &ext_state) const
1448 json::object *enode_obj = new json::object ();
1450 enode_obj->set ("point", get_point ().to_json ());
1451 enode_obj->set ("state", get_state ().to_json (ext_state));
1452 enode_obj->set ("status", new json::string (status_to_str (m_status)));
1453 enode_obj->set ("idx", new json::integer_number (m_index));
1454 enode_obj->set ("processed_stmts",
1455 new json::integer_number (m_num_processed_stmts));
1457 return enode_obj;
1460 } // namespace ana
1462 /* Return true if FNDECL has a gimple body. */
1463 // TODO: is there a pre-canned way to do this?
1465 bool
1466 fndecl_has_gimple_body_p (tree fndecl)
1468 if (fndecl == NULL_TREE)
1469 return false;
1471 cgraph_node *n = cgraph_node::get (fndecl);
1472 if (!n)
1473 return false;
1475 return n->has_gimple_body_p ();
1478 namespace ana {
1480 /* Modify STATE in place, applying the effects of the stmt at this node's
1481 point. */
1483 exploded_node::on_stmt_flags
1484 exploded_node::on_stmt (exploded_graph &eg,
1485 const supernode *snode,
1486 const gimple *stmt,
1487 program_state *state,
1488 uncertainty_t *uncertainty,
1489 bool *out_could_have_done_work,
1490 path_context *path_ctxt)
1492 logger *logger = eg.get_logger ();
1493 LOG_SCOPE (logger);
1494 if (logger)
1496 logger->start_log_line ();
1497 pp_gimple_stmt_1 (logger->get_printer (), stmt, 0, (dump_flags_t)0);
1498 logger->end_log_line ();
1501 /* Update input_location in case of ICE: make it easier to track down which
1502 source construct we're failing to handle. */
1503 input_location = stmt->location;
1505 gcc_assert (state->m_region_model);
1507 /* Preserve the old state. It is used here for looking
1508 up old checker states, for determining state transitions, and
1509 also within impl_region_model_context and impl_sm_context for
1510 going from tree to svalue_id. */
1511 const program_state old_state (*state);
1513 impl_region_model_context ctxt (eg, this,
1514 &old_state, state, uncertainty,
1515 path_ctxt, stmt, nullptr,
1516 out_could_have_done_work);
1518 /* Handle call summaries here. */
1519 if (cgraph_edge *cgedge
1520 = supergraph_call_edge (snode->get_function (), stmt))
1521 if (eg.get_analysis_plan ().use_summary_p (cgedge))
1523 function *called_fn = get_ultimate_function_for_cgraph_edge (cgedge);
1524 per_function_data *called_fn_data
1525 = eg.get_per_function_data (called_fn);
1526 if (called_fn_data)
1528 gcc_assert (called_fn);
1529 return replay_call_summaries (eg,
1530 snode,
1531 as_a <const gcall *> (stmt),
1532 state,
1533 path_ctxt,
1534 *called_fn,
1535 *called_fn_data,
1536 &ctxt);
1540 bool unknown_side_effects = false;
1541 bool terminate_path = false;
1543 on_stmt_pre (eg, stmt, state, &terminate_path,
1544 &unknown_side_effects, &ctxt);
1546 if (terminate_path)
1547 return on_stmt_flags::terminate_path ();
1549 int sm_idx;
1550 sm_state_map *smap;
1551 FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
1553 const state_machine &sm = eg.get_ext_state ().get_sm (sm_idx);
1554 const sm_state_map *old_smap
1555 = old_state.m_checker_states[sm_idx];
1556 sm_state_map *new_smap = state->m_checker_states[sm_idx];
1557 impl_sm_context sm_ctxt (eg, sm_idx, sm, this, &old_state, state,
1558 old_smap, new_smap, path_ctxt, NULL,
1559 unknown_side_effects);
1561 /* Allow the state_machine to handle the stmt. */
1562 if (sm.on_stmt (&sm_ctxt, snode, stmt))
1563 unknown_side_effects = false;
1566 if (path_ctxt->terminate_path_p ())
1567 return on_stmt_flags::terminate_path ();
1569 on_stmt_post (stmt, state, unknown_side_effects, &ctxt);
1571 return on_stmt_flags ();
1574 /* Handle the pre-sm-state part of STMT, modifying STATE in-place.
1575 Write true to *OUT_TERMINATE_PATH if the path should be terminated.
1576 Write true to *OUT_UNKNOWN_SIDE_EFFECTS if the stmt has unknown
1577 side effects. */
1579 void
1580 exploded_node::on_stmt_pre (exploded_graph &eg,
1581 const gimple *stmt,
1582 program_state *state,
1583 bool *out_terminate_path,
1584 bool *out_unknown_side_effects,
1585 region_model_context *ctxt)
1587 /* Handle special-case calls that require the full program_state. */
1588 if (const gcall *call = dyn_cast <const gcall *> (stmt))
1590 if (is_special_named_call_p (call, "__analyzer_dump", 0))
1592 /* Handle the builtin "__analyzer_dump" by dumping state
1593 to stderr. */
1594 state->dump (eg.get_ext_state (), true);
1595 return;
1597 else if (is_special_named_call_p (call, "__analyzer_dump_state", 2))
1599 state->impl_call_analyzer_dump_state (call, eg.get_ext_state (),
1600 ctxt);
1601 return;
1603 else if (is_setjmp_call_p (call))
1605 state->m_region_model->on_setjmp (call, this, ctxt);
1606 if (ctxt)
1607 ctxt->maybe_did_work ();
1608 return;
1610 else if (is_longjmp_call_p (call))
1612 on_longjmp (eg, call, state, ctxt);
1613 *out_terminate_path = true;
1614 if (ctxt)
1615 ctxt->maybe_did_work ();
1616 return;
1620 /* Otherwise, defer to m_region_model. */
1621 state->m_region_model->on_stmt_pre (stmt,
1622 out_unknown_side_effects,
1623 ctxt);
1626 /* Handle the post-sm-state part of STMT, modifying STATE in-place. */
1628 void
1629 exploded_node::on_stmt_post (const gimple *stmt,
1630 program_state *state,
1631 bool unknown_side_effects,
1632 region_model_context *ctxt)
1634 if (const gcall *call = dyn_cast <const gcall *> (stmt))
1635 state->m_region_model->on_call_post (call, unknown_side_effects, ctxt);
1638 /* A concrete call_info subclass representing a replay of a call summary. */
1640 class call_summary_edge_info : public call_info
1642 public:
1643 call_summary_edge_info (const call_details &cd,
1644 const function &called_fn,
1645 call_summary *summary,
1646 const extrinsic_state &ext_state)
1647 : call_info (cd, called_fn),
1648 m_called_fn (called_fn),
1649 m_summary (summary),
1650 m_ext_state (ext_state)
1653 bool update_state (program_state *state,
1654 const exploded_edge *,
1655 region_model_context *ctxt) const final override
1657 /* Update STATE based on summary_end_state. */
1658 call_details cd (get_call_details (state->m_region_model, ctxt));
1659 call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
1660 const program_state &summary_end_state = m_summary->get_state ();
1661 return state->replay_call_summary (r, summary_end_state);
1664 bool update_model (region_model *model,
1665 const exploded_edge *,
1666 region_model_context *ctxt) const final override
1668 /* Update STATE based on summary_end_state. */
1669 call_details cd (get_call_details (model, ctxt));
1670 call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
1671 const program_state &summary_end_state = m_summary->get_state ();
1672 model->replay_call_summary (r, *summary_end_state.m_region_model);
1673 return true;
1676 label_text get_desc (bool /*can_colorize*/) const final override
1678 return m_summary->get_desc ();
1681 private:
1682 const function &m_called_fn;
1683 call_summary *m_summary;
1684 const extrinsic_state &m_ext_state;
1687 /* Use PATH_CTXT to bifurcate, which when handled will add custom edges
1688 for a replay of the various feasible summaries in CALLED_FN_DATA. */
1690 exploded_node::on_stmt_flags
1691 exploded_node::replay_call_summaries (exploded_graph &eg,
1692 const supernode *snode,
1693 const gcall *call_stmt,
1694 program_state *state,
1695 path_context *path_ctxt,
1696 const function &called_fn,
1697 per_function_data &called_fn_data,
1698 region_model_context *ctxt)
1700 logger *logger = eg.get_logger ();
1701 LOG_SCOPE (logger);
1703 /* Each summary will call bifurcate on the PATH_CTXT. */
1704 for (auto summary : called_fn_data.m_summaries)
1705 replay_call_summary (eg, snode, call_stmt, state,
1706 path_ctxt, called_fn, summary, ctxt);
1707 path_ctxt->terminate_path ();
1709 return on_stmt_flags ();
1712 /* Use PATH_CTXT to bifurcate, which when handled will add a
1713 custom edge for a replay of SUMMARY, if the summary's
1714 conditions are feasible based on the current state. */
1716 void
1717 exploded_node::replay_call_summary (exploded_graph &eg,
1718 const supernode *snode,
1719 const gcall *call_stmt,
1720 program_state *old_state,
1721 path_context *path_ctxt,
1722 const function &called_fn,
1723 call_summary *summary,
1724 region_model_context *ctxt)
1726 logger *logger = eg.get_logger ();
1727 LOG_SCOPE (logger);
1728 gcc_assert (snode);
1729 gcc_assert (call_stmt);
1730 gcc_assert (old_state);
1731 gcc_assert (summary);
1733 if (logger)
1734 logger->log ("using %s as summary for call to %qE from %qE",
1735 summary->get_desc ().get (),
1736 called_fn.decl,
1737 snode->get_function ()->decl);
1738 const extrinsic_state &ext_state = eg.get_ext_state ();
1739 const program_state &summary_end_state = summary->get_state ();
1740 if (logger)
1742 pretty_printer *pp = logger->get_printer ();
1744 logger->start_log_line ();
1745 pp_string (pp, "callsite state: ");
1746 old_state->dump_to_pp (ext_state, true, false, pp);
1747 logger->end_log_line ();
1749 logger->start_log_line ();
1750 pp_string (pp, "summary end state: ");
1751 summary_end_state.dump_to_pp (ext_state, true, false, pp);
1752 logger->end_log_line ();
1755 program_state new_state (*old_state);
1757 call_details cd (call_stmt, new_state.m_region_model, ctxt);
1758 call_summary_replay r (cd, called_fn, summary, ext_state);
1760 if (path_ctxt)
1761 path_ctxt->bifurcate (make_unique<call_summary_edge_info> (cd,
1762 called_fn,
1763 summary,
1764 ext_state));
1768 /* Consider the effect of following superedge SUCC from this node.
1770 Return true if it's feasible to follow the edge, or false
1771 if it's infeasible.
1773 Examples: if it's the "true" branch within
1774 a CFG and we know the conditional is false, we know it's infeasible.
1775 If it's one of multiple interprocedual "return" edges, then only
1776 the edge back to the most recent callsite is feasible.
1778 Update NEXT_STATE accordingly (e.g. to record that a condition was
1779 true or false, or that the NULL-ness of a pointer has been checked,
1780 pushing/popping stack frames, etc).
1782 Update NEXT_POINT accordingly (updating the call string). */
1784 bool
1785 exploded_node::on_edge (exploded_graph &eg,
1786 const superedge *succ,
1787 program_point *next_point,
1788 program_state *next_state,
1789 uncertainty_t *uncertainty)
1791 LOG_FUNC (eg.get_logger ());
1793 if (!next_point->on_edge (eg, succ))
1794 return false;
1796 if (!next_state->on_edge (eg, this, succ, uncertainty))
1797 return false;
1799 return true;
1802 /* Verify that the stack at LONGJMP_POINT is still valid, given a call
1803 to "setjmp" at SETJMP_POINT - the stack frame that "setjmp" was
1804 called in must still be valid.
1806 Caveat: this merely checks the call_strings in the points; it doesn't
1807 detect the case where a frame returns and is then called again. */
1809 static bool
1810 valid_longjmp_stack_p (const program_point &longjmp_point,
1811 const program_point &setjmp_point)
1813 const call_string &cs_at_longjmp = longjmp_point.get_call_string ();
1814 const call_string &cs_at_setjmp = setjmp_point.get_call_string ();
1816 if (cs_at_longjmp.length () < cs_at_setjmp.length ())
1817 return false;
1819 /* Check that the call strings match, up to the depth of the
1820 setjmp point. */
1821 for (unsigned depth = 0; depth < cs_at_setjmp.length (); depth++)
1822 if (cs_at_longjmp[depth] != cs_at_setjmp[depth])
1823 return false;
1825 return true;
1828 /* A pending_diagnostic subclass for complaining about bad longjmps,
1829 where the enclosing function of the "setjmp" has returned (and thus
1830 the stack frame no longer exists). */
1832 class stale_jmp_buf : public pending_diagnostic_subclass<stale_jmp_buf>
1834 public:
1835 stale_jmp_buf (const gcall *setjmp_call, const gcall *longjmp_call,
1836 const program_point &setjmp_point)
1837 : m_setjmp_call (setjmp_call), m_longjmp_call (longjmp_call),
1838 m_setjmp_point (setjmp_point), m_stack_pop_event (NULL)
1841 int get_controlling_option () const final override
1843 return OPT_Wanalyzer_stale_setjmp_buffer;
1846 bool emit (diagnostic_emission_context &ctxt) final override
1848 return ctxt.warn ("%qs called after enclosing function of %qs has returned",
1849 get_user_facing_name (m_longjmp_call),
1850 get_user_facing_name (m_setjmp_call));
1853 const char *get_kind () const final override
1854 { return "stale_jmp_buf"; }
1856 bool operator== (const stale_jmp_buf &other) const
1858 return (m_setjmp_call == other.m_setjmp_call
1859 && m_longjmp_call == other.m_longjmp_call);
1862 bool
1863 maybe_add_custom_events_for_superedge (const exploded_edge &eedge,
1864 checker_path *emission_path)
1865 final override
1867 /* Detect exactly when the stack first becomes invalid,
1868 and issue an event then. */
1869 if (m_stack_pop_event)
1870 return false;
1871 const exploded_node *src_node = eedge.m_src;
1872 const program_point &src_point = src_node->get_point ();
1873 const exploded_node *dst_node = eedge.m_dest;
1874 const program_point &dst_point = dst_node->get_point ();
1875 if (valid_longjmp_stack_p (src_point, m_setjmp_point)
1876 && !valid_longjmp_stack_p (dst_point, m_setjmp_point))
1878 /* Compare with diagnostic_manager::add_events_for_superedge. */
1879 const int src_stack_depth = src_point.get_stack_depth ();
1880 m_stack_pop_event = new precanned_custom_event
1881 (event_loc_info (src_point.get_location (),
1882 src_point.get_fndecl (),
1883 src_stack_depth),
1884 "stack frame is popped here, invalidating saved environment");
1885 emission_path->add_event
1886 (std::unique_ptr<custom_event> (m_stack_pop_event));
1887 return false;
1889 return false;
1892 label_text describe_final_event (const evdesc::final_event &ev) final override
1894 if (m_stack_pop_event)
1895 return ev.formatted_print
1896 ("%qs called after enclosing function of %qs returned at %@",
1897 get_user_facing_name (m_longjmp_call),
1898 get_user_facing_name (m_setjmp_call),
1899 m_stack_pop_event->get_id_ptr ());
1900 else
1901 return ev.formatted_print
1902 ("%qs called after enclosing function of %qs has returned",
1903 get_user_facing_name (m_longjmp_call),
1904 get_user_facing_name (m_setjmp_call));;
1908 private:
1909 const gcall *m_setjmp_call;
1910 const gcall *m_longjmp_call;
1911 program_point m_setjmp_point;
1912 custom_event *m_stack_pop_event;
1915 /* Handle LONGJMP_CALL, a call to longjmp or siglongjmp.
1917 Attempt to locate where setjmp/sigsetjmp was called on the jmp_buf and build
1918 an exploded_node and exploded_edge to it representing a rewind to that frame,
1919 handling the various kinds of failure that can occur. */
1921 void
1922 exploded_node::on_longjmp (exploded_graph &eg,
1923 const gcall *longjmp_call,
1924 program_state *new_state,
1925 region_model_context *ctxt)
1927 tree buf_ptr = gimple_call_arg (longjmp_call, 0);
1928 gcc_assert (POINTER_TYPE_P (TREE_TYPE (buf_ptr)));
1930 region_model *new_region_model = new_state->m_region_model;
1931 const svalue *buf_ptr_sval = new_region_model->get_rvalue (buf_ptr, ctxt);
1932 const region *buf = new_region_model->deref_rvalue (buf_ptr_sval, buf_ptr,
1933 ctxt);
1935 const svalue *buf_content_sval
1936 = new_region_model->get_store_value (buf, ctxt);
1937 const setjmp_svalue *setjmp_sval
1938 = buf_content_sval->dyn_cast_setjmp_svalue ();
1939 if (!setjmp_sval)
1940 return;
1942 const setjmp_record tmp_setjmp_record = setjmp_sval->get_setjmp_record ();
1944 /* Build a custom enode and eedge for rewinding from the longjmp/siglongjmp
1945 call back to the setjmp/sigsetjmp. */
1946 rewind_info_t rewind_info (tmp_setjmp_record, longjmp_call);
1948 const gcall *setjmp_call = rewind_info.get_setjmp_call ();
1949 const program_point &setjmp_point = rewind_info.get_setjmp_point ();
1951 const program_point &longjmp_point = get_point ();
1953 /* Verify that the setjmp's call_stack hasn't been popped. */
1954 if (!valid_longjmp_stack_p (longjmp_point, setjmp_point))
1956 ctxt->warn (make_unique<stale_jmp_buf> (setjmp_call,
1957 longjmp_call,
1958 setjmp_point));
1959 return;
1962 gcc_assert (longjmp_point.get_stack_depth ()
1963 >= setjmp_point.get_stack_depth ());
1965 /* Update the state for use by the destination node. */
1967 /* Stash the current number of diagnostics so that we can update
1968 any that this adds to show where the longjmp is rewinding to. */
1970 diagnostic_manager *dm = &eg.get_diagnostic_manager ();
1971 unsigned prev_num_diagnostics = dm->get_num_diagnostics ();
1973 new_region_model->on_longjmp (longjmp_call, setjmp_call,
1974 setjmp_point.get_stack_depth (), ctxt);
1976 /* Detect leaks in the new state relative to the old state. */
1977 program_state::detect_leaks (get_state (), *new_state, NULL,
1978 eg.get_ext_state (), ctxt);
1980 program_point next_point
1981 = program_point::after_supernode (setjmp_point.get_supernode (),
1982 setjmp_point.get_call_string ());
1984 exploded_node *next
1985 = eg.get_or_create_node (next_point, *new_state, this);
1987 /* Create custom exploded_edge for a longjmp. */
1988 if (next)
1990 exploded_edge *eedge
1991 = eg.add_edge (const_cast<exploded_node *> (this), next, NULL, true,
1992 make_unique<rewind_info_t> (tmp_setjmp_record,
1993 longjmp_call));
1995 /* For any diagnostics that were queued here (such as leaks) we want
1996 the checker_path to show the rewinding events after the "final event"
1997 so that the user sees where the longjmp is rewinding to (otherwise the
1998 path is meaningless).
2000 For example, we want to emit something like:
2001 | NN | {
2002 | NN | longjmp (env, 1);
2003 | | ~~~~~~~~~~~~~~~~
2004 | | |
2005 | | (10) 'ptr' leaks here; was allocated at (7)
2006 | | (11) rewinding from 'longjmp' in 'inner'...
2008 <-------------+
2010 'outer': event 12
2012 | NN | i = setjmp(env);
2013 | | ^~~~~~
2014 | | |
2015 | | (12) ...to 'setjmp' in 'outer' (saved at (2))
2017 where the "final" event above is event (10), but we want to append
2018 events (11) and (12) afterwards.
2020 Do this by setting m_trailing_eedge on any diagnostics that were
2021 just saved. */
2022 unsigned num_diagnostics = dm->get_num_diagnostics ();
2023 for (unsigned i = prev_num_diagnostics; i < num_diagnostics; i++)
2025 saved_diagnostic *sd = dm->get_saved_diagnostic (i);
2026 sd->m_trailing_eedge = eedge;
2031 /* Subroutine of exploded_graph::process_node for finding the successors
2032 of the supernode for a function exit basic block.
2034 Ensure that pop_frame is called, potentially queuing diagnostics about
2035 leaks. */
2037 void
2038 exploded_node::detect_leaks (exploded_graph &eg)
2040 LOG_FUNC_1 (eg.get_logger (), "EN: %i", m_index);
2042 gcc_assert (get_point ().get_supernode ()->return_p ());
2044 /* If we're not a "top-level" function, do nothing; pop_frame
2045 will be called when handling the return superedge. */
2046 if (get_point ().get_stack_depth () > 1)
2047 return;
2049 /* We have a "top-level" function. */
2050 gcc_assert (get_point ().get_stack_depth () == 1);
2052 const program_state &old_state = get_state ();
2054 /* Work with a temporary copy of the state: pop the frame, and see
2055 what leaks (via purge_unused_svalues). */
2056 program_state new_state (old_state);
2058 gcc_assert (new_state.m_region_model);
2060 uncertainty_t uncertainty;
2061 impl_region_model_context ctxt (eg, this,
2062 &old_state, &new_state, &uncertainty, NULL,
2063 get_stmt ());
2064 const svalue *result = NULL;
2065 new_state.m_region_model->pop_frame (NULL, &result, &ctxt, nullptr);
2066 program_state::detect_leaks (old_state, new_state, result,
2067 eg.get_ext_state (), &ctxt);
2070 /* Dump the successors and predecessors of this enode to OUTF. */
2072 void
2073 exploded_node::dump_succs_and_preds (FILE *outf) const
2075 unsigned i;
2076 exploded_edge *e;
2078 auto_vec<exploded_node *> preds (m_preds.length ());
2079 FOR_EACH_VEC_ELT (m_preds, i, e)
2080 preds.quick_push (e->m_src);
2081 pretty_printer pp;
2082 print_enode_indices (&pp, preds);
2083 fprintf (outf, "preds: %s\n",
2084 pp_formatted_text (&pp));
2087 auto_vec<exploded_node *> succs (m_succs.length ());
2088 FOR_EACH_VEC_ELT (m_succs, i, e)
2089 succs.quick_push (e->m_dest);
2090 pretty_printer pp;
2091 print_enode_indices (&pp, succs);
2092 fprintf (outf, "succs: %s\n",
2093 pp_formatted_text (&pp));
2097 /* class dynamic_call_info_t : public custom_edge_info. */
2099 /* Implementation of custom_edge_info::update_model vfunc
2100 for dynamic_call_info_t.
2102 Update state for a dynamically discovered call (or return), by pushing
2103 or popping the a frame for the appropriate function. */
2105 bool
2106 dynamic_call_info_t::update_model (region_model *model,
2107 const exploded_edge *eedge,
2108 region_model_context *ctxt) const
2110 gcc_assert (eedge);
2111 if (m_is_returning_call)
2112 model->update_for_return_gcall (m_dynamic_call, ctxt);
2113 else
2115 function *callee = eedge->m_dest->get_function ();
2116 model->update_for_gcall (m_dynamic_call, ctxt, callee);
2118 return true;
2121 /* Implementation of custom_edge_info::add_events_to_path vfunc
2122 for dynamic_call_info_t. */
2124 void
2125 dynamic_call_info_t::add_events_to_path (checker_path *emission_path,
2126 const exploded_edge &eedge) const
2128 const exploded_node *src_node = eedge.m_src;
2129 const program_point &src_point = src_node->get_point ();
2130 const int src_stack_depth = src_point.get_stack_depth ();
2131 const exploded_node *dest_node = eedge.m_dest;
2132 const program_point &dest_point = dest_node->get_point ();
2133 const int dest_stack_depth = dest_point.get_stack_depth ();
2135 if (m_is_returning_call)
2136 emission_path->add_event
2137 (make_unique<return_event> (eedge,
2138 event_loc_info (m_dynamic_call
2139 ? m_dynamic_call->location
2140 : UNKNOWN_LOCATION,
2141 dest_point.get_fndecl (),
2142 dest_stack_depth)));
2143 else
2144 emission_path->add_event
2145 (make_unique<call_event> (eedge,
2146 event_loc_info (m_dynamic_call
2147 ? m_dynamic_call->location
2148 : UNKNOWN_LOCATION,
2149 src_point.get_fndecl (),
2150 src_stack_depth)));
2153 /* class rewind_info_t : public custom_edge_info. */
2155 /* Implementation of custom_edge_info::update_model vfunc
2156 for rewind_info_t.
2158 Update state for the special-case of a rewind of a longjmp
2159 to a setjmp (which doesn't have a superedge, but does affect
2160 state). */
2162 bool
2163 rewind_info_t::update_model (region_model *model,
2164 const exploded_edge *eedge,
2165 region_model_context *) const
2167 gcc_assert (eedge);
2168 const program_point &longjmp_point = eedge->m_src->get_point ();
2169 const program_point &setjmp_point = eedge->m_dest->get_point ();
2171 gcc_assert (longjmp_point.get_stack_depth ()
2172 >= setjmp_point.get_stack_depth ());
2174 model->on_longjmp (get_longjmp_call (),
2175 get_setjmp_call (),
2176 setjmp_point.get_stack_depth (), NULL);
2177 return true;
2180 /* Implementation of custom_edge_info::add_events_to_path vfunc
2181 for rewind_info_t. */
2183 void
2184 rewind_info_t::add_events_to_path (checker_path *emission_path,
2185 const exploded_edge &eedge) const
2187 const exploded_node *src_node = eedge.m_src;
2188 const program_point &src_point = src_node->get_point ();
2189 const int src_stack_depth = src_point.get_stack_depth ();
2190 const exploded_node *dst_node = eedge.m_dest;
2191 const program_point &dst_point = dst_node->get_point ();
2192 const int dst_stack_depth = dst_point.get_stack_depth ();
2194 emission_path->add_event
2195 (make_unique<rewind_from_longjmp_event>
2196 (&eedge,
2197 event_loc_info (get_longjmp_call ()->location,
2198 src_point.get_fndecl (),
2199 src_stack_depth),
2200 this));
2201 emission_path->add_event
2202 (make_unique<rewind_to_setjmp_event>
2203 (&eedge,
2204 event_loc_info (get_setjmp_call ()->location,
2205 dst_point.get_fndecl (),
2206 dst_stack_depth),
2207 this));
2210 /* class exploded_edge : public dedge<eg_traits>. */
2212 /* exploded_edge's ctor. */
2214 exploded_edge::exploded_edge (exploded_node *src, exploded_node *dest,
2215 const superedge *sedge, bool could_do_work,
2216 std::unique_ptr<custom_edge_info> custom_info)
2217 : dedge<eg_traits> (src, dest), m_sedge (sedge),
2218 m_custom_info (std::move (custom_info)),
2219 m_could_do_work_p (could_do_work)
2223 /* Implementation of dedge::dump_dot vfunc for exploded_edge.
2224 Use the label of the underlying superedge, if any. */
2226 void
2227 exploded_edge::dump_dot (graphviz_out *gv, const dump_args_t &) const
2229 pretty_printer *pp = gv->get_pp ();
2231 m_src->dump_dot_id (pp);
2232 pp_string (pp, " -> ");
2233 m_dest->dump_dot_id (pp);
2234 dump_dot_label (pp);
2237 /* Second half of exploded_edge::dump_dot. This is split out
2238 for use by trimmed_graph::dump_dot and base_feasible_edge::dump_dot. */
2240 void
2241 exploded_edge::dump_dot_label (pretty_printer *pp) const
2243 const char *style = "\"solid,bold\"";
2244 const char *color = "black";
2245 int weight = 10;
2246 const char *constraint = "true";
2248 if (m_sedge)
2249 switch (m_sedge->m_kind)
2251 default:
2252 gcc_unreachable ();
2253 case SUPEREDGE_CFG_EDGE:
2254 break;
2255 case SUPEREDGE_CALL:
2256 color = "red";
2257 //constraint = "false";
2258 break;
2259 case SUPEREDGE_RETURN:
2260 color = "green";
2261 //constraint = "false";
2262 break;
2263 case SUPEREDGE_INTRAPROCEDURAL_CALL:
2264 style = "\"dotted\"";
2265 break;
2267 if (m_custom_info)
2269 color = "red";
2270 style = "\"dotted\"";
2273 pp_printf (pp,
2274 (" [style=%s, color=%s, weight=%d, constraint=%s,"
2275 " headlabel=\""),
2276 style, color, weight, constraint);
2278 if (m_sedge)
2279 m_sedge->dump_label_to_pp (pp, false);
2280 else if (m_custom_info)
2281 m_custom_info->print (pp);
2283 pp_printf (pp, "%s",
2284 could_do_work_p () ? "(could do work)" : "DOES NO WORK");
2286 //pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
2288 pp_printf (pp, "\"];\n");
2291 /* Return a new json::object of the form
2292 {"src_idx": int, the index of the source exploded edge,
2293 "dst_idx": int, the index of the destination exploded edge,
2294 "sedge": (optional) object for the superedge, if any,
2295 "custom": (optional) str, a description, if this is a custom edge}. */
2297 json::object *
2298 exploded_edge::to_json () const
2300 json::object *eedge_obj = new json::object ();
2301 eedge_obj->set ("src_idx", new json::integer_number (m_src->m_index));
2302 eedge_obj->set ("dst_idx", new json::integer_number (m_dest->m_index));
2303 if (m_sedge)
2304 eedge_obj->set ("sedge", m_sedge->to_json ());
2305 if (m_custom_info)
2307 pretty_printer pp;
2308 pp_format_decoder (&pp) = default_tree_printer;
2309 m_custom_info->print (&pp);
2310 eedge_obj->set ("custom", new json::string (pp_formatted_text (&pp)));
2312 return eedge_obj;
2315 /* struct stats. */
2317 /* stats' ctor. */
2319 stats::stats (int num_supernodes)
2320 : m_node_reuse_count (0),
2321 m_node_reuse_after_merge_count (0),
2322 m_num_supernodes (num_supernodes)
2324 for (int i = 0; i < NUM_POINT_KINDS; i++)
2325 m_num_nodes[i] = 0;
2328 /* Log these stats in multiline form to LOGGER. */
2330 void
2331 stats::log (logger *logger) const
2333 gcc_assert (logger);
2334 for (int i = 0; i < NUM_POINT_KINDS; i++)
2335 if (m_num_nodes[i] > 0)
2336 logger->log ("m_num_nodes[%s]: %i",
2337 point_kind_to_string (static_cast <enum point_kind> (i)),
2338 m_num_nodes[i]);
2339 logger->log ("m_node_reuse_count: %i", m_node_reuse_count);
2340 logger->log ("m_node_reuse_after_merge_count: %i",
2341 m_node_reuse_after_merge_count);
2344 /* Dump these stats in multiline form to OUT. */
2346 void
2347 stats::dump (FILE *out) const
2349 for (int i = 0; i < NUM_POINT_KINDS; i++)
2350 if (m_num_nodes[i] > 0)
2351 fprintf (out, "m_num_nodes[%s]: %i\n",
2352 point_kind_to_string (static_cast <enum point_kind> (i)),
2353 m_num_nodes[i]);
2354 fprintf (out, "m_node_reuse_count: %i\n", m_node_reuse_count);
2355 fprintf (out, "m_node_reuse_after_merge_count: %i\n",
2356 m_node_reuse_after_merge_count);
2358 if (m_num_supernodes > 0)
2359 fprintf (out, "PK_AFTER_SUPERNODE nodes per supernode: %.2f\n",
2360 (float)m_num_nodes[PK_AFTER_SUPERNODE] / (float)m_num_supernodes);
2363 /* Return the total number of enodes recorded within this object. */
2366 stats::get_total_enodes () const
2368 int result = 0;
2369 for (int i = 0; i < NUM_POINT_KINDS; i++)
2370 result += m_num_nodes[i];
2371 return result;
2374 /* struct per_function_data. */
2376 per_function_data::~per_function_data ()
2378 for (auto iter : m_summaries)
2379 delete iter;
2382 void
2383 per_function_data::add_call_summary (exploded_node *node)
2385 m_summaries.safe_push (new call_summary (this, node));
2388 /* strongly_connected_components's ctor. Tarjan's SCC algorithm. */
2390 strongly_connected_components::
2391 strongly_connected_components (const supergraph &sg, logger *logger)
2392 : m_sg (sg), m_per_node (m_sg.num_nodes ())
2394 LOG_SCOPE (logger);
2395 auto_timevar tv (TV_ANALYZER_SCC);
2397 for (int i = 0; i < m_sg.num_nodes (); i++)
2398 m_per_node.quick_push (per_node_data ());
2400 for (int i = 0; i < m_sg.num_nodes (); i++)
2401 if (m_per_node[i].m_index == -1)
2402 strong_connect (i);
2404 if (0)
2405 dump ();
2408 /* Dump this object to stderr. */
2410 DEBUG_FUNCTION void
2411 strongly_connected_components::dump () const
2413 for (int i = 0; i < m_sg.num_nodes (); i++)
2415 const per_node_data &v = m_per_node[i];
2416 fprintf (stderr, "SN %i: index: %i lowlink: %i on_stack: %i\n",
2417 i, v.m_index, v.m_lowlink, v.m_on_stack);
2421 /* Return a new json::array of per-snode SCC ids. */
2423 json::array *
2424 strongly_connected_components::to_json () const
2426 json::array *scc_arr = new json::array ();
2427 for (int i = 0; i < m_sg.num_nodes (); i++)
2428 scc_arr->append (new json::integer_number (get_scc_id (i)));
2429 return scc_arr;
2432 /* Subroutine of strongly_connected_components's ctor, part of Tarjan's
2433 SCC algorithm. */
2435 void
2436 strongly_connected_components::strong_connect (unsigned index)
2438 supernode *v_snode = m_sg.get_node_by_index (index);
2440 /* Set the depth index for v to the smallest unused index. */
2441 per_node_data *v = &m_per_node[index];
2442 v->m_index = index;
2443 v->m_lowlink = index;
2444 m_stack.safe_push (index);
2445 v->m_on_stack = true;
2446 index++;
2448 /* Consider successors of v. */
2449 unsigned i;
2450 superedge *sedge;
2451 FOR_EACH_VEC_ELT (v_snode->m_succs, i, sedge)
2453 if (sedge->get_kind () != SUPEREDGE_CFG_EDGE
2454 && sedge->get_kind () != SUPEREDGE_INTRAPROCEDURAL_CALL)
2455 continue;
2456 supernode *w_snode = sedge->m_dest;
2457 per_node_data *w = &m_per_node[w_snode->m_index];
2458 if (w->m_index == -1)
2460 /* Successor w has not yet been visited; recurse on it. */
2461 strong_connect (w_snode->m_index);
2462 v->m_lowlink = MIN (v->m_lowlink, w->m_lowlink);
2464 else if (w->m_on_stack)
2466 /* Successor w is in stack S and hence in the current SCC
2467 If w is not on stack, then (v, w) is a cross-edge in the DFS
2468 tree and must be ignored. */
2469 v->m_lowlink = MIN (v->m_lowlink, w->m_index);
2473 /* If v is a root node, pop the stack and generate an SCC. */
2475 if (v->m_lowlink == v->m_index)
2477 per_node_data *w;
2478 do {
2479 int idx = m_stack.pop ();
2480 w = &m_per_node[idx];
2481 w->m_on_stack = false;
2482 } while (w != v);
2486 /* worklist's ctor. */
2488 worklist::worklist (const exploded_graph &eg, const analysis_plan &plan)
2489 : m_scc (eg.get_supergraph (), eg.get_logger ()),
2490 m_plan (plan),
2491 m_queue (key_t (*this, NULL))
2495 /* Return the number of nodes in the worklist. */
2497 unsigned
2498 worklist::length () const
2500 return m_queue.nodes ();
2503 /* Return the next node in the worklist, removing it. */
2505 exploded_node *
2506 worklist::take_next ()
2508 return m_queue.extract_min ();
2511 /* Return the next node in the worklist without removing it. */
2513 exploded_node *
2514 worklist::peek_next ()
2516 return m_queue.min ();
2519 /* Add ENODE to the worklist. */
2521 void
2522 worklist::add_node (exploded_node *enode)
2524 gcc_assert (enode->get_status () == exploded_node::STATUS_WORKLIST);
2525 m_queue.insert (key_t (*this, enode), enode);
2528 /* Comparator for implementing worklist::key_t comparison operators.
2529 Return negative if KA is before KB
2530 Return positive if KA is after KB
2531 Return 0 if they are equal.
2533 The ordering of the worklist is critical for performance and for
2534 avoiding node explosions. Ideally we want all enodes at a CFG join-point
2535 with the same callstring to be sorted next to each other in the worklist
2536 so that a run of consecutive enodes can be merged and processed "in bulk"
2537 rather than individually or pairwise, minimizing the number of new enodes
2538 created. */
2541 worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb)
2543 const program_point &point_a = ka.m_enode->get_point ();
2544 const program_point &point_b = kb.m_enode->get_point ();
2545 const call_string &call_string_a = point_a.get_call_string ();
2546 const call_string &call_string_b = point_b.get_call_string ();
2548 /* Order empty-callstring points with different functions based on the
2549 analysis_plan, so that we generate summaries before they are used. */
2550 if (flag_analyzer_call_summaries
2551 && call_string_a.empty_p ()
2552 && call_string_b.empty_p ()
2553 && point_a.get_function () != NULL
2554 && point_b.get_function () != NULL
2555 && point_a.get_function () != point_b.get_function ())
2557 if (int cmp = ka.m_worklist.m_plan.cmp_function (point_a.get_function (),
2558 point_b.get_function ()))
2559 return cmp;
2562 /* Sort by callstring, so that nodes with deeper call strings are processed
2563 before those with shallower call strings.
2564 If we have
2565 splitting BB
2568 fn call no fn call
2571 join BB
2572 then we want the path inside the function call to be fully explored up
2573 to the return to the join BB before we explore on the "no fn call" path,
2574 so that both enodes at the join BB reach the front of the worklist at
2575 the same time and thus have a chance of being merged. */
2576 int cs_cmp = call_string::cmp (call_string_a, call_string_b);
2577 if (cs_cmp)
2578 return cs_cmp;
2580 /* Order by SCC. */
2581 int scc_id_a = ka.get_scc_id (ka.m_enode);
2582 int scc_id_b = kb.get_scc_id (kb.m_enode);
2583 if (scc_id_a != scc_id_b)
2584 return scc_id_a - scc_id_b;
2586 /* If in same SCC, order by supernode index (an arbitrary but stable
2587 ordering). */
2588 const supernode *snode_a = ka.m_enode->get_supernode ();
2589 const supernode *snode_b = kb.m_enode->get_supernode ();
2590 if (snode_a == NULL)
2592 if (snode_b != NULL)
2593 /* One is NULL. */
2594 return -1;
2595 else
2596 /* Both are NULL. */
2597 return 0;
2599 if (snode_b == NULL)
2600 /* One is NULL. */
2601 return 1;
2602 /* Neither are NULL. */
2603 gcc_assert (snode_a && snode_b);
2604 if (snode_a->m_index != snode_b->m_index)
2605 return snode_a->m_index - snode_b->m_index;
2607 gcc_assert (snode_a == snode_b);
2609 /* Order within supernode via program point. */
2610 int within_snode_cmp
2611 = function_point::cmp_within_supernode (point_a.get_function_point (),
2612 point_b.get_function_point ());
2613 if (within_snode_cmp)
2614 return within_snode_cmp;
2616 /* Otherwise, we ought to have the same program_point. */
2617 gcc_assert (point_a == point_b);
2619 const program_state &state_a = ka.m_enode->get_state ();
2620 const program_state &state_b = kb.m_enode->get_state ();
2622 /* Sort by sm-state, so that identical sm-states are grouped
2623 together in the worklist. */
2624 for (unsigned sm_idx = 0; sm_idx < state_a.m_checker_states.length ();
2625 ++sm_idx)
2627 sm_state_map *smap_a = state_a.m_checker_states[sm_idx];
2628 sm_state_map *smap_b = state_b.m_checker_states[sm_idx];
2630 if (int smap_cmp = sm_state_map::cmp (*smap_a, *smap_b))
2631 return smap_cmp;
2634 /* Otherwise, we have two enodes at the same program point but with
2635 different states. We don't have a good total ordering on states,
2636 so order them by enode index, so that we have at least have a
2637 stable sort. */
2638 return ka.m_enode->m_index - kb.m_enode->m_index;
2641 /* Return a new json::object of the form
2642 {"scc" : [per-snode-IDs]}, */
2644 json::object *
2645 worklist::to_json () const
2647 json::object *worklist_obj = new json::object ();
2649 worklist_obj->set ("scc", m_scc.to_json ());
2651 /* The following field isn't yet being JSONified:
2652 queue_t m_queue; */
2654 return worklist_obj;
2657 /* exploded_graph's ctor. */
2659 exploded_graph::exploded_graph (const supergraph &sg, logger *logger,
2660 const extrinsic_state &ext_state,
2661 const state_purge_map *purge_map,
2662 const analysis_plan &plan,
2663 int verbosity)
2664 : m_sg (sg), m_logger (logger),
2665 m_worklist (*this, plan),
2666 m_ext_state (ext_state),
2667 m_purge_map (purge_map),
2668 m_plan (plan),
2669 m_diagnostic_manager (logger, ext_state.get_engine (), verbosity),
2670 m_global_stats (m_sg.num_nodes ()),
2671 m_functionless_stats (m_sg.num_nodes ()),
2672 m_PK_AFTER_SUPERNODE_per_snode (m_sg.num_nodes ())
2674 m_origin = get_or_create_node
2675 (program_point::origin (*ext_state.get_model_manager ()),
2676 program_state (ext_state), NULL);
2677 for (int i = 0; i < m_sg.num_nodes (); i++)
2678 m_PK_AFTER_SUPERNODE_per_snode.quick_push (i);
2681 /* exploded_graph's dtor. */
2683 exploded_graph::~exploded_graph ()
2685 for (auto iter : m_per_point_data)
2686 delete iter.second;
2687 for (auto iter : m_per_function_data)
2688 delete iter.second;
2689 for (auto iter : m_per_function_stats)
2690 delete iter.second;
2691 for (auto iter : m_per_call_string_data)
2692 delete iter.second;
2695 /* Subroutine for use when implementing __attribute__((tainted_args))
2696 on functions and on function pointer fields in structs.
2698 Called on STATE representing a call to FNDECL.
2699 Mark all params of FNDECL in STATE as "tainted". Mark the value of all
2700 regions pointed to by params of FNDECL as "tainted".
2702 Return true if successful; return false if the "taint" state machine
2703 was not found. */
2705 static bool
2706 mark_params_as_tainted (program_state *state, tree fndecl,
2707 const extrinsic_state &ext_state)
2709 unsigned taint_sm_idx;
2710 if (!ext_state.get_sm_idx_by_name ("taint", &taint_sm_idx))
2711 return false;
2712 sm_state_map *smap = state->m_checker_states[taint_sm_idx];
2714 const state_machine &sm = ext_state.get_sm (taint_sm_idx);
2715 state_machine::state_t tainted = sm.get_state_by_name ("tainted");
2717 region_model_manager *mgr = ext_state.get_model_manager ();
2719 function *fun = DECL_STRUCT_FUNCTION (fndecl);
2720 gcc_assert (fun);
2722 for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
2723 iter_parm = DECL_CHAIN (iter_parm))
2725 tree param = iter_parm;
2726 if (tree parm_default_ssa = ssa_default_def (fun, iter_parm))
2727 param = parm_default_ssa;
2728 const region *param_reg = state->m_region_model->get_lvalue (param, NULL);
2729 const svalue *init_sval = mgr->get_or_create_initial_value (param_reg);
2730 smap->set_state (state->m_region_model, init_sval,
2731 tainted, NULL /*origin_new_sval*/, ext_state);
2732 if (POINTER_TYPE_P (TREE_TYPE (param)))
2734 const region *pointee_reg = mgr->get_symbolic_region (init_sval);
2735 /* Mark "*param" as tainted. */
2736 const svalue *init_pointee_sval
2737 = mgr->get_or_create_initial_value (pointee_reg);
2738 smap->set_state (state->m_region_model, init_pointee_sval,
2739 tainted, NULL /*origin_new_sval*/, ext_state);
2743 return true;
2746 /* Custom event for use by tainted_args_function_info when a function
2747 has been marked with __attribute__((tainted_args)). */
2749 class tainted_args_function_custom_event : public custom_event
2751 public:
2752 tainted_args_function_custom_event (const event_loc_info &loc_info)
2753 : custom_event (loc_info),
2754 m_fndecl (loc_info.m_fndecl)
2758 label_text get_desc (bool can_colorize) const final override
2760 return make_label_text
2761 (can_colorize,
2762 "function %qE marked with %<__attribute__((tainted_args))%>",
2763 m_fndecl);
2766 private:
2767 tree m_fndecl;
2770 /* Custom exploded_edge info for top-level calls to a function
2771 marked with __attribute__((tainted_args)). */
2773 class tainted_args_function_info : public custom_edge_info
2775 public:
2776 tainted_args_function_info (tree fndecl)
2777 : m_fndecl (fndecl)
2780 void print (pretty_printer *pp) const final override
2782 pp_string (pp, "call to tainted_args function");
2785 bool update_model (region_model *,
2786 const exploded_edge *,
2787 region_model_context *) const final override
2789 /* No-op. */
2790 return true;
2793 void add_events_to_path (checker_path *emission_path,
2794 const exploded_edge &) const final override
2796 emission_path->add_event
2797 (make_unique<tainted_args_function_custom_event>
2798 (event_loc_info (DECL_SOURCE_LOCATION (m_fndecl), m_fndecl, 0)));
2801 private:
2802 tree m_fndecl;
2805 /* Ensure that there is an exploded_node representing an external call to
2806 FUN, adding it to the worklist if creating it.
2808 Add an edge from the origin exploded_node to the function entrypoint
2809 exploded_node.
2811 Return the exploded_node for the entrypoint to the function. */
2813 exploded_node *
2814 exploded_graph::add_function_entry (const function &fun)
2816 gcc_assert (gimple_has_body_p (fun.decl));
2818 /* Be idempotent. */
2819 function *key = const_cast<function *> (&fun);
2820 if (m_functions_with_enodes.contains (key))
2822 logger * const logger = get_logger ();
2823 if (logger)
2824 logger->log ("entrypoint for %qE already exists", fun.decl);
2825 return NULL;
2828 program_point point
2829 = program_point::from_function_entry (*m_ext_state.get_model_manager (),
2830 m_sg, fun);
2831 program_state state (m_ext_state);
2832 state.push_frame (m_ext_state, fun);
2834 std::unique_ptr<custom_edge_info> edge_info = NULL;
2836 if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (fun.decl)))
2838 if (mark_params_as_tainted (&state, fun.decl, m_ext_state))
2839 edge_info = make_unique<tainted_args_function_info> (fun.decl);
2842 if (!state.m_valid)
2843 return NULL;
2845 exploded_node *enode = get_or_create_node (point, state, NULL);
2846 if (!enode)
2847 return NULL;
2849 add_edge (m_origin, enode, NULL, false, std::move (edge_info));
2851 m_functions_with_enodes.add (key);
2853 return enode;
2856 /* Get or create an exploded_node for (POINT, STATE).
2857 If a new node is created, it is added to the worklist.
2859 Use ENODE_FOR_DIAG, a pre-existing enode, for any diagnostics
2860 that need to be emitted (e.g. when purging state *before* we have
2861 a new enode). */
2863 exploded_node *
2864 exploded_graph::get_or_create_node (const program_point &point,
2865 const program_state &state,
2866 exploded_node *enode_for_diag)
2868 logger * const logger = get_logger ();
2869 LOG_FUNC (logger);
2870 if (logger)
2872 format f (false);
2873 pretty_printer *pp = logger->get_printer ();
2874 logger->start_log_line ();
2875 pp_string (pp, "point: ");
2876 point.print (pp, f);
2877 logger->end_log_line ();
2878 logger->start_log_line ();
2879 pp_string (pp, "state: ");
2880 state.dump_to_pp (m_ext_state, true, false, pp);
2881 logger->end_log_line ();
2884 /* Stop exploring paths for which we don't know how to effectively
2885 model the state. */
2886 if (!state.m_valid)
2888 if (logger)
2889 logger->log ("invalid state; not creating node");
2890 return NULL;
2893 auto_cfun sentinel (point.get_function ());
2895 state.validate (get_ext_state ());
2897 //state.dump (get_ext_state ());
2899 /* Prune state to try to improve the chances of a cache hit,
2900 avoiding generating redundant nodes. */
2901 uncertainty_t uncertainty;
2902 program_state pruned_state
2903 = state.prune_for_point (*this, point, enode_for_diag, &uncertainty);
2905 pruned_state.validate (get_ext_state ());
2907 //pruned_state.dump (get_ext_state ());
2909 if (logger)
2911 pretty_printer *pp = logger->get_printer ();
2912 logger->start_log_line ();
2913 pp_string (pp, "pruned_state: ");
2914 pruned_state.dump_to_pp (m_ext_state, true, false, pp);
2915 logger->end_log_line ();
2916 pruned_state.m_region_model->dump_to_pp (logger->get_printer (), true,
2917 false);
2920 stats *per_fn_stats = get_or_create_function_stats (point.get_function ());
2922 stats *per_cs_stats
2923 = &get_or_create_per_call_string_data (point.get_call_string ())->m_stats;
2925 point_and_state ps (point, pruned_state);
2926 ps.validate (m_ext_state);
2927 if (exploded_node **slot = m_point_and_state_to_node.get (&ps))
2929 /* An exploded_node for PS already exists. */
2930 if (logger)
2931 logger->log ("reused EN: %i", (*slot)->m_index);
2932 m_global_stats.m_node_reuse_count++;
2933 per_fn_stats->m_node_reuse_count++;
2934 per_cs_stats->m_node_reuse_count++;
2935 return *slot;
2938 per_program_point_data *per_point_data
2939 = get_or_create_per_program_point_data (point);
2941 /* Consider merging state with another enode at this program_point. */
2942 if (flag_analyzer_state_merge)
2944 exploded_node *existing_enode;
2945 unsigned i;
2946 FOR_EACH_VEC_ELT (per_point_data->m_enodes, i, existing_enode)
2948 if (logger)
2949 logger->log ("considering merging with existing EN: %i for point",
2950 existing_enode->m_index);
2951 gcc_assert (existing_enode->get_point () == point);
2952 const program_state &existing_state = existing_enode->get_state ();
2954 /* This merges successfully within the loop. */
2956 program_state merged_state (m_ext_state);
2957 if (pruned_state.can_merge_with_p (existing_state, m_ext_state, point,
2958 &merged_state))
2960 merged_state.validate (m_ext_state);
2961 if (logger)
2962 logger->log ("merging new state with that of EN: %i",
2963 existing_enode->m_index);
2965 /* Try again for a cache hit.
2966 Whether we get one or not, merged_state's value_ids have no
2967 relationship to those of the input state, and thus to those
2968 of CHANGE, so we must purge any svalue_ids from *CHANGE. */
2969 ps.set_state (merged_state);
2971 if (exploded_node **slot = m_point_and_state_to_node.get (&ps))
2973 /* An exploded_node for PS already exists. */
2974 if (logger)
2975 logger->log ("reused EN: %i", (*slot)->m_index);
2976 m_global_stats.m_node_reuse_after_merge_count++;
2977 per_fn_stats->m_node_reuse_after_merge_count++;
2978 per_cs_stats->m_node_reuse_after_merge_count++;
2979 return *slot;
2982 else
2983 if (logger)
2984 logger->log ("not merging new state with that of EN: %i",
2985 existing_enode->m_index);
2989 /* Impose a limit on the number of enodes per program point, and
2990 simply stop if we exceed it. */
2991 if ((int)per_point_data->m_enodes.length ()
2992 >= param_analyzer_max_enodes_per_program_point)
2994 pretty_printer pp;
2995 point.print (&pp, format (false));
2996 print_enode_indices (&pp, per_point_data->m_enodes);
2997 if (logger)
2998 logger->log ("not creating enode; too many at program point: %s",
2999 pp_formatted_text (&pp));
3000 warning_at (point.get_location (), OPT_Wanalyzer_too_complex,
3001 "terminating analysis for this program point: %s",
3002 pp_formatted_text (&pp));
3003 per_point_data->m_excess_enodes++;
3004 return NULL;
3007 ps.validate (m_ext_state);
3009 /* An exploded_node for "ps" doesn't already exist; create one. */
3010 exploded_node *node = new exploded_node (ps, m_nodes.length ());
3011 add_node (node);
3012 m_point_and_state_to_node.put (node->get_ps_key (), node);
3014 /* Update per-program_point data. */
3015 per_point_data->m_enodes.safe_push (node);
3017 const enum point_kind node_pk = node->get_point ().get_kind ();
3018 m_global_stats.m_num_nodes[node_pk]++;
3019 per_fn_stats->m_num_nodes[node_pk]++;
3020 per_cs_stats->m_num_nodes[node_pk]++;
3022 if (node_pk == PK_AFTER_SUPERNODE)
3023 m_PK_AFTER_SUPERNODE_per_snode[point.get_supernode ()->m_index]++;
3025 if (logger)
3027 format f (false);
3028 pretty_printer *pp = logger->get_printer ();
3029 logger->log ("created EN: %i", node->m_index);
3030 logger->start_log_line ();
3031 pp_string (pp, "point: ");
3032 point.print (pp, f);
3033 logger->end_log_line ();
3034 logger->start_log_line ();
3035 pp_string (pp, "pruned_state: ");
3036 pruned_state.dump_to_pp (m_ext_state, true, false, pp);
3037 logger->end_log_line ();
3040 /* Add the new node to the worlist. */
3041 m_worklist.add_node (node);
3042 return node;
3045 /* Add an exploded_edge from SRC to DEST, recording its association
3046 with SEDGE (which may be NULL), and, if non-NULL, taking ownership
3047 of CUSTOM_INFO. COULD_DO_WORK is used for detecting infinite loops.
3048 Return the newly-created eedge. */
3050 exploded_edge *
3051 exploded_graph::add_edge (exploded_node *src, exploded_node *dest,
3052 const superedge *sedge, bool could_do_work,
3053 std::unique_ptr<custom_edge_info> custom_info)
3055 if (get_logger ())
3056 get_logger ()->log ("creating edge EN: %i -> EN: %i",
3057 src->m_index, dest->m_index);
3058 exploded_edge *e
3059 = new exploded_edge (src, dest, sedge, could_do_work,
3060 std::move (custom_info));
3061 digraph<eg_traits>::add_edge (e);
3062 return e;
3065 /* Ensure that this graph has per-program_point-data for POINT;
3066 borrow a pointer to it. */
3068 per_program_point_data *
3069 exploded_graph::
3070 get_or_create_per_program_point_data (const program_point &point)
3072 if (per_program_point_data **slot = m_per_point_data.get (&point))
3073 return *slot;
3075 per_program_point_data *per_point_data = new per_program_point_data (point);
3076 m_per_point_data.put (&per_point_data->m_key, per_point_data);
3077 return per_point_data;
3080 /* Get this graph's per-program-point-data for POINT if there is any,
3081 otherwise NULL. */
3083 per_program_point_data *
3084 exploded_graph::get_per_program_point_data (const program_point &point) const
3086 if (per_program_point_data **slot
3087 = const_cast <point_map_t &> (m_per_point_data).get (&point))
3088 return *slot;
3090 return NULL;
3093 /* Ensure that this graph has per-call_string-data for CS;
3094 borrow a pointer to it. */
3096 per_call_string_data *
3097 exploded_graph::get_or_create_per_call_string_data (const call_string &cs)
3099 if (per_call_string_data **slot = m_per_call_string_data.get (&cs))
3100 return *slot;
3102 per_call_string_data *data = new per_call_string_data (cs, m_sg.num_nodes ());
3103 m_per_call_string_data.put (&data->m_key,
3104 data);
3105 return data;
3108 /* Ensure that this graph has per-function-data for FUN;
3109 borrow a pointer to it. */
3111 per_function_data *
3112 exploded_graph::get_or_create_per_function_data (function *fun)
3114 if (per_function_data **slot = m_per_function_data.get (fun))
3115 return *slot;
3117 per_function_data *data = new per_function_data ();
3118 m_per_function_data.put (fun, data);
3119 return data;
3122 /* Get this graph's per-function-data for FUN if there is any,
3123 otherwise NULL. */
3125 per_function_data *
3126 exploded_graph::get_per_function_data (function *fun) const
3128 if (per_function_data **slot
3129 = const_cast <per_function_data_t &> (m_per_function_data).get (fun))
3130 return *slot;
3132 return NULL;
3135 /* Return true if FUN should be traversed directly, rather than only as
3136 called via other functions. */
3138 static bool
3139 toplevel_function_p (const function &fun, logger *logger)
3141 /* Don't directly traverse into functions that have an "__analyzer_"
3142 prefix. Doing so is useful for the analyzer test suite, allowing
3143 us to have functions that are called in traversals, but not directly
3144 explored, thus testing how the analyzer handles calls and returns.
3145 With this, we can have DejaGnu directives that cover just the case
3146 of where a function is called by another function, without generating
3147 excess messages from the case of the first function being traversed
3148 directly. */
3149 #define ANALYZER_PREFIX "__analyzer_"
3150 if (!strncmp (IDENTIFIER_POINTER (DECL_NAME (fun.decl)), ANALYZER_PREFIX,
3151 strlen (ANALYZER_PREFIX)))
3153 if (logger)
3154 logger->log ("not traversing %qE (starts with %qs)",
3155 fun.decl, ANALYZER_PREFIX);
3156 return false;
3159 if (logger)
3160 logger->log ("traversing %qE (all checks passed)", fun.decl);
3162 return true;
3165 /* Custom event for use by tainted_call_info when a callback field has been
3166 marked with __attribute__((tainted_args)), for labelling the field. */
3168 class tainted_args_field_custom_event : public custom_event
3170 public:
3171 tainted_args_field_custom_event (tree field)
3172 : custom_event (event_loc_info (DECL_SOURCE_LOCATION (field), NULL_TREE, 0)),
3173 m_field (field)
3177 label_text get_desc (bool can_colorize) const final override
3179 return make_label_text (can_colorize,
3180 "field %qE of %qT"
3181 " is marked with %<__attribute__((tainted_args))%>",
3182 m_field, DECL_CONTEXT (m_field));
3185 private:
3186 tree m_field;
3189 /* Custom event for use by tainted_call_info when a callback field has been
3190 marked with __attribute__((tainted_args)), for labelling the function used
3191 in that callback. */
3193 class tainted_args_callback_custom_event : public custom_event
3195 public:
3196 tainted_args_callback_custom_event (const event_loc_info &loc_info,
3197 tree field)
3198 : custom_event (loc_info),
3199 m_field (field)
3203 label_text get_desc (bool can_colorize) const final override
3205 return make_label_text (can_colorize,
3206 "function %qE used as initializer for field %qE"
3207 " marked with %<__attribute__((tainted_args))%>",
3208 get_fndecl (), m_field);
3211 private:
3212 tree m_field;
3215 /* Custom edge info for use when adding a function used by a callback field
3216 marked with '__attribute__((tainted_args))'. */
3218 class tainted_args_call_info : public custom_edge_info
3220 public:
3221 tainted_args_call_info (tree field, tree fndecl, location_t loc)
3222 : m_field (field), m_fndecl (fndecl), m_loc (loc)
3225 void print (pretty_printer *pp) const final override
3227 pp_string (pp, "call to tainted field");
3230 bool update_model (region_model *,
3231 const exploded_edge *,
3232 region_model_context *) const final override
3234 /* No-op. */
3235 return true;
3238 void add_events_to_path (checker_path *emission_path,
3239 const exploded_edge &) const final override
3241 /* Show the field in the struct declaration, e.g.
3242 "(1) field 'store' is marked with '__attribute__((tainted_args))'" */
3243 emission_path->add_event
3244 (make_unique<tainted_args_field_custom_event> (m_field));
3246 /* Show the callback in the initializer
3247 e.g.
3248 "(2) function 'gadget_dev_desc_UDC_store' used as initializer
3249 for field 'store' marked with '__attribute__((tainted_args))'". */
3250 emission_path->add_event
3251 (make_unique<tainted_args_callback_custom_event>
3252 (event_loc_info (m_loc, m_fndecl, 0),
3253 m_field));
3256 private:
3257 tree m_field;
3258 tree m_fndecl;
3259 location_t m_loc;
3262 /* Given an initializer at LOC for FIELD marked with
3263 '__attribute__((tainted_args))' initialized with FNDECL, add an
3264 entrypoint to FNDECL to EG (and to its worklist) where the params to
3265 FNDECL are marked as tainted. */
3267 static void
3268 add_tainted_args_callback (exploded_graph *eg, tree field, tree fndecl,
3269 location_t loc)
3271 logger *logger = eg->get_logger ();
3273 LOG_SCOPE (logger);
3275 if (!gimple_has_body_p (fndecl))
3276 return;
3278 const extrinsic_state &ext_state = eg->get_ext_state ();
3280 function *fun = DECL_STRUCT_FUNCTION (fndecl);
3281 gcc_assert (fun);
3283 program_point point
3284 = program_point::from_function_entry (*ext_state.get_model_manager (),
3285 eg->get_supergraph (), *fun);
3286 program_state state (ext_state);
3287 state.push_frame (ext_state, *fun);
3289 if (!mark_params_as_tainted (&state, fndecl, ext_state))
3290 return;
3292 if (!state.m_valid)
3293 return;
3295 exploded_node *enode = eg->get_or_create_node (point, state, NULL);
3296 if (logger)
3298 if (enode)
3299 logger->log ("created EN %i for tainted_args %qE entrypoint",
3300 enode->m_index, fndecl);
3301 else
3303 logger->log ("did not create enode for tainted_args %qE entrypoint",
3304 fndecl);
3305 return;
3309 eg->add_edge (eg->get_origin (), enode, NULL, false,
3310 make_unique<tainted_args_call_info> (field, fndecl, loc));
3313 /* Callback for walk_tree for finding callbacks within initializers;
3314 ensure that any callback initializer where the corresponding field is
3315 marked with '__attribute__((tainted_args))' is treated as an entrypoint
3316 to the analysis, special-casing that the inputs to the callback are
3317 untrustworthy. */
3319 static tree
3320 add_any_callbacks (tree *tp, int *, void *data)
3322 exploded_graph *eg = (exploded_graph *)data;
3323 if (TREE_CODE (*tp) == CONSTRUCTOR)
3325 /* Find fields with the "tainted_args" attribute.
3326 walk_tree only walks the values, not the index values;
3327 look at the index values. */
3328 unsigned HOST_WIDE_INT idx;
3329 constructor_elt *ce;
3331 for (idx = 0; vec_safe_iterate (CONSTRUCTOR_ELTS (*tp), idx, &ce);
3332 idx++)
3333 if (ce->index && TREE_CODE (ce->index) == FIELD_DECL)
3334 if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (ce->index)))
3336 tree value = ce->value;
3337 if (TREE_CODE (value) == ADDR_EXPR
3338 && TREE_CODE (TREE_OPERAND (value, 0)) == FUNCTION_DECL)
3339 add_tainted_args_callback (eg, ce->index,
3340 TREE_OPERAND (value, 0),
3341 EXPR_LOCATION (value));
3345 return NULL_TREE;
3348 /* Add initial nodes to EG, with entrypoints for externally-callable
3349 functions. */
3351 void
3352 exploded_graph::build_initial_worklist ()
3354 logger * const logger = get_logger ();
3355 LOG_SCOPE (logger);
3357 cgraph_node *node;
3358 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
3360 function *fun = node->get_fun ();
3361 gcc_assert (fun);
3362 if (!toplevel_function_p (*fun, logger))
3363 continue;
3364 exploded_node *enode = add_function_entry (*fun);
3365 if (logger)
3367 if (enode)
3368 logger->log ("created EN %i for %qE entrypoint",
3369 enode->m_index, fun->decl);
3370 else
3371 logger->log ("did not create enode for %qE entrypoint", fun->decl);
3375 /* Find callbacks that are reachable from global initializers. */
3376 varpool_node *vpnode;
3377 FOR_EACH_VARIABLE (vpnode)
3379 tree decl = vpnode->decl;
3380 tree init = DECL_INITIAL (decl);
3381 if (!init)
3382 continue;
3383 walk_tree (&init, add_any_callbacks, this, NULL);
3387 /* The main loop of the analysis.
3388 Take freshly-created exploded_nodes from the worklist, calling
3389 process_node on them to explore the <point, state> graph.
3390 Add edges to their successors, potentially creating new successors
3391 (which are also added to the worklist). */
3393 void
3394 exploded_graph::process_worklist ()
3396 logger * const logger = get_logger ();
3397 LOG_SCOPE (logger);
3398 auto_timevar tv (TV_ANALYZER_WORKLIST);
3400 while (m_worklist.length () > 0)
3402 exploded_node *node = m_worklist.take_next ();
3403 gcc_assert (node->get_status () == exploded_node::STATUS_WORKLIST);
3404 gcc_assert (node->m_succs.length () == 0
3405 || node == m_origin);
3407 if (logger)
3408 logger->log ("next to process: EN: %i", node->m_index);
3410 /* If we have a run of nodes that are before-supernode, try merging and
3411 processing them together, rather than pairwise or individually. */
3412 if (flag_analyzer_state_merge && node != m_origin)
3413 if (maybe_process_run_of_before_supernode_enodes (node))
3414 goto handle_limit;
3416 /* Avoid exponential explosions of nodes by attempting to merge
3417 nodes that are at the same program point and which have
3418 sufficiently similar state. */
3419 if (flag_analyzer_state_merge && node != m_origin)
3420 if (exploded_node *node_2 = m_worklist.peek_next ())
3422 gcc_assert (node_2->get_status ()
3423 == exploded_node::STATUS_WORKLIST);
3424 gcc_assert (node->m_succs.length () == 0);
3425 gcc_assert (node_2->m_succs.length () == 0);
3427 gcc_assert (node != node_2);
3429 if (logger)
3430 logger->log ("peek worklist: EN: %i", node_2->m_index);
3432 if (node->get_point () == node_2->get_point ())
3434 const program_point &point = node->get_point ();
3435 if (logger)
3437 format f (false);
3438 pretty_printer *pp = logger->get_printer ();
3439 logger->start_log_line ();
3440 logger->log_partial
3441 ("got potential merge EN: %i and EN: %i at ",
3442 node->m_index, node_2->m_index);
3443 point.print (pp, f);
3444 logger->end_log_line ();
3446 const program_state &state = node->get_state ();
3447 const program_state &state_2 = node_2->get_state ();
3449 /* They shouldn't be equal, or we wouldn't have two
3450 separate nodes. */
3451 gcc_assert (state != state_2);
3453 program_state merged_state (m_ext_state);
3454 if (state.can_merge_with_p (state_2, m_ext_state,
3455 point, &merged_state))
3457 if (logger)
3458 logger->log ("merging EN: %i and EN: %i",
3459 node->m_index, node_2->m_index);
3461 if (merged_state == state)
3463 /* Then merge node_2 into node by adding an edge. */
3464 add_edge (node_2, node, NULL, false);
3466 /* Remove node_2 from the worklist. */
3467 m_worklist.take_next ();
3468 node_2->set_status (exploded_node::STATUS_MERGER);
3470 /* Continue processing "node" below. */
3472 else if (merged_state == state_2)
3474 /* Then merge node into node_2, and leave node_2
3475 in the worklist, to be processed on the next
3476 iteration. */
3477 add_edge (node, node_2, NULL, false);
3478 node->set_status (exploded_node::STATUS_MERGER);
3479 continue;
3481 else
3483 /* We have a merged state that differs from
3484 both state and state_2. */
3486 /* Remove node_2 from the worklist. */
3487 m_worklist.take_next ();
3489 /* Create (or get) an exploded node for the merged
3490 states, adding to the worklist. */
3491 exploded_node *merged_enode
3492 = get_or_create_node (node->get_point (),
3493 merged_state, node);
3494 if (merged_enode == NULL)
3495 continue;
3497 if (logger)
3498 logger->log ("merged EN: %i and EN: %i into EN: %i",
3499 node->m_index, node_2->m_index,
3500 merged_enode->m_index);
3502 /* "node" and "node_2" have both now been removed
3503 from the worklist; we should not process them.
3505 "merged_enode" may be a new node; if so it will be
3506 processed in a subsequent iteration.
3507 Alternatively, "merged_enode" could be an existing
3508 node; one way the latter can
3509 happen is if we end up merging a succession of
3510 similar nodes into one. */
3512 /* If merged_node is one of the two we were merging,
3513 add it back to the worklist to ensure it gets
3514 processed.
3516 Add edges from the merged nodes to it (but not a
3517 self-edge). */
3518 if (merged_enode == node)
3519 m_worklist.add_node (merged_enode);
3520 else
3522 add_edge (node, merged_enode, NULL, false);
3523 node->set_status (exploded_node::STATUS_MERGER);
3526 if (merged_enode == node_2)
3527 m_worklist.add_node (merged_enode);
3528 else
3530 add_edge (node_2, merged_enode, NULL, false);
3531 node_2->set_status (exploded_node::STATUS_MERGER);
3534 continue;
3538 /* TODO: should we attempt more than two nodes,
3539 or just do pairs of nodes? (and hope that we get
3540 a cascade of mergers). */
3544 process_node (node);
3546 handle_limit:
3547 /* Impose a hard limit on the number of exploded nodes, to ensure
3548 that the analysis terminates in the face of pathological state
3549 explosion (or bugs).
3551 Specifically, the limit is on the number of PK_AFTER_SUPERNODE
3552 exploded nodes, looking at supernode exit events.
3554 We use exit rather than entry since there can be multiple
3555 entry ENs, one per phi; the number of PK_AFTER_SUPERNODE ought
3556 to be equivalent to the number of supernodes multiplied by the
3557 number of states. */
3558 const int limit = m_sg.num_nodes () * param_analyzer_bb_explosion_factor;
3559 if (m_global_stats.m_num_nodes[PK_AFTER_SUPERNODE] > limit)
3561 if (logger)
3562 logger->log ("bailing out; too many nodes");
3563 warning_at (node->get_point ().get_location (),
3564 OPT_Wanalyzer_too_complex,
3565 "analysis bailed out early"
3566 " (%i 'after-snode' enodes; %i enodes)",
3567 m_global_stats.m_num_nodes[PK_AFTER_SUPERNODE],
3568 m_nodes.length ());
3569 return;
3574 /* Attempt to process a consecutive run of sufficiently-similar nodes in
3575 the worklist at a CFG join-point (having already popped ENODE from the
3576 head of the worklist).
3578 If ENODE's point is of the form (before-supernode, SNODE) and the next
3579 nodes in the worklist are a consecutive run of enodes of the same form,
3580 for the same supernode as ENODE (but potentially from different in-edges),
3581 process them all together, setting their status to STATUS_BULK_MERGED,
3582 and return true.
3583 Otherwise, return false, in which case ENODE must be processed in the
3584 normal way.
3586 When processing them all together, generate successor states based
3587 on phi nodes for the appropriate CFG edges, and then attempt to merge
3588 these states into a minimal set of merged successor states, partitioning
3589 the inputs by merged successor state.
3591 Create new exploded nodes for all of the merged states, and add edges
3592 connecting the input enodes to the corresponding merger exploded nodes.
3594 We hope we have a much smaller number of merged successor states
3595 compared to the number of input enodes - ideally just one,
3596 if all successor states can be merged.
3598 Processing and merging many together as one operation rather than as
3599 pairs avoids scaling issues where per-pair mergers could bloat the
3600 graph with merger nodes (especially so after switch statements). */
3602 bool
3603 exploded_graph::
3604 maybe_process_run_of_before_supernode_enodes (exploded_node *enode)
3606 /* A struct for tracking per-input state. */
3607 struct item
3609 item (exploded_node *input_enode)
3610 : m_input_enode (input_enode),
3611 m_processed_state (input_enode->get_state ()),
3612 m_merger_idx (-1)
3615 exploded_node *m_input_enode;
3616 program_state m_processed_state;
3617 int m_merger_idx;
3620 gcc_assert (enode->get_status () == exploded_node::STATUS_WORKLIST);
3621 gcc_assert (enode->m_succs.length () == 0);
3623 const program_point &point = enode->get_point ();
3625 if (point.get_kind () != PK_BEFORE_SUPERNODE)
3626 return false;
3628 const supernode *snode = point.get_supernode ();
3630 logger * const logger = get_logger ();
3631 LOG_SCOPE (logger);
3633 /* Find a run of enodes in the worklist that are before the same supernode,
3634 but potentially from different in-edges. */
3635 auto_vec <exploded_node *> enodes;
3636 enodes.safe_push (enode);
3637 while (exploded_node *enode_2 = m_worklist.peek_next ())
3639 gcc_assert (enode_2->get_status ()
3640 == exploded_node::STATUS_WORKLIST);
3641 gcc_assert (enode_2->m_succs.length () == 0);
3643 const program_point &point_2 = enode_2->get_point ();
3645 if (point_2.get_kind () == PK_BEFORE_SUPERNODE
3646 && point_2.get_supernode () == snode
3647 && &point_2.get_call_string () == &point.get_call_string ())
3649 enodes.safe_push (enode_2);
3650 m_worklist.take_next ();
3652 else
3653 break;
3656 /* If the only node is ENODE, then give up. */
3657 if (enodes.length () == 1)
3658 return false;
3660 if (logger)
3661 logger->log ("got run of %i enodes for SN: %i",
3662 enodes.length (), snode->m_index);
3664 /* All of these enodes have a shared successor point (even if they
3665 were for different in-edges). */
3666 program_point next_point (point.get_next ());
3668 /* Calculate the successor state for each enode in enodes. */
3669 auto_delete_vec<item> items (enodes.length ());
3670 unsigned i;
3671 exploded_node *iter_enode;
3672 FOR_EACH_VEC_ELT (enodes, i, iter_enode)
3674 item *it = new item (iter_enode);
3675 items.quick_push (it);
3676 const program_state &state = iter_enode->get_state ();
3677 program_state *next_state = &it->m_processed_state;
3678 next_state->validate (m_ext_state);
3679 const program_point &iter_point = iter_enode->get_point ();
3680 if (const superedge *iter_sedge = iter_point.get_from_edge ())
3682 uncertainty_t uncertainty;
3683 impl_region_model_context ctxt (*this, iter_enode,
3684 &state, next_state,
3685 &uncertainty, NULL, NULL);
3686 const cfg_superedge *last_cfg_superedge
3687 = iter_sedge->dyn_cast_cfg_superedge ();
3688 if (last_cfg_superedge)
3689 next_state->m_region_model->update_for_phis
3690 (snode, last_cfg_superedge, &ctxt);
3692 next_state->validate (m_ext_state);
3695 /* Attempt to partition the items into a set of merged states.
3696 We hope we have a much smaller number of merged states
3697 compared to the number of input enodes - ideally just one,
3698 if all can be merged. */
3699 auto_delete_vec <program_state> merged_states;
3700 auto_vec<item *> first_item_for_each_merged_state;
3701 item *it;
3702 FOR_EACH_VEC_ELT (items, i, it)
3704 const program_state &it_state = it->m_processed_state;
3705 program_state *merged_state;
3706 unsigned iter_merger_idx;
3707 FOR_EACH_VEC_ELT (merged_states, iter_merger_idx, merged_state)
3709 merged_state->validate (m_ext_state);
3710 program_state merge (m_ext_state);
3711 if (it_state.can_merge_with_p (*merged_state, m_ext_state,
3712 next_point, &merge))
3714 *merged_state = merge;
3715 merged_state->validate (m_ext_state);
3716 it->m_merger_idx = iter_merger_idx;
3717 if (logger)
3718 logger->log ("reusing merger state %i for item %i (EN: %i)",
3719 it->m_merger_idx, i, it->m_input_enode->m_index);
3720 goto got_merger;
3723 /* If it couldn't be merged with any existing merged_states,
3724 create a new one. */
3725 if (it->m_merger_idx == -1)
3727 it->m_merger_idx = merged_states.length ();
3728 merged_states.safe_push (new program_state (it_state));
3729 first_item_for_each_merged_state.safe_push (it);
3730 if (logger)
3731 logger->log ("using new merger state %i for item %i (EN: %i)",
3732 it->m_merger_idx, i, it->m_input_enode->m_index);
3734 got_merger:
3735 gcc_assert (it->m_merger_idx >= 0);
3736 gcc_assert ((unsigned)it->m_merger_idx < merged_states.length ());
3739 /* Create merger nodes. */
3740 auto_vec<exploded_node *> next_enodes (merged_states.length ());
3741 program_state *merged_state;
3742 FOR_EACH_VEC_ELT (merged_states, i, merged_state)
3744 exploded_node *src_enode
3745 = first_item_for_each_merged_state[i]->m_input_enode;
3746 exploded_node *next
3747 = get_or_create_node (next_point, *merged_state, src_enode);
3748 /* "next" could be NULL; we handle that when adding the edges below. */
3749 next_enodes.quick_push (next);
3750 if (logger)
3752 if (next)
3753 logger->log ("using EN: %i for merger state %i", next->m_index, i);
3754 else
3755 logger->log ("using NULL enode for merger state %i", i);
3759 /* Create edges from each input enode to the appropriate successor enode.
3760 Update the status of the now-processed input enodes. */
3761 FOR_EACH_VEC_ELT (items, i, it)
3763 exploded_node *next = next_enodes[it->m_merger_idx];
3764 if (next)
3765 add_edge (it->m_input_enode, next, NULL,
3766 false); /* no "work" is done during merger. */
3767 it->m_input_enode->set_status (exploded_node::STATUS_BULK_MERGED);
3770 if (logger)
3771 logger->log ("merged %i in-enodes into %i out-enode(s) at SN: %i",
3772 items.length (), merged_states.length (), snode->m_index);
3774 return true;
3777 /* Return true if STMT must appear at the start of its exploded node, and
3778 thus we can't consolidate its effects within a run of other statements,
3779 where PREV_STMT was the previous statement. */
3781 static bool
3782 stmt_requires_new_enode_p (const gimple *stmt,
3783 const gimple *prev_stmt)
3785 if (const gcall *call = dyn_cast <const gcall *> (stmt))
3787 /* Stop consolidating at calls to
3788 "__analyzer_dump_exploded_nodes", so they always appear at the
3789 start of an exploded_node. */
3790 if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes",
3792 return true;
3794 /* sm-signal.cc injects an additional custom eedge at "signal" calls
3795 from the registration enode to the handler enode, separate from the
3796 regular next state, which defeats the "detect state change" logic
3797 in process_node. Work around this via special-casing, to ensure
3798 we split the enode immediately before any "signal" call. */
3799 if (is_special_named_call_p (call, "signal", 2, true))
3800 return true;
3803 /* If we had a PREV_STMT with an unknown location, and this stmt
3804 has a known location, then if a state change happens here, it
3805 could be consolidated into PREV_STMT, giving us an event with
3806 no location. Ensure that STMT gets its own exploded_node to
3807 avoid this. */
3808 if (get_pure_location (prev_stmt->location) == UNKNOWN_LOCATION
3809 && get_pure_location (stmt->location) != UNKNOWN_LOCATION)
3810 return true;
3812 return false;
3815 /* Return true if OLD_STATE and NEW_STATE are sufficiently different that
3816 we should split enodes and create an exploded_edge separating them
3817 (which makes it easier to identify state changes of intereset when
3818 constructing checker_paths). */
3820 static bool
3821 state_change_requires_new_enode_p (const program_state &old_state,
3822 const program_state &new_state)
3824 /* Changes in dynamic extents signify creations of heap/alloca regions
3825 and resizings of heap regions; likely to be of interest in
3826 diagnostic paths. */
3827 if (old_state.m_region_model->get_dynamic_extents ()
3828 != new_state.m_region_model->get_dynamic_extents ())
3829 return true;
3831 /* Changes in sm-state are of interest. */
3832 int sm_idx;
3833 sm_state_map *smap;
3834 FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
3836 const sm_state_map *old_smap = old_state.m_checker_states[sm_idx];
3837 const sm_state_map *new_smap = new_state.m_checker_states[sm_idx];
3838 if (*old_smap != *new_smap)
3839 return true;
3842 return false;
3845 /* Create enodes and eedges for the function calls that doesn't have an
3846 underlying call superedge.
3848 Such case occurs when GCC's middle end didn't know which function to
3849 call but the analyzer does (with the help of current state).
3851 Some example such calls are dynamically dispatched calls to virtual
3852 functions or calls that happen via function pointer. */
3854 bool
3855 exploded_graph::maybe_create_dynamic_call (const gcall *call,
3856 tree fn_decl,
3857 exploded_node *node,
3858 program_state next_state,
3859 program_point &next_point,
3860 uncertainty_t *uncertainty,
3861 logger *logger)
3863 LOG_FUNC (logger);
3865 const program_point *this_point = &node->get_point ();
3866 function *fun = DECL_STRUCT_FUNCTION (fn_decl);
3867 if (fun)
3869 const supergraph &sg = this->get_supergraph ();
3870 supernode *sn_entry = sg.get_node_for_function_entry (*fun);
3871 supernode *sn_exit = sg.get_node_for_function_exit (*fun);
3873 program_point new_point
3874 = program_point::before_supernode (sn_entry,
3875 NULL,
3876 this_point->get_call_string ());
3878 new_point.push_to_call_stack (sn_exit,
3879 next_point.get_supernode());
3881 /* Impose a maximum recursion depth and don't analyze paths
3882 that exceed it further.
3883 This is something of a blunt workaround, but it only
3884 applies to recursion (and mutual recursion), not to
3885 general call stacks. */
3886 if (new_point.get_call_string ().calc_recursion_depth ()
3887 > param_analyzer_max_recursion_depth)
3889 if (logger)
3890 logger->log ("rejecting call edge: recursion limit exceeded");
3891 return false;
3894 next_state.push_call (*this, node, call, uncertainty);
3896 if (next_state.m_valid)
3898 if (logger)
3899 logger->log ("Discovered call to %s [SN: %i -> SN: %i]",
3900 function_name(fun),
3901 this_point->get_supernode ()->m_index,
3902 sn_entry->m_index);
3904 exploded_node *enode = get_or_create_node (new_point,
3905 next_state,
3906 node);
3907 if (enode)
3908 add_edge (node,enode, NULL,
3909 false, /* No work is done by the call itself. */
3910 make_unique<dynamic_call_info_t> (call));
3911 return true;
3914 return false;
3917 /* Subclass of path_context for use within exploded_graph::process_node,
3918 so that we can split states e.g. at "realloc" calls. */
3920 class impl_path_context : public path_context
3922 public:
3923 impl_path_context (const program_state *cur_state,
3924 logger *logger)
3925 : m_cur_state (cur_state),
3926 m_logger (logger),
3927 m_terminate_path (false)
3931 bool bifurcation_p () const
3933 return m_custom_eedge_infos.length () > 0;
3936 const program_state &get_state_at_bifurcation () const
3938 gcc_assert (m_state_at_bifurcation);
3939 return *m_state_at_bifurcation;
3942 void
3943 bifurcate (std::unique_ptr<custom_edge_info> info) final override
3945 if (m_logger)
3946 m_logger->log ("bifurcating path");
3948 if (m_state_at_bifurcation)
3949 /* Verify that the state at bifurcation is consistent when we
3950 split into multiple out-edges. */
3951 gcc_assert (*m_state_at_bifurcation == *m_cur_state);
3952 else
3953 /* Take a copy of the cur_state at the moment when bifurcation
3954 happens. */
3955 m_state_at_bifurcation
3956 = std::unique_ptr<program_state> (new program_state (*m_cur_state));
3958 /* Take ownership of INFO. */
3959 m_custom_eedge_infos.safe_push (info.release ());
3962 void terminate_path () final override
3964 if (m_logger)
3965 m_logger->log ("terminating path");
3966 m_terminate_path = true;
3969 bool terminate_path_p () const final override
3971 return m_terminate_path;
3974 const vec<custom_edge_info *> & get_custom_eedge_infos ()
3976 return m_custom_eedge_infos;
3979 private:
3980 const program_state *m_cur_state;
3982 logger *m_logger;
3984 /* Lazily-created copy of the state before the split. */
3985 std::unique_ptr<program_state> m_state_at_bifurcation;
3987 auto_vec <custom_edge_info *> m_custom_eedge_infos;
3989 bool m_terminate_path;
3992 /* A subclass of pending_diagnostic for complaining about jumps through NULL
3993 function pointers. */
3995 class jump_through_null : public pending_diagnostic_subclass<jump_through_null>
3997 public:
3998 jump_through_null (const gcall *call)
3999 : m_call (call)
4002 const char *get_kind () const final override
4004 return "jump_through_null";
4007 bool operator== (const jump_through_null &other) const
4009 return m_call == other.m_call;
4012 int get_controlling_option () const final override
4014 return OPT_Wanalyzer_jump_through_null;
4017 bool emit (diagnostic_emission_context &ctxt) final override
4019 return ctxt.warn ("jump through null pointer");
4022 label_text describe_final_event (const evdesc::final_event &ev) final override
4024 return ev.formatted_print ("jump through null pointer here");
4027 private:
4028 const gcall *m_call;
4031 /* The core of exploded_graph::process_worklist (the main analysis loop),
4032 handling one node in the worklist.
4034 Get successor <point, state> pairs for NODE, calling get_or_create on
4035 them, and adding an exploded_edge to each successors.
4037 Freshly-created nodes will be added to the worklist. */
4039 void
4040 exploded_graph::process_node (exploded_node *node)
4042 logger * const logger = get_logger ();
4043 LOG_FUNC_1 (logger, "EN: %i", node->m_index);
4045 node->set_status (exploded_node::STATUS_PROCESSED);
4047 const program_point &point = node->get_point ();
4049 /* Update cfun and input_location in case of an ICE: make it easier to
4050 track down which source construct we're failing to handle. */
4051 auto_cfun sentinel (node->get_function ());
4052 const gimple *stmt = point.get_stmt ();
4053 if (stmt)
4054 input_location = stmt->location;
4056 const program_state &state = node->get_state ();
4057 if (logger)
4059 pretty_printer *pp = logger->get_printer ();
4060 logger->start_log_line ();
4061 pp_string (pp, "point: ");
4062 point.print (pp, format (false));
4063 pp_string (pp, ", state: ");
4064 state.dump_to_pp (m_ext_state, true, false, pp);
4065 logger->end_log_line ();
4068 switch (point.get_kind ())
4070 default:
4071 gcc_unreachable ();
4072 case PK_ORIGIN:
4073 /* This node exists to simplify finding the shortest path
4074 to an exploded_node. */
4075 break;
4077 case PK_BEFORE_SUPERNODE:
4079 program_state next_state (state);
4080 uncertainty_t uncertainty;
4082 if (point.get_from_edge ())
4084 impl_region_model_context ctxt (*this, node,
4085 &state, &next_state,
4086 &uncertainty, NULL, NULL);
4087 const cfg_superedge *last_cfg_superedge
4088 = point.get_from_edge ()->dyn_cast_cfg_superedge ();
4089 if (last_cfg_superedge)
4090 next_state.m_region_model->update_for_phis
4091 (node->get_supernode (),
4092 last_cfg_superedge,
4093 &ctxt);
4094 program_state::detect_leaks (state, next_state, NULL,
4095 get_ext_state (), &ctxt);
4098 program_point next_point (point.get_next ());
4099 exploded_node *next = get_or_create_node (next_point, next_state, node);
4100 if (next)
4101 add_edge (node, next, NULL,
4102 false); /* Assume no work is done at phi nodes. */
4104 break;
4105 case PK_BEFORE_STMT:
4107 /* Determine the effect of a run of one or more statements
4108 within one supernode, generating an edge to the program_point
4109 after the last statement that's processed.
4111 Stop iterating statements and thus consolidating into one enode
4112 when:
4113 - reaching the end of the statements in the supernode
4114 - if an sm-state-change occurs (so that it gets its own
4115 exploded_node)
4116 - if "-fanalyzer-fine-grained" is active
4117 - encountering certain statements must appear at the start of
4118 their enode (for which stmt_requires_new_enode_p returns true)
4120 Update next_state in-place, to get the result of the one
4121 or more stmts that are processed.
4123 Split the node in-place if an sm-state-change occurs, so that
4124 the sm-state-change occurs on an edge where the src enode has
4125 exactly one stmt, the one that caused the change. */
4126 program_state next_state (state);
4128 impl_path_context path_ctxt (&next_state, logger);
4130 bool could_have_done_work = false;
4131 uncertainty_t uncertainty;
4132 const supernode *snode = point.get_supernode ();
4133 unsigned stmt_idx;
4134 const gimple *prev_stmt = NULL;
4135 for (stmt_idx = point.get_stmt_idx ();
4136 stmt_idx < snode->m_stmts.length ();
4137 stmt_idx++)
4139 const gimple *stmt = snode->m_stmts[stmt_idx];
4141 if (stmt_idx > point.get_stmt_idx ())
4142 if (stmt_requires_new_enode_p (stmt, prev_stmt))
4144 stmt_idx--;
4145 break;
4147 prev_stmt = stmt;
4149 program_state old_state (next_state);
4151 /* Process the stmt. */
4152 exploded_node::on_stmt_flags flags
4153 = node->on_stmt (*this, snode, stmt, &next_state, &uncertainty,
4154 &could_have_done_work, &path_ctxt);
4155 node->m_num_processed_stmts++;
4157 /* If flags.m_terminate_path, stop analyzing; any nodes/edges
4158 will have been added by on_stmt (e.g. for handling longjmp). */
4159 if (flags.m_terminate_path)
4160 return;
4162 if (next_state.m_region_model)
4164 impl_region_model_context ctxt (*this, node,
4165 &old_state, &next_state,
4166 &uncertainty, NULL, stmt);
4167 program_state::detect_leaks (old_state, next_state, NULL,
4168 get_ext_state (), &ctxt);
4171 unsigned next_idx = stmt_idx + 1;
4172 program_point next_point
4173 = (next_idx < point.get_supernode ()->m_stmts.length ()
4174 ? program_point::before_stmt (point.get_supernode (), next_idx,
4175 point.get_call_string ())
4176 : program_point::after_supernode (point.get_supernode (),
4177 point.get_call_string ()));
4178 next_state = next_state.prune_for_point (*this, next_point, node,
4179 &uncertainty);
4181 if (flag_analyzer_fine_grained
4182 || state_change_requires_new_enode_p (old_state, next_state)
4183 || path_ctxt.bifurcation_p ()
4184 || path_ctxt.terminate_path_p ())
4186 program_point split_point
4187 = program_point::before_stmt (point.get_supernode (),
4188 stmt_idx,
4189 point.get_call_string ());
4190 if (split_point != node->get_point ())
4192 /* If we're not at the start of NODE, split the enode at
4193 this stmt, so we have:
4194 node -> split_enode
4195 so that when split_enode is processed the next edge
4196 we add will be:
4197 split_enode -> next
4198 and any state change will effectively occur on that
4199 latter edge, and split_enode will contain just stmt. */
4200 if (logger)
4201 logger->log ("getting split_enode");
4202 exploded_node *split_enode
4203 = get_or_create_node (split_point, old_state, node);
4204 if (!split_enode)
4205 return;
4206 /* "stmt" will be reprocessed when split_enode is
4207 processed. */
4208 node->m_num_processed_stmts--;
4209 if (logger)
4210 logger->log ("creating edge to split_enode");
4211 add_edge (node, split_enode, NULL, could_have_done_work);
4212 return;
4214 else
4215 /* If we're at the start of NODE, stop iterating,
4216 so that an edge will be created from NODE to
4217 (next_point, next_state) below. */
4218 break;
4221 unsigned next_idx = stmt_idx + 1;
4222 program_point next_point
4223 = (next_idx < point.get_supernode ()->m_stmts.length ()
4224 ? program_point::before_stmt (point.get_supernode (), next_idx,
4225 point.get_call_string ())
4226 : program_point::after_supernode (point.get_supernode (),
4227 point.get_call_string ()));
4228 if (path_ctxt.terminate_path_p ())
4230 if (logger)
4231 logger->log ("not adding node: terminating path");
4233 else
4235 exploded_node *next
4236 = get_or_create_node (next_point, next_state, node);
4237 if (next)
4238 add_edge (node, next, NULL, could_have_done_work);
4241 /* If we have custom edge infos, "bifurcate" the state
4242 accordingly, potentially creating a new state/enode/eedge
4243 instances. For example, to handle a "realloc" call, we
4244 might split into 3 states, for the "failure",
4245 "resizing in place", and "moving to a new buffer" cases. */
4246 for (auto edge_info_iter : path_ctxt.get_custom_eedge_infos ())
4248 /* Take ownership of the edge infos from the path_ctxt. */
4249 std::unique_ptr<custom_edge_info> edge_info (edge_info_iter);
4250 if (logger)
4252 logger->start_log_line ();
4253 logger->log_partial ("bifurcating for edge: ");
4254 edge_info->print (logger->get_printer ());
4255 logger->end_log_line ();
4257 program_state bifurcated_new_state
4258 (path_ctxt.get_state_at_bifurcation ());
4260 /* Apply edge_info to state. */
4261 impl_region_model_context
4262 bifurcation_ctxt (*this,
4263 node, // enode_for_diag
4264 &path_ctxt.get_state_at_bifurcation (),
4265 &bifurcated_new_state,
4266 NULL, // uncertainty_t *uncertainty
4267 NULL, // path_context *path_ctxt
4268 stmt);
4269 if (edge_info->update_state (&bifurcated_new_state,
4270 NULL, /* no exploded_edge yet. */
4271 &bifurcation_ctxt))
4273 exploded_node *next2
4274 = get_or_create_node (next_point, bifurcated_new_state, node);
4275 if (next2)
4276 add_edge (node, next2, NULL,
4277 true /* assume that work could be done */,
4278 std::move (edge_info));
4280 else
4282 if (logger)
4283 logger->log ("infeasible state, not adding node");
4287 break;
4288 case PK_AFTER_SUPERNODE:
4290 bool found_a_superedge = false;
4291 bool is_an_exit_block = false;
4292 /* If this is an EXIT BB, detect leaks, and potentially
4293 create a function summary. */
4294 if (point.get_supernode ()->return_p ())
4296 is_an_exit_block = true;
4297 node->detect_leaks (*this);
4298 if (flag_analyzer_call_summaries
4299 && point.get_call_string ().empty_p ())
4301 /* TODO: create function summary
4302 There can be more than one; each corresponds to a different
4303 final enode in the function. */
4304 if (logger)
4306 pretty_printer *pp = logger->get_printer ();
4307 logger->start_log_line ();
4308 logger->log_partial
4309 ("would create function summary for %qE; state: ",
4310 point.get_fndecl ());
4311 state.dump_to_pp (m_ext_state, true, false, pp);
4312 logger->end_log_line ();
4314 per_function_data *per_fn_data
4315 = get_or_create_per_function_data (point.get_function ());
4316 per_fn_data->add_call_summary (node);
4319 /* Traverse into successors of the supernode. */
4320 int i;
4321 superedge *succ;
4322 FOR_EACH_VEC_ELT (point.get_supernode ()->m_succs, i, succ)
4324 found_a_superedge = true;
4325 if (logger)
4327 label_text succ_desc (succ->get_description (false));
4328 logger->log ("considering SN: %i -> SN: %i (%s)",
4329 succ->m_src->m_index, succ->m_dest->m_index,
4330 succ_desc.get ());
4333 program_point next_point
4334 = program_point::before_supernode (succ->m_dest, succ,
4335 point.get_call_string ());
4336 program_state next_state (state);
4337 uncertainty_t uncertainty;
4339 /* Make use the current state and try to discover and analyse
4340 indirect function calls (a call that doesn't have an underlying
4341 cgraph edge representing call).
4343 Some examples of such calls are virtual function calls
4344 and calls that happen via a function pointer. */
4345 if (succ->m_kind == SUPEREDGE_INTRAPROCEDURAL_CALL
4346 && !(succ->get_any_callgraph_edge ()))
4348 const gcall *call
4349 = point.get_supernode ()->get_final_call ();
4351 impl_region_model_context ctxt (*this,
4352 node,
4353 &state,
4354 &next_state,
4355 &uncertainty,
4356 NULL,
4357 point.get_stmt());
4359 region_model *model = state.m_region_model;
4360 bool call_discovered = false;
4362 if (tree fn_decl = model->get_fndecl_for_call (call, &ctxt))
4363 call_discovered = maybe_create_dynamic_call (call,
4364 fn_decl,
4365 node,
4366 next_state,
4367 next_point,
4368 &uncertainty,
4369 logger);
4370 if (!call_discovered)
4372 /* Check for jump through NULL. */
4373 if (tree fn_ptr = gimple_call_fn (call))
4375 const svalue *fn_ptr_sval
4376 = model->get_rvalue (fn_ptr, &ctxt);
4377 if (fn_ptr_sval->all_zeroes_p ())
4378 ctxt.warn (make_unique<jump_through_null> (call));
4381 /* An unknown function or a special function was called
4382 at this point, in such case, don't terminate the
4383 analysis of the current function.
4385 The analyzer handles calls to such functions while
4386 analysing the stmt itself, so the function call
4387 must have been handled by the anlyzer till now. */
4388 exploded_node *next
4389 = get_or_create_node (next_point,
4390 next_state,
4391 node);
4392 if (next)
4393 add_edge (node, next, succ,
4394 true /* assume that work is done */);
4398 if (!node->on_edge (*this, succ, &next_point, &next_state,
4399 &uncertainty))
4401 if (logger)
4402 logger->log ("skipping impossible edge to SN: %i",
4403 succ->m_dest->m_index);
4404 continue;
4406 exploded_node *next = get_or_create_node (next_point, next_state,
4407 node);
4408 if (next)
4410 add_edge (node, next, succ, false);
4412 /* We might have a function entrypoint. */
4413 detect_infinite_recursion (next);
4417 /* Return from the calls which doesn't have a return superedge.
4418 Such case occurs when GCC's middle end didn't knew which function to
4419 call but analyzer did. */
4420 if ((is_an_exit_block && !found_a_superedge)
4421 && (!point.get_call_string ().empty_p ()))
4423 const call_string &cs = point.get_call_string ();
4424 program_point next_point
4425 = program_point::before_supernode (cs.get_caller_node (),
4426 NULL,
4427 cs);
4428 program_state next_state (state);
4429 uncertainty_t uncertainty;
4431 const gcall *call
4432 = next_point.get_supernode ()->get_returning_call ();
4434 if (call)
4435 next_state.returning_call (*this, node, call, &uncertainty);
4437 if (next_state.m_valid)
4439 next_point.pop_from_call_stack ();
4440 exploded_node *enode = get_or_create_node (next_point,
4441 next_state,
4442 node);
4443 if (enode)
4444 add_edge (node, enode, NULL, false,
4445 make_unique<dynamic_call_info_t> (call, true));
4449 break;
4453 /* Ensure that this graph has a stats instance for FN, return it.
4454 FN can be NULL, in which case a stats instances is returned covering
4455 "functionless" parts of the graph (the origin node). */
4457 stats *
4458 exploded_graph::get_or_create_function_stats (function *fn)
4460 if (!fn)
4461 return &m_functionless_stats;
4463 if (stats **slot = m_per_function_stats.get (fn))
4464 return *slot;
4465 else
4467 int num_supernodes = fn ? n_basic_blocks_for_fn (fn) : 0;
4468 /* not quite the num supernodes, but nearly. */
4469 stats *new_stats = new stats (num_supernodes);
4470 m_per_function_stats.put (fn, new_stats);
4471 return new_stats;
4475 /* Print bar charts to PP showing:
4476 - the number of enodes per function, and
4477 - for each function:
4478 - the number of enodes per supernode/BB
4479 - the number of excess enodes per supernode/BB beyond the
4480 per-program-point limit, if there were any. */
4482 void
4483 exploded_graph::print_bar_charts (pretty_printer *pp) const
4485 cgraph_node *cgnode;
4487 pp_string (pp, "enodes per function:");
4488 pp_newline (pp);
4489 bar_chart enodes_per_function;
4490 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cgnode)
4492 function *fn = cgnode->get_fun ();
4493 const stats * const *s_ptr
4494 = const_cast <function_stat_map_t &> (m_per_function_stats).get (fn);
4495 enodes_per_function.add_item (function_name (fn),
4496 s_ptr ? (*s_ptr)->get_total_enodes () : 0);
4498 enodes_per_function.print (pp);
4500 /* Accumulate number of enodes per supernode. */
4501 auto_vec<unsigned> enodes_per_supernode (m_sg.num_nodes ());
4502 for (int i = 0; i < m_sg.num_nodes (); i++)
4503 enodes_per_supernode.quick_push (0);
4504 int i;
4505 exploded_node *enode;
4506 FOR_EACH_VEC_ELT (m_nodes, i, enode)
4508 const supernode *iter_snode = enode->get_supernode ();
4509 if (!iter_snode)
4510 continue;
4511 enodes_per_supernode[iter_snode->m_index]++;
4514 /* Accumulate excess enodes per supernode. */
4515 auto_vec<unsigned> excess_enodes_per_supernode (m_sg.num_nodes ());
4516 for (int i = 0; i < m_sg.num_nodes (); i++)
4517 excess_enodes_per_supernode.quick_push (0);
4518 for (point_map_t::iterator iter = m_per_point_data.begin ();
4519 iter != m_per_point_data.end (); ++iter)
4521 const program_point *point = (*iter).first;
4522 const supernode *iter_snode = point->get_supernode ();
4523 if (!iter_snode)
4524 continue;
4525 const per_program_point_data *point_data = (*iter).second;
4526 excess_enodes_per_supernode[iter_snode->m_index]
4527 += point_data->m_excess_enodes;
4530 /* Show per-function bar_charts of enodes per supernode/BB. */
4531 pp_string (pp, "per-function enodes per supernode/BB:");
4532 pp_newline (pp);
4533 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cgnode)
4535 function *fn = cgnode->get_fun ();
4536 pp_printf (pp, "function: %qs", function_name (fn));
4537 pp_newline (pp);
4539 bar_chart enodes_per_snode;
4540 bar_chart excess_enodes_per_snode;
4541 bool have_excess_enodes = false;
4542 for (int i = 0; i < m_sg.num_nodes (); i++)
4544 const supernode *iter_snode = m_sg.get_node_by_index (i);
4545 if (iter_snode->get_function () != fn)
4546 continue;
4547 pretty_printer tmp_pp;
4548 pp_printf (&tmp_pp, "sn %i (bb %i)",
4549 iter_snode->m_index, iter_snode->m_bb->index);
4550 enodes_per_snode.add_item (pp_formatted_text (&tmp_pp),
4551 enodes_per_supernode[iter_snode->m_index]);
4552 const int num_excess
4553 = excess_enodes_per_supernode[iter_snode->m_index];
4554 excess_enodes_per_snode.add_item (pp_formatted_text (&tmp_pp),
4555 num_excess);
4556 if (num_excess)
4557 have_excess_enodes = true;
4559 enodes_per_snode.print (pp);
4560 if (have_excess_enodes)
4562 pp_printf (pp, "EXCESS ENODES:");
4563 pp_newline (pp);
4564 excess_enodes_per_snode.print (pp);
4569 /* Write all stats information to this graph's logger, if any. */
4571 void
4572 exploded_graph::log_stats () const
4574 logger * const logger = get_logger ();
4575 if (!logger)
4576 return;
4578 LOG_SCOPE (logger);
4580 m_ext_state.get_engine ()->log_stats (logger);
4582 logger->log ("m_sg.num_nodes (): %i", m_sg.num_nodes ());
4583 logger->log ("m_nodes.length (): %i", m_nodes.length ());
4584 logger->log ("m_edges.length (): %i", m_edges.length ());
4585 logger->log ("remaining enodes in worklist: %i", m_worklist.length ());
4587 logger->log ("global stats:");
4588 m_global_stats.log (logger);
4590 for (function_stat_map_t::iterator iter = m_per_function_stats.begin ();
4591 iter != m_per_function_stats.end ();
4592 ++iter)
4594 function *fn = (*iter).first;
4595 log_scope s (logger, function_name (fn));
4596 (*iter).second->log (logger);
4599 print_bar_charts (logger->get_printer ());
4602 /* Dump all stats information to OUT. */
4604 void
4605 exploded_graph::dump_stats (FILE *out) const
4607 fprintf (out, "m_sg.num_nodes (): %i\n", m_sg.num_nodes ());
4608 fprintf (out, "m_nodes.length (): %i\n", m_nodes.length ());
4609 fprintf (out, "m_edges.length (): %i\n", m_edges.length ());
4610 fprintf (out, "remaining enodes in worklist: %i", m_worklist.length ());
4612 fprintf (out, "global stats:\n");
4613 m_global_stats.dump (out);
4615 for (function_stat_map_t::iterator iter = m_per_function_stats.begin ();
4616 iter != m_per_function_stats.end ();
4617 ++iter)
4619 function *fn = (*iter).first;
4620 fprintf (out, "function: %s\n", function_name (fn));
4621 (*iter).second->dump (out);
4624 fprintf (out, "PK_AFTER_SUPERNODE per supernode:\n");
4625 for (unsigned i = 0; i < m_PK_AFTER_SUPERNODE_per_snode.length (); i++)
4626 fprintf (out, " SN %i: %3i\n", i, m_PK_AFTER_SUPERNODE_per_snode[i]);
4629 void
4630 exploded_graph::dump_states_for_supernode (FILE *out,
4631 const supernode *snode) const
4633 fprintf (out, "PK_AFTER_SUPERNODE nodes for SN: %i\n", snode->m_index);
4634 int i;
4635 exploded_node *enode;
4636 int state_idx = 0;
4637 FOR_EACH_VEC_ELT (m_nodes, i, enode)
4639 const supernode *iter_snode = enode->get_supernode ();
4640 if (enode->get_point ().get_kind () == PK_AFTER_SUPERNODE
4641 && iter_snode == snode)
4643 pretty_printer pp;
4644 pp_format_decoder (&pp) = default_tree_printer;
4645 enode->get_state ().dump_to_pp (m_ext_state, true, false, &pp);
4646 fprintf (out, "state %i: EN: %i\n %s\n",
4647 state_idx++, enode->m_index,
4648 pp_formatted_text (&pp));
4651 fprintf (out, "#exploded_node for PK_AFTER_SUPERNODE for SN: %i = %i\n",
4652 snode->m_index, state_idx);
4655 /* Return a new json::object of the form
4656 {"nodes" : [objs for enodes],
4657 "edges" : [objs for eedges],
4658 "ext_state": object for extrinsic_state,
4659 "diagnostic_manager": object for diagnostic_manager}. */
4661 json::object *
4662 exploded_graph::to_json () const
4664 json::object *egraph_obj = new json::object ();
4666 /* Nodes. */
4668 json::array *nodes_arr = new json::array ();
4669 unsigned i;
4670 exploded_node *n;
4671 FOR_EACH_VEC_ELT (m_nodes, i, n)
4672 nodes_arr->append (n->to_json (m_ext_state));
4673 egraph_obj->set ("nodes", nodes_arr);
4676 /* Edges. */
4678 json::array *edges_arr = new json::array ();
4679 unsigned i;
4680 exploded_edge *n;
4681 FOR_EACH_VEC_ELT (m_edges, i, n)
4682 edges_arr->append (n->to_json ());
4683 egraph_obj->set ("edges", edges_arr);
4686 /* m_sg is JSONified at the top-level. */
4688 egraph_obj->set ("ext_state", m_ext_state.to_json ());
4689 egraph_obj->set ("worklist", m_worklist.to_json ());
4690 egraph_obj->set ("diagnostic_manager", m_diagnostic_manager.to_json ());
4692 /* The following fields aren't yet being JSONified:
4693 const state_purge_map *const m_purge_map;
4694 const analysis_plan &m_plan;
4695 stats m_global_stats;
4696 function_stat_map_t m_per_function_stats;
4697 stats m_functionless_stats;
4698 call_string_data_map_t m_per_call_string_data;
4699 auto_vec<int> m_PK_AFTER_SUPERNODE_per_snode; */
4701 return egraph_obj;
4704 /* class exploded_path. */
4706 /* Copy ctor. */
4708 exploded_path::exploded_path (const exploded_path &other)
4709 : m_edges (other.m_edges.length ())
4711 int i;
4712 const exploded_edge *eedge;
4713 FOR_EACH_VEC_ELT (other.m_edges, i, eedge)
4714 m_edges.quick_push (eedge);
4717 /* Look for the last use of SEARCH_STMT within this path.
4718 If found write the edge's index to *OUT_IDX and return true, otherwise
4719 return false. */
4721 bool
4722 exploded_path::find_stmt_backwards (const gimple *search_stmt,
4723 int *out_idx) const
4725 int i;
4726 const exploded_edge *eedge;
4727 FOR_EACH_VEC_ELT_REVERSE (m_edges, i, eedge)
4729 const exploded_node *dst_node = eedge->m_dest;
4730 const program_point &dst_point = dst_node->get_point ();
4731 const gimple *stmt = dst_point.get_stmt ();
4732 if (stmt == search_stmt)
4734 *out_idx = i;
4735 return true;
4738 return false;
4741 /* Get the final exploded_node in this path, which must be non-empty. */
4743 exploded_node *
4744 exploded_path::get_final_enode () const
4746 gcc_assert (m_edges.length () > 0);
4747 return m_edges[m_edges.length () - 1]->m_dest;
4750 /* Check state along this path, returning true if it is feasible.
4751 If OUT is non-NULL, and the path is infeasible, write a new
4752 feasibility_problem to *OUT. */
4754 bool
4755 exploded_path::feasible_p (logger *logger,
4756 std::unique_ptr<feasibility_problem> *out,
4757 engine *eng, const exploded_graph *eg) const
4759 LOG_SCOPE (logger);
4761 feasibility_state state (eng->get_model_manager (),
4762 eg->get_supergraph ());
4764 /* Traverse the path, updating this state. */
4765 for (unsigned edge_idx = 0; edge_idx < m_edges.length (); edge_idx++)
4767 const exploded_edge *eedge = m_edges[edge_idx];
4768 if (logger)
4769 logger->log ("considering edge %i: EN:%i -> EN:%i",
4770 edge_idx,
4771 eedge->m_src->m_index,
4772 eedge->m_dest->m_index);
4774 std::unique_ptr <rejected_constraint> rc;
4775 if (!state.maybe_update_for_edge (logger, eedge, nullptr, &rc))
4777 gcc_assert (rc);
4778 if (out)
4780 const exploded_node &src_enode = *eedge->m_src;
4781 const program_point &src_point = src_enode.get_point ();
4782 const gimple *last_stmt
4783 = src_point.get_supernode ()->get_last_stmt ();
4784 *out = ::make_unique<feasibility_problem> (edge_idx, *eedge,
4785 last_stmt,
4786 std::move (rc));
4788 return false;
4791 if (logger)
4793 logger->log ("state after edge %i: EN:%i -> EN:%i",
4794 edge_idx,
4795 eedge->m_src->m_index,
4796 eedge->m_dest->m_index);
4797 logger->start_log_line ();
4798 state.get_model ().dump_to_pp (logger->get_printer (), true, false);
4799 logger->end_log_line ();
4803 return true;
4806 /* Dump this path in multiline form to PP.
4807 If EXT_STATE is non-NULL, then show the nodes. */
4809 void
4810 exploded_path::dump_to_pp (pretty_printer *pp,
4811 const extrinsic_state *ext_state) const
4813 for (unsigned i = 0; i < m_edges.length (); i++)
4815 const exploded_edge *eedge = m_edges[i];
4816 pp_printf (pp, "m_edges[%i]: EN %i -> EN %i",
4818 eedge->m_src->m_index,
4819 eedge->m_dest->m_index);
4820 pp_newline (pp);
4822 if (ext_state)
4823 eedge->m_dest->dump_to_pp (pp, *ext_state);
4827 /* Dump this path in multiline form to FP. */
4829 void
4830 exploded_path::dump (FILE *fp, const extrinsic_state *ext_state) const
4832 pretty_printer pp;
4833 pp_format_decoder (&pp) = default_tree_printer;
4834 pp_show_color (&pp) = pp_show_color (global_dc->printer);
4835 pp.set_output_stream (fp);
4836 dump_to_pp (&pp, ext_state);
4837 pp_flush (&pp);
4840 /* Dump this path in multiline form to stderr. */
4842 DEBUG_FUNCTION void
4843 exploded_path::dump (const extrinsic_state *ext_state) const
4845 dump (stderr, ext_state);
4848 /* Dump this path verbosely to FILENAME. */
4850 void
4851 exploded_path::dump_to_file (const char *filename,
4852 const extrinsic_state &ext_state) const
4854 FILE *fp = fopen (filename, "w");
4855 if (!fp)
4856 return;
4857 pretty_printer pp;
4858 pp_format_decoder (&pp) = default_tree_printer;
4859 pp.set_output_stream (fp);
4860 dump_to_pp (&pp, &ext_state);
4861 pp_flush (&pp);
4862 fclose (fp);
4865 /* class feasibility_problem. */
4867 void
4868 feasibility_problem::dump_to_pp (pretty_printer *pp) const
4870 pp_printf (pp, "edge from EN: %i to EN: %i",
4871 m_eedge.m_src->m_index, m_eedge.m_dest->m_index);
4872 if (m_rc)
4874 pp_string (pp, "; rejected constraint: ");
4875 m_rc->dump_to_pp (pp);
4876 pp_string (pp, "; rmodel: ");
4877 m_rc->get_model ().dump_to_pp (pp, true, false);
4881 /* class feasibility_state. */
4883 /* Ctor for feasibility_state, at the beginning of a path. */
4885 feasibility_state::feasibility_state (region_model_manager *manager,
4886 const supergraph &sg)
4887 : m_model (manager),
4888 m_snodes_visited (sg.m_nodes.length ())
4890 bitmap_clear (m_snodes_visited);
4893 /* Copy ctor for feasibility_state, for extending a path. */
4895 feasibility_state::feasibility_state (const feasibility_state &other)
4896 : m_model (other.m_model),
4897 m_snodes_visited (const_sbitmap (other.m_snodes_visited)->n_bits)
4899 bitmap_copy (m_snodes_visited, other.m_snodes_visited);
4902 feasibility_state::feasibility_state (const region_model &model,
4903 const supergraph &sg)
4904 : m_model (model),
4905 m_snodes_visited (sg.m_nodes.length ())
4907 bitmap_clear (m_snodes_visited);
4910 feasibility_state &
4911 feasibility_state::operator= (const feasibility_state &other)
4913 m_model = other.m_model;
4914 bitmap_copy (m_snodes_visited, other.m_snodes_visited);
4915 return *this;
4918 /* The heart of feasibility-checking.
4920 Attempt to update this state in-place based on traversing EEDGE
4921 in a path.
4922 Update the model for the stmts in the src enode.
4923 Attempt to add constraints for EEDGE.
4925 If feasible, return true.
4926 Otherwise, return false and write to *OUT_RC. */
4928 bool
4929 feasibility_state::
4930 maybe_update_for_edge (logger *logger,
4931 const exploded_edge *eedge,
4932 region_model_context *ctxt,
4933 std::unique_ptr<rejected_constraint> *out_rc)
4935 const exploded_node &src_enode = *eedge->m_src;
4936 const program_point &src_point = src_enode.get_point ();
4937 if (logger)
4939 logger->start_log_line ();
4940 src_point.print (logger->get_printer (), format (false));
4941 logger->end_log_line ();
4944 /* Update state for the stmts that were processed in each enode. */
4945 for (unsigned stmt_idx = 0; stmt_idx < src_enode.m_num_processed_stmts;
4946 stmt_idx++)
4948 const gimple *stmt = src_enode.get_processed_stmt (stmt_idx);
4950 /* Update cfun and input_location in case of ICE: make it easier to
4951 track down which source construct we're failing to handle. */
4952 auto_cfun sentinel (src_point.get_function ());
4953 input_location = stmt->location;
4955 update_for_stmt (stmt);
4958 const superedge *sedge = eedge->m_sedge;
4959 if (sedge)
4961 if (logger)
4963 label_text desc (sedge->get_description (false));
4964 logger->log (" sedge: SN:%i -> SN:%i %s",
4965 sedge->m_src->m_index,
4966 sedge->m_dest->m_index,
4967 desc.get ());
4970 const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
4971 if (!m_model.maybe_update_for_edge (*sedge, last_stmt, ctxt, out_rc))
4973 if (logger)
4975 logger->start_log_line ();
4976 logger->log_partial ("rejecting due to region model: ");
4977 m_model.dump_to_pp (logger->get_printer (), true, false);
4978 logger->end_log_line ();
4980 return false;
4983 else
4985 /* Special-case the initial eedge from the origin node to the
4986 initial function by pushing a frame for it. */
4987 if (src_point.get_kind () == PK_ORIGIN)
4989 gcc_assert (eedge->m_src->m_index == 0);
4990 gcc_assert (eedge->m_dest->get_point ().get_kind ()
4991 == PK_BEFORE_SUPERNODE);
4992 function *fun = eedge->m_dest->get_function ();
4993 gcc_assert (fun);
4994 m_model.push_frame (*fun, NULL, ctxt);
4995 if (logger)
4996 logger->log (" pushing frame for %qD", fun->decl);
4998 else if (eedge->m_custom_info)
5000 eedge->m_custom_info->update_model (&m_model, eedge, ctxt);
5004 /* Handle phi nodes on an edge leaving a PK_BEFORE_SUPERNODE (to
5005 a PK_BEFORE_STMT, or a PK_AFTER_SUPERNODE if no stmts).
5006 This will typically not be associated with a superedge. */
5007 if (src_point.get_from_edge ())
5009 const cfg_superedge *last_cfg_superedge
5010 = src_point.get_from_edge ()->dyn_cast_cfg_superedge ();
5011 const exploded_node &dst_enode = *eedge->m_dest;
5012 const unsigned dst_snode_idx = dst_enode.get_supernode ()->m_index;
5013 if (last_cfg_superedge)
5015 if (logger)
5016 logger->log (" update for phis");
5017 m_model.update_for_phis (src_enode.get_supernode (),
5018 last_cfg_superedge,
5019 ctxt);
5020 /* If we've entering an snode that we've already visited on this
5021 epath, then we need do fix things up for loops; see the
5022 comment for store::loop_replay_fixup.
5023 Perhaps we should probably also verify the callstring,
5024 and track program_points, but hopefully doing it by supernode
5025 is good enough. */
5026 if (bitmap_bit_p (m_snodes_visited, dst_snode_idx))
5027 m_model.loop_replay_fixup (dst_enode.get_state ().m_region_model);
5029 bitmap_set_bit (m_snodes_visited, dst_snode_idx);
5031 return true;
5034 /* Update this object for the effects of STMT. */
5036 void
5037 feasibility_state::update_for_stmt (const gimple *stmt)
5039 if (const gassign *assign = dyn_cast <const gassign *> (stmt))
5040 m_model.on_assignment (assign, NULL);
5041 else if (const gasm *asm_stmt = dyn_cast <const gasm *> (stmt))
5042 m_model.on_asm_stmt (asm_stmt, NULL);
5043 else if (const gcall *call = dyn_cast <const gcall *> (stmt))
5045 bool unknown_side_effects = m_model.on_call_pre (call, NULL);
5046 m_model.on_call_post (call, unknown_side_effects, NULL);
5048 else if (const greturn *return_ = dyn_cast <const greturn *> (stmt))
5049 m_model.on_return (return_, NULL);
5052 /* Dump this object to PP. */
5054 void
5055 feasibility_state::dump_to_pp (pretty_printer *pp,
5056 bool simple, bool multiline) const
5058 m_model.dump_to_pp (pp, simple, multiline);
5061 /* A family of cluster subclasses for use when generating .dot output for
5062 exploded graphs (-fdump-analyzer-exploded-graph), for grouping the
5063 enodes into hierarchical boxes.
5065 All functionless enodes appear in the top-level graph.
5066 Every (function, call_string) pair gets its own cluster. Within that
5067 cluster, each supernode gets its own cluster.
5069 Hence all enodes relating to a particular function with a particular
5070 callstring will be in a cluster together; all enodes for the same
5071 function but with a different callstring will be in a different
5072 cluster. */
5074 /* Base class of cluster for clustering exploded_node instances in .dot
5075 output, based on various subclass-specific criteria. */
5077 class exploded_cluster : public cluster<eg_traits>
5081 /* Cluster containing all exploded_node instances for one supernode. */
5083 class supernode_cluster : public exploded_cluster
5085 public:
5086 supernode_cluster (const supernode *supernode) : m_supernode (supernode) {}
5088 // TODO: dtor?
5090 void dump_dot (graphviz_out *gv, const dump_args_t &args) const final override
5092 gv->println ("subgraph \"cluster_supernode_%i\" {", m_supernode->m_index);
5093 gv->indent ();
5094 gv->println ("style=\"dashed\";");
5095 gv->println ("label=\"SN: %i (bb: %i; scc: %i)\";",
5096 m_supernode->m_index, m_supernode->m_bb->index,
5097 args.m_eg.get_scc_id (*m_supernode));
5099 int i;
5100 exploded_node *enode;
5101 FOR_EACH_VEC_ELT (m_enodes, i, enode)
5102 enode->dump_dot (gv, args);
5104 /* Terminate subgraph. */
5105 gv->outdent ();
5106 gv->println ("}");
5109 void add_node (exploded_node *en) final override
5111 m_enodes.safe_push (en);
5114 /* Comparator for use by auto_vec<supernode_cluster *>::qsort. */
5116 static int cmp_ptr_ptr (const void *p1, const void *p2)
5118 const supernode_cluster *c1
5119 = *(const supernode_cluster * const *)p1;
5120 const supernode_cluster *c2
5121 = *(const supernode_cluster * const *)p2;
5122 return c1->m_supernode->m_index - c2->m_supernode->m_index;
5125 private:
5126 const supernode *m_supernode;
5127 auto_vec <exploded_node *> m_enodes;
5130 /* Cluster containing all supernode_cluster instances for one
5131 (function, call_string) pair. */
5133 class function_call_string_cluster : public exploded_cluster
5135 public:
5136 function_call_string_cluster (function *fun, const call_string &cs)
5137 : m_fun (fun), m_cs (cs) {}
5139 ~function_call_string_cluster ()
5141 for (map_t::iterator iter = m_map.begin ();
5142 iter != m_map.end ();
5143 ++iter)
5144 delete (*iter).second;
5147 void dump_dot (graphviz_out *gv, const dump_args_t &args) const final override
5149 const char *funcname = function_name (m_fun);
5151 gv->println ("subgraph \"cluster_function_%s\" {",
5152 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (m_fun->decl)));
5153 gv->indent ();
5154 gv->write_indent ();
5155 gv->print ("label=\"call string: ");
5156 m_cs.print (gv->get_pp ());
5157 gv->print (" function: %s \";", funcname);
5158 gv->print ("\n");
5160 /* Dump m_map, sorting it to avoid churn when comparing dumps. */
5161 auto_vec<supernode_cluster *> child_clusters (m_map.elements ());
5162 for (map_t::iterator iter = m_map.begin ();
5163 iter != m_map.end ();
5164 ++iter)
5165 child_clusters.quick_push ((*iter).second);
5167 child_clusters.qsort (supernode_cluster::cmp_ptr_ptr);
5169 unsigned i;
5170 supernode_cluster *child_cluster;
5171 FOR_EACH_VEC_ELT (child_clusters, i, child_cluster)
5172 child_cluster->dump_dot (gv, args);
5174 /* Terminate subgraph. */
5175 gv->outdent ();
5176 gv->println ("}");
5179 void add_node (exploded_node *en) final override
5181 const supernode *supernode = en->get_supernode ();
5182 gcc_assert (supernode);
5183 supernode_cluster **slot = m_map.get (supernode);
5184 if (slot)
5185 (*slot)->add_node (en);
5186 else
5188 supernode_cluster *child = new supernode_cluster (supernode);
5189 m_map.put (supernode, child);
5190 child->add_node (en);
5194 /* Comparator for use by auto_vec<function_call_string_cluster *>. */
5196 static int cmp_ptr_ptr (const void *p1, const void *p2)
5198 const function_call_string_cluster *c1
5199 = *(const function_call_string_cluster * const *)p1;
5200 const function_call_string_cluster *c2
5201 = *(const function_call_string_cluster * const *)p2;
5202 if (int cmp_names
5203 = strcmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (c1->m_fun->decl)),
5204 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (c2->m_fun->decl))))
5205 return cmp_names;
5206 return call_string::cmp (c1->m_cs, c2->m_cs);
5209 private:
5210 function *m_fun;
5211 const call_string &m_cs;
5212 typedef ordered_hash_map<const supernode *, supernode_cluster *> map_t;
5213 map_t m_map;
5216 /* Keys for root_cluster. */
5218 struct function_call_string
5220 function_call_string (function *fun, const call_string *cs)
5221 : m_fun (fun), m_cs (cs)
5223 gcc_assert (fun);
5224 gcc_assert (cs);
5227 function *m_fun;
5228 const call_string *m_cs;
5231 } // namespace ana
5233 template <> struct default_hash_traits<function_call_string>
5234 : public pod_hash_traits<function_call_string>
5236 static const bool empty_zero_p = false;
5239 template <>
5240 inline hashval_t
5241 pod_hash_traits<function_call_string>::hash (value_type v)
5243 return (pointer_hash <function>::hash (v.m_fun)
5244 ^ pointer_hash <const call_string>::hash (v.m_cs));
5247 template <>
5248 inline bool
5249 pod_hash_traits<function_call_string>::equal (const value_type &existing,
5250 const value_type &candidate)
5252 return existing.m_fun == candidate.m_fun && &existing.m_cs == &candidate.m_cs;
5254 template <>
5255 inline void
5256 pod_hash_traits<function_call_string>::mark_deleted (value_type &v)
5258 v.m_fun = reinterpret_cast<function *> (1);
5260 template <>
5261 inline void
5262 pod_hash_traits<function_call_string>::mark_empty (value_type &v)
5264 v.m_fun = NULL;
5266 template <>
5267 inline bool
5268 pod_hash_traits<function_call_string>::is_deleted (value_type v)
5270 return v.m_fun == reinterpret_cast<function *> (1);
5272 template <>
5273 inline bool
5274 pod_hash_traits<function_call_string>::is_empty (value_type v)
5276 return v.m_fun == NULL;
5279 namespace ana {
5281 /* Top-level cluster for generating .dot output for exploded graphs,
5282 handling the functionless nodes, and grouping the remaining nodes by
5283 callstring. */
5285 class root_cluster : public exploded_cluster
5287 public:
5288 ~root_cluster ()
5290 for (map_t::iterator iter = m_map.begin ();
5291 iter != m_map.end ();
5292 ++iter)
5293 delete (*iter).second;
5296 void dump_dot (graphviz_out *gv, const dump_args_t &args) const final override
5298 int i;
5299 exploded_node *enode;
5300 FOR_EACH_VEC_ELT (m_functionless_enodes, i, enode)
5301 enode->dump_dot (gv, args);
5303 /* Dump m_map, sorting it to avoid churn when comparing dumps. */
5304 auto_vec<function_call_string_cluster *> child_clusters (m_map.elements ());
5305 for (map_t::iterator iter = m_map.begin ();
5306 iter != m_map.end ();
5307 ++iter)
5308 child_clusters.quick_push ((*iter).second);
5310 child_clusters.qsort (function_call_string_cluster::cmp_ptr_ptr);
5312 function_call_string_cluster *child_cluster;
5313 FOR_EACH_VEC_ELT (child_clusters, i, child_cluster)
5314 child_cluster->dump_dot (gv, args);
5317 void add_node (exploded_node *en) final override
5319 function *fun = en->get_function ();
5320 if (!fun)
5322 m_functionless_enodes.safe_push (en);
5323 return;
5326 const call_string &cs = en->get_point ().get_call_string ();
5327 function_call_string key (fun, &cs);
5328 function_call_string_cluster **slot = m_map.get (key);
5329 if (slot)
5330 (*slot)->add_node (en);
5331 else
5333 function_call_string_cluster *child
5334 = new function_call_string_cluster (fun, cs);
5335 m_map.put (key, child);
5336 child->add_node (en);
5340 private:
5341 typedef hash_map<function_call_string, function_call_string_cluster *> map_t;
5342 map_t m_map;
5344 /* This should just be the origin exploded_node. */
5345 auto_vec <exploded_node *> m_functionless_enodes;
5348 /* Subclass of range_label for use within
5349 exploded_graph::dump_exploded_nodes for implementing
5350 -fdump-analyzer-exploded-nodes: a label for a specific
5351 exploded_node. */
5353 class enode_label : public range_label
5355 public:
5356 enode_label (const extrinsic_state &ext_state,
5357 exploded_node *enode)
5358 : m_ext_state (ext_state), m_enode (enode) {}
5360 label_text get_text (unsigned) const final override
5362 pretty_printer pp;
5363 pp_format_decoder (&pp) = default_tree_printer;
5364 m_enode->get_state ().dump_to_pp (m_ext_state, true, false, &pp);
5365 return make_label_text (false, "EN: %i: %s",
5366 m_enode->m_index, pp_formatted_text (&pp));
5369 private:
5370 const extrinsic_state &m_ext_state;
5371 exploded_node *m_enode;
5374 /* Postprocessing support for dumping the exploded nodes.
5375 Handle -fdump-analyzer-exploded-nodes,
5376 -fdump-analyzer-exploded-nodes-2, and the
5377 "__analyzer_dump_exploded_nodes" builtin. */
5379 void
5380 exploded_graph::dump_exploded_nodes () const
5382 // TODO
5383 /* Locate calls to __analyzer_dump_exploded_nodes. */
5384 // Print how many egs there are for them?
5385 /* Better: log them as we go, and record the exploded nodes
5386 in question. */
5388 /* Show every enode. */
5390 /* Gather them by stmt, so that we can more clearly see the
5391 "hotspots" requiring numerous exploded nodes. */
5393 /* Alternatively, simply throw them all into one big rich_location
5394 and see if the label-printing will sort it out...
5395 This requires them all to be in the same source file. */
5397 if (flag_dump_analyzer_exploded_nodes)
5399 auto_timevar tv (TV_ANALYZER_DUMP);
5400 gcc_rich_location richloc (UNKNOWN_LOCATION);
5401 unsigned i;
5402 exploded_node *enode;
5403 FOR_EACH_VEC_ELT (m_nodes, i, enode)
5405 if (const gimple *stmt = enode->get_stmt ())
5407 if (get_pure_location (richloc.get_loc ()) == UNKNOWN_LOCATION)
5408 richloc.set_range (0, stmt->location, SHOW_RANGE_WITH_CARET);
5409 else
5410 richloc.add_range (stmt->location,
5411 SHOW_RANGE_WITHOUT_CARET,
5412 new enode_label (m_ext_state, enode));
5415 warning_at (&richloc, 0, "%i exploded nodes", m_nodes.length ());
5417 /* Repeat the warning without all the labels, so that message is visible
5418 (the other one may well have scrolled past the terminal limit). */
5419 warning_at (richloc.get_loc (), 0,
5420 "%i exploded nodes", m_nodes.length ());
5422 if (m_worklist.length () > 0)
5423 warning_at (richloc.get_loc (), 0,
5424 "worklist still contains %i nodes", m_worklist.length ());
5427 /* Dump the egraph in textual form to a dump file. */
5428 if (flag_dump_analyzer_exploded_nodes_2)
5430 auto_timevar tv (TV_ANALYZER_DUMP);
5431 char *filename
5432 = concat (dump_base_name, ".eg.txt", NULL);
5433 FILE *outf = fopen (filename, "w");
5434 if (!outf)
5435 error_at (UNKNOWN_LOCATION, "unable to open %qs for writing", filename);
5436 free (filename);
5438 fprintf (outf, "exploded graph for %s\n", dump_base_name);
5439 fprintf (outf, " nodes: %i\n", m_nodes.length ());
5440 fprintf (outf, " edges: %i\n", m_edges.length ());
5442 unsigned i;
5443 exploded_node *enode;
5444 FOR_EACH_VEC_ELT (m_nodes, i, enode)
5446 fprintf (outf, "\nEN %i:\n", enode->m_index);
5447 enode->dump_succs_and_preds (outf);
5448 pretty_printer pp;
5449 enode->get_point ().print (&pp, format (true));
5450 fprintf (outf, "%s\n", pp_formatted_text (&pp));
5451 text_art::dump_to_file (enode->get_state (), outf);
5454 fclose (outf);
5457 /* Dump the egraph in textual form to multiple dump files, one per enode. */
5458 if (flag_dump_analyzer_exploded_nodes_3)
5460 auto_timevar tv (TV_ANALYZER_DUMP);
5462 unsigned i;
5463 exploded_node *enode;
5464 FOR_EACH_VEC_ELT (m_nodes, i, enode)
5466 char *filename
5467 = xasprintf ("%s.en-%i.txt", dump_base_name, i);
5468 FILE *outf = fopen (filename, "w");
5469 if (!outf)
5470 error_at (UNKNOWN_LOCATION, "unable to open %qs for writing",
5471 filename);
5472 free (filename);
5474 fprintf (outf, "EN %i:\n", enode->m_index);
5475 enode->dump_succs_and_preds (outf);
5476 pretty_printer pp;
5477 enode->get_point ().print (&pp, format (true));
5478 fprintf (outf, "%s\n", pp_formatted_text (&pp));
5479 text_art::dump_to_file (enode->get_state (), outf);
5481 fclose (outf);
5485 /* Emit a warning at any call to "__analyzer_dump_exploded_nodes",
5486 giving the number of processed exploded nodes for "before-stmt",
5487 and the IDs of processed, merger, and worklist enodes.
5489 We highlight the count of *processed* enodes since this is of most
5490 interest in DejaGnu tests for ensuring that state merger has
5491 happened.
5493 We don't show the count of merger and worklist enodes, as this is
5494 more of an implementation detail of the merging/worklist that we
5495 don't want to bake into our expected DejaGnu messages. */
5497 unsigned i;
5498 exploded_node *enode;
5499 hash_set<const gimple *> seen;
5500 FOR_EACH_VEC_ELT (m_nodes, i, enode)
5502 if (enode->get_point ().get_kind () != PK_BEFORE_STMT)
5503 continue;
5505 if (const gimple *stmt = enode->get_stmt ())
5506 if (const gcall *call = dyn_cast <const gcall *> (stmt))
5507 if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes",
5510 if (seen.contains (stmt))
5511 continue;
5513 auto_vec<exploded_node *> processed_enodes;
5514 auto_vec<exploded_node *> merger_enodes;
5515 auto_vec<exploded_node *> worklist_enodes;
5516 /* This is O(N^2). */
5517 unsigned j;
5518 exploded_node *other_enode;
5519 FOR_EACH_VEC_ELT (m_nodes, j, other_enode)
5521 if (other_enode->get_point ().get_kind () != PK_BEFORE_STMT)
5522 continue;
5523 if (other_enode->get_stmt () == stmt)
5524 switch (other_enode->get_status ())
5526 default:
5527 gcc_unreachable ();
5528 case exploded_node::STATUS_WORKLIST:
5529 worklist_enodes.safe_push (other_enode);
5530 break;
5531 case exploded_node::STATUS_PROCESSED:
5532 processed_enodes.safe_push (other_enode);
5533 break;
5534 case exploded_node::STATUS_MERGER:
5535 merger_enodes.safe_push (other_enode);
5536 break;
5540 pretty_printer pp;
5541 pp_character (&pp, '[');
5542 print_enode_indices (&pp, processed_enodes);
5543 if (merger_enodes.length () > 0)
5545 pp_string (&pp, "] merger(s): [");
5546 print_enode_indices (&pp, merger_enodes);
5548 if (worklist_enodes.length () > 0)
5550 pp_string (&pp, "] worklist: [");
5551 print_enode_indices (&pp, worklist_enodes);
5553 pp_character (&pp, ']');
5555 warning_n (stmt->location, 0, processed_enodes.length (),
5556 "%i processed enode: %s",
5557 "%i processed enodes: %s",
5558 processed_enodes.length (), pp_formatted_text (&pp));
5559 seen.add (stmt);
5561 /* If the argument is non-zero, then print all of the states
5562 of the various enodes. */
5563 tree t_arg = fold (gimple_call_arg (call, 0));
5564 if (TREE_CODE (t_arg) != INTEGER_CST)
5566 error_at (call->location,
5567 "integer constant required for arg 1");
5568 return;
5570 int i_arg = TREE_INT_CST_LOW (t_arg);
5571 if (i_arg)
5573 exploded_node *other_enode;
5574 FOR_EACH_VEC_ELT (processed_enodes, j, other_enode)
5576 fprintf (stderr, "%i of %i: EN %i:\n",
5577 j + 1, processed_enodes.length (),
5578 other_enode->m_index);
5579 other_enode->dump_succs_and_preds (stderr);
5580 /* Dump state. */
5581 other_enode->get_state ().dump (m_ext_state, false);
5588 DEBUG_FUNCTION exploded_node *
5589 exploded_graph::get_node_by_index (int idx) const
5591 exploded_node *enode = m_nodes[idx];
5592 gcc_assert (enode->m_index == idx);
5593 return enode;
5596 /* Ensure that there is an exploded_node for a top-level call to FNDECL. */
5598 void
5599 exploded_graph::on_escaped_function (tree fndecl)
5601 logger * const logger = get_logger ();
5602 LOG_FUNC_1 (logger, "%qE", fndecl);
5604 cgraph_node *cgnode = cgraph_node::get (fndecl);
5605 if (!cgnode)
5606 return;
5608 function *fun = cgnode->get_fun ();
5609 if (!fun)
5610 return;
5612 if (!gimple_has_body_p (fndecl))
5613 return;
5615 exploded_node *enode = add_function_entry (*fun);
5616 if (logger)
5618 if (enode)
5619 logger->log ("created EN %i for %qE entrypoint",
5620 enode->m_index, fun->decl);
5621 else
5622 logger->log ("did not create enode for %qE entrypoint", fun->decl);
5626 /* A collection of classes for visualizing the callgraph in .dot form
5627 (as represented in the supergraph). */
5629 /* Forward decls. */
5630 class viz_callgraph_node;
5631 class viz_callgraph_edge;
5632 class viz_callgraph;
5633 class viz_callgraph_cluster;
5635 /* Traits for using "digraph.h" to visualize the callgraph. */
5637 struct viz_callgraph_traits
5639 typedef viz_callgraph_node node_t;
5640 typedef viz_callgraph_edge edge_t;
5641 typedef viz_callgraph graph_t;
5642 struct dump_args_t
5644 dump_args_t (const exploded_graph *eg) : m_eg (eg) {}
5645 const exploded_graph *m_eg;
5647 typedef viz_callgraph_cluster cluster_t;
5650 /* Subclass of dnode representing a function within the callgraph. */
5652 class viz_callgraph_node : public dnode<viz_callgraph_traits>
5654 friend class viz_callgraph;
5656 public:
5657 viz_callgraph_node (function *fun, int index)
5658 : m_fun (fun), m_index (index), m_num_supernodes (0), m_num_superedges (0)
5660 gcc_assert (fun);
5663 void dump_dot (graphviz_out *gv, const dump_args_t &args) const final override
5665 pretty_printer *pp = gv->get_pp ();
5667 dump_dot_id (pp);
5668 pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
5669 "lightgrey");
5670 pp_write_text_to_stream (pp);
5672 pp_printf (pp, "VCG: %i: %s", m_index, function_name (m_fun));
5673 pp_newline (pp);
5675 pp_printf (pp, "supernodes: %i\n", m_num_supernodes);
5676 pp_newline (pp);
5678 pp_printf (pp, "superedges: %i\n", m_num_superedges);
5679 pp_newline (pp);
5681 if (args.m_eg)
5683 unsigned i;
5684 exploded_node *enode;
5685 unsigned num_enodes = 0;
5686 FOR_EACH_VEC_ELT (args.m_eg->m_nodes, i, enode)
5688 if (enode->get_point ().get_function () == m_fun)
5689 num_enodes++;
5691 pp_printf (pp, "enodes: %i\n", num_enodes);
5692 pp_newline (pp);
5694 // TODO: also show the per-callstring breakdown
5695 const exploded_graph::call_string_data_map_t *per_cs_data
5696 = args.m_eg->get_per_call_string_data ();
5697 for (exploded_graph::call_string_data_map_t::iterator iter
5698 = per_cs_data->begin ();
5699 iter != per_cs_data->end ();
5700 ++iter)
5702 const call_string *cs = (*iter).first;
5703 //per_call_string_data *data = (*iter).second;
5704 num_enodes = 0;
5705 FOR_EACH_VEC_ELT (args.m_eg->m_nodes, i, enode)
5707 if (enode->get_point ().get_function () == m_fun
5708 && &enode->get_point ().get_call_string () == cs)
5709 num_enodes++;
5711 if (num_enodes > 0)
5713 cs->print (pp);
5714 pp_printf (pp, ": %i\n", num_enodes);
5718 /* Show any summaries. */
5719 per_function_data *data = args.m_eg->get_per_function_data (m_fun);
5720 if (data)
5722 pp_newline (pp);
5723 pp_printf (pp, "summaries: %i\n", data->m_summaries.length ());
5724 for (auto summary : data->m_summaries)
5726 pp_printf (pp, "\nsummary: %s:\n", summary->get_desc ().get ());
5727 const extrinsic_state &ext_state = args.m_eg->get_ext_state ();
5728 const program_state &state = summary->get_state ();
5729 state.dump_to_pp (ext_state, false, true, pp);
5730 pp_newline (pp);
5735 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
5736 pp_string (pp, "\"];\n\n");
5737 pp_flush (pp);
5740 void dump_dot_id (pretty_printer *pp) const
5742 pp_printf (pp, "vcg_%i", m_index);
5745 private:
5746 function *m_fun;
5747 int m_index;
5748 int m_num_supernodes;
5749 int m_num_superedges;
5752 /* Subclass of dedge representing a callgraph edge. */
5754 class viz_callgraph_edge : public dedge<viz_callgraph_traits>
5756 public:
5757 viz_callgraph_edge (viz_callgraph_node *src, viz_callgraph_node *dest)
5758 : dedge<viz_callgraph_traits> (src, dest)
5761 void dump_dot (graphviz_out *gv, const dump_args_t &) const
5762 final override
5764 pretty_printer *pp = gv->get_pp ();
5766 const char *style = "\"solid,bold\"";
5767 const char *color = "black";
5768 int weight = 10;
5769 const char *constraint = "true";
5771 m_src->dump_dot_id (pp);
5772 pp_string (pp, " -> ");
5773 m_dest->dump_dot_id (pp);
5774 pp_printf (pp,
5775 (" [style=%s, color=%s, weight=%d, constraint=%s,"
5776 " headlabel=\""),
5777 style, color, weight, constraint);
5778 pp_printf (pp, "\"];\n");
5782 /* Subclass of digraph representing the callgraph. */
5784 class viz_callgraph : public digraph<viz_callgraph_traits>
5786 public:
5787 viz_callgraph (const supergraph &sg);
5789 viz_callgraph_node *get_vcg_node_for_function (function *fun)
5791 return *m_map.get (fun);
5794 viz_callgraph_node *get_vcg_node_for_snode (supernode *snode)
5796 return get_vcg_node_for_function (snode->m_fun);
5799 private:
5800 hash_map<function *, viz_callgraph_node *> m_map;
5803 /* Placeholder subclass of cluster. */
5805 class viz_callgraph_cluster : public cluster<viz_callgraph_traits>
5809 /* viz_callgraph's ctor. */
5811 viz_callgraph::viz_callgraph (const supergraph &sg)
5813 cgraph_node *node;
5814 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
5816 function *fun = node->get_fun ();
5817 viz_callgraph_node *vcg_node
5818 = new viz_callgraph_node (fun, m_nodes.length ());
5819 m_map.put (fun, vcg_node);
5820 add_node (vcg_node);
5823 unsigned i;
5824 superedge *sedge;
5825 FOR_EACH_VEC_ELT (sg.m_edges, i, sedge)
5827 viz_callgraph_node *vcg_src = get_vcg_node_for_snode (sedge->m_src);
5828 if (vcg_src->m_fun)
5829 get_vcg_node_for_function (vcg_src->m_fun)->m_num_superedges++;
5830 if (sedge->dyn_cast_call_superedge ())
5832 viz_callgraph_node *vcg_dest = get_vcg_node_for_snode (sedge->m_dest);
5833 viz_callgraph_edge *vcg_edge
5834 = new viz_callgraph_edge (vcg_src, vcg_dest);
5835 add_edge (vcg_edge);
5839 supernode *snode;
5840 FOR_EACH_VEC_ELT (sg.m_nodes, i, snode)
5842 if (snode->m_fun)
5843 get_vcg_node_for_function (snode->m_fun)->m_num_supernodes++;
5847 /* Dump the callgraph to FILENAME. */
5849 static void
5850 dump_callgraph (const supergraph &sg, const char *filename,
5851 const exploded_graph *eg)
5853 FILE *outf = fopen (filename, "w");
5854 if (!outf)
5855 return;
5857 // TODO
5858 viz_callgraph vcg (sg);
5859 vcg.dump_dot (filename, NULL, viz_callgraph_traits::dump_args_t (eg));
5861 fclose (outf);
5864 /* Dump the callgraph to "<srcfile>.callgraph.dot". */
5866 static void
5867 dump_callgraph (const supergraph &sg, const exploded_graph *eg)
5869 auto_timevar tv (TV_ANALYZER_DUMP);
5870 char *filename = concat (dump_base_name, ".callgraph.dot", NULL);
5871 dump_callgraph (sg, filename, eg);
5872 free (filename);
5875 /* Subclass of dot_annotator for implementing
5876 DUMP_BASE_NAME.supergraph-eg.dot, a post-analysis dump of the supergraph.
5878 Annotate the supergraph nodes by printing the exploded nodes in concise
5879 form within them, next to their pertinent statements where appropriate,
5880 colorizing the exploded nodes based on sm-state.
5881 Also show saved diagnostics within the exploded nodes, giving information
5882 on whether they were feasible, and, if infeasible, where the problem
5883 was. */
5885 class exploded_graph_annotator : public dot_annotator
5887 public:
5888 exploded_graph_annotator (const exploded_graph &eg)
5889 : m_eg (eg)
5891 /* Avoid O(N^2) by prepopulating m_enodes_per_snodes. */
5892 unsigned i;
5893 supernode *snode;
5894 FOR_EACH_VEC_ELT (eg.get_supergraph ().m_nodes, i, snode)
5895 m_enodes_per_snodes.safe_push (new auto_vec <exploded_node *> ());
5896 exploded_node *enode;
5897 FOR_EACH_VEC_ELT (m_eg.m_nodes, i, enode)
5898 if (enode->get_supernode ())
5899 m_enodes_per_snodes[enode->get_supernode ()->m_index]->safe_push (enode);
5902 /* Show exploded nodes for BEFORE_SUPERNODE points before N. */
5903 bool add_node_annotations (graphviz_out *gv, const supernode &n,
5904 bool within_table)
5905 const final override
5907 if (!within_table)
5908 return false;
5909 gv->begin_tr ();
5910 pretty_printer *pp = gv->get_pp ();
5912 gv->begin_td ();
5913 pp_string (pp, "BEFORE");
5914 pp_printf (pp, " (scc: %i)", m_eg.get_scc_id (n));
5915 gv->end_td ();
5917 unsigned i;
5918 exploded_node *enode;
5919 bool had_enode = false;
5920 FOR_EACH_VEC_ELT (*m_enodes_per_snodes[n.m_index], i, enode)
5922 gcc_assert (enode->get_supernode () == &n);
5923 const program_point &point = enode->get_point ();
5924 if (point.get_kind () != PK_BEFORE_SUPERNODE)
5925 continue;
5926 print_enode (gv, enode);
5927 had_enode = true;
5929 if (!had_enode)
5930 pp_string (pp, "<TD BGCOLOR=\"red\">UNREACHED</TD>");
5931 pp_flush (pp);
5932 gv->end_tr ();
5933 return true;
5936 /* Show exploded nodes for STMT. */
5937 void add_stmt_annotations (graphviz_out *gv, const gimple *stmt,
5938 bool within_row)
5939 const final override
5941 if (!within_row)
5942 return;
5943 pretty_printer *pp = gv->get_pp ();
5945 const supernode *snode
5946 = m_eg.get_supergraph ().get_supernode_for_stmt (stmt);
5947 unsigned i;
5948 exploded_node *enode;
5949 bool had_td = false;
5950 FOR_EACH_VEC_ELT (*m_enodes_per_snodes[snode->m_index], i, enode)
5952 const program_point &point = enode->get_point ();
5953 if (point.get_kind () != PK_BEFORE_STMT)
5954 continue;
5955 if (point.get_stmt () != stmt)
5956 continue;
5957 print_enode (gv, enode);
5958 had_td = true;
5960 pp_flush (pp);
5961 if (!had_td)
5963 gv->begin_td ();
5964 gv->end_td ();
5968 /* Show exploded nodes for AFTER_SUPERNODE points after N. */
5969 bool add_after_node_annotations (graphviz_out *gv, const supernode &n)
5970 const final override
5972 gv->begin_tr ();
5973 pretty_printer *pp = gv->get_pp ();
5975 gv->begin_td ();
5976 pp_string (pp, "AFTER");
5977 gv->end_td ();
5979 unsigned i;
5980 exploded_node *enode;
5981 FOR_EACH_VEC_ELT (*m_enodes_per_snodes[n.m_index], i, enode)
5983 gcc_assert (enode->get_supernode () == &n);
5984 const program_point &point = enode->get_point ();
5985 if (point.get_kind () != PK_AFTER_SUPERNODE)
5986 continue;
5987 print_enode (gv, enode);
5989 pp_flush (pp);
5990 gv->end_tr ();
5991 return true;
5994 private:
5995 /* Concisely print a TD element for ENODE, showing the index, status,
5996 and any saved_diagnostics at the enode. Colorize it to show sm-state.
5998 Ideally we'd dump ENODE's state here, hidden behind some kind of
5999 interactive disclosure method like a tooltip, so that the states
6000 can be explored without overwhelming the graph.
6001 However, I wasn't able to get graphviz/xdot to show tooltips on
6002 individual elements within a HTML-like label. */
6003 void print_enode (graphviz_out *gv, const exploded_node *enode) const
6005 pretty_printer *pp = gv->get_pp ();
6006 pp_printf (pp, "<TD BGCOLOR=\"%s\">",
6007 enode->get_dot_fillcolor ());
6008 pp_printf (pp, "<TABLE BORDER=\"0\">");
6009 gv->begin_trtd ();
6010 pp_printf (pp, "EN: %i", enode->m_index);
6011 switch (enode->get_status ())
6013 default:
6014 gcc_unreachable ();
6015 case exploded_node::STATUS_WORKLIST:
6016 pp_string (pp, "(W)");
6017 break;
6018 case exploded_node::STATUS_PROCESSED:
6019 break;
6020 case exploded_node::STATUS_MERGER:
6021 pp_string (pp, "(M)");
6022 break;
6023 case exploded_node::STATUS_BULK_MERGED:
6024 pp_string (pp, "(BM)");
6025 break;
6027 gv->end_tdtr ();
6029 /* Dump any saved_diagnostics at this enode. */
6030 for (unsigned i = 0; i < enode->get_num_diagnostics (); i++)
6032 const saved_diagnostic *sd = enode->get_saved_diagnostic (i);
6033 print_saved_diagnostic (gv, sd);
6035 pp_printf (pp, "</TABLE>");
6036 pp_printf (pp, "</TD>");
6039 /* Print a TABLE element for SD, showing the kind, the length of the
6040 exploded_path, whether the path was feasible, and if infeasible,
6041 what the problem was. */
6042 void print_saved_diagnostic (graphviz_out *gv,
6043 const saved_diagnostic *sd) const
6045 pretty_printer *pp = gv->get_pp ();
6046 gv->begin_trtd ();
6047 pp_printf (pp, "<TABLE BORDER=\"0\">");
6048 gv->begin_tr ();
6049 pp_string (pp, "<TD BGCOLOR=\"green\">");
6050 pp_printf (pp, "DIAGNOSTIC: %s", sd->m_d->get_kind ());
6051 gv->end_tdtr ();
6052 gv->begin_trtd ();
6053 if (sd->get_best_epath ())
6054 pp_printf (pp, "epath length: %i", sd->get_epath_length ());
6055 else
6056 pp_printf (pp, "no best epath");
6057 gv->end_tdtr ();
6058 if (const feasibility_problem *p = sd->get_feasibility_problem ())
6060 gv->begin_trtd ();
6061 pp_printf (pp, "INFEASIBLE at eedge %i: EN:%i -> EN:%i",
6062 p->m_eedge_idx,
6063 p->m_eedge.m_src->m_index,
6064 p->m_eedge.m_dest->m_index);
6065 pp_write_text_as_html_like_dot_to_stream (pp);
6066 gv->end_tdtr ();
6067 gv->begin_trtd ();
6068 p->m_eedge.m_sedge->dump (pp);
6069 pp_write_text_as_html_like_dot_to_stream (pp);
6070 gv->end_tdtr ();
6071 gv->begin_trtd ();
6072 pp_gimple_stmt_1 (pp, p->m_last_stmt, 0, (dump_flags_t)0);
6073 pp_write_text_as_html_like_dot_to_stream (pp);
6074 gv->end_tdtr ();
6075 /* Ideally we'd print p->m_model here; see the notes above about
6076 tooltips. */
6078 pp_printf (pp, "</TABLE>");
6079 gv->end_tdtr ();
6082 const exploded_graph &m_eg;
6083 auto_delete_vec<auto_vec <exploded_node *> > m_enodes_per_snodes;
6086 /* Implement -fdump-analyzer-json. */
6088 static void
6089 dump_analyzer_json (const supergraph &sg,
6090 const exploded_graph &eg)
6092 auto_timevar tv (TV_ANALYZER_DUMP);
6093 char *filename = concat (dump_base_name, ".analyzer.json.gz", NULL);
6094 gzFile output = gzopen (filename, "w");
6095 if (!output)
6097 error_at (UNKNOWN_LOCATION, "unable to open %qs for writing", filename);
6098 free (filename);
6099 return;
6102 json::object *toplev_obj = new json::object ();
6103 toplev_obj->set ("sgraph", sg.to_json ());
6104 toplev_obj->set ("egraph", eg.to_json ());
6106 pretty_printer pp;
6107 toplev_obj->print (&pp, flag_diagnostics_json_formatting);
6108 pp_formatted_text (&pp);
6110 delete toplev_obj;
6112 if (gzputs (output, pp_formatted_text (&pp)) == EOF
6113 || gzclose (output))
6114 error_at (UNKNOWN_LOCATION, "error writing %qs", filename);
6116 free (filename);
6119 /* Concrete subclass of plugin_analyzer_init_iface, allowing plugins
6120 to register new state machines. */
6122 class plugin_analyzer_init_impl : public plugin_analyzer_init_iface
6124 public:
6125 plugin_analyzer_init_impl (auto_delete_vec <state_machine> *checkers,
6126 known_function_manager *known_fn_mgr,
6127 logger *logger)
6128 : m_checkers (checkers),
6129 m_known_fn_mgr (known_fn_mgr),
6130 m_logger (logger)
6133 void register_state_machine (std::unique_ptr<state_machine> sm) final override
6135 LOG_SCOPE (m_logger);
6136 m_checkers->safe_push (sm.release ());
6139 void register_known_function (const char *name,
6140 std::unique_ptr<known_function> kf) final override
6142 LOG_SCOPE (m_logger);
6143 m_known_fn_mgr->add (name, std::move (kf));
6146 logger *get_logger () const final override
6148 return m_logger;
6151 private:
6152 auto_delete_vec <state_machine> *m_checkers;
6153 known_function_manager *m_known_fn_mgr;
6154 logger *m_logger;
6157 /* Run the analysis "engine". */
6159 void
6160 impl_run_checkers (logger *logger)
6162 LOG_SCOPE (logger);
6164 if (logger)
6166 logger->log ("BITS_BIG_ENDIAN: %i", BITS_BIG_ENDIAN ? 1 : 0);
6167 logger->log ("BYTES_BIG_ENDIAN: %i", BYTES_BIG_ENDIAN ? 1 : 0);
6168 logger->log ("WORDS_BIG_ENDIAN: %i", WORDS_BIG_ENDIAN ? 1 : 0);
6169 log_stashed_constants (logger);
6172 /* If using LTO, ensure that the cgraph nodes have function bodies. */
6173 cgraph_node *node;
6174 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
6175 node->get_untransformed_body ();
6177 /* Create the supergraph. */
6178 supergraph sg (logger);
6180 engine eng (&sg, logger);
6182 state_purge_map *purge_map = NULL;
6184 if (flag_analyzer_state_purge)
6185 purge_map = new state_purge_map (sg, eng.get_model_manager (), logger);
6187 if (flag_dump_analyzer_supergraph)
6189 /* Dump supergraph pre-analysis. */
6190 auto_timevar tv (TV_ANALYZER_DUMP);
6191 char *filename = concat (dump_base_name, ".supergraph.dot", NULL);
6192 supergraph::dump_args_t args ((enum supergraph_dot_flags)0, NULL);
6193 sg.dump_dot (filename, args);
6194 free (filename);
6197 if (flag_dump_analyzer_state_purge)
6199 auto_timevar tv (TV_ANALYZER_DUMP);
6200 state_purge_annotator a (purge_map);
6201 char *filename = concat (dump_base_name, ".state-purge.dot", NULL);
6202 supergraph::dump_args_t args ((enum supergraph_dot_flags)0, &a);
6203 sg.dump_dot (filename, args);
6204 free (filename);
6207 auto_delete_vec <state_machine> checkers;
6208 make_checkers (checkers, logger);
6210 register_known_functions (*eng.get_known_function_manager (),
6211 *eng.get_model_manager ());
6213 plugin_analyzer_init_impl data (&checkers,
6214 eng.get_known_function_manager (),
6215 logger);
6216 invoke_plugin_callbacks (PLUGIN_ANALYZER_INIT, &data);
6218 if (logger)
6220 int i;
6221 state_machine *sm;
6222 FOR_EACH_VEC_ELT (checkers, i, sm)
6223 logger->log ("checkers[%i]: %s", i, sm->get_name ());
6226 /* Extrinsic state shared by nodes in the graph. */
6227 const extrinsic_state ext_state (checkers, &eng, logger);
6229 const analysis_plan plan (sg, logger);
6231 /* The exploded graph. */
6232 exploded_graph eg (sg, logger, ext_state, purge_map, plan,
6233 analyzer_verbosity);
6235 /* Add entrypoints to the graph for externally-callable functions. */
6236 eg.build_initial_worklist ();
6238 /* Now process the worklist, exploring the <point, state> graph. */
6239 eg.process_worklist ();
6241 if (warn_analyzer_infinite_loop)
6242 eg.detect_infinite_loops ();
6244 if (flag_dump_analyzer_exploded_graph)
6246 auto_timevar tv (TV_ANALYZER_DUMP);
6247 char *filename
6248 = concat (dump_base_name, ".eg.dot", NULL);
6249 exploded_graph::dump_args_t args (eg);
6250 root_cluster c;
6251 eg.dump_dot (filename, &c, args);
6252 free (filename);
6255 /* Now emit any saved diagnostics. */
6256 eg.get_diagnostic_manager ().emit_saved_diagnostics (eg);
6258 eg.dump_exploded_nodes ();
6260 eg.log_stats ();
6262 if (flag_dump_analyzer_callgraph)
6263 dump_callgraph (sg, &eg);
6265 if (flag_dump_analyzer_supergraph)
6267 /* Dump post-analysis form of supergraph. */
6268 auto_timevar tv (TV_ANALYZER_DUMP);
6269 char *filename = concat (dump_base_name, ".supergraph-eg.dot", NULL);
6270 exploded_graph_annotator a (eg);
6271 supergraph::dump_args_t args ((enum supergraph_dot_flags)0, &a);
6272 sg.dump_dot (filename, args);
6273 free (filename);
6276 if (flag_dump_analyzer_json)
6277 dump_analyzer_json (sg, eg);
6279 if (flag_dump_analyzer_untracked)
6280 eng.get_model_manager ()->dump_untracked_regions ();
6282 delete purge_map;
6284 /* Free up any dominance info that we may have created. */
6285 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
6287 function *fun = node->get_fun ();
6288 free_dominance_info (fun, CDI_DOMINATORS);
6292 /* Handle -fdump-analyzer and -fdump-analyzer-stderr. */
6293 static FILE *dump_fout = NULL;
6295 /* Track if we're responsible for closing dump_fout. */
6296 static bool owns_dump_fout = false;
6298 /* If dumping is enabled, attempt to create dump_fout if it hasn't already
6299 been opened. Return it. */
6301 FILE *
6302 get_or_create_any_logfile ()
6304 if (!dump_fout)
6306 if (flag_dump_analyzer_stderr)
6307 dump_fout = stderr;
6308 else if (flag_dump_analyzer)
6310 char *dump_filename = concat (dump_base_name, ".analyzer.txt", NULL);
6311 dump_fout = fopen (dump_filename, "w");
6312 free (dump_filename);
6313 if (dump_fout)
6314 owns_dump_fout = true;
6317 return dump_fout;
6320 /* External entrypoint to the analysis "engine".
6321 Set up any dumps, then call impl_run_checkers. */
6323 void
6324 run_checkers ()
6326 /* Save input_location. */
6327 location_t saved_input_location = input_location;
6330 log_user the_logger (NULL);
6331 get_or_create_any_logfile ();
6332 if (dump_fout)
6333 the_logger.set_logger (new logger (dump_fout, 0, 0,
6334 *global_dc->printer));
6335 LOG_SCOPE (the_logger.get_logger ());
6337 impl_run_checkers (the_logger.get_logger ());
6339 /* end of lifetime of the_logger (so that dump file is closed after the
6340 various dtors run). */
6343 if (owns_dump_fout)
6345 fclose (dump_fout);
6346 owns_dump_fout = false;
6347 dump_fout = NULL;
6350 /* Restore input_location. Subsequent passes may assume that input_location
6351 is some arbitrary value *not* in the block tree, which might be violated
6352 if we didn't restore it. */
6353 input_location = saved_input_location;
6356 } // namespace ana
6358 #endif /* #if ENABLE_ANALYZER */