Branch data Line data Source code
1 : : /* The analysis "engine".
2 : : Copyright (C) 2019-2024 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it
8 : : under the terms of the GNU General Public License as published by
9 : : the Free Software Foundation; either version 3, or (at your option)
10 : : any later version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : #include "config.h"
22 : : #define INCLUDE_MEMORY
23 : : #include "system.h"
24 : : #include "coretypes.h"
25 : : #include "make-unique.h"
26 : : #include "tree.h"
27 : : #include "fold-const.h"
28 : : #include "gcc-rich-location.h"
29 : : #include "diagnostic-core.h"
30 : : #include "diagnostic-event-id.h"
31 : : #include "diagnostic-path.h"
32 : : #include "function.h"
33 : : #include "pretty-print.h"
34 : : #include "sbitmap.h"
35 : : #include "bitmap.h"
36 : : #include "ordered-hash-map.h"
37 : : #include "analyzer/analyzer.h"
38 : : #include "analyzer/analyzer-logging.h"
39 : : #include "analyzer/call-string.h"
40 : : #include "analyzer/program-point.h"
41 : : #include "analyzer/store.h"
42 : : #include "analyzer/region-model.h"
43 : : #include "analyzer/constraint-manager.h"
44 : : #include "analyzer/sm.h"
45 : : #include "analyzer/pending-diagnostic.h"
46 : : #include "analyzer/diagnostic-manager.h"
47 : : #include "cfg.h"
48 : : #include "basic-block.h"
49 : : #include "gimple.h"
50 : : #include "gimple-iterator.h"
51 : : #include "gimple-pretty-print.h"
52 : : #include "cgraph.h"
53 : : #include "digraph.h"
54 : : #include "analyzer/supergraph.h"
55 : : #include "analyzer/program-state.h"
56 : : #include "analyzer/exploded-graph.h"
57 : : #include "analyzer/analysis-plan.h"
58 : : #include "analyzer/checker-path.h"
59 : : #include "analyzer/state-purge.h"
60 : : #include "analyzer/bar-chart.h"
61 : : #include "analyzer/call-info.h"
62 : : #include <zlib.h>
63 : : #include "plugin.h"
64 : : #include "target.h"
65 : : #include <memory>
66 : : #include "stringpool.h"
67 : : #include "attribs.h"
68 : : #include "tree-dfa.h"
69 : : #include "analyzer/known-function-manager.h"
70 : : #include "analyzer/call-summary.h"
71 : :
72 : : /* For an overview, see gcc/doc/analyzer.texi. */
73 : :
74 : : #if ENABLE_ANALYZER
75 : :
76 : : namespace ana {
77 : :
78 : : /* class impl_region_model_context : public region_model_context. */
79 : :
80 : 1657145 : impl_region_model_context::
81 : : impl_region_model_context (exploded_graph &eg,
82 : : exploded_node *enode_for_diag,
83 : : const program_state *old_state,
84 : : program_state *new_state,
85 : : uncertainty_t *uncertainty,
86 : : path_context *path_ctxt,
87 : : const gimple *stmt,
88 : : stmt_finder *stmt_finder,
89 : 1657145 : bool *out_could_have_done_work)
90 : 1657145 : : m_eg (&eg), m_logger (eg.get_logger ()),
91 : 1657145 : m_enode_for_diag (enode_for_diag),
92 : 1657145 : m_old_state (old_state),
93 : 1657145 : m_new_state (new_state),
94 : 1657145 : m_stmt (stmt),
95 : 1657145 : m_stmt_finder (stmt_finder),
96 : 1657145 : m_ext_state (eg.get_ext_state ()),
97 : 1657145 : m_uncertainty (uncertainty),
98 : 1657145 : m_path_ctxt (path_ctxt),
99 : 1657145 : m_out_could_have_done_work (out_could_have_done_work)
100 : : {
101 : 1657145 : }
102 : :
103 : 4 : impl_region_model_context::
104 : : impl_region_model_context (program_state *state,
105 : : const extrinsic_state &ext_state,
106 : : uncertainty_t *uncertainty,
107 : 4 : logger *logger)
108 : 4 : : m_eg (NULL), m_logger (logger), m_enode_for_diag (NULL),
109 : 4 : m_old_state (NULL),
110 : 4 : m_new_state (state),
111 : 4 : m_stmt (NULL),
112 : 4 : m_stmt_finder (NULL),
113 : 4 : m_ext_state (ext_state),
114 : 4 : m_uncertainty (uncertainty),
115 : 4 : m_path_ctxt (NULL),
116 : 4 : m_out_could_have_done_work (nullptr)
117 : : {
118 : 4 : }
119 : :
120 : : bool
121 : 3889 : impl_region_model_context::warn (std::unique_ptr<pending_diagnostic> d,
122 : : const stmt_finder *custom_finder)
123 : : {
124 : 3889 : LOG_FUNC (get_logger ());
125 : 3889 : auto curr_stmt_finder = custom_finder ? custom_finder : m_stmt_finder;
126 : 3889 : if (m_stmt == NULL && curr_stmt_finder == NULL)
127 : : {
128 : 377 : if (get_logger ())
129 : 0 : get_logger ()->log ("rejecting diagnostic: no stmt");
130 : 377 : return false;
131 : : }
132 : 3512 : if (m_eg)
133 : : {
134 : 3512 : bool terminate_path = d->terminate_path_p ();
135 : 3512 : pending_location ploc (m_enode_for_diag,
136 : 3512 : m_enode_for_diag->get_supernode (),
137 : : m_stmt,
138 : 3512 : curr_stmt_finder);
139 : 3512 : if (m_eg->get_diagnostic_manager ().add_diagnostic (ploc,
140 : : std::move (d)))
141 : : {
142 : 3324 : if (m_path_ctxt
143 : 2384 : && terminate_path
144 : 925 : && flag_analyzer_suppress_followups)
145 : 744 : m_path_ctxt->terminate_path ();
146 : 3324 : return true;
147 : : }
148 : : }
149 : : return false;
150 : 3889 : }
151 : :
152 : : void
153 : 242 : impl_region_model_context::add_note (std::unique_ptr<pending_note> pn)
154 : : {
155 : 242 : LOG_FUNC (get_logger ());
156 : 242 : if (m_eg)
157 : 242 : m_eg->get_diagnostic_manager ().add_note (std::move (pn));
158 : 242 : }
159 : :
160 : : void
161 : 202 : impl_region_model_context::add_event (std::unique_ptr<checker_event> event)
162 : : {
163 : 202 : LOG_FUNC (get_logger ());
164 : 202 : if (m_eg)
165 : 202 : m_eg->get_diagnostic_manager ().add_event (std::move (event));
166 : 202 : }
167 : :
168 : : void
169 : 85115 : impl_region_model_context::on_svalue_leak (const svalue *sval)
170 : :
171 : : {
172 : 850159 : for (sm_state_map *smap : m_new_state->m_checker_states)
173 : 594814 : smap->on_svalue_leak (sval, this);
174 : 85115 : }
175 : :
176 : : void
177 : 687489 : impl_region_model_context::
178 : : on_liveness_change (const svalue_set &live_svalues,
179 : : const region_model *model)
180 : : {
181 : 6868822 : for (sm_state_map *smap : m_new_state->m_checker_states)
182 : 4806355 : smap->on_liveness_change (live_svalues, model, m_ext_state, this);
183 : 687489 : }
184 : :
185 : : void
186 : 70409 : impl_region_model_context::on_unknown_change (const svalue *sval,
187 : : bool is_mutable)
188 : : {
189 : 70409 : if (!sval->can_have_associated_state_p ())
190 : : return;
191 : 548027 : for (sm_state_map *smap : m_new_state->m_checker_states)
192 : 383588 : smap->on_unknown_change (sval, is_mutable, m_ext_state);
193 : : }
194 : :
195 : : void
196 : 209 : impl_region_model_context::on_escaped_function (tree fndecl)
197 : : {
198 : 209 : m_eg->on_escaped_function (fndecl);
199 : 209 : }
200 : :
201 : : uncertainty_t *
202 : 5731234 : impl_region_model_context::get_uncertainty ()
203 : : {
204 : 5731234 : return m_uncertainty;
205 : : }
206 : :
207 : : /* Purge state involving SVAL. The region_model has already been purged,
208 : : so we only need to purge other state in the program_state:
209 : : the sm-state. */
210 : :
211 : : void
212 : 21240 : impl_region_model_context::purge_state_involving (const svalue *sval)
213 : : {
214 : 21240 : int i;
215 : 21240 : sm_state_map *smap;
216 : 169920 : FOR_EACH_VEC_ELT (m_new_state->m_checker_states, i, smap)
217 : 148680 : smap->purge_state_involving (sval, m_ext_state);
218 : 21240 : }
219 : :
220 : : void
221 : 5103 : impl_region_model_context::bifurcate (std::unique_ptr<custom_edge_info> info)
222 : : {
223 : 5103 : if (m_path_ctxt)
224 : 5103 : m_path_ctxt->bifurcate (std::move (info));
225 : 5103 : }
226 : :
227 : : void
228 : 1965 : impl_region_model_context::terminate_path ()
229 : : {
230 : 1965 : if (m_path_ctxt)
231 : 1965 : return m_path_ctxt->terminate_path ();
232 : : }
233 : :
234 : : /* struct setjmp_record. */
235 : :
236 : : int
237 : 0 : setjmp_record::cmp (const setjmp_record &rec1, const setjmp_record &rec2)
238 : : {
239 : 0 : if (int cmp_enode = rec1.m_enode->m_index - rec2.m_enode->m_index)
240 : : return cmp_enode;
241 : 0 : gcc_assert (&rec1 == &rec2);
242 : : return 0;
243 : : }
244 : :
245 : : /* class setjmp_svalue : public svalue. */
246 : :
247 : : /* Implementation of svalue::accept vfunc for setjmp_svalue. */
248 : :
249 : : void
250 : 1711 : setjmp_svalue::accept (visitor *v) const
251 : : {
252 : 1711 : v->visit_setjmp_svalue (this);
253 : 1711 : }
254 : :
255 : : /* Implementation of svalue::dump_to_pp vfunc for setjmp_svalue. */
256 : :
257 : : void
258 : 0 : setjmp_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
259 : : {
260 : 0 : if (simple)
261 : 0 : pp_printf (pp, "SETJMP(EN: %i)", get_enode_index ());
262 : : else
263 : 0 : pp_printf (pp, "setjmp_svalue(EN%i)", get_enode_index ());
264 : 0 : }
265 : :
266 : : /* Get the index of the stored exploded_node. */
267 : :
268 : : int
269 : 0 : setjmp_svalue::get_enode_index () const
270 : : {
271 : 0 : return m_setjmp_record.m_enode->m_index;
272 : : }
273 : :
274 : : /* Concrete implementation of sm_context, wiring it up to the rest of this
275 : : file. */
276 : :
277 : 2494259 : class impl_sm_context : public sm_context
278 : : {
279 : : public:
280 : 2495145 : impl_sm_context (exploded_graph &eg,
281 : : int sm_idx,
282 : : const state_machine &sm,
283 : : exploded_node *enode_for_diag,
284 : : const program_state *old_state,
285 : : program_state *new_state,
286 : : const sm_state_map *old_smap,
287 : : sm_state_map *new_smap,
288 : : path_context *path_ctxt,
289 : : const stmt_finder *stmt_finder = NULL,
290 : : bool unknown_side_effects = false)
291 : 2495145 : : sm_context (sm_idx, sm),
292 : 2495145 : m_logger (eg.get_logger ()),
293 : 2495145 : m_eg (eg), m_enode_for_diag (enode_for_diag),
294 : 2495145 : m_old_state (old_state), m_new_state (new_state),
295 : 2495145 : m_old_smap (old_smap), m_new_smap (new_smap),
296 : 2495145 : m_path_ctxt (path_ctxt),
297 : 2495145 : m_stmt_finder (stmt_finder),
298 : 886 : m_unknown_side_effects (unknown_side_effects)
299 : : {
300 : : }
301 : :
302 : 263060 : logger *get_logger () const { return m_logger.get_logger (); }
303 : :
304 : 466660 : tree get_fndecl_for_call (const gcall *call) final override
305 : : {
306 : 466660 : impl_region_model_context old_ctxt
307 : : (m_eg, m_enode_for_diag, NULL, NULL, NULL/*m_enode->get_state ()*/,
308 : 466660 : NULL, call);
309 : 466660 : region_model *model = m_new_state->m_region_model;
310 : 466660 : return model->get_fndecl_for_call (call, &old_ctxt);
311 : 466660 : }
312 : :
313 : 93086 : state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
314 : : tree var) final override
315 : : {
316 : 93086 : logger * const logger = get_logger ();
317 : 93086 : LOG_FUNC (logger);
318 : : /* Use NULL ctxt on this get_rvalue call to avoid triggering
319 : : uninitialized value warnings. */
320 : 93086 : const svalue *var_old_sval
321 : 93086 : = m_old_state->m_region_model->get_rvalue (var, NULL);
322 : :
323 : 93086 : state_machine::state_t current
324 : 93086 : = m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ());
325 : 186172 : return current;
326 : 93086 : }
327 : 112149 : state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
328 : : const svalue *sval) final override
329 : : {
330 : 112149 : logger * const logger = get_logger ();
331 : 112149 : LOG_FUNC (logger);
332 : 112149 : state_machine::state_t current
333 : 112149 : = m_old_smap->get_state (sval, m_eg.get_ext_state ());
334 : 224298 : return current;
335 : 112149 : }
336 : :
337 : :
338 : 45690 : void set_next_state (const gimple *,
339 : : tree var,
340 : : state_machine::state_t to,
341 : : tree origin) final override
342 : : {
343 : 45690 : logger * const logger = get_logger ();
344 : 45690 : LOG_FUNC (logger);
345 : 45690 : const svalue *var_new_sval
346 : 45690 : = m_new_state->m_region_model->get_rvalue (var, NULL);
347 : 45690 : const svalue *origin_new_sval
348 : 45690 : = m_new_state->m_region_model->get_rvalue (origin, NULL);
349 : :
350 : : /* We use the new sval here to avoid issues with uninitialized values. */
351 : 45690 : state_machine::state_t current
352 : 45690 : = m_old_smap->get_state (var_new_sval, m_eg.get_ext_state ());
353 : 45690 : if (logger)
354 : 23 : logger->log ("%s: state transition of %qE: %s -> %s",
355 : 23 : m_sm.get_name (),
356 : : var,
357 : : current->get_name (),
358 : : to->get_name ());
359 : 45690 : m_new_smap->set_state (m_new_state->m_region_model, var_new_sval,
360 : 45690 : to, origin_new_sval, m_eg.get_ext_state ());
361 : 45690 : }
362 : :
363 : 4866 : void set_next_state (const gimple *stmt,
364 : : const svalue *sval,
365 : : state_machine::state_t to,
366 : : tree origin) final override
367 : : {
368 : 4866 : logger * const logger = get_logger ();
369 : 4866 : LOG_FUNC (logger);
370 : 4866 : impl_region_model_context old_ctxt
371 : : (m_eg, m_enode_for_diag, NULL, NULL, NULL/*m_enode->get_state ()*/,
372 : 4866 : NULL, stmt);
373 : :
374 : 4866 : const svalue *origin_new_sval
375 : 4866 : = m_new_state->m_region_model->get_rvalue (origin, NULL);
376 : :
377 : 4866 : state_machine::state_t current
378 : 4866 : = m_old_smap->get_state (sval, m_eg.get_ext_state ());
379 : 4866 : if (logger)
380 : : {
381 : 0 : logger->start_log_line ();
382 : 0 : logger->log_partial ("%s: state transition of ",
383 : 0 : m_sm.get_name ());
384 : 0 : sval->dump_to_pp (logger->get_printer (), true);
385 : 0 : logger->log_partial (": %s -> %s",
386 : : current->get_name (),
387 : : to->get_name ());
388 : 0 : logger->end_log_line ();
389 : : }
390 : 4866 : m_new_smap->set_state (m_new_state->m_region_model, sval,
391 : 4866 : to, origin_new_sval, m_eg.get_ext_state ());
392 : 4866 : }
393 : :
394 : 7146 : void warn (const supernode *snode, const gimple *stmt,
395 : : tree var,
396 : : std::unique_ptr<pending_diagnostic> d) final override
397 : : {
398 : 7146 : LOG_FUNC (get_logger ());
399 : 7146 : gcc_assert (d);
400 : 7146 : const svalue *var_old_sval
401 : 7146 : = m_old_state->m_region_model->get_rvalue (var, NULL);
402 : 7146 : state_machine::state_t current
403 : : = (var
404 : 7146 : ? m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ())
405 : 97 : : m_old_smap->get_global_state ());
406 : 7146 : bool terminate_path = d->terminate_path_p ();
407 : 7146 : pending_location ploc (m_enode_for_diag, snode, stmt, m_stmt_finder);
408 : 7146 : m_eg.get_diagnostic_manager ().add_diagnostic
409 : 7146 : (&m_sm, ploc,
410 : : var, var_old_sval, current, std::move (d));
411 : 7146 : if (m_path_ctxt
412 : 7138 : && terminate_path
413 : 271 : && flag_analyzer_suppress_followups)
414 : 263 : m_path_ctxt->terminate_path ();
415 : 7146 : }
416 : :
417 : 123 : void warn (const supernode *snode, const gimple *stmt,
418 : : const svalue *sval,
419 : : std::unique_ptr<pending_diagnostic> d) final override
420 : : {
421 : 123 : LOG_FUNC (get_logger ());
422 : 123 : gcc_assert (d);
423 : 123 : state_machine::state_t current
424 : : = (sval
425 : 123 : ? m_old_smap->get_state (sval, m_eg.get_ext_state ())
426 : 0 : : m_old_smap->get_global_state ());
427 : 123 : bool terminate_path = d->terminate_path_p ();
428 : 123 : pending_location ploc (m_enode_for_diag, snode, stmt, m_stmt_finder);
429 : 123 : m_eg.get_diagnostic_manager ().add_diagnostic
430 : 123 : (&m_sm, ploc,
431 : : NULL_TREE, sval, current, std::move (d));
432 : 123 : if (m_path_ctxt
433 : 13 : && terminate_path
434 : 0 : && flag_analyzer_suppress_followups)
435 : 0 : m_path_ctxt->terminate_path ();
436 : 123 : }
437 : :
438 : : /* Hook for picking more readable trees for SSA names of temporaries,
439 : : so that rather than e.g.
440 : : "double-free of '<unknown>'"
441 : : we can print:
442 : : "double-free of 'inbuf.data'". */
443 : :
444 : 7671 : tree get_diagnostic_tree (tree expr) final override
445 : : {
446 : : /* Only for SSA_NAMEs of temporaries; otherwise, return EXPR, as it's
447 : : likely to be the least surprising tree to report. */
448 : 7671 : if (TREE_CODE (expr) != SSA_NAME)
449 : : return expr;
450 : 7556 : if (SSA_NAME_VAR (expr) != NULL)
451 : : return expr;
452 : :
453 : 476 : gcc_assert (m_new_state);
454 : 476 : const svalue *sval = m_new_state->m_region_model->get_rvalue (expr, NULL);
455 : : /* Find trees for all regions storing the value. */
456 : 476 : if (tree t = m_new_state->m_region_model->get_representative_tree (sval))
457 : : return t;
458 : : else
459 : : return expr;
460 : : }
461 : :
462 : 148 : tree get_diagnostic_tree (const svalue *sval) final override
463 : : {
464 : 148 : return m_new_state->m_region_model->get_representative_tree (sval);
465 : : }
466 : :
467 : 286742 : state_machine::state_t get_global_state () const final override
468 : : {
469 : 286742 : return m_old_state->m_checker_states[m_sm_idx]->get_global_state ();
470 : : }
471 : :
472 : 24910 : void set_global_state (state_machine::state_t state) final override
473 : : {
474 : 24910 : m_new_state->m_checker_states[m_sm_idx]->set_global_state (state);
475 : 24910 : }
476 : :
477 : 10491 : void clear_all_per_svalue_state () final override
478 : : {
479 : 10491 : m_new_state->m_checker_states[m_sm_idx]->clear_all_per_svalue_state ();
480 : 10491 : }
481 : :
482 : 18 : void on_custom_transition (custom_transition *transition) final override
483 : : {
484 : 18 : transition->impl_transition (&m_eg,
485 : : const_cast<exploded_node *> (m_enode_for_diag),
486 : : m_sm_idx);
487 : 18 : }
488 : :
489 : 261159 : tree is_zero_assignment (const gimple *stmt) final override
490 : : {
491 : 261159 : const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
492 : 149918 : if (!assign_stmt)
493 : : return NULL_TREE;
494 : 149918 : impl_region_model_context old_ctxt
495 : 149918 : (m_eg, m_enode_for_diag, m_old_state, m_new_state, NULL, NULL, stmt);
496 : 299836 : if (const svalue *sval
497 : 149918 : = m_new_state->m_region_model->get_gassign_result (assign_stmt,
498 : : &old_ctxt))
499 : 143864 : if (tree cst = sval->maybe_get_constant ())
500 : 36633 : if (::zerop(cst))
501 : 14845 : return gimple_assign_lhs (assign_stmt);
502 : : return NULL_TREE;
503 : 149918 : }
504 : :
505 : 30 : path_context *get_path_context () const final override
506 : : {
507 : 30 : return m_path_ctxt;
508 : : }
509 : :
510 : 65032 : bool unknown_side_effects_p () const final override
511 : : {
512 : 65032 : return m_unknown_side_effects;
513 : : }
514 : :
515 : 308075 : const program_state *get_old_program_state () const final override
516 : : {
517 : 308075 : return m_old_state;
518 : : }
519 : :
520 : 1915 : const program_state *get_new_program_state () const final override
521 : : {
522 : 1915 : return m_new_state;
523 : : }
524 : :
525 : : log_user m_logger;
526 : : exploded_graph &m_eg;
527 : : exploded_node *m_enode_for_diag;
528 : : const program_state *m_old_state;
529 : : program_state *m_new_state;
530 : : const sm_state_map *m_old_smap;
531 : : sm_state_map *m_new_smap;
532 : : path_context *m_path_ctxt;
533 : : const stmt_finder *m_stmt_finder;
534 : :
535 : : /* Are we handling an external function with unknown side effects? */
536 : : bool m_unknown_side_effects;
537 : : };
538 : :
539 : : bool
540 : 798078 : impl_region_model_context::
541 : : get_state_map_by_name (const char *name,
542 : : sm_state_map **out_smap,
543 : : const state_machine **out_sm,
544 : : unsigned *out_sm_idx,
545 : : std::unique_ptr<sm_context> *out_sm_context)
546 : : {
547 : 798078 : if (!m_new_state)
548 : : return false;
549 : :
550 : 792928 : unsigned sm_idx;
551 : 792928 : if (!m_ext_state.get_sm_idx_by_name (name, &sm_idx))
552 : : return false;
553 : :
554 : 792210 : const state_machine *sm = &m_ext_state.get_sm (sm_idx);
555 : 792210 : sm_state_map *new_smap = m_new_state->m_checker_states[sm_idx];
556 : :
557 : 792210 : *out_smap = new_smap;
558 : 792210 : *out_sm = sm;
559 : 792210 : if (out_sm_idx)
560 : 791306 : *out_sm_idx = sm_idx;
561 : 792210 : if (out_sm_context)
562 : : {
563 : 886 : const sm_state_map *old_smap = m_old_state->m_checker_states[sm_idx];
564 : 886 : *out_sm_context
565 : 886 : = make_unique<impl_sm_context> (*m_eg,
566 : : sm_idx,
567 : : *sm,
568 : 886 : m_enode_for_diag,
569 : 886 : m_old_state,
570 : 886 : m_new_state,
571 : : old_smap,
572 : : new_smap,
573 : 886 : m_path_ctxt,
574 : 886 : m_stmt_finder,
575 : 1772 : false);
576 : : }
577 : : return true;
578 : : }
579 : :
580 : : /* Subclass of stmt_finder for finding the best stmt to report the leak at,
581 : : given the emission path. */
582 : :
583 : 2092 : class leak_stmt_finder : public stmt_finder
584 : : {
585 : : public:
586 : 3645 : leak_stmt_finder (const exploded_graph &eg, tree var)
587 : 1553 : : m_eg (eg), m_var (var) {}
588 : :
589 : 1553 : std::unique_ptr<stmt_finder> clone () const final override
590 : : {
591 : 1553 : return make_unique<leak_stmt_finder> (m_eg, m_var);
592 : : }
593 : :
594 : 990 : const gimple *find_stmt (const exploded_path &epath)
595 : : final override
596 : : {
597 : 990 : logger * const logger = m_eg.get_logger ();
598 : 990 : LOG_FUNC (logger);
599 : :
600 : 990 : if (m_var && TREE_CODE (m_var) == SSA_NAME)
601 : : {
602 : : /* Locate the final write to this SSA name in the path. */
603 : 932 : const gimple *def_stmt = SSA_NAME_DEF_STMT (m_var);
604 : :
605 : 932 : int idx_of_def_stmt;
606 : 932 : bool found = epath.find_stmt_backwards (def_stmt, &idx_of_def_stmt);
607 : 932 : if (!found)
608 : 58 : goto not_found;
609 : :
610 : : /* What was the next write to the underlying var
611 : : after the SSA name was set? (if any). */
612 : :
613 : 874 : for (unsigned idx = idx_of_def_stmt + 1;
614 : 34544 : idx < epath.m_edges.length ();
615 : : ++idx)
616 : : {
617 : 16420 : const exploded_edge *eedge = epath.m_edges[idx];
618 : 16420 : if (logger)
619 : 0 : logger->log ("eedge[%i]: EN %i -> EN %i",
620 : : idx,
621 : 0 : eedge->m_src->m_index,
622 : 0 : eedge->m_dest->m_index);
623 : 16420 : const exploded_node *dst_node = eedge->m_dest;
624 : 16420 : const program_point &dst_point = dst_node->get_point ();
625 : 16420 : const gimple *stmt = dst_point.get_stmt ();
626 : 16420 : if (!stmt)
627 : 6002 : continue;
628 : 18720 : if (const gassign *assign = dyn_cast <const gassign *> (stmt))
629 : : {
630 : 2322 : tree lhs = gimple_assign_lhs (assign);
631 : 2322 : if (TREE_CODE (lhs) == SSA_NAME
632 : 3270 : && SSA_NAME_VAR (lhs) == SSA_NAME_VAR (m_var))
633 : 22 : return assign;
634 : : }
635 : : }
636 : : }
637 : :
638 : 58 : not_found:
639 : :
640 : : /* Look backwards for the first statement with a location. */
641 : 968 : int i;
642 : 968 : const exploded_edge *eedge;
643 : 4934 : FOR_EACH_VEC_ELT_REVERSE (epath.m_edges, i, eedge)
644 : : {
645 : 3966 : if (logger)
646 : 0 : logger->log ("eedge[%i]: EN %i -> EN %i",
647 : : i,
648 : 0 : eedge->m_src->m_index,
649 : 0 : eedge->m_dest->m_index);
650 : 3966 : const exploded_node *dst_node = eedge->m_dest;
651 : 3966 : const program_point &dst_point = dst_node->get_point ();
652 : 3966 : const gimple *stmt = dst_point.get_stmt ();
653 : 3966 : if (stmt)
654 : 1720 : if (get_pure_location (stmt->location) != UNKNOWN_LOCATION)
655 : 968 : return stmt;
656 : : }
657 : :
658 : 0 : gcc_unreachable ();
659 : : return NULL;
660 : 990 : }
661 : :
662 : : private:
663 : : const exploded_graph &m_eg;
664 : : tree m_var;
665 : : };
666 : :
667 : : /* A measurement of how good EXPR is for presenting to the user, so
668 : : that e.g. we can say prefer printing
669 : : "leak of 'tmp.m_ptr'"
670 : : over:
671 : : "leak of '<unknown>'". */
672 : :
673 : : static int
674 : 25026 : readability (const_tree expr)
675 : : {
676 : : /* Arbitrarily-chosen "high readability" value. */
677 : 41706 : const int HIGH_READABILITY = 65536;
678 : :
679 : 41706 : gcc_assert (expr);
680 : 41706 : switch (TREE_CODE (expr))
681 : : {
682 : 4214 : case COMPONENT_REF:
683 : 4214 : case MEM_REF:
684 : : /* Impose a slight readability penalty relative to that of
685 : : operand 0. */
686 : 4214 : return readability (TREE_OPERAND (expr, 0)) - 16;
687 : :
688 : 19076 : case SSA_NAME:
689 : 19076 : {
690 : 19076 : if (tree var = SSA_NAME_VAR (expr))
691 : : {
692 : 11228 : if (DECL_ARTIFICIAL (var))
693 : : {
694 : : /* If we have an SSA name for an artificial var,
695 : : only use it if it has a debug expr associated with
696 : : it that fixup_tree_for_diagnostic can use. */
697 : 28 : if (VAR_P (var) && DECL_HAS_DEBUG_EXPR_P (var))
698 : 0 : return readability (DECL_DEBUG_EXPR (var)) - 1;
699 : : }
700 : : else
701 : : {
702 : : /* Slightly favor the underlying var over the SSA name to
703 : : avoid having them compare equal. */
704 : 11200 : return readability (var) - 1;
705 : : }
706 : : }
707 : : /* Avoid printing '<unknown>' for SSA names for temporaries. */
708 : : return -1;
709 : : }
710 : 12872 : break;
711 : :
712 : 12872 : case PARM_DECL:
713 : 12872 : case VAR_DECL:
714 : 12872 : if (DECL_NAME (expr))
715 : : return HIGH_READABILITY;
716 : : else
717 : : /* We don't want to print temporaries. For example, the C FE
718 : : prints them as e.g. "<Uxxxx>" where "xxxx" is the low 16 bits
719 : : of the tree pointer (see pp_c_tree_decl_identifier). */
720 : : return -1;
721 : :
722 : : case RESULT_DECL:
723 : : /* Printing "<return-value>" isn't ideal, but is less awful than
724 : : trying to print a temporary. */
725 : : return HIGH_READABILITY / 2;
726 : :
727 : 1266 : case NOP_EXPR:
728 : 1266 : {
729 : : /* Impose a moderate readability penalty for casts. */
730 : 1266 : const int CAST_PENALTY = 32;
731 : 1266 : return readability (TREE_OPERAND (expr, 0)) - CAST_PENALTY;
732 : : }
733 : :
734 : : case INTEGER_CST:
735 : : return HIGH_READABILITY;
736 : :
737 : 328 : default:
738 : 328 : return 0;
739 : : }
740 : :
741 : : return 0;
742 : : }
743 : :
744 : : /* A qsort comparator for trees to sort them into most user-readable to
745 : : least user-readable. */
746 : :
747 : : int
748 : 12513 : readability_comparator (const void *p1, const void *p2)
749 : : {
750 : 12513 : path_var pv1 = *(path_var const *)p1;
751 : 12513 : path_var pv2 = *(path_var const *)p2;
752 : :
753 : 12513 : const int tree_r1 = readability (pv1.m_tree);
754 : 12513 : const int tree_r2 = readability (pv2.m_tree);
755 : :
756 : : /* Favor items that are deeper on the stack and hence more recent;
757 : : this also favors locals over globals. */
758 : 12513 : const int COST_PER_FRAME = 64;
759 : 12513 : const int depth_r1 = pv1.m_stack_depth * COST_PER_FRAME;
760 : 12513 : const int depth_r2 = pv2.m_stack_depth * COST_PER_FRAME;
761 : :
762 : : /* Combine the scores from the tree and from the stack depth.
763 : : This e.g. lets us have a slightly penalized cast in the most
764 : : recent stack frame "beat" an uncast value in an older stack frame. */
765 : 12513 : const int sum_r1 = tree_r1 + depth_r1;
766 : 12513 : const int sum_r2 = tree_r2 + depth_r2;
767 : 12513 : if (int cmp = sum_r2 - sum_r1)
768 : : return cmp;
769 : :
770 : : /* Otherwise, more readable trees win. */
771 : 2779 : if (int cmp = tree_r2 - tree_r1)
772 : : return cmp;
773 : :
774 : : /* Otherwise, if they have the same readability, then impose an
775 : : arbitrary deterministic ordering on them. */
776 : :
777 : 2779 : if (int cmp = TREE_CODE (pv1.m_tree) - TREE_CODE (pv2.m_tree))
778 : : return cmp;
779 : :
780 : 2719 : switch (TREE_CODE (pv1.m_tree))
781 : : {
782 : : default:
783 : : break;
784 : 2689 : case SSA_NAME:
785 : 2689 : if (int cmp = (SSA_NAME_VERSION (pv1.m_tree)
786 : 2689 : - SSA_NAME_VERSION (pv2.m_tree)))
787 : : return cmp;
788 : : break;
789 : 0 : case PARM_DECL:
790 : 0 : case VAR_DECL:
791 : 0 : case RESULT_DECL:
792 : 0 : if (int cmp = DECL_UID (pv1.m_tree) - DECL_UID (pv2.m_tree))
793 : : return cmp;
794 : : break;
795 : : }
796 : :
797 : : /* TODO: We ought to find ways of sorting such cases. */
798 : : return 0;
799 : : }
800 : :
801 : : /* Return true is SNODE is the EXIT node of a function, or is one
802 : : of the final snodes within its function.
803 : :
804 : : Specifically, handle the final supernodes before the EXIT node,
805 : : for the case of clobbers that happen immediately before exiting.
806 : : We need a run of snodes leading to the return_p snode, where all edges are
807 : : intraprocedural, and every snode has just one successor.
808 : :
809 : : We use this when suppressing leak reports at the end of "main". */
810 : :
811 : : static bool
812 : 2092 : returning_from_function_p (const supernode *snode)
813 : : {
814 : 2092 : if (!snode)
815 : : return false;
816 : :
817 : : unsigned count = 0;
818 : : const supernode *iter = snode;
819 : 3223 : while (true)
820 : : {
821 : 3223 : if (iter->return_p ())
822 : : return true;
823 : 1316 : if (iter->m_succs.length () != 1)
824 : : return false;
825 : 1131 : const superedge *sedge = iter->m_succs[0];
826 : 1131 : if (sedge->get_kind () != SUPEREDGE_CFG_EDGE)
827 : : return false;
828 : 1131 : iter = sedge->m_dest;
829 : :
830 : : /* Impose a limit to ensure we terminate for pathological cases.
831 : :
832 : : We only care about the final 3 nodes, due to cases like:
833 : : BB:
834 : : (clobber causing leak)
835 : :
836 : : BB:
837 : : <label>:
838 : : return _val;
839 : :
840 : : EXIT BB.*/
841 : 1131 : if (++count > 3)
842 : : return false;
843 : : }
844 : : }
845 : :
846 : : /* Find the best tree for SVAL and call SM's on_leak vfunc with it.
847 : : If on_leak returns a pending_diagnostic, queue it up to be reported,
848 : : so that we potentially complain about a leak of SVAL in the given STATE. */
849 : :
850 : : void
851 : 2092 : impl_region_model_context::on_state_leak (const state_machine &sm,
852 : : const svalue *sval,
853 : : state_machine::state_t state)
854 : : {
855 : 2092 : logger * const logger = get_logger ();
856 : 2092 : LOG_SCOPE (logger);
857 : 2092 : if (logger)
858 : : {
859 : 0 : logger->start_log_line ();
860 : 0 : logger->log_partial ("considering leak of ");
861 : 0 : sval->dump_to_pp (logger->get_printer (), true);
862 : 0 : logger->end_log_line ();
863 : : }
864 : :
865 : 2092 : if (!m_eg)
866 : : return;
867 : :
868 : : /* m_old_state also needs to be non-NULL so that the sm_ctxt can look
869 : : up the old state of SVAL. */
870 : 2092 : gcc_assert (m_old_state);
871 : :
872 : : /* SVAL has leaked within the new state: it is not used by any reachable
873 : : regions.
874 : : We need to convert it back to a tree, but since it's likely no regions
875 : : use it, we have to find the "best" tree for it in the old_state. */
876 : 2092 : svalue_set visited;
877 : 2092 : path_var leaked_pv
878 : 2092 : = m_old_state->m_region_model->get_representative_path_var (sval,
879 : : &visited);
880 : :
881 : : /* Strip off top-level casts */
882 : 2092 : if (leaked_pv.m_tree && TREE_CODE (leaked_pv.m_tree) == NOP_EXPR)
883 : 116 : leaked_pv.m_tree = TREE_OPERAND (leaked_pv.m_tree, 0);
884 : :
885 : : /* This might be NULL; the pending_diagnostic subclasses need to cope
886 : : with this. */
887 : 2092 : tree leaked_tree = leaked_pv.m_tree;
888 : 2092 : if (logger)
889 : : {
890 : 0 : if (leaked_tree)
891 : 0 : logger->log ("best leaked_tree: %qE", leaked_tree);
892 : : else
893 : 0 : logger->log ("best leaked_tree: NULL");
894 : : }
895 : :
896 : 2092 : leak_stmt_finder stmt_finder (*m_eg, leaked_tree);
897 : 2092 : gcc_assert (m_enode_for_diag);
898 : :
899 : : /* Don't complain about leaks when returning from "main". */
900 : 2092 : if (returning_from_function_p (m_enode_for_diag->get_supernode ()))
901 : : {
902 : 1907 : tree fndecl = m_enode_for_diag->get_function ()->decl;
903 : 1907 : if (id_equal (DECL_NAME (fndecl), "main"))
904 : : {
905 : 74 : if (logger)
906 : 0 : logger->log ("not reporting leak from main");
907 : 74 : return;
908 : : }
909 : : }
910 : :
911 : 2018 : tree leaked_tree_for_diag = fixup_tree_for_diagnostic (leaked_tree);
912 : 2018 : std::unique_ptr<pending_diagnostic> pd = sm.on_leak (leaked_tree_for_diag);
913 : 2018 : if (pd)
914 : : {
915 : 1553 : pending_location ploc (m_enode_for_diag,
916 : 1553 : m_enode_for_diag->get_supernode (),
917 : : m_stmt,
918 : 1553 : &stmt_finder);
919 : 1553 : m_eg->get_diagnostic_manager ().add_diagnostic
920 : 1553 : (&sm, ploc,
921 : : leaked_tree_for_diag, sval, state, std::move (pd));
922 : : }
923 : 2092 : }
924 : :
925 : : /* Implementation of region_model_context::on_condition vfunc.
926 : : Notify all state machines about the condition, which could lead to
927 : : state transitions. */
928 : :
929 : : void
930 : 35451 : impl_region_model_context::on_condition (const svalue *lhs,
931 : : enum tree_code op,
932 : : const svalue *rhs)
933 : : {
934 : 35451 : int sm_idx;
935 : 35451 : sm_state_map *smap;
936 : 283362 : FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
937 : : {
938 : 247911 : const state_machine &sm = m_ext_state.get_sm (sm_idx);
939 : 495822 : impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
940 : : m_old_state, m_new_state,
941 : 495822 : m_old_state->m_checker_states[sm_idx],
942 : 495822 : m_new_state->m_checker_states[sm_idx],
943 : 247911 : m_path_ctxt);
944 : 247911 : sm.on_condition (&sm_ctxt,
945 : 247911 : (m_enode_for_diag
946 : 247911 : ? m_enode_for_diag->get_supernode ()
947 : : : NULL),
948 : : m_stmt,
949 : : lhs, op, rhs);
950 : 247911 : }
951 : 35451 : }
952 : :
953 : : /* Implementation of region_model_context::on_bounded_ranges vfunc.
954 : : Notify all state machines about the ranges, which could lead to
955 : : state transitions. */
956 : :
957 : : void
958 : 7691 : impl_region_model_context::on_bounded_ranges (const svalue &sval,
959 : : const bounded_ranges &ranges)
960 : : {
961 : 7691 : int sm_idx;
962 : 7691 : sm_state_map *smap;
963 : 61528 : FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
964 : : {
965 : 53837 : const state_machine &sm = m_ext_state.get_sm (sm_idx);
966 : 107674 : impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
967 : : m_old_state, m_new_state,
968 : 107674 : m_old_state->m_checker_states[sm_idx],
969 : 107674 : m_new_state->m_checker_states[sm_idx],
970 : 53837 : m_path_ctxt);
971 : 53837 : sm.on_bounded_ranges (&sm_ctxt,
972 : 53837 : (m_enode_for_diag
973 : 53837 : ? m_enode_for_diag->get_supernode ()
974 : : : NULL),
975 : : m_stmt, sval, ranges);
976 : 53837 : }
977 : 7691 : }
978 : :
979 : : /* Implementation of region_model_context::on_pop_frame vfunc.
980 : : Notify all state machines about the frame being popped, which
981 : : could lead to states being discarded. */
982 : :
983 : : void
984 : 18925 : impl_region_model_context::on_pop_frame (const frame_region *frame_reg)
985 : : {
986 : 18925 : int sm_idx;
987 : 18925 : sm_state_map *smap;
988 : 150948 : FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
989 : : {
990 : 132023 : const state_machine &sm = m_ext_state.get_sm (sm_idx);
991 : 132023 : sm.on_pop_frame (smap, frame_reg);
992 : : }
993 : 18925 : }
994 : :
995 : : /* Implementation of region_model_context::on_phi vfunc.
996 : : Notify all state machines about the phi, which could lead to
997 : : state transitions. */
998 : :
999 : : void
1000 : 28164 : impl_region_model_context::on_phi (const gphi *phi, tree rhs)
1001 : : {
1002 : 28164 : int sm_idx;
1003 : 28164 : sm_state_map *smap;
1004 : 225312 : FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
1005 : : {
1006 : 197148 : const state_machine &sm = m_ext_state.get_sm (sm_idx);
1007 : 394296 : impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
1008 : : m_old_state, m_new_state,
1009 : 394296 : m_old_state->m_checker_states[sm_idx],
1010 : 394296 : m_new_state->m_checker_states[sm_idx],
1011 : 197148 : m_path_ctxt);
1012 : 197148 : sm.on_phi (&sm_ctxt, m_enode_for_diag->get_supernode (), phi, rhs);
1013 : 197148 : }
1014 : 28164 : }
1015 : :
1016 : : /* Implementation of region_model_context::on_unexpected_tree_code vfunc.
1017 : : Mark the new state as being invalid for further exploration.
1018 : : TODO(stage1): introduce a warning for when this occurs. */
1019 : :
1020 : : void
1021 : 54 : impl_region_model_context::on_unexpected_tree_code (tree t,
1022 : : const dump_location_t &loc)
1023 : : {
1024 : 54 : logger * const logger = get_logger ();
1025 : 54 : if (logger)
1026 : 0 : logger->log ("unhandled tree code: %qs in %qs at %s:%i",
1027 : 0 : get_tree_code_name (TREE_CODE (t)),
1028 : 0 : loc.get_impl_location ().m_function,
1029 : 0 : loc.get_impl_location ().m_file,
1030 : 0 : loc.get_impl_location ().m_line);
1031 : 54 : if (m_new_state)
1032 : 54 : m_new_state->m_valid = false;
1033 : 54 : }
1034 : :
1035 : : /* Implementation of region_model_context::maybe_did_work vfunc.
1036 : : Mark that "externally visible work" has occurred, and thus we
1037 : : shouldn't report an infinite loop here. */
1038 : :
1039 : : void
1040 : 33160 : impl_region_model_context::maybe_did_work ()
1041 : : {
1042 : 33160 : if (m_out_could_have_done_work)
1043 : 31347 : *m_out_could_have_done_work = true;
1044 : 33160 : }
1045 : :
1046 : : /* struct point_and_state. */
1047 : :
1048 : : /* Assert that this object is sane. */
1049 : :
1050 : : void
1051 : 864511 : point_and_state::validate (const extrinsic_state &ext_state) const
1052 : : {
1053 : : /* Skip this in a release build. */
1054 : : #if !CHECKING_P
1055 : : return;
1056 : : #endif
1057 : :
1058 : 864511 : m_point.validate ();
1059 : :
1060 : 864511 : m_state.validate (ext_state);
1061 : :
1062 : : /* Verify that the callstring's model of the stack corresponds to that
1063 : : of the region_model. */
1064 : : /* They should have the same depth. */
1065 : 1721461 : gcc_assert (m_point.get_stack_depth ()
1066 : : == m_state.m_region_model->get_stack_depth ());
1067 : : /* Check the functions in the callstring vs those in the frames
1068 : : at each depth. */
1069 : 1339348 : for (const frame_region *iter_frame
1070 : 864511 : = m_state.m_region_model->get_current_frame ();
1071 : 2203859 : iter_frame; iter_frame = iter_frame->get_calling_frame ())
1072 : : {
1073 : 1339348 : int index = iter_frame->get_index ();
1074 : 1339348 : gcc_assert (m_point.get_function_at_depth (index)
1075 : : == &iter_frame->get_function ());
1076 : : }
1077 : 864511 : }
1078 : :
1079 : : /* Subroutine of print_enode_indices: print a run of indices from START_IDX
1080 : : to END_IDX to PP, using and updating *FIRST_RUN. */
1081 : :
1082 : : static void
1083 : 6368 : print_run (pretty_printer *pp, int start_idx, int end_idx,
1084 : : bool *first_run)
1085 : : {
1086 : 6368 : if (!(*first_run))
1087 : 3655 : pp_string (pp, ", ");
1088 : 6368 : *first_run = false;
1089 : 6368 : if (start_idx == end_idx)
1090 : 3408 : pp_printf (pp, "EN: %i", start_idx);
1091 : : else
1092 : 2960 : pp_printf (pp, "EN: %i-%i", start_idx, end_idx);
1093 : 6368 : }
1094 : :
1095 : : /* Print the indices within ENODES to PP, collecting them as
1096 : : runs/singletons e.g. "EN: 4-7, EN: 20-23, EN: 42". */
1097 : :
1098 : : static void
1099 : 2728 : print_enode_indices (pretty_printer *pp,
1100 : : const auto_vec<exploded_node *> &enodes)
1101 : : {
1102 : 2728 : int cur_start_idx = -1;
1103 : 2728 : int cur_finish_idx = -1;
1104 : 2728 : bool first_run = true;
1105 : 2728 : unsigned i;
1106 : 2728 : exploded_node *enode;
1107 : 18910 : FOR_EACH_VEC_ELT (enodes, i, enode)
1108 : : {
1109 : 16182 : if (cur_start_idx == -1)
1110 : : {
1111 : 2713 : gcc_assert (cur_finish_idx == -1);
1112 : 2713 : cur_start_idx = cur_finish_idx = enode->m_index;
1113 : : }
1114 : : else
1115 : : {
1116 : 13469 : if (enode->m_index == cur_finish_idx + 1)
1117 : : /* Continuation of a run. */
1118 : : cur_finish_idx = enode->m_index;
1119 : : else
1120 : : {
1121 : : /* Finish existing run, start a new one. */
1122 : 3655 : gcc_assert (cur_start_idx >= 0);
1123 : 3655 : gcc_assert (cur_finish_idx >= 0);
1124 : 3655 : print_run (pp, cur_start_idx, cur_finish_idx,
1125 : : &first_run);
1126 : 3655 : cur_start_idx = cur_finish_idx = enode->m_index;
1127 : : }
1128 : : }
1129 : : }
1130 : : /* Finish any existing run. */
1131 : 2728 : if (cur_start_idx >= 0)
1132 : : {
1133 : 2713 : gcc_assert (cur_finish_idx >= 0);
1134 : 2713 : print_run (pp, cur_start_idx, cur_finish_idx,
1135 : : &first_run);
1136 : : }
1137 : 2728 : }
1138 : :
1139 : : /* struct eg_traits::dump_args_t. */
1140 : :
1141 : : /* The <FILENAME>.eg.dot output can quickly become unwieldy if we show
1142 : : full details for all enodes (both in terms of CPU time to render it,
1143 : : and in terms of being meaningful to a human viewing it).
1144 : :
1145 : : If we show just the IDs then the resulting graph is usually viewable,
1146 : : but then we have to keep switching back and forth between the .dot
1147 : : view and other dumps.
1148 : :
1149 : : This function implements a heuristic for showing detail at the enodes
1150 : : that (we hope) matter, and just the ID at other enodes, fixing the CPU
1151 : : usage of the .dot viewer, and drawing the attention of the viewer
1152 : : to these enodes.
1153 : :
1154 : : Return true if ENODE should be shown in detail in .dot output.
1155 : : Return false if no detail should be shown for ENODE. */
1156 : :
1157 : : bool
1158 : 740 : eg_traits::dump_args_t::show_enode_details_p (const exploded_node &enode) const
1159 : : {
1160 : : /* If the number of exploded nodes isn't too large, we may as well show
1161 : : all enodes in full detail in the .dot output. */
1162 : 740 : if (m_eg.m_nodes.length ()
1163 : 740 : <= (unsigned) param_analyzer_max_enodes_for_full_dump)
1164 : : return true;
1165 : :
1166 : : /* Otherwise, assume that what's most interesting are state explosions,
1167 : : and thus the places where this happened.
1168 : : Expand enodes at program points where we hit the per-enode limit, so we
1169 : : can investigate what exploded. */
1170 : 0 : const per_program_point_data *per_point_data
1171 : 0 : = m_eg.get_per_program_point_data (enode.get_point ());
1172 : 0 : return per_point_data->m_excess_enodes > 0;
1173 : : }
1174 : :
1175 : : /* class exploded_node : public dnode<eg_traits>. */
1176 : :
1177 : : const char *
1178 : 0 : exploded_node::status_to_str (enum status s)
1179 : : {
1180 : 0 : switch (s)
1181 : : {
1182 : 0 : default: gcc_unreachable ();
1183 : : case STATUS_WORKLIST: return "WORKLIST";
1184 : 0 : case STATUS_PROCESSED: return "PROCESSED";
1185 : 0 : case STATUS_MERGER: return "MERGER";
1186 : 0 : case STATUS_BULK_MERGED: return "BULK_MERGED";
1187 : : }
1188 : : }
1189 : :
1190 : : /* exploded_node's ctor. */
1191 : :
1192 : 428749 : exploded_node::exploded_node (const point_and_state &ps,
1193 : 428749 : int index)
1194 : 428749 : : m_ps (ps), m_status (STATUS_WORKLIST), m_index (index),
1195 : 428749 : m_num_processed_stmts (0)
1196 : : {
1197 : 428749 : gcc_checking_assert (ps.get_state ().m_region_model->canonicalized_p ());
1198 : 428749 : }
1199 : :
1200 : : /* Get the stmt that was processed in this enode at index IDX.
1201 : : IDX is an index within the stmts processed at this enode, rather
1202 : : than within those of the supernode. */
1203 : :
1204 : : const gimple *
1205 : 133734 : exploded_node::get_processed_stmt (unsigned idx) const
1206 : : {
1207 : 133734 : gcc_assert (idx < m_num_processed_stmts);
1208 : 133734 : const program_point &point = get_point ();
1209 : 133734 : gcc_assert (point.get_kind () == PK_BEFORE_STMT);
1210 : 133734 : const supernode *snode = get_supernode ();
1211 : 133734 : const unsigned int point_stmt_idx = point.get_stmt_idx ();
1212 : 133734 : const unsigned int idx_within_snode = point_stmt_idx + idx;
1213 : 133734 : const gimple *stmt = snode->m_stmts[idx_within_snode];
1214 : 133734 : return stmt;
1215 : : }
1216 : :
1217 : : /* For use by dump_dot, get a value for the .dot "fillcolor" attribute.
1218 : : Colorize by sm-state, to make it easier to see how sm-state propagates
1219 : : through the exploded_graph. */
1220 : :
1221 : : const char *
1222 : 1485 : exploded_node::get_dot_fillcolor () const
1223 : : {
1224 : 1485 : const program_state &state = get_state ();
1225 : :
1226 : : /* We want to be able to easily distinguish the no-sm-state case,
1227 : : and to be able to distinguish cases where there's a single state
1228 : : from each other.
1229 : :
1230 : : Sum the sm_states, and use the result to choose from a table,
1231 : : modulo table-size, special-casing the "no sm-state" case. */
1232 : 1485 : int total_sm_state = 0;
1233 : 1485 : int i;
1234 : 1485 : sm_state_map *smap;
1235 : 11880 : FOR_EACH_VEC_ELT (state.m_checker_states, i, smap)
1236 : : {
1237 : 12050 : for (sm_state_map::iterator_t iter = smap->begin ();
1238 : 12050 : iter != smap->end ();
1239 : 1655 : ++iter)
1240 : 1655 : total_sm_state += (*iter).second.m_state->get_id ();
1241 : 10395 : total_sm_state += smap->get_global_state ()->get_id ();
1242 : : }
1243 : :
1244 : 1485 : if (total_sm_state > 0)
1245 : : {
1246 : : /* An arbitrarily-picked collection of light colors. */
1247 : 990 : const char * const colors[]
1248 : : = {"azure", "coral", "cornsilk", "lightblue", "yellow",
1249 : : "honeydew", "lightpink", "lightsalmon", "palegreen1",
1250 : : "wheat", "seashell"};
1251 : 990 : const int num_colors = ARRAY_SIZE (colors);
1252 : 990 : return colors[total_sm_state % num_colors];
1253 : : }
1254 : : else
1255 : : /* No sm-state. */
1256 : : return "lightgrey";
1257 : : }
1258 : :
1259 : : /* Implementation of dnode::dump_dot vfunc for exploded_node. */
1260 : :
1261 : : void
1262 : 740 : exploded_node::dump_dot (graphviz_out *gv, const dump_args_t &args) const
1263 : : {
1264 : 740 : pretty_printer *pp = gv->get_pp ();
1265 : :
1266 : 740 : dump_dot_id (pp);
1267 : 740 : pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
1268 : : get_dot_fillcolor ());
1269 : 740 : pp_write_text_to_stream (pp);
1270 : :
1271 : 740 : pp_printf (pp, "EN: %i", m_index);
1272 : 740 : if (m_status == STATUS_MERGER)
1273 : 0 : pp_string (pp, " (merger)");
1274 : 740 : else if (m_status == STATUS_BULK_MERGED)
1275 : 50 : pp_string (pp, " (bulk merged)");
1276 : 740 : pp_newline (pp);
1277 : :
1278 : 740 : if (args.show_enode_details_p (*this))
1279 : : {
1280 : 740 : format f (true);
1281 : 740 : m_ps.get_point ().print (pp, f);
1282 : 740 : pp_newline (pp);
1283 : :
1284 : 740 : const extrinsic_state &ext_state = args.m_eg.get_ext_state ();
1285 : 740 : const program_state &state = m_ps.get_state ();
1286 : 740 : state.dump_to_pp (ext_state, false, true, pp);
1287 : 740 : pp_newline (pp);
1288 : :
1289 : 740 : dump_processed_stmts (pp);
1290 : : }
1291 : :
1292 : 740 : dump_saved_diagnostics (pp);
1293 : :
1294 : 740 : args.dump_extra_info (this, pp);
1295 : :
1296 : 740 : pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
1297 : :
1298 : 740 : pp_string (pp, "\"];\n\n");
1299 : :
1300 : : /* It can be hard to locate the saved diagnostics as text within the
1301 : : enode nodes, so add extra nodes to the graph for each saved_diagnostic,
1302 : : highlighted in red.
1303 : : Compare with dump_saved_diagnostics. */
1304 : 740 : {
1305 : 740 : unsigned i;
1306 : 740 : const saved_diagnostic *sd;
1307 : 1505 : FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
1308 : : {
1309 : 25 : sd->dump_as_dot_node (pp);
1310 : :
1311 : : /* Add edge connecting this enode to the saved_diagnostic. */
1312 : 25 : dump_dot_id (pp);
1313 : 25 : pp_string (pp, " -> ");
1314 : 25 : sd->dump_dot_id (pp);
1315 : 25 : pp_string (pp, " [style=\"dotted\" arrowhead=\"none\"];");
1316 : 25 : pp_newline (pp);
1317 : : }
1318 : : }
1319 : :
1320 : 740 : pp_flush (pp);
1321 : 740 : }
1322 : :
1323 : : /* Show any stmts that were processed within this enode,
1324 : : and their index within the supernode. */
1325 : : void
1326 : 895 : exploded_node::dump_processed_stmts (pretty_printer *pp) const
1327 : : {
1328 : 895 : if (m_num_processed_stmts > 0)
1329 : : {
1330 : 350 : const program_point &point = get_point ();
1331 : 350 : gcc_assert (point.get_kind () == PK_BEFORE_STMT);
1332 : 350 : const supernode *snode = get_supernode ();
1333 : 350 : const unsigned int point_stmt_idx = point.get_stmt_idx ();
1334 : :
1335 : 350 : pp_printf (pp, "stmts: %i", m_num_processed_stmts);
1336 : 350 : pp_newline (pp);
1337 : 1003 : for (unsigned i = 0; i < m_num_processed_stmts; i++)
1338 : : {
1339 : 653 : const unsigned int idx_within_snode = point_stmt_idx + i;
1340 : 653 : const gimple *stmt = snode->m_stmts[idx_within_snode];
1341 : 653 : pp_printf (pp, " %i: ", idx_within_snode);
1342 : 653 : pp_gimple_stmt_1 (pp, stmt, 0, (dump_flags_t)0);
1343 : 653 : pp_newline (pp);
1344 : : }
1345 : : }
1346 : 895 : }
1347 : :
1348 : : /* Dump any saved_diagnostics at this enode to PP. */
1349 : :
1350 : : void
1351 : 895 : exploded_node::dump_saved_diagnostics (pretty_printer *pp) const
1352 : : {
1353 : 895 : unsigned i;
1354 : 895 : const saved_diagnostic *sd;
1355 : 935 : FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
1356 : : {
1357 : 40 : pp_printf (pp, "DIAGNOSTIC: %s (sd: %i)",
1358 : 40 : sd->m_d->get_kind (), sd->get_index ());
1359 : 40 : pp_newline (pp);
1360 : : }
1361 : 895 : }
1362 : :
1363 : : /* Dump this to PP in a form suitable for use as an id in .dot output. */
1364 : :
1365 : : void
1366 : 2255 : exploded_node::dump_dot_id (pretty_printer *pp) const
1367 : : {
1368 : 2255 : pp_printf (pp, "exploded_node_%i", m_index);
1369 : 2255 : }
1370 : :
1371 : : /* Dump a multiline representation of this node to PP. */
1372 : :
1373 : : void
1374 : 0 : exploded_node::dump_to_pp (pretty_printer *pp,
1375 : : const extrinsic_state &ext_state) const
1376 : : {
1377 : 0 : pp_printf (pp, "EN: %i", m_index);
1378 : 0 : pp_newline (pp);
1379 : :
1380 : 0 : format f (true);
1381 : 0 : m_ps.get_point ().print (pp, f);
1382 : 0 : pp_newline (pp);
1383 : :
1384 : 0 : m_ps.get_state ().dump_to_pp (ext_state, false, true, pp);
1385 : 0 : pp_newline (pp);
1386 : 0 : }
1387 : :
1388 : : /* Dump a multiline representation of this node to FILE. */
1389 : :
1390 : : void
1391 : 0 : exploded_node::dump (FILE *fp,
1392 : : const extrinsic_state &ext_state) const
1393 : : {
1394 : 0 : pretty_printer pp;
1395 : 0 : pp_format_decoder (&pp) = default_tree_printer;
1396 : 0 : pp_show_color (&pp) = pp_show_color (global_dc->printer);
1397 : 0 : pp.buffer->stream = fp;
1398 : 0 : dump_to_pp (&pp, ext_state);
1399 : 0 : pp_flush (&pp);
1400 : 0 : }
1401 : :
1402 : : /* Dump a multiline representation of this node to stderr. */
1403 : :
1404 : : DEBUG_FUNCTION void
1405 : 0 : exploded_node::dump (const extrinsic_state &ext_state) const
1406 : : {
1407 : 0 : dump (stderr, ext_state);
1408 : 0 : }
1409 : :
1410 : : /* Return a new json::object of the form
1411 : : {"point" : object for program_point,
1412 : : "state" : object for program_state,
1413 : : "status" : str,
1414 : : "idx" : int,
1415 : : "processed_stmts" : int}. */
1416 : :
1417 : : json::object *
1418 : 0 : exploded_node::to_json (const extrinsic_state &ext_state) const
1419 : : {
1420 : 0 : json::object *enode_obj = new json::object ();
1421 : :
1422 : 0 : enode_obj->set ("point", get_point ().to_json ());
1423 : 0 : enode_obj->set ("state", get_state ().to_json (ext_state));
1424 : 0 : enode_obj->set ("status", new json::string (status_to_str (m_status)));
1425 : 0 : enode_obj->set ("idx", new json::integer_number (m_index));
1426 : 0 : enode_obj->set ("processed_stmts",
1427 : 0 : new json::integer_number (m_num_processed_stmts));
1428 : :
1429 : 0 : return enode_obj;
1430 : : }
1431 : :
1432 : : } // namespace ana
1433 : :
1434 : : /* Return true if FNDECL has a gimple body. */
1435 : : // TODO: is there a pre-canned way to do this?
1436 : :
1437 : : bool
1438 : 34346 : fndecl_has_gimple_body_p (tree fndecl)
1439 : : {
1440 : 34346 : if (fndecl == NULL_TREE)
1441 : : return false;
1442 : :
1443 : 34346 : cgraph_node *n = cgraph_node::get (fndecl);
1444 : 34346 : if (!n)
1445 : : return false;
1446 : :
1447 : 34346 : return n->has_gimple_body_p ();
1448 : : }
1449 : :
1450 : : namespace ana {
1451 : :
1452 : : /* Modify STATE in place, applying the effects of the stmt at this node's
1453 : : point. */
1454 : :
1455 : : exploded_node::on_stmt_flags
1456 : 286582 : exploded_node::on_stmt (exploded_graph &eg,
1457 : : const supernode *snode,
1458 : : const gimple *stmt,
1459 : : program_state *state,
1460 : : uncertainty_t *uncertainty,
1461 : : bool *out_could_have_done_work,
1462 : : path_context *path_ctxt)
1463 : : {
1464 : 286582 : logger *logger = eg.get_logger ();
1465 : 286582 : LOG_SCOPE (logger);
1466 : 286582 : if (logger)
1467 : : {
1468 : 96 : logger->start_log_line ();
1469 : 96 : pp_gimple_stmt_1 (logger->get_printer (), stmt, 0, (dump_flags_t)0);
1470 : 96 : logger->end_log_line ();
1471 : : }
1472 : :
1473 : : /* Update input_location in case of ICE: make it easier to track down which
1474 : : source construct we're failing to handle. */
1475 : 286582 : input_location = stmt->location;
1476 : :
1477 : 286582 : gcc_assert (state->m_region_model);
1478 : :
1479 : : /* Preserve the old state. It is used here for looking
1480 : : up old checker states, for determining state transitions, and
1481 : : also within impl_region_model_context and impl_sm_context for
1482 : : going from tree to svalue_id. */
1483 : 286582 : const program_state old_state (*state);
1484 : :
1485 : 286582 : impl_region_model_context ctxt (eg, this,
1486 : : &old_state, state, uncertainty,
1487 : : path_ctxt, stmt, nullptr,
1488 : 286582 : out_could_have_done_work);
1489 : :
1490 : : /* Handle call summaries here. */
1491 : 286582 : if (cgraph_edge *cgedge
1492 : 286582 : = supergraph_call_edge (snode->get_function (), stmt))
1493 : 8611 : if (eg.get_analysis_plan ().use_summary_p (cgedge))
1494 : : {
1495 : 1245 : function *called_fn = get_ultimate_function_for_cgraph_edge (cgedge);
1496 : 1245 : per_function_data *called_fn_data
1497 : 1245 : = eg.get_per_function_data (called_fn);
1498 : 1245 : if (called_fn_data)
1499 : : {
1500 : 1158 : gcc_assert (called_fn);
1501 : 1158 : return replay_call_summaries (eg,
1502 : : snode,
1503 : : as_a <const gcall *> (stmt),
1504 : : state,
1505 : : path_ctxt,
1506 : : *called_fn,
1507 : : *called_fn_data,
1508 : 1158 : &ctxt);
1509 : : }
1510 : : }
1511 : :
1512 : 285424 : bool unknown_side_effects = false;
1513 : 285424 : bool terminate_path = false;
1514 : :
1515 : 285424 : on_stmt_pre (eg, stmt, state, &terminate_path,
1516 : : &unknown_side_effects, &ctxt);
1517 : :
1518 : 285424 : if (terminate_path)
1519 : 74 : return on_stmt_flags::terminate_path ();
1520 : :
1521 : : int sm_idx;
1522 : : sm_state_map *smap;
1523 : 2280713 : FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
1524 : : {
1525 : 1995363 : const state_machine &sm = eg.get_ext_state ().get_sm (sm_idx);
1526 : 1995363 : const sm_state_map *old_smap
1527 : 1995363 : = old_state.m_checker_states[sm_idx];
1528 : 1995363 : sm_state_map *new_smap = state->m_checker_states[sm_idx];
1529 : 1995363 : impl_sm_context sm_ctxt (eg, sm_idx, sm, this, &old_state, state,
1530 : : old_smap, new_smap, path_ctxt, NULL,
1531 : 1995363 : unknown_side_effects);
1532 : :
1533 : : /* Allow the state_machine to handle the stmt. */
1534 : 1995363 : if (sm.on_stmt (&sm_ctxt, snode, stmt))
1535 : 29102 : unknown_side_effects = false;
1536 : 1995363 : }
1537 : :
1538 : 285350 : if (path_ctxt->terminate_path_p ())
1539 : 895 : return on_stmt_flags::terminate_path ();
1540 : :
1541 : 284455 : on_stmt_post (stmt, state, unknown_side_effects, &ctxt);
1542 : :
1543 : 284455 : return on_stmt_flags ();
1544 : 286582 : }
1545 : :
1546 : : /* Handle the pre-sm-state part of STMT, modifying STATE in-place.
1547 : : Write true to *OUT_TERMINATE_PATH if the path should be terminated.
1548 : : Write true to *OUT_UNKNOWN_SIDE_EFFECTS if the stmt has unknown
1549 : : side effects. */
1550 : :
1551 : : void
1552 : 285424 : exploded_node::on_stmt_pre (exploded_graph &eg,
1553 : : const gimple *stmt,
1554 : : program_state *state,
1555 : : bool *out_terminate_path,
1556 : : bool *out_unknown_side_effects,
1557 : : region_model_context *ctxt)
1558 : : {
1559 : : /* Handle special-case calls that require the full program_state. */
1560 : 285424 : if (const gcall *call = dyn_cast <const gcall *> (stmt))
1561 : : {
1562 : 66932 : if (is_special_named_call_p (call, "__analyzer_dump", 0))
1563 : : {
1564 : : /* Handle the builtin "__analyzer_dump" by dumping state
1565 : : to stderr. */
1566 : 0 : state->dump (eg.get_ext_state (), true);
1567 : 0 : return;
1568 : : }
1569 : 66932 : else if (is_special_named_call_p (call, "__analyzer_dump_state", 2))
1570 : : {
1571 : 411 : state->impl_call_analyzer_dump_state (call, eg.get_ext_state (),
1572 : : ctxt);
1573 : 411 : return;
1574 : : }
1575 : 66521 : else if (is_setjmp_call_p (call))
1576 : : {
1577 : 40 : state->m_region_model->on_setjmp (call, this, ctxt);
1578 : 40 : if (ctxt)
1579 : 40 : ctxt->maybe_did_work ();
1580 : 40 : return;
1581 : : }
1582 : 66481 : else if (is_longjmp_call_p (call))
1583 : : {
1584 : 74 : on_longjmp (eg, call, state, ctxt);
1585 : 74 : *out_terminate_path = true;
1586 : 74 : if (ctxt)
1587 : 74 : ctxt->maybe_did_work ();
1588 : 74 : return;
1589 : : }
1590 : : }
1591 : :
1592 : : /* Otherwise, defer to m_region_model. */
1593 : 284899 : state->m_region_model->on_stmt_pre (stmt,
1594 : : out_unknown_side_effects,
1595 : : ctxt);
1596 : : }
1597 : :
1598 : : /* Handle the post-sm-state part of STMT, modifying STATE in-place. */
1599 : :
1600 : : void
1601 : 284455 : exploded_node::on_stmt_post (const gimple *stmt,
1602 : : program_state *state,
1603 : : bool unknown_side_effects,
1604 : : region_model_context *ctxt)
1605 : : {
1606 : 284455 : if (const gcall *call = dyn_cast <const gcall *> (stmt))
1607 : 66522 : state->m_region_model->on_call_post (call, unknown_side_effects, ctxt);
1608 : 284455 : }
1609 : :
1610 : : /* A concrete call_info subclass representing a replay of a call summary. */
1611 : :
1612 : : class call_summary_edge_info : public call_info
1613 : : {
1614 : : public:
1615 : 2876 : call_summary_edge_info (const call_details &cd,
1616 : : const function &called_fn,
1617 : : call_summary *summary,
1618 : : const extrinsic_state &ext_state)
1619 : 2876 : : call_info (cd, called_fn),
1620 : 2876 : m_called_fn (called_fn),
1621 : 2876 : m_summary (summary),
1622 : 2876 : m_ext_state (ext_state)
1623 : : {}
1624 : :
1625 : 1813 : bool update_state (program_state *state,
1626 : : const exploded_edge *,
1627 : : region_model_context *ctxt) const final override
1628 : : {
1629 : : /* Update STATE based on summary_end_state. */
1630 : 1813 : call_details cd (get_call_details (state->m_region_model, ctxt));
1631 : 1813 : call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
1632 : 1813 : const program_state &summary_end_state = m_summary->get_state ();
1633 : 1813 : return state->replay_call_summary (r, summary_end_state);
1634 : 1813 : }
1635 : :
1636 : 138 : bool update_model (region_model *model,
1637 : : const exploded_edge *,
1638 : : region_model_context *ctxt) const final override
1639 : : {
1640 : : /* Update STATE based on summary_end_state. */
1641 : 138 : call_details cd (get_call_details (model, ctxt));
1642 : 138 : call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
1643 : 138 : const program_state &summary_end_state = m_summary->get_state ();
1644 : 138 : model->replay_call_summary (r, *summary_end_state.m_region_model);
1645 : 138 : return true;
1646 : 138 : }
1647 : :
1648 : 114 : label_text get_desc (bool /*can_colorize*/) const final override
1649 : : {
1650 : 114 : return m_summary->get_desc ();
1651 : : }
1652 : :
1653 : : private:
1654 : : const function &m_called_fn;
1655 : : call_summary *m_summary;
1656 : : const extrinsic_state &m_ext_state;
1657 : : };
1658 : :
1659 : : /* Use PATH_CTXT to bifurcate, which when handled will add custom edges
1660 : : for a replay of the various feasible summaries in CALLED_FN_DATA. */
1661 : :
1662 : : exploded_node::on_stmt_flags
1663 : 1158 : exploded_node::replay_call_summaries (exploded_graph &eg,
1664 : : const supernode *snode,
1665 : : const gcall *call_stmt,
1666 : : program_state *state,
1667 : : path_context *path_ctxt,
1668 : : const function &called_fn,
1669 : : per_function_data &called_fn_data,
1670 : : region_model_context *ctxt)
1671 : : {
1672 : 1158 : logger *logger = eg.get_logger ();
1673 : 1158 : LOG_SCOPE (logger);
1674 : :
1675 : : /* Each summary will call bifurcate on the PATH_CTXT. */
1676 : 6350 : for (auto summary : called_fn_data.m_summaries)
1677 : 2876 : replay_call_summary (eg, snode, call_stmt, state,
1678 : : path_ctxt, called_fn, summary, ctxt);
1679 : 1158 : path_ctxt->terminate_path ();
1680 : :
1681 : 1158 : return on_stmt_flags ();
1682 : 1158 : }
1683 : :
1684 : : /* Use PATH_CTXT to bifurcate, which when handled will add a
1685 : : custom edge for a replay of SUMMARY, if the summary's
1686 : : conditions are feasible based on the current state. */
1687 : :
1688 : : void
1689 : 2876 : exploded_node::replay_call_summary (exploded_graph &eg,
1690 : : const supernode *snode,
1691 : : const gcall *call_stmt,
1692 : : program_state *old_state,
1693 : : path_context *path_ctxt,
1694 : : const function &called_fn,
1695 : : call_summary *summary,
1696 : : region_model_context *ctxt)
1697 : : {
1698 : 2876 : logger *logger = eg.get_logger ();
1699 : 2876 : LOG_SCOPE (logger);
1700 : 2876 : gcc_assert (snode);
1701 : 2876 : gcc_assert (call_stmt);
1702 : 2876 : gcc_assert (old_state);
1703 : 2876 : gcc_assert (summary);
1704 : :
1705 : 2876 : if (logger)
1706 : 0 : logger->log ("using %s as summary for call to %qE from %qE",
1707 : 0 : summary->get_desc ().get (),
1708 : 0 : called_fn.decl,
1709 : 0 : snode->get_function ()->decl);
1710 : 2876 : const extrinsic_state &ext_state = eg.get_ext_state ();
1711 : 2876 : const program_state &summary_end_state = summary->get_state ();
1712 : 2876 : if (logger)
1713 : : {
1714 : 0 : pretty_printer *pp = logger->get_printer ();
1715 : :
1716 : 0 : logger->start_log_line ();
1717 : 0 : pp_string (pp, "callsite state: ");
1718 : 0 : old_state->dump_to_pp (ext_state, true, false, pp);
1719 : 0 : logger->end_log_line ();
1720 : :
1721 : 0 : logger->start_log_line ();
1722 : 0 : pp_string (pp, "summary end state: ");
1723 : 0 : summary_end_state.dump_to_pp (ext_state, true, false, pp);
1724 : 0 : logger->end_log_line ();
1725 : : }
1726 : :
1727 : 2876 : program_state new_state (*old_state);
1728 : :
1729 : 2876 : call_details cd (call_stmt, new_state.m_region_model, ctxt);
1730 : 2876 : call_summary_replay r (cd, called_fn, summary, ext_state);
1731 : :
1732 : 2876 : if (path_ctxt)
1733 : 2876 : path_ctxt->bifurcate (make_unique<call_summary_edge_info> (cd,
1734 : : called_fn,
1735 : : summary,
1736 : : ext_state));
1737 : 2876 : }
1738 : :
1739 : :
1740 : : /* Consider the effect of following superedge SUCC from this node.
1741 : :
1742 : : Return true if it's feasible to follow the edge, or false
1743 : : if it's infeasible.
1744 : :
1745 : : Examples: if it's the "true" branch within
1746 : : a CFG and we know the conditional is false, we know it's infeasible.
1747 : : If it's one of multiple interprocedual "return" edges, then only
1748 : : the edge back to the most recent callsite is feasible.
1749 : :
1750 : : Update NEXT_STATE accordingly (e.g. to record that a condition was
1751 : : true or false, or that the NULL-ness of a pointer has been checked,
1752 : : pushing/popping stack frames, etc).
1753 : :
1754 : : Update NEXT_POINT accordingly (updating the call string). */
1755 : :
1756 : : bool
1757 : 173742 : exploded_node::on_edge (exploded_graph &eg,
1758 : : const superedge *succ,
1759 : : program_point *next_point,
1760 : : program_state *next_state,
1761 : : uncertainty_t *uncertainty)
1762 : : {
1763 : 173742 : LOG_FUNC (eg.get_logger ());
1764 : :
1765 : 173742 : if (!next_point->on_edge (eg, succ))
1766 : : return false;
1767 : :
1768 : 148827 : if (!next_state->on_edge (eg, this, succ, uncertainty))
1769 : : return false;
1770 : :
1771 : : return true;
1772 : 173742 : }
1773 : :
1774 : : /* Verify that the stack at LONGJMP_POINT is still valid, given a call
1775 : : to "setjmp" at SETJMP_POINT - the stack frame that "setjmp" was
1776 : : called in must still be valid.
1777 : :
1778 : : Caveat: this merely checks the call_strings in the points; it doesn't
1779 : : detect the case where a frame returns and is then called again. */
1780 : :
1781 : : static bool
1782 : 89 : valid_longjmp_stack_p (const program_point &longjmp_point,
1783 : : const program_point &setjmp_point)
1784 : : {
1785 : 89 : const call_string &cs_at_longjmp = longjmp_point.get_call_string ();
1786 : 89 : const call_string &cs_at_setjmp = setjmp_point.get_call_string ();
1787 : :
1788 : 214 : if (cs_at_longjmp.length () < cs_at_setjmp.length ())
1789 : : return false;
1790 : :
1791 : : /* Check that the call strings match, up to the depth of the
1792 : : setjmp point. */
1793 : 191 : for (unsigned depth = 0; depth < cs_at_setjmp.length (); depth++)
1794 : 42 : if (cs_at_longjmp[depth] != cs_at_setjmp[depth])
1795 : : return false;
1796 : :
1797 : : return true;
1798 : : }
1799 : :
1800 : : /* A pending_diagnostic subclass for complaining about bad longjmps,
1801 : : where the enclosing function of the "setjmp" has returned (and thus
1802 : : the stack frame no longer exists). */
1803 : :
1804 : : class stale_jmp_buf : public pending_diagnostic_subclass<stale_jmp_buf>
1805 : : {
1806 : : public:
1807 : 6 : stale_jmp_buf (const gcall *setjmp_call, const gcall *longjmp_call,
1808 : : const program_point &setjmp_point)
1809 : 6 : : m_setjmp_call (setjmp_call), m_longjmp_call (longjmp_call),
1810 : 6 : m_setjmp_point (setjmp_point), m_stack_pop_event (NULL)
1811 : : {}
1812 : :
1813 : 12 : int get_controlling_option () const final override
1814 : : {
1815 : 12 : return OPT_Wanalyzer_stale_setjmp_buffer;
1816 : : }
1817 : :
1818 : 6 : bool emit (diagnostic_emission_context &ctxt) final override
1819 : : {
1820 : 6 : return ctxt.warn ("%qs called after enclosing function of %qs has returned",
1821 : : get_user_facing_name (m_longjmp_call),
1822 : 6 : get_user_facing_name (m_setjmp_call));
1823 : : }
1824 : :
1825 : 24 : const char *get_kind () const final override
1826 : 24 : { return "stale_jmp_buf"; }
1827 : :
1828 : 6 : bool operator== (const stale_jmp_buf &other) const
1829 : : {
1830 : 6 : return (m_setjmp_call == other.m_setjmp_call
1831 : 6 : && m_longjmp_call == other.m_longjmp_call);
1832 : : }
1833 : :
1834 : : bool
1835 : 36 : maybe_add_custom_events_for_superedge (const exploded_edge &eedge,
1836 : : checker_path *emission_path)
1837 : : final override
1838 : : {
1839 : : /* Detect exactly when the stack first becomes invalid,
1840 : : and issue an event then. */
1841 : 36 : if (m_stack_pop_event)
1842 : : return false;
1843 : 36 : const exploded_node *src_node = eedge.m_src;
1844 : 36 : const program_point &src_point = src_node->get_point ();
1845 : 36 : const exploded_node *dst_node = eedge.m_dest;
1846 : 36 : const program_point &dst_point = dst_node->get_point ();
1847 : 36 : if (valid_longjmp_stack_p (src_point, m_setjmp_point)
1848 : 36 : && !valid_longjmp_stack_p (dst_point, m_setjmp_point))
1849 : : {
1850 : : /* Compare with diagnostic_manager::add_events_for_superedge. */
1851 : 6 : const int src_stack_depth = src_point.get_stack_depth ();
1852 : 12 : m_stack_pop_event = new precanned_custom_event
1853 : 6 : (event_loc_info (src_point.get_location (),
1854 : : src_point.get_fndecl (),
1855 : : src_stack_depth),
1856 : 12 : "stack frame is popped here, invalidating saved environment");
1857 : 6 : emission_path->add_event
1858 : 6 : (std::unique_ptr<custom_event> (m_stack_pop_event));
1859 : 6 : return false;
1860 : : }
1861 : : return false;
1862 : : }
1863 : :
1864 : 12 : label_text describe_final_event (const evdesc::final_event &ev) final override
1865 : : {
1866 : 12 : if (m_stack_pop_event)
1867 : 12 : return ev.formatted_print
1868 : : ("%qs called after enclosing function of %qs returned at %@",
1869 : : get_user_facing_name (m_longjmp_call),
1870 : : get_user_facing_name (m_setjmp_call),
1871 : 12 : m_stack_pop_event->get_id_ptr ());
1872 : : else
1873 : 0 : return ev.formatted_print
1874 : : ("%qs called after enclosing function of %qs has returned",
1875 : : get_user_facing_name (m_longjmp_call),
1876 : 0 : get_user_facing_name (m_setjmp_call));;
1877 : : }
1878 : :
1879 : :
1880 : : private:
1881 : : const gcall *m_setjmp_call;
1882 : : const gcall *m_longjmp_call;
1883 : : program_point m_setjmp_point;
1884 : : custom_event *m_stack_pop_event;
1885 : : };
1886 : :
1887 : : /* Handle LONGJMP_CALL, a call to longjmp or siglongjmp.
1888 : :
1889 : : Attempt to locate where setjmp/sigsetjmp was called on the jmp_buf and build
1890 : : an exploded_node and exploded_edge to it representing a rewind to that frame,
1891 : : handling the various kinds of failure that can occur. */
1892 : :
1893 : : void
1894 : 74 : exploded_node::on_longjmp (exploded_graph &eg,
1895 : : const gcall *longjmp_call,
1896 : : program_state *new_state,
1897 : : region_model_context *ctxt)
1898 : : {
1899 : 74 : tree buf_ptr = gimple_call_arg (longjmp_call, 0);
1900 : 74 : gcc_assert (POINTER_TYPE_P (TREE_TYPE (buf_ptr)));
1901 : :
1902 : 74 : region_model *new_region_model = new_state->m_region_model;
1903 : 74 : const svalue *buf_ptr_sval = new_region_model->get_rvalue (buf_ptr, ctxt);
1904 : 74 : const region *buf = new_region_model->deref_rvalue (buf_ptr_sval, buf_ptr,
1905 : : ctxt);
1906 : :
1907 : 74 : const svalue *buf_content_sval
1908 : 74 : = new_region_model->get_store_value (buf, ctxt);
1909 : 74 : const setjmp_svalue *setjmp_sval
1910 : 74 : = buf_content_sval->dyn_cast_setjmp_svalue ();
1911 : 74 : if (!setjmp_sval)
1912 : 51 : return;
1913 : :
1914 : 29 : const setjmp_record tmp_setjmp_record = setjmp_sval->get_setjmp_record ();
1915 : :
1916 : : /* Build a custom enode and eedge for rewinding from the longjmp/siglongjmp
1917 : : call back to the setjmp/sigsetjmp. */
1918 : 29 : rewind_info_t rewind_info (tmp_setjmp_record, longjmp_call);
1919 : :
1920 : 29 : const gcall *setjmp_call = rewind_info.get_setjmp_call ();
1921 : 29 : const program_point &setjmp_point = rewind_info.get_setjmp_point ();
1922 : :
1923 : 29 : const program_point &longjmp_point = get_point ();
1924 : :
1925 : : /* Verify that the setjmp's call_stack hasn't been popped. */
1926 : 29 : if (!valid_longjmp_stack_p (longjmp_point, setjmp_point))
1927 : : {
1928 : 6 : ctxt->warn (make_unique<stale_jmp_buf> (setjmp_call,
1929 : : longjmp_call,
1930 : : setjmp_point));
1931 : 6 : return;
1932 : : }
1933 : :
1934 : 69 : gcc_assert (longjmp_point.get_stack_depth ()
1935 : : >= setjmp_point.get_stack_depth ());
1936 : :
1937 : : /* Update the state for use by the destination node. */
1938 : :
1939 : : /* Stash the current number of diagnostics so that we can update
1940 : : any that this adds to show where the longjmp is rewinding to. */
1941 : :
1942 : 23 : diagnostic_manager *dm = &eg.get_diagnostic_manager ();
1943 : 23 : unsigned prev_num_diagnostics = dm->get_num_diagnostics ();
1944 : :
1945 : 46 : new_region_model->on_longjmp (longjmp_call, setjmp_call,
1946 : : setjmp_point.get_stack_depth (), ctxt);
1947 : :
1948 : : /* Detect leaks in the new state relative to the old state. */
1949 : 23 : program_state::detect_leaks (get_state (), *new_state, NULL,
1950 : : eg.get_ext_state (), ctxt);
1951 : :
1952 : 23 : program_point next_point
1953 : 23 : = program_point::after_supernode (setjmp_point.get_supernode (),
1954 : : setjmp_point.get_call_string ());
1955 : :
1956 : 23 : exploded_node *next
1957 : 23 : = eg.get_or_create_node (next_point, *new_state, this);
1958 : :
1959 : : /* Create custom exploded_edge for a longjmp. */
1960 : 23 : if (next)
1961 : : {
1962 : 23 : exploded_edge *eedge
1963 : 23 : = eg.add_edge (const_cast<exploded_node *> (this), next, NULL, true,
1964 : 46 : make_unique<rewind_info_t> (tmp_setjmp_record,
1965 : : longjmp_call));
1966 : :
1967 : : /* For any diagnostics that were queued here (such as leaks) we want
1968 : : the checker_path to show the rewinding events after the "final event"
1969 : : so that the user sees where the longjmp is rewinding to (otherwise the
1970 : : path is meaningless).
1971 : :
1972 : : For example, we want to emit something like:
1973 : : | NN | {
1974 : : | NN | longjmp (env, 1);
1975 : : | | ~~~~~~~~~~~~~~~~
1976 : : | | |
1977 : : | | (10) 'ptr' leaks here; was allocated at (7)
1978 : : | | (11) rewinding from 'longjmp' in 'inner'...
1979 : : |
1980 : : <-------------+
1981 : : |
1982 : : 'outer': event 12
1983 : : |
1984 : : | NN | i = setjmp(env);
1985 : : | | ^~~~~~
1986 : : | | |
1987 : : | | (12) ...to 'setjmp' in 'outer' (saved at (2))
1988 : :
1989 : : where the "final" event above is event (10), but we want to append
1990 : : events (11) and (12) afterwards.
1991 : :
1992 : : Do this by setting m_trailing_eedge on any diagnostics that were
1993 : : just saved. */
1994 : 23 : unsigned num_diagnostics = dm->get_num_diagnostics ();
1995 : 31 : for (unsigned i = prev_num_diagnostics; i < num_diagnostics; i++)
1996 : : {
1997 : 8 : saved_diagnostic *sd = dm->get_saved_diagnostic (i);
1998 : 8 : sd->m_trailing_eedge = eedge;
1999 : : }
2000 : : }
2001 : 29 : }
2002 : :
2003 : : /* Subroutine of exploded_graph::process_node for finding the successors
2004 : : of the supernode for a function exit basic block.
2005 : :
2006 : : Ensure that pop_frame is called, potentially queuing diagnostics about
2007 : : leaks. */
2008 : :
2009 : : void
2010 : 18904 : exploded_node::detect_leaks (exploded_graph &eg)
2011 : : {
2012 : 18904 : LOG_FUNC_1 (eg.get_logger (), "EN: %i", m_index);
2013 : :
2014 : 18904 : gcc_assert (get_point ().get_supernode ()->return_p ());
2015 : :
2016 : : /* If we're not a "top-level" function, do nothing; pop_frame
2017 : : will be called when handling the return superedge. */
2018 : 37808 : if (get_point ().get_stack_depth () > 1)
2019 : 6294 : return;
2020 : :
2021 : : /* We have a "top-level" function. */
2022 : 12610 : gcc_assert (get_point ().get_stack_depth () == 1);
2023 : :
2024 : 12610 : const program_state &old_state = get_state ();
2025 : :
2026 : : /* Work with a temporary copy of the state: pop the frame, and see
2027 : : what leaks (via purge_unused_svalues). */
2028 : 12610 : program_state new_state (old_state);
2029 : :
2030 : 12610 : gcc_assert (new_state.m_region_model);
2031 : :
2032 : 12610 : uncertainty_t uncertainty;
2033 : 12610 : impl_region_model_context ctxt (eg, this,
2034 : : &old_state, &new_state, &uncertainty, NULL,
2035 : 12610 : get_stmt ());
2036 : 12610 : const svalue *result = NULL;
2037 : 12610 : new_state.m_region_model->pop_frame (NULL, &result, &ctxt);
2038 : 12610 : program_state::detect_leaks (old_state, new_state, result,
2039 : : eg.get_ext_state (), &ctxt);
2040 : 31514 : }
2041 : :
2042 : : /* Dump the successors and predecessors of this enode to OUTF. */
2043 : :
2044 : : void
2045 : 0 : exploded_node::dump_succs_and_preds (FILE *outf) const
2046 : : {
2047 : 0 : unsigned i;
2048 : 0 : exploded_edge *e;
2049 : 0 : {
2050 : 0 : auto_vec<exploded_node *> preds (m_preds.length ());
2051 : 0 : FOR_EACH_VEC_ELT (m_preds, i, e)
2052 : 0 : preds.quick_push (e->m_src);
2053 : 0 : pretty_printer pp;
2054 : 0 : print_enode_indices (&pp, preds);
2055 : 0 : fprintf (outf, "preds: %s\n",
2056 : : pp_formatted_text (&pp));
2057 : 0 : }
2058 : 0 : {
2059 : 0 : auto_vec<exploded_node *> succs (m_succs.length ());
2060 : 0 : FOR_EACH_VEC_ELT (m_succs, i, e)
2061 : 0 : succs.quick_push (e->m_dest);
2062 : 0 : pretty_printer pp;
2063 : 0 : print_enode_indices (&pp, succs);
2064 : 0 : fprintf (outf, "succs: %s\n",
2065 : : pp_formatted_text (&pp));
2066 : 0 : }
2067 : 0 : }
2068 : :
2069 : : /* class dynamic_call_info_t : public custom_edge_info. */
2070 : :
2071 : : /* Implementation of custom_edge_info::update_model vfunc
2072 : : for dynamic_call_info_t.
2073 : :
2074 : : Update state for a dynamically discovered call (or return), by pushing
2075 : : or popping the a frame for the appropriate function. */
2076 : :
2077 : : bool
2078 : 350 : dynamic_call_info_t::update_model (region_model *model,
2079 : : const exploded_edge *eedge,
2080 : : region_model_context *ctxt) const
2081 : : {
2082 : 350 : gcc_assert (eedge);
2083 : 350 : if (m_is_returning_call)
2084 : 161 : model->update_for_return_gcall (m_dynamic_call, ctxt);
2085 : : else
2086 : : {
2087 : 189 : function *callee = eedge->m_dest->get_function ();
2088 : 189 : model->update_for_gcall (m_dynamic_call, ctxt, callee);
2089 : : }
2090 : 350 : return true;
2091 : : }
2092 : :
2093 : : /* Implementation of custom_edge_info::add_events_to_path vfunc
2094 : : for dynamic_call_info_t. */
2095 : :
2096 : : void
2097 : 65 : dynamic_call_info_t::add_events_to_path (checker_path *emission_path,
2098 : : const exploded_edge &eedge) const
2099 : : {
2100 : 65 : const exploded_node *src_node = eedge.m_src;
2101 : 65 : const program_point &src_point = src_node->get_point ();
2102 : 65 : const int src_stack_depth = src_point.get_stack_depth ();
2103 : 65 : const exploded_node *dest_node = eedge.m_dest;
2104 : 65 : const program_point &dest_point = dest_node->get_point ();
2105 : 65 : const int dest_stack_depth = dest_point.get_stack_depth ();
2106 : :
2107 : 65 : if (m_is_returning_call)
2108 : 23 : emission_path->add_event
2109 : 23 : (make_unique<return_event> (eedge,
2110 : 46 : event_loc_info (m_dynamic_call
2111 : : ? m_dynamic_call->location
2112 : : : UNKNOWN_LOCATION,
2113 : : dest_point.get_fndecl (),
2114 : : dest_stack_depth)));
2115 : : else
2116 : 42 : emission_path->add_event
2117 : 42 : (make_unique<call_event> (eedge,
2118 : 84 : event_loc_info (m_dynamic_call
2119 : : ? m_dynamic_call->location
2120 : : : UNKNOWN_LOCATION,
2121 : : src_point.get_fndecl (),
2122 : : src_stack_depth)));
2123 : 65 : }
2124 : :
2125 : : /* class rewind_info_t : public custom_edge_info. */
2126 : :
2127 : : /* Implementation of custom_edge_info::update_model vfunc
2128 : : for rewind_info_t.
2129 : :
2130 : : Update state for the special-case of a rewind of a longjmp
2131 : : to a setjmp (which doesn't have a superedge, but does affect
2132 : : state). */
2133 : :
2134 : : bool
2135 : 13 : rewind_info_t::update_model (region_model *model,
2136 : : const exploded_edge *eedge,
2137 : : region_model_context *) const
2138 : : {
2139 : 13 : gcc_assert (eedge);
2140 : 13 : const program_point &longjmp_point = eedge->m_src->get_point ();
2141 : 13 : const program_point &setjmp_point = eedge->m_dest->get_point ();
2142 : :
2143 : 39 : gcc_assert (longjmp_point.get_stack_depth ()
2144 : : >= setjmp_point.get_stack_depth ());
2145 : :
2146 : 26 : model->on_longjmp (get_longjmp_call (),
2147 : : get_setjmp_call (),
2148 : : setjmp_point.get_stack_depth (), NULL);
2149 : 13 : return true;
2150 : : }
2151 : :
2152 : : /* Implementation of custom_edge_info::add_events_to_path vfunc
2153 : : for rewind_info_t. */
2154 : :
2155 : : void
2156 : 17 : rewind_info_t::add_events_to_path (checker_path *emission_path,
2157 : : const exploded_edge &eedge) const
2158 : : {
2159 : 17 : const exploded_node *src_node = eedge.m_src;
2160 : 17 : const program_point &src_point = src_node->get_point ();
2161 : 17 : const int src_stack_depth = src_point.get_stack_depth ();
2162 : 17 : const exploded_node *dst_node = eedge.m_dest;
2163 : 17 : const program_point &dst_point = dst_node->get_point ();
2164 : 17 : const int dst_stack_depth = dst_point.get_stack_depth ();
2165 : :
2166 : 17 : emission_path->add_event
2167 : 17 : (make_unique<rewind_from_longjmp_event>
2168 : 34 : (&eedge,
2169 : 17 : event_loc_info (get_longjmp_call ()->location,
2170 : : src_point.get_fndecl (),
2171 : : src_stack_depth),
2172 : 17 : this));
2173 : 17 : emission_path->add_event
2174 : 17 : (make_unique<rewind_to_setjmp_event>
2175 : 34 : (&eedge,
2176 : 17 : event_loc_info (get_setjmp_call ()->location,
2177 : : dst_point.get_fndecl (),
2178 : : dst_stack_depth),
2179 : 17 : this));
2180 : 17 : }
2181 : :
2182 : : /* class exploded_edge : public dedge<eg_traits>. */
2183 : :
2184 : : /* exploded_edge's ctor. */
2185 : :
2186 : 446631 : exploded_edge::exploded_edge (exploded_node *src, exploded_node *dest,
2187 : : const superedge *sedge, bool could_do_work,
2188 : 446631 : std::unique_ptr<custom_edge_info> custom_info)
2189 : 446631 : : dedge<eg_traits> (src, dest), m_sedge (sedge),
2190 : 446631 : m_custom_info (std::move (custom_info)),
2191 : 446631 : m_could_do_work_p (could_do_work)
2192 : : {
2193 : 446631 : }
2194 : :
2195 : : /* Implementation of dedge::dump_dot vfunc for exploded_edge.
2196 : : Use the label of the underlying superedge, if any. */
2197 : :
2198 : : void
2199 : 745 : exploded_edge::dump_dot (graphviz_out *gv, const dump_args_t &) const
2200 : : {
2201 : 745 : pretty_printer *pp = gv->get_pp ();
2202 : :
2203 : 745 : m_src->dump_dot_id (pp);
2204 : 745 : pp_string (pp, " -> ");
2205 : 745 : m_dest->dump_dot_id (pp);
2206 : 745 : dump_dot_label (pp);
2207 : 745 : }
2208 : :
2209 : : /* Second half of exploded_edge::dump_dot. This is split out
2210 : : for use by trimmed_graph::dump_dot and base_feasible_edge::dump_dot. */
2211 : :
2212 : : void
2213 : 890 : exploded_edge::dump_dot_label (pretty_printer *pp) const
2214 : : {
2215 : 890 : const char *style = "\"solid,bold\"";
2216 : 890 : const char *color = "black";
2217 : 890 : int weight = 10;
2218 : 890 : const char *constraint = "true";
2219 : :
2220 : 890 : if (m_sedge)
2221 : 245 : switch (m_sedge->m_kind)
2222 : : {
2223 : 0 : default:
2224 : 0 : gcc_unreachable ();
2225 : : case SUPEREDGE_CFG_EDGE:
2226 : : break;
2227 : 10 : case SUPEREDGE_CALL:
2228 : 10 : color = "red";
2229 : : //constraint = "false";
2230 : 10 : break;
2231 : 10 : case SUPEREDGE_RETURN:
2232 : 10 : color = "green";
2233 : : //constraint = "false";
2234 : 10 : break;
2235 : 0 : case SUPEREDGE_INTRAPROCEDURAL_CALL:
2236 : 0 : style = "\"dotted\"";
2237 : 0 : break;
2238 : : }
2239 : 890 : if (m_custom_info)
2240 : : {
2241 : 0 : color = "red";
2242 : 0 : style = "\"dotted\"";
2243 : : }
2244 : :
2245 : 890 : pp_printf (pp,
2246 : : (" [style=%s, color=%s, weight=%d, constraint=%s,"
2247 : : " headlabel=\""),
2248 : : style, color, weight, constraint);
2249 : :
2250 : 890 : if (m_sedge)
2251 : 245 : m_sedge->dump_label_to_pp (pp, false);
2252 : 645 : else if (m_custom_info)
2253 : 0 : m_custom_info->print (pp);
2254 : :
2255 : 1725 : pp_printf (pp, "%s",
2256 : 890 : could_do_work_p () ? "(could do work)" : "DOES NO WORK");
2257 : :
2258 : : //pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
2259 : :
2260 : 890 : pp_printf (pp, "\"];\n");
2261 : 890 : }
2262 : :
2263 : : /* Return a new json::object of the form
2264 : : {"src_idx": int, the index of the source exploded edge,
2265 : : "dst_idx": int, the index of the destination exploded edge,
2266 : : "sedge": (optional) object for the superedge, if any,
2267 : : "custom": (optional) str, a description, if this is a custom edge}. */
2268 : :
2269 : : json::object *
2270 : 0 : exploded_edge::to_json () const
2271 : : {
2272 : 0 : json::object *eedge_obj = new json::object ();
2273 : 0 : eedge_obj->set ("src_idx", new json::integer_number (m_src->m_index));
2274 : 0 : eedge_obj->set ("dst_idx", new json::integer_number (m_dest->m_index));
2275 : 0 : if (m_sedge)
2276 : 0 : eedge_obj->set ("sedge", m_sedge->to_json ());
2277 : 0 : if (m_custom_info)
2278 : : {
2279 : 0 : pretty_printer pp;
2280 : 0 : pp_format_decoder (&pp) = default_tree_printer;
2281 : 0 : m_custom_info->print (&pp);
2282 : 0 : eedge_obj->set ("custom", new json::string (pp_formatted_text (&pp)));
2283 : 0 : }
2284 : 0 : return eedge_obj;
2285 : : }
2286 : :
2287 : : /* struct stats. */
2288 : :
2289 : : /* stats' ctor. */
2290 : :
2291 : 28014 : stats::stats (int num_supernodes)
2292 : 28014 : : m_node_reuse_count (0),
2293 : 28014 : m_node_reuse_after_merge_count (0),
2294 : 28014 : m_num_supernodes (num_supernodes)
2295 : : {
2296 : 196098 : for (int i = 0; i < NUM_POINT_KINDS; i++)
2297 : 168084 : m_num_nodes[i] = 0;
2298 : 28014 : }
2299 : :
2300 : : /* Log these stats in multiline form to LOGGER. */
2301 : :
2302 : : void
2303 : 4 : stats::log (logger *logger) const
2304 : : {
2305 : 4 : gcc_assert (logger);
2306 : 28 : for (int i = 0; i < NUM_POINT_KINDS; i++)
2307 : 24 : if (m_num_nodes[i] > 0)
2308 : 14 : logger->log ("m_num_nodes[%s]: %i",
2309 : : point_kind_to_string (static_cast <enum point_kind> (i)),
2310 : : m_num_nodes[i]);
2311 : 4 : logger->log ("m_node_reuse_count: %i", m_node_reuse_count);
2312 : 4 : logger->log ("m_node_reuse_after_merge_count: %i",
2313 : 4 : m_node_reuse_after_merge_count);
2314 : 4 : }
2315 : :
2316 : : /* Dump these stats in multiline form to OUT. */
2317 : :
2318 : : void
2319 : 0 : stats::dump (FILE *out) const
2320 : : {
2321 : 0 : for (int i = 0; i < NUM_POINT_KINDS; i++)
2322 : 0 : if (m_num_nodes[i] > 0)
2323 : 0 : fprintf (out, "m_num_nodes[%s]: %i\n",
2324 : : point_kind_to_string (static_cast <enum point_kind> (i)),
2325 : : m_num_nodes[i]);
2326 : 0 : fprintf (out, "m_node_reuse_count: %i\n", m_node_reuse_count);
2327 : 0 : fprintf (out, "m_node_reuse_after_merge_count: %i\n",
2328 : 0 : m_node_reuse_after_merge_count);
2329 : :
2330 : 0 : if (m_num_supernodes > 0)
2331 : 0 : fprintf (out, "PK_AFTER_SUPERNODE nodes per supernode: %.2f\n",
2332 : 0 : (float)m_num_nodes[PK_AFTER_SUPERNODE] / (float)m_num_supernodes);
2333 : 0 : }
2334 : :
2335 : : /* Return the total number of enodes recorded within this object. */
2336 : :
2337 : : int
2338 : 2 : stats::get_total_enodes () const
2339 : : {
2340 : 2 : int result = 0;
2341 : 14 : for (int i = 0; i < NUM_POINT_KINDS; i++)
2342 : 12 : result += m_num_nodes[i];
2343 : 2 : return result;
2344 : : }
2345 : :
2346 : : /* struct per_function_data. */
2347 : :
2348 : 9414 : per_function_data::~per_function_data ()
2349 : : {
2350 : 39861 : for (auto iter : m_summaries)
2351 : 11619 : delete iter;
2352 : 9414 : }
2353 : :
2354 : : void
2355 : 11619 : per_function_data::add_call_summary (exploded_node *node)
2356 : : {
2357 : 11619 : m_summaries.safe_push (new call_summary (this, node));
2358 : 11619 : }
2359 : :
2360 : : /* strongly_connected_components's ctor. Tarjan's SCC algorithm. */
2361 : :
2362 : 3783 : strongly_connected_components::
2363 : 3783 : strongly_connected_components (const supergraph &sg, logger *logger)
2364 : 7561 : : m_sg (sg), m_per_node (m_sg.num_nodes ())
2365 : : {
2366 : 3783 : LOG_SCOPE (logger);
2367 : 3783 : auto_timevar tv (TV_ANALYZER_SCC);
2368 : :
2369 : 149277 : for (int i = 0; i < m_sg.num_nodes (); i++)
2370 : 70858 : m_per_node.quick_push (per_node_data ());
2371 : :
2372 : 149277 : for (int i = 0; i < m_sg.num_nodes (); i++)
2373 : 70858 : if (m_per_node[i].m_index == -1)
2374 : 11683 : strong_connect (i);
2375 : :
2376 : 3783 : if (0)
2377 : : dump ();
2378 : 3783 : }
2379 : :
2380 : : /* Dump this object to stderr. */
2381 : :
2382 : : DEBUG_FUNCTION void
2383 : 0 : strongly_connected_components::dump () const
2384 : : {
2385 : 0 : for (int i = 0; i < m_sg.num_nodes (); i++)
2386 : : {
2387 : 0 : const per_node_data &v = m_per_node[i];
2388 : 0 : fprintf (stderr, "SN %i: index: %i lowlink: %i on_stack: %i\n",
2389 : 0 : i, v.m_index, v.m_lowlink, v.m_on_stack);
2390 : : }
2391 : 0 : }
2392 : :
2393 : : /* Return a new json::array of per-snode SCC ids. */
2394 : :
2395 : : json::array *
2396 : 0 : strongly_connected_components::to_json () const
2397 : : {
2398 : 0 : json::array *scc_arr = new json::array ();
2399 : 0 : for (int i = 0; i < m_sg.num_nodes (); i++)
2400 : 0 : scc_arr->append (new json::integer_number (get_scc_id (i)));
2401 : 0 : return scc_arr;
2402 : : }
2403 : :
2404 : : /* Subroutine of strongly_connected_components's ctor, part of Tarjan's
2405 : : SCC algorithm. */
2406 : :
2407 : : void
2408 : 70858 : strongly_connected_components::strong_connect (unsigned index)
2409 : : {
2410 : 70858 : supernode *v_snode = m_sg.get_node_by_index (index);
2411 : :
2412 : : /* Set the depth index for v to the smallest unused index. */
2413 : 70858 : per_node_data *v = &m_per_node[index];
2414 : 70858 : v->m_index = index;
2415 : 70858 : v->m_lowlink = index;
2416 : 70858 : m_stack.safe_push (index);
2417 : 70858 : v->m_on_stack = true;
2418 : 70858 : index++;
2419 : :
2420 : : /* Consider successors of v. */
2421 : 70858 : unsigned i;
2422 : 70858 : superedge *sedge;
2423 : 151468 : FOR_EACH_VEC_ELT (v_snode->m_succs, i, sedge)
2424 : : {
2425 : 80610 : if (sedge->get_kind () != SUPEREDGE_CFG_EDGE
2426 : 80610 : && sedge->get_kind () != SUPEREDGE_INTRAPROCEDURAL_CALL)
2427 : 7922 : continue;
2428 : 72688 : supernode *w_snode = sedge->m_dest;
2429 : 72688 : per_node_data *w = &m_per_node[w_snode->m_index];
2430 : 72688 : if (w->m_index == -1)
2431 : : {
2432 : : /* Successor w has not yet been visited; recurse on it. */
2433 : 59175 : strong_connect (w_snode->m_index);
2434 : 59175 : v->m_lowlink = MIN (v->m_lowlink, w->m_lowlink);
2435 : : }
2436 : 13513 : else if (w->m_on_stack)
2437 : : {
2438 : : /* Successor w is in stack S and hence in the current SCC
2439 : : If w is not on stack, then (v, w) is a cross-edge in the DFS
2440 : : tree and must be ignored. */
2441 : 2224 : v->m_lowlink = MIN (v->m_lowlink, w->m_index);
2442 : : }
2443 : : }
2444 : :
2445 : : /* If v is a root node, pop the stack and generate an SCC. */
2446 : :
2447 : 70858 : if (v->m_lowlink == v->m_index)
2448 : : {
2449 : 70858 : per_node_data *w;
2450 : 70858 : do {
2451 : 70858 : int idx = m_stack.pop ();
2452 : 70858 : w = &m_per_node[idx];
2453 : 70858 : w->m_on_stack = false;
2454 : 70858 : } while (w != v);
2455 : : }
2456 : 70858 : }
2457 : :
2458 : : /* worklist's ctor. */
2459 : :
2460 : 3783 : worklist::worklist (const exploded_graph &eg, const analysis_plan &plan)
2461 : 3783 : : m_scc (eg.get_supergraph (), eg.get_logger ()),
2462 : 3783 : m_plan (plan),
2463 : 3783 : m_queue (key_t (*this, NULL))
2464 : : {
2465 : 3783 : }
2466 : :
2467 : : /* Return the number of nodes in the worklist. */
2468 : :
2469 : : unsigned
2470 : 396189 : worklist::length () const
2471 : : {
2472 : 396189 : return m_queue.nodes ();
2473 : : }
2474 : :
2475 : : /* Return the next node in the worklist, removing it. */
2476 : :
2477 : : exploded_node *
2478 : 427773 : worklist::take_next ()
2479 : : {
2480 : 427773 : return m_queue.extract_min ();
2481 : : }
2482 : :
2483 : : /* Return the next node in the worklist without removing it. */
2484 : :
2485 : : exploded_node *
2486 : 521247 : worklist::peek_next ()
2487 : : {
2488 : 521247 : return m_queue.min ();
2489 : : }
2490 : :
2491 : : /* Add ENODE to the worklist. */
2492 : :
2493 : : void
2494 : 428749 : worklist::add_node (exploded_node *enode)
2495 : : {
2496 : 428749 : gcc_assert (enode->get_status () == exploded_node::STATUS_WORKLIST);
2497 : 428749 : m_queue.insert (key_t (*this, enode), enode);
2498 : 428749 : }
2499 : :
2500 : : /* Comparator for implementing worklist::key_t comparison operators.
2501 : : Return negative if KA is before KB
2502 : : Return positive if KA is after KB
2503 : : Return 0 if they are equal.
2504 : :
2505 : : The ordering of the worklist is critical for performance and for
2506 : : avoiding node explosions. Ideally we want all enodes at a CFG join-point
2507 : : with the same callstring to be sorted next to each other in the worklist
2508 : : so that a run of consecutive enodes can be merged and processed "in bulk"
2509 : : rather than individually or pairwise, minimizing the number of new enodes
2510 : : created. */
2511 : :
2512 : : int
2513 : 1605337 : worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb)
2514 : : {
2515 : 1605337 : const program_point &point_a = ka.m_enode->get_point ();
2516 : 1605337 : const program_point &point_b = kb.m_enode->get_point ();
2517 : 1605337 : const call_string &call_string_a = point_a.get_call_string ();
2518 : 1605337 : const call_string &call_string_b = point_b.get_call_string ();
2519 : :
2520 : : /* Order empty-callstring points with different functions based on the
2521 : : analysis_plan, so that we generate summaries before they are used. */
2522 : 1605337 : if (flag_analyzer_call_summaries
2523 : 1022466 : && call_string_a.empty_p ()
2524 : 958559 : && call_string_b.empty_p ()
2525 : 958559 : && point_a.get_function () != NULL
2526 : 958559 : && point_b.get_function () != NULL
2527 : 2553289 : && point_a.get_function () != point_b.get_function ())
2528 : : {
2529 : 359218 : if (int cmp = ka.m_worklist.m_plan.cmp_function (point_a.get_function (),
2530 : : point_b.get_function ()))
2531 : : return cmp;
2532 : : }
2533 : :
2534 : : /* Sort by callstring, so that nodes with deeper call strings are processed
2535 : : before those with shallower call strings.
2536 : : If we have
2537 : : splitting BB
2538 : : / \
2539 : : / \
2540 : : fn call no fn call
2541 : : \ /
2542 : : \ /
2543 : : join BB
2544 : : then we want the path inside the function call to be fully explored up
2545 : : to the return to the join BB before we explore on the "no fn call" path,
2546 : : so that both enodes at the join BB reach the front of the worklist at
2547 : : the same time and thus have a chance of being merged. */
2548 : 1246119 : int cs_cmp = call_string::cmp (call_string_a, call_string_b);
2549 : 1246119 : if (cs_cmp)
2550 : : return cs_cmp;
2551 : :
2552 : : /* Order by SCC. */
2553 : 1008334 : int scc_id_a = ka.get_scc_id (ka.m_enode);
2554 : 1008334 : int scc_id_b = kb.get_scc_id (kb.m_enode);
2555 : 1008334 : if (scc_id_a != scc_id_b)
2556 : 695742 : return scc_id_a - scc_id_b;
2557 : :
2558 : : /* If in same SCC, order by supernode index (an arbitrary but stable
2559 : : ordering). */
2560 : 312592 : const supernode *snode_a = ka.m_enode->get_supernode ();
2561 : 312592 : const supernode *snode_b = kb.m_enode->get_supernode ();
2562 : 312592 : if (snode_a == NULL)
2563 : : {
2564 : 0 : if (snode_b != NULL)
2565 : : /* One is NULL. */
2566 : : return -1;
2567 : : else
2568 : : /* Both are NULL. */
2569 : 0 : return 0;
2570 : : }
2571 : 312592 : if (snode_b == NULL)
2572 : : /* One is NULL. */
2573 : : return 1;
2574 : : /* Neither are NULL. */
2575 : 308821 : gcc_assert (snode_a && snode_b);
2576 : 308821 : if (snode_a->m_index != snode_b->m_index)
2577 : 6650 : return snode_a->m_index - snode_b->m_index;
2578 : :
2579 : 302171 : gcc_assert (snode_a == snode_b);
2580 : :
2581 : : /* Order within supernode via program point. */
2582 : 302171 : int within_snode_cmp
2583 : 302171 : = function_point::cmp_within_supernode (point_a.get_function_point (),
2584 : : point_b.get_function_point ());
2585 : 302171 : if (within_snode_cmp)
2586 : : return within_snode_cmp;
2587 : :
2588 : : /* Otherwise, we ought to have the same program_point. */
2589 : 165720 : gcc_assert (point_a == point_b);
2590 : :
2591 : 165720 : const program_state &state_a = ka.m_enode->get_state ();
2592 : 165720 : const program_state &state_b = kb.m_enode->get_state ();
2593 : :
2594 : : /* Sort by sm-state, so that identical sm-states are grouped
2595 : : together in the worklist. */
2596 : 1287898 : for (unsigned sm_idx = 0; sm_idx < state_a.m_checker_states.length ();
2597 : : ++sm_idx)
2598 : : {
2599 : 578777 : sm_state_map *smap_a = state_a.m_checker_states[sm_idx];
2600 : 578777 : sm_state_map *smap_b = state_b.m_checker_states[sm_idx];
2601 : :
2602 : 578777 : if (int smap_cmp = sm_state_map::cmp (*smap_a, *smap_b))
2603 : 100548 : return smap_cmp;
2604 : : }
2605 : :
2606 : : /* Otherwise, we have two enodes at the same program point but with
2607 : : different states. We don't have a good total ordering on states,
2608 : : so order them by enode index, so that we have at least have a
2609 : : stable sort. */
2610 : 65172 : return ka.m_enode->m_index - kb.m_enode->m_index;
2611 : : }
2612 : :
2613 : : /* Return a new json::object of the form
2614 : : {"scc" : [per-snode-IDs]}, */
2615 : :
2616 : : json::object *
2617 : 0 : worklist::to_json () const
2618 : : {
2619 : 0 : json::object *worklist_obj = new json::object ();
2620 : :
2621 : 0 : worklist_obj->set ("scc", m_scc.to_json ());
2622 : :
2623 : : /* The following field isn't yet being JSONified:
2624 : : queue_t m_queue; */
2625 : :
2626 : 0 : return worklist_obj;
2627 : : }
2628 : :
2629 : : /* exploded_graph's ctor. */
2630 : :
2631 : 3783 : exploded_graph::exploded_graph (const supergraph &sg, logger *logger,
2632 : : const extrinsic_state &ext_state,
2633 : : const state_purge_map *purge_map,
2634 : : const analysis_plan &plan,
2635 : 3783 : int verbosity)
2636 : 3783 : : m_sg (sg), m_logger (logger),
2637 : 3783 : m_worklist (*this, plan),
2638 : 3783 : m_ext_state (ext_state),
2639 : 3783 : m_purge_map (purge_map),
2640 : 3783 : m_plan (plan),
2641 : 3783 : m_diagnostic_manager (logger, ext_state.get_engine (), verbosity),
2642 : 7561 : m_global_stats (m_sg.num_nodes ()),
2643 : 7561 : m_functionless_stats (m_sg.num_nodes ()),
2644 : 15127 : m_PK_AFTER_SUPERNODE_per_snode (m_sg.num_nodes ())
2645 : : {
2646 : 7566 : m_origin = get_or_create_node
2647 : 3783 : (program_point::origin (*ext_state.get_model_manager ()),
2648 : 7566 : program_state (ext_state), NULL);
2649 : 149277 : for (int i = 0; i < m_sg.num_nodes (); i++)
2650 : 70858 : m_PK_AFTER_SUPERNODE_per_snode.quick_push (i);
2651 : 3783 : }
2652 : :
2653 : : /* exploded_graph's dtor. */
2654 : :
2655 : 3783 : exploded_graph::~exploded_graph ()
2656 : : {
2657 : 616879 : for (auto iter : m_per_point_data)
2658 : 613096 : delete iter.second;
2659 : 22611 : for (auto iter : m_per_function_data)
2660 : 9414 : delete iter.second;
2661 : 19020 : for (auto iter : m_per_function_stats)
2662 : 11459 : delete iter.second;
2663 : 21761 : for (auto iter : m_per_call_string_data)
2664 : 8989 : delete iter.second;
2665 : 7566 : }
2666 : :
2667 : : /* Subroutine for use when implementing __attribute__((tainted_args))
2668 : : on functions and on function pointer fields in structs.
2669 : :
2670 : : Called on STATE representing a call to FNDECL.
2671 : : Mark all params of FNDECL in STATE as "tainted". Mark the value of all
2672 : : regions pointed to by params of FNDECL as "tainted".
2673 : :
2674 : : Return true if successful; return false if the "taint" state machine
2675 : : was not found. */
2676 : :
2677 : : static bool
2678 : 205 : mark_params_as_tainted (program_state *state, tree fndecl,
2679 : : const extrinsic_state &ext_state)
2680 : : {
2681 : 205 : unsigned taint_sm_idx;
2682 : 205 : if (!ext_state.get_sm_idx_by_name ("taint", &taint_sm_idx))
2683 : : return false;
2684 : 205 : sm_state_map *smap = state->m_checker_states[taint_sm_idx];
2685 : :
2686 : 205 : const state_machine &sm = ext_state.get_sm (taint_sm_idx);
2687 : 205 : state_machine::state_t tainted = sm.get_state_by_name ("tainted");
2688 : :
2689 : 205 : region_model_manager *mgr = ext_state.get_model_manager ();
2690 : :
2691 : 205 : function *fun = DECL_STRUCT_FUNCTION (fndecl);
2692 : 205 : gcc_assert (fun);
2693 : :
2694 : 487 : for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
2695 : 282 : iter_parm = DECL_CHAIN (iter_parm))
2696 : : {
2697 : 282 : tree param = iter_parm;
2698 : 282 : if (tree parm_default_ssa = ssa_default_def (fun, iter_parm))
2699 : 212 : param = parm_default_ssa;
2700 : 282 : const region *param_reg = state->m_region_model->get_lvalue (param, NULL);
2701 : 282 : const svalue *init_sval = mgr->get_or_create_initial_value (param_reg);
2702 : 282 : smap->set_state (state->m_region_model, init_sval,
2703 : : tainted, NULL /*origin_new_sval*/, ext_state);
2704 : 282 : if (POINTER_TYPE_P (TREE_TYPE (param)))
2705 : : {
2706 : 54 : const region *pointee_reg = mgr->get_symbolic_region (init_sval);
2707 : : /* Mark "*param" as tainted. */
2708 : 54 : const svalue *init_pointee_sval
2709 : 54 : = mgr->get_or_create_initial_value (pointee_reg);
2710 : 54 : smap->set_state (state->m_region_model, init_pointee_sval,
2711 : : tainted, NULL /*origin_new_sval*/, ext_state);
2712 : : }
2713 : : }
2714 : :
2715 : : return true;
2716 : : }
2717 : :
2718 : : /* Custom event for use by tainted_args_function_info when a function
2719 : : has been marked with __attribute__((tainted_args)). */
2720 : :
2721 : : class tainted_args_function_custom_event : public custom_event
2722 : : {
2723 : : public:
2724 : 121 : tainted_args_function_custom_event (const event_loc_info &loc_info)
2725 : 121 : : custom_event (loc_info),
2726 : 121 : m_fndecl (loc_info.m_fndecl)
2727 : : {
2728 : : }
2729 : :
2730 : 242 : label_text get_desc (bool can_colorize) const final override
2731 : : {
2732 : 242 : return make_label_text
2733 : : (can_colorize,
2734 : : "function %qE marked with %<__attribute__((tainted_args))%>",
2735 : 242 : m_fndecl);
2736 : : }
2737 : :
2738 : : private:
2739 : : tree m_fndecl;
2740 : : };
2741 : :
2742 : : /* Custom exploded_edge info for top-level calls to a function
2743 : : marked with __attribute__((tainted_args)). */
2744 : :
2745 : : class tainted_args_function_info : public custom_edge_info
2746 : : {
2747 : : public:
2748 : 193 : tainted_args_function_info (tree fndecl)
2749 : 193 : : m_fndecl (fndecl)
2750 : : {}
2751 : :
2752 : 0 : void print (pretty_printer *pp) const final override
2753 : : {
2754 : 0 : pp_string (pp, "call to tainted_args function");
2755 : 0 : };
2756 : :
2757 : 0 : bool update_model (region_model *,
2758 : : const exploded_edge *,
2759 : : region_model_context *) const final override
2760 : : {
2761 : : /* No-op. */
2762 : 0 : return true;
2763 : : }
2764 : :
2765 : 121 : void add_events_to_path (checker_path *emission_path,
2766 : : const exploded_edge &) const final override
2767 : : {
2768 : 121 : emission_path->add_event
2769 : 121 : (make_unique<tainted_args_function_custom_event>
2770 : 242 : (event_loc_info (DECL_SOURCE_LOCATION (m_fndecl), m_fndecl, 0)));
2771 : 121 : }
2772 : :
2773 : : private:
2774 : : tree m_fndecl;
2775 : : };
2776 : :
2777 : : /* Ensure that there is an exploded_node representing an external call to
2778 : : FUN, adding it to the worklist if creating it.
2779 : :
2780 : : Add an edge from the origin exploded_node to the function entrypoint
2781 : : exploded_node.
2782 : :
2783 : : Return the exploded_node for the entrypoint to the function. */
2784 : :
2785 : : exploded_node *
2786 : 11510 : exploded_graph::add_function_entry (const function &fun)
2787 : : {
2788 : 11510 : gcc_assert (gimple_has_body_p (fun.decl));
2789 : :
2790 : : /* Be idempotent. */
2791 : 11510 : function *key = const_cast<function *> (&fun);
2792 : 11510 : if (m_functions_with_enodes.contains (key))
2793 : : {
2794 : 204 : logger * const logger = get_logger ();
2795 : 204 : if (logger)
2796 : 0 : logger->log ("entrypoint for %qE already exists", fun.decl);
2797 : 204 : return NULL;
2798 : : }
2799 : :
2800 : 11306 : program_point point
2801 : 11306 : = program_point::from_function_entry (*m_ext_state.get_model_manager (),
2802 : : m_sg, fun);
2803 : 11306 : program_state state (m_ext_state);
2804 : 11306 : state.push_frame (m_ext_state, fun);
2805 : :
2806 : 11306 : std::unique_ptr<custom_edge_info> edge_info = NULL;
2807 : :
2808 : 11306 : if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (fun.decl)))
2809 : : {
2810 : 193 : if (mark_params_as_tainted (&state, fun.decl, m_ext_state))
2811 : 193 : edge_info = make_unique<tainted_args_function_info> (fun.decl);
2812 : : }
2813 : :
2814 : 11306 : if (!state.m_valid)
2815 : : return NULL;
2816 : :
2817 : 11306 : exploded_node *enode = get_or_create_node (point, state, NULL);
2818 : 11306 : if (!enode)
2819 : : return NULL;
2820 : :
2821 : 11296 : add_edge (m_origin, enode, NULL, false, std::move (edge_info));
2822 : :
2823 : 11296 : m_functions_with_enodes.add (key);
2824 : :
2825 : 11296 : return enode;
2826 : 11306 : }
2827 : :
2828 : : /* Get or create an exploded_node for (POINT, STATE).
2829 : : If a new node is created, it is added to the worklist.
2830 : :
2831 : : Use ENODE_FOR_DIAG, a pre-existing enode, for any diagnostics
2832 : : that need to be emitted (e.g. when purging state *before* we have
2833 : : a new enode). */
2834 : :
2835 : : exploded_node *
2836 : 435766 : exploded_graph::get_or_create_node (const program_point &point,
2837 : : const program_state &state,
2838 : : exploded_node *enode_for_diag)
2839 : : {
2840 : 435766 : logger * const logger = get_logger ();
2841 : 435766 : LOG_FUNC (logger);
2842 : 435766 : if (logger)
2843 : : {
2844 : 122 : format f (false);
2845 : 122 : pretty_printer *pp = logger->get_printer ();
2846 : 122 : logger->start_log_line ();
2847 : 122 : pp_string (pp, "point: ");
2848 : 122 : point.print (pp, f);
2849 : 122 : logger->end_log_line ();
2850 : 122 : logger->start_log_line ();
2851 : 122 : pp_string (pp, "state: ");
2852 : 122 : state.dump_to_pp (m_ext_state, true, false, pp);
2853 : 122 : logger->end_log_line ();
2854 : : }
2855 : :
2856 : : /* Stop exploring paths for which we don't know how to effectively
2857 : : model the state. */
2858 : 435766 : if (!state.m_valid)
2859 : : {
2860 : 4 : if (logger)
2861 : 0 : logger->log ("invalid state; not creating node");
2862 : 4 : return NULL;
2863 : : }
2864 : :
2865 : 435762 : auto_cfun sentinel (point.get_function ());
2866 : :
2867 : 435762 : state.validate (get_ext_state ());
2868 : :
2869 : : //state.dump (get_ext_state ());
2870 : :
2871 : : /* Prune state to try to improve the chances of a cache hit,
2872 : : avoiding generating redundant nodes. */
2873 : 435762 : uncertainty_t uncertainty;
2874 : 435762 : program_state pruned_state
2875 : 435762 : = state.prune_for_point (*this, point, enode_for_diag, &uncertainty);
2876 : :
2877 : 435762 : pruned_state.validate (get_ext_state ());
2878 : :
2879 : : //pruned_state.dump (get_ext_state ());
2880 : :
2881 : 435762 : if (logger)
2882 : : {
2883 : 122 : pretty_printer *pp = logger->get_printer ();
2884 : 122 : logger->start_log_line ();
2885 : 122 : pp_string (pp, "pruned_state: ");
2886 : 122 : pruned_state.dump_to_pp (m_ext_state, true, false, pp);
2887 : 122 : logger->end_log_line ();
2888 : 122 : pruned_state.m_region_model->dump_to_pp (logger->get_printer (), true,
2889 : : false);
2890 : : }
2891 : :
2892 : 435762 : stats *per_fn_stats = get_or_create_function_stats (point.get_function ());
2893 : :
2894 : 435762 : stats *per_cs_stats
2895 : 435762 : = &get_or_create_per_call_string_data (point.get_call_string ())->m_stats;
2896 : :
2897 : 435762 : point_and_state ps (point, pruned_state);
2898 : 435762 : ps.validate (m_ext_state);
2899 : 435762 : if (exploded_node **slot = m_point_and_state_to_node.get (&ps))
2900 : : {
2901 : : /* An exploded_node for PS already exists. */
2902 : 3066 : if (logger)
2903 : 5 : logger->log ("reused EN: %i", (*slot)->m_index);
2904 : 3066 : m_global_stats.m_node_reuse_count++;
2905 : 3066 : per_fn_stats->m_node_reuse_count++;
2906 : 3066 : per_cs_stats->m_node_reuse_count++;
2907 : 3066 : return *slot;
2908 : : }
2909 : :
2910 : 432696 : per_program_point_data *per_point_data
2911 : 432696 : = get_or_create_per_program_point_data (point);
2912 : :
2913 : : /* Consider merging state with another enode at this program_point. */
2914 : 432696 : if (flag_analyzer_state_merge)
2915 : : {
2916 : : exploded_node *existing_enode;
2917 : : unsigned i;
2918 : 707969 : FOR_EACH_VEC_ELT (per_point_data->m_enodes, i, existing_enode)
2919 : : {
2920 : 280519 : if (logger)
2921 : 157 : logger->log ("considering merging with existing EN: %i for point",
2922 : 157 : existing_enode->m_index);
2923 : 280519 : gcc_assert (existing_enode->get_point () == point);
2924 : 280519 : const program_state &existing_state = existing_enode->get_state ();
2925 : :
2926 : : /* This merges successfully within the loop. */
2927 : :
2928 : 280519 : program_state merged_state (m_ext_state);
2929 : 280519 : if (pruned_state.can_merge_with_p (existing_state, m_ext_state, point,
2930 : : &merged_state))
2931 : : {
2932 : 58215 : merged_state.validate (m_ext_state);
2933 : 58215 : if (logger)
2934 : 114 : logger->log ("merging new state with that of EN: %i",
2935 : 114 : existing_enode->m_index);
2936 : :
2937 : : /* Try again for a cache hit.
2938 : : Whether we get one or not, merged_state's value_ids have no
2939 : : relationship to those of the input state, and thus to those
2940 : : of CHANGE, so we must purge any svalue_ids from *CHANGE. */
2941 : 58215 : ps.set_state (merged_state);
2942 : :
2943 : 58215 : if (exploded_node **slot = m_point_and_state_to_node.get (&ps))
2944 : : {
2945 : : /* An exploded_node for PS already exists. */
2946 : 2072 : if (logger)
2947 : 2 : logger->log ("reused EN: %i", (*slot)->m_index);
2948 : 2072 : m_global_stats.m_node_reuse_after_merge_count++;
2949 : 2072 : per_fn_stats->m_node_reuse_after_merge_count++;
2950 : 2072 : per_cs_stats->m_node_reuse_after_merge_count++;
2951 : 2072 : return *slot;
2952 : : }
2953 : : }
2954 : : else
2955 : 222304 : if (logger)
2956 : 43 : logger->log ("not merging new state with that of EN: %i",
2957 : 43 : existing_enode->m_index);
2958 : 280519 : }
2959 : : }
2960 : :
2961 : : /* Impose a limit on the number of enodes per program point, and
2962 : : simply stop if we exceed it. */
2963 : 430624 : if ((int)per_point_data->m_enodes.length ()
2964 : 430624 : >= param_analyzer_max_enodes_per_program_point)
2965 : : {
2966 : 1875 : pretty_printer pp;
2967 : 1875 : point.print (&pp, format (false));
2968 : 1875 : print_enode_indices (&pp, per_point_data->m_enodes);
2969 : 1875 : if (logger)
2970 : 0 : logger->log ("not creating enode; too many at program point: %s",
2971 : : pp_formatted_text (&pp));
2972 : 1875 : warning_at (point.get_location (), OPT_Wanalyzer_too_complex,
2973 : : "terminating analysis for this program point: %s",
2974 : : pp_formatted_text (&pp));
2975 : 1875 : per_point_data->m_excess_enodes++;
2976 : 1875 : return NULL;
2977 : 1875 : }
2978 : :
2979 : 428749 : ps.validate (m_ext_state);
2980 : :
2981 : : /* An exploded_node for "ps" doesn't already exist; create one. */
2982 : 853720 : exploded_node *node = new exploded_node (ps, m_nodes.length ());
2983 : 428749 : add_node (node);
2984 : 428749 : m_point_and_state_to_node.put (node->get_ps_key (), node);
2985 : :
2986 : : /* Update per-program_point data. */
2987 : 428749 : per_point_data->m_enodes.safe_push (node);
2988 : :
2989 : 428749 : const enum point_kind node_pk = node->get_point ().get_kind ();
2990 : 428749 : m_global_stats.m_num_nodes[node_pk]++;
2991 : 428749 : per_fn_stats->m_num_nodes[node_pk]++;
2992 : 428749 : per_cs_stats->m_num_nodes[node_pk]++;
2993 : :
2994 : 428749 : if (node_pk == PK_AFTER_SUPERNODE)
2995 : 132263 : m_PK_AFTER_SUPERNODE_per_snode[point.get_supernode ()->m_index]++;
2996 : :
2997 : 428749 : if (logger)
2998 : : {
2999 : 115 : format f (false);
3000 : 115 : pretty_printer *pp = logger->get_printer ();
3001 : 115 : logger->log ("created EN: %i", node->m_index);
3002 : 115 : logger->start_log_line ();
3003 : 115 : pp_string (pp, "point: ");
3004 : 115 : point.print (pp, f);
3005 : 115 : logger->end_log_line ();
3006 : 115 : logger->start_log_line ();
3007 : 115 : pp_string (pp, "pruned_state: ");
3008 : 115 : pruned_state.dump_to_pp (m_ext_state, true, false, pp);
3009 : 115 : logger->end_log_line ();
3010 : : }
3011 : :
3012 : : /* Add the new node to the worlist. */
3013 : 428749 : m_worklist.add_node (node);
3014 : 428749 : return node;
3015 : 871528 : }
3016 : :
3017 : : /* Add an exploded_edge from SRC to DEST, recording its association
3018 : : with SEDGE (which may be NULL), and, if non-NULL, taking ownership
3019 : : of CUSTOM_INFO. COULD_DO_WORK is used for detecting infinite loops.
3020 : : Return the newly-created eedge. */
3021 : :
3022 : : exploded_edge *
3023 : 446631 : exploded_graph::add_edge (exploded_node *src, exploded_node *dest,
3024 : : const superedge *sedge, bool could_do_work,
3025 : : std::unique_ptr<custom_edge_info> custom_info)
3026 : : {
3027 : 446631 : if (get_logger ())
3028 : 124 : get_logger ()->log ("creating edge EN: %i -> EN: %i",
3029 : 124 : src->m_index, dest->m_index);
3030 : 446631 : exploded_edge *e
3031 : : = new exploded_edge (src, dest, sedge, could_do_work,
3032 : 446631 : std::move (custom_info));
3033 : 446631 : digraph<eg_traits>::add_edge (e);
3034 : 446631 : return e;
3035 : : }
3036 : :
3037 : : /* Ensure that this graph has per-program_point-data for POINT;
3038 : : borrow a pointer to it. */
3039 : :
3040 : : per_program_point_data *
3041 : 432696 : exploded_graph::
3042 : : get_or_create_per_program_point_data (const program_point &point)
3043 : : {
3044 : 432696 : if (per_program_point_data **slot = m_per_point_data.get (&point))
3045 : 126148 : return *slot;
3046 : :
3047 : 306548 : per_program_point_data *per_point_data = new per_program_point_data (point);
3048 : 306548 : m_per_point_data.put (&per_point_data->m_key, per_point_data);
3049 : 306548 : return per_point_data;
3050 : : }
3051 : :
3052 : : /* Get this graph's per-program-point-data for POINT if there is any,
3053 : : otherwise NULL. */
3054 : :
3055 : : per_program_point_data *
3056 : 0 : exploded_graph::get_per_program_point_data (const program_point &point) const
3057 : : {
3058 : 0 : if (per_program_point_data **slot
3059 : 0 : = const_cast <point_map_t &> (m_per_point_data).get (&point))
3060 : 0 : return *slot;
3061 : :
3062 : : return NULL;
3063 : : }
3064 : :
3065 : : /* Ensure that this graph has per-call_string-data for CS;
3066 : : borrow a pointer to it. */
3067 : :
3068 : : per_call_string_data *
3069 : 435762 : exploded_graph::get_or_create_per_call_string_data (const call_string &cs)
3070 : : {
3071 : 435762 : if (per_call_string_data **slot = m_per_call_string_data.get (&cs))
3072 : 426773 : return *slot;
3073 : :
3074 : 17973 : per_call_string_data *data = new per_call_string_data (cs, m_sg.num_nodes ());
3075 : 8989 : m_per_call_string_data.put (&data->m_key,
3076 : : data);
3077 : 8989 : return data;
3078 : : }
3079 : :
3080 : : /* Ensure that this graph has per-function-data for FUN;
3081 : : borrow a pointer to it. */
3082 : :
3083 : : per_function_data *
3084 : 11619 : exploded_graph::get_or_create_per_function_data (function *fun)
3085 : : {
3086 : 11619 : if (per_function_data **slot = m_per_function_data.get (fun))
3087 : 2205 : return *slot;
3088 : :
3089 : 9414 : per_function_data *data = new per_function_data ();
3090 : 9414 : m_per_function_data.put (fun, data);
3091 : 9414 : return data;
3092 : : }
3093 : :
3094 : : /* Get this graph's per-function-data for FUN if there is any,
3095 : : otherwise NULL. */
3096 : :
3097 : : per_function_data *
3098 : 1260 : exploded_graph::get_per_function_data (function *fun) const
3099 : : {
3100 : 2520 : if (per_function_data **slot
3101 : 1260 : = const_cast <per_function_data_t &> (m_per_function_data).get (fun))
3102 : 1173 : return *slot;
3103 : :
3104 : : return NULL;
3105 : : }
3106 : :
3107 : : /* Return true if FUN should be traversed directly, rather than only as
3108 : : called via other functions. */
3109 : :
3110 : : static bool
3111 : 11464 : toplevel_function_p (const function &fun, logger *logger)
3112 : : {
3113 : : /* Don't directly traverse into functions that have an "__analyzer_"
3114 : : prefix. Doing so is useful for the analyzer test suite, allowing
3115 : : us to have functions that are called in traversals, but not directly
3116 : : explored, thus testing how the analyzer handles calls and returns.
3117 : : With this, we can have DejaGnu directives that cover just the case
3118 : : of where a function is called by another function, without generating
3119 : : excess messages from the case of the first function being traversed
3120 : : directly. */
3121 : : #define ANALYZER_PREFIX "__analyzer_"
3122 : 11464 : if (!strncmp (IDENTIFIER_POINTER (DECL_NAME (fun.decl)), ANALYZER_PREFIX,
3123 : : strlen (ANALYZER_PREFIX)))
3124 : : {
3125 : 158 : if (logger)
3126 : 0 : logger->log ("not traversing %qE (starts with %qs)",
3127 : : fun.decl, ANALYZER_PREFIX);
3128 : 158 : return false;
3129 : : }
3130 : :
3131 : 11306 : if (logger)
3132 : 2 : logger->log ("traversing %qE (all checks passed)", fun.decl);
3133 : :
3134 : : return true;
3135 : : }
3136 : :
3137 : : /* Custom event for use by tainted_call_info when a callback field has been
3138 : : marked with __attribute__((tainted_args)), for labelling the field. */
3139 : :
3140 : : class tainted_args_field_custom_event : public custom_event
3141 : : {
3142 : : public:
3143 : 4 : tainted_args_field_custom_event (tree field)
3144 : 4 : : custom_event (event_loc_info (DECL_SOURCE_LOCATION (field), NULL_TREE, 0)),
3145 : 4 : m_field (field)
3146 : : {
3147 : 4 : }
3148 : :
3149 : 8 : label_text get_desc (bool can_colorize) const final override
3150 : : {
3151 : 8 : return make_label_text (can_colorize,
3152 : : "field %qE of %qT"
3153 : : " is marked with %<__attribute__((tainted_args))%>",
3154 : 8 : m_field, DECL_CONTEXT (m_field));
3155 : : }
3156 : :
3157 : : private:
3158 : : tree m_field;
3159 : : };
3160 : :
3161 : : /* Custom event for use by tainted_call_info when a callback field has been
3162 : : marked with __attribute__((tainted_args)), for labelling the function used
3163 : : in that callback. */
3164 : :
3165 : : class tainted_args_callback_custom_event : public custom_event
3166 : : {
3167 : : public:
3168 : 4 : tainted_args_callback_custom_event (const event_loc_info &loc_info,
3169 : : tree field)
3170 : 4 : : custom_event (loc_info),
3171 : 4 : m_field (field)
3172 : : {
3173 : : }
3174 : :
3175 : 8 : label_text get_desc (bool can_colorize) const final override
3176 : : {
3177 : 8 : return make_label_text (can_colorize,
3178 : : "function %qE used as initializer for field %qE"
3179 : : " marked with %<__attribute__((tainted_args))%>",
3180 : 8 : get_fndecl (), m_field);
3181 : : }
3182 : :
3183 : : private:
3184 : : tree m_field;
3185 : : };
3186 : :
3187 : : /* Custom edge info for use when adding a function used by a callback field
3188 : : marked with '__attribute__((tainted_args))'. */
3189 : :
3190 : : class tainted_args_call_info : public custom_edge_info
3191 : : {
3192 : : public:
3193 : 12 : tainted_args_call_info (tree field, tree fndecl, location_t loc)
3194 : 12 : : m_field (field), m_fndecl (fndecl), m_loc (loc)
3195 : : {}
3196 : :
3197 : 0 : void print (pretty_printer *pp) const final override
3198 : : {
3199 : 0 : pp_string (pp, "call to tainted field");
3200 : 0 : };
3201 : :
3202 : 0 : bool update_model (region_model *,
3203 : : const exploded_edge *,
3204 : : region_model_context *) const final override
3205 : : {
3206 : : /* No-op. */
3207 : 0 : return true;
3208 : : }
3209 : :
3210 : 4 : void add_events_to_path (checker_path *emission_path,
3211 : : const exploded_edge &) const final override
3212 : : {
3213 : : /* Show the field in the struct declaration, e.g.
3214 : : "(1) field 'store' is marked with '__attribute__((tainted_args))'" */
3215 : 4 : emission_path->add_event
3216 : 4 : (make_unique<tainted_args_field_custom_event> (m_field));
3217 : :
3218 : : /* Show the callback in the initializer
3219 : : e.g.
3220 : : "(2) function 'gadget_dev_desc_UDC_store' used as initializer
3221 : : for field 'store' marked with '__attribute__((tainted_args))'". */
3222 : 4 : emission_path->add_event
3223 : 4 : (make_unique<tainted_args_callback_custom_event>
3224 : 8 : (event_loc_info (m_loc, m_fndecl, 0),
3225 : : m_field));
3226 : 4 : }
3227 : :
3228 : : private:
3229 : : tree m_field;
3230 : : tree m_fndecl;
3231 : : location_t m_loc;
3232 : : };
3233 : :
3234 : : /* Given an initializer at LOC for FIELD marked with
3235 : : '__attribute__((tainted_args))' initialized with FNDECL, add an
3236 : : entrypoint to FNDECL to EG (and to its worklist) where the params to
3237 : : FNDECL are marked as tainted. */
3238 : :
3239 : : static void
3240 : 12 : add_tainted_args_callback (exploded_graph *eg, tree field, tree fndecl,
3241 : : location_t loc)
3242 : : {
3243 : 12 : logger *logger = eg->get_logger ();
3244 : :
3245 : 12 : LOG_SCOPE (logger);
3246 : :
3247 : 12 : if (!gimple_has_body_p (fndecl))
3248 : : return;
3249 : :
3250 : 12 : const extrinsic_state &ext_state = eg->get_ext_state ();
3251 : :
3252 : 12 : function *fun = DECL_STRUCT_FUNCTION (fndecl);
3253 : 12 : gcc_assert (fun);
3254 : :
3255 : 12 : program_point point
3256 : 12 : = program_point::from_function_entry (*ext_state.get_model_manager (),
3257 : : eg->get_supergraph (), *fun);
3258 : 12 : program_state state (ext_state);
3259 : 12 : state.push_frame (ext_state, *fun);
3260 : :
3261 : 12 : if (!mark_params_as_tainted (&state, fndecl, ext_state))
3262 : : return;
3263 : :
3264 : 12 : if (!state.m_valid)
3265 : : return;
3266 : :
3267 : 12 : exploded_node *enode = eg->get_or_create_node (point, state, NULL);
3268 : 12 : if (logger)
3269 : : {
3270 : 0 : if (enode)
3271 : 0 : logger->log ("created EN %i for tainted_args %qE entrypoint",
3272 : 0 : enode->m_index, fndecl);
3273 : : else
3274 : : {
3275 : 0 : logger->log ("did not create enode for tainted_args %qE entrypoint",
3276 : : fndecl);
3277 : 0 : return;
3278 : : }
3279 : : }
3280 : :
3281 : 12 : eg->add_edge (eg->get_origin (), enode, NULL, false,
3282 : 24 : make_unique<tainted_args_call_info> (field, fndecl, loc));
3283 : 12 : }
3284 : :
3285 : : /* Callback for walk_tree for finding callbacks within initializers;
3286 : : ensure that any callback initializer where the corresponding field is
3287 : : marked with '__attribute__((tainted_args))' is treated as an entrypoint
3288 : : to the analysis, special-casing that the inputs to the callback are
3289 : : untrustworthy. */
3290 : :
3291 : : static tree
3292 : 33304 : add_any_callbacks (tree *tp, int *, void *data)
3293 : : {
3294 : 33304 : exploded_graph *eg = (exploded_graph *)data;
3295 : 33304 : if (TREE_CODE (*tp) == CONSTRUCTOR)
3296 : : {
3297 : : /* Find fields with the "tainted_args" attribute.
3298 : : walk_tree only walks the values, not the index values;
3299 : : look at the index values. */
3300 : : unsigned HOST_WIDE_INT idx;
3301 : : constructor_elt *ce;
3302 : :
3303 : 22383 : for (idx = 0; vec_safe_iterate (CONSTRUCTOR_ELTS (*tp), idx, &ce);
3304 : : idx++)
3305 : 16726 : if (ce->index && TREE_CODE (ce->index) == FIELD_DECL)
3306 : 15588 : if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (ce->index)))
3307 : : {
3308 : 12 : tree value = ce->value;
3309 : 12 : if (TREE_CODE (value) == ADDR_EXPR
3310 : 12 : && TREE_CODE (TREE_OPERAND (value, 0)) == FUNCTION_DECL)
3311 : 12 : add_tainted_args_callback (eg, ce->index,
3312 : 12 : TREE_OPERAND (value, 0),
3313 : : EXPR_LOCATION (value));
3314 : : }
3315 : : }
3316 : :
3317 : 33304 : return NULL_TREE;
3318 : : }
3319 : :
3320 : : /* Add initial nodes to EG, with entrypoints for externally-callable
3321 : : functions. */
3322 : :
3323 : : void
3324 : 3783 : exploded_graph::build_initial_worklist ()
3325 : : {
3326 : 3783 : logger * const logger = get_logger ();
3327 : 3783 : LOG_SCOPE (logger);
3328 : :
3329 : 3783 : cgraph_node *node;
3330 : 15247 : FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
3331 : : {
3332 : 11464 : function *fun = node->get_fun ();
3333 : 11464 : gcc_assert (fun);
3334 : 11464 : if (!toplevel_function_p (*fun, logger))
3335 : 158 : continue;
3336 : 11306 : exploded_node *enode = add_function_entry (*fun);
3337 : 11306 : if (logger)
3338 : : {
3339 : 2 : if (enode)
3340 : 2 : logger->log ("created EN %i for %qE entrypoint",
3341 : 2 : enode->m_index, fun->decl);
3342 : : else
3343 : 0 : logger->log ("did not create enode for %qE entrypoint", fun->decl);
3344 : : }
3345 : : }
3346 : :
3347 : : /* Find callbacks that are reachable from global initializers. */
3348 : 3783 : varpool_node *vpnode;
3349 : 21690 : FOR_EACH_VARIABLE (vpnode)
3350 : : {
3351 : 7062 : tree decl = vpnode->decl;
3352 : 7062 : tree init = DECL_INITIAL (decl);
3353 : 7062 : if (!init)
3354 : 1324 : continue;
3355 : 5738 : walk_tree (&init, add_any_callbacks, this, NULL);
3356 : : }
3357 : 3783 : }
3358 : :
3359 : : /* The main loop of the analysis.
3360 : : Take freshly-created exploded_nodes from the worklist, calling
3361 : : process_node on them to explore the <point, state> graph.
3362 : : Add edges to their successors, potentially creating new successors
3363 : : (which are also added to the worklist). */
3364 : :
3365 : : void
3366 : 3783 : exploded_graph::process_worklist ()
3367 : : {
3368 : 3783 : logger * const logger = get_logger ();
3369 : 3783 : LOG_SCOPE (logger);
3370 : 3783 : auto_timevar tv (TV_ANALYZER_WORKLIST);
3371 : :
3372 : 399970 : while (m_worklist.length () > 0)
3373 : : {
3374 : 392474 : exploded_node *node = m_worklist.take_next ();
3375 : 392474 : gcc_assert (node->get_status () == exploded_node::STATUS_WORKLIST);
3376 : 392474 : gcc_assert (node->m_succs.length () == 0
3377 : : || node == m_origin);
3378 : :
3379 : 392474 : if (logger)
3380 : 110 : logger->log ("next to process: EN: %i", node->m_index);
3381 : :
3382 : : /* If we have a run of nodes that are before-supernode, try merging and
3383 : : processing them together, rather than pairwise or individually. */
3384 : 392474 : if (flag_analyzer_state_merge && node != m_origin)
3385 : 385875 : if (maybe_process_run_of_before_supernode_enodes (node))
3386 : 16051 : goto handle_limit;
3387 : :
3388 : : /* Avoid exponential explosions of nodes by attempting to merge
3389 : : nodes that are at the same program point and which have
3390 : : sufficiently similar state. */
3391 : 376423 : if (flag_analyzer_state_merge && node != m_origin)
3392 : 369824 : if (exploded_node *node_2 = m_worklist.peek_next ())
3393 : : {
3394 : 305973 : gcc_assert (node_2->get_status ()
3395 : : == exploded_node::STATUS_WORKLIST);
3396 : 305973 : gcc_assert (node->m_succs.length () == 0);
3397 : 305973 : gcc_assert (node_2->m_succs.length () == 0);
3398 : :
3399 : 305973 : gcc_assert (node != node_2);
3400 : :
3401 : 305973 : if (logger)
3402 : 85 : logger->log ("peek worklist: EN: %i", node_2->m_index);
3403 : :
3404 : 305973 : if (node->get_point () == node_2->get_point ())
3405 : : {
3406 : 38474 : const program_point &point = node->get_point ();
3407 : 38474 : if (logger)
3408 : : {
3409 : 3 : format f (false);
3410 : 3 : pretty_printer *pp = logger->get_printer ();
3411 : 3 : logger->start_log_line ();
3412 : 3 : logger->log_partial
3413 : 3 : ("got potential merge EN: %i and EN: %i at ",
3414 : 3 : node->m_index, node_2->m_index);
3415 : 3 : point.print (pp, f);
3416 : 3 : logger->end_log_line ();
3417 : : }
3418 : 38474 : const program_state &state = node->get_state ();
3419 : 38474 : const program_state &state_2 = node_2->get_state ();
3420 : :
3421 : : /* They shouldn't be equal, or we wouldn't have two
3422 : : separate nodes. */
3423 : 38474 : gcc_assert (state != state_2);
3424 : :
3425 : 38474 : program_state merged_state (m_ext_state);
3426 : 38474 : if (state.can_merge_with_p (state_2, m_ext_state,
3427 : : point, &merged_state))
3428 : : {
3429 : 521 : if (logger)
3430 : 0 : logger->log ("merging EN: %i and EN: %i",
3431 : 0 : node->m_index, node_2->m_index);
3432 : :
3433 : 521 : if (merged_state == state)
3434 : : {
3435 : : /* Then merge node_2 into node by adding an edge. */
3436 : 18 : add_edge (node_2, node, NULL, false);
3437 : :
3438 : : /* Remove node_2 from the worklist. */
3439 : 18 : m_worklist.take_next ();
3440 : 18 : node_2->set_status (exploded_node::STATUS_MERGER);
3441 : :
3442 : : /* Continue processing "node" below. */
3443 : : }
3444 : 503 : else if (merged_state == state_2)
3445 : : {
3446 : : /* Then merge node into node_2, and leave node_2
3447 : : in the worklist, to be processed on the next
3448 : : iteration. */
3449 : 455 : add_edge (node, node_2, NULL, false);
3450 : 455 : node->set_status (exploded_node::STATUS_MERGER);
3451 : 455 : continue;
3452 : : }
3453 : : else
3454 : : {
3455 : : /* We have a merged state that differs from
3456 : : both state and state_2. */
3457 : :
3458 : : /* Remove node_2 from the worklist. */
3459 : 48 : m_worklist.take_next ();
3460 : :
3461 : : /* Create (or get) an exploded node for the merged
3462 : : states, adding to the worklist. */
3463 : 48 : exploded_node *merged_enode
3464 : 48 : = get_or_create_node (node->get_point (),
3465 : : merged_state, node);
3466 : 48 : if (merged_enode == NULL)
3467 : 1 : continue;
3468 : :
3469 : 47 : if (logger)
3470 : 0 : logger->log ("merged EN: %i and EN: %i into EN: %i",
3471 : 0 : node->m_index, node_2->m_index,
3472 : 0 : merged_enode->m_index);
3473 : :
3474 : : /* "node" and "node_2" have both now been removed
3475 : : from the worklist; we should not process them.
3476 : :
3477 : : "merged_enode" may be a new node; if so it will be
3478 : : processed in a subsequent iteration.
3479 : : Alternatively, "merged_enode" could be an existing
3480 : : node; one way the latter can
3481 : : happen is if we end up merging a succession of
3482 : : similar nodes into one. */
3483 : :
3484 : : /* If merged_node is one of the two we were merging,
3485 : : add it back to the worklist to ensure it gets
3486 : : processed.
3487 : :
3488 : : Add edges from the merged nodes to it (but not a
3489 : : self-edge). */
3490 : 47 : if (merged_enode == node)
3491 : 0 : m_worklist.add_node (merged_enode);
3492 : : else
3493 : : {
3494 : 47 : add_edge (node, merged_enode, NULL, false);
3495 : 47 : node->set_status (exploded_node::STATUS_MERGER);
3496 : : }
3497 : :
3498 : 47 : if (merged_enode == node_2)
3499 : 0 : m_worklist.add_node (merged_enode);
3500 : : else
3501 : : {
3502 : 47 : add_edge (node_2, merged_enode, NULL, false);
3503 : 47 : node_2->set_status (exploded_node::STATUS_MERGER);
3504 : : }
3505 : :
3506 : 47 : continue;
3507 : 47 : }
3508 : : }
3509 : :
3510 : : /* TODO: should we attempt more than two nodes,
3511 : : or just do pairs of nodes? (and hope that we get
3512 : : a cascade of mergers). */
3513 : 38474 : }
3514 : : }
3515 : :
3516 : 375920 : process_node (node);
3517 : :
3518 : 391971 : handle_limit:
3519 : : /* Impose a hard limit on the number of exploded nodes, to ensure
3520 : : that the analysis terminates in the face of pathological state
3521 : : explosion (or bugs).
3522 : :
3523 : : Specifically, the limit is on the number of PK_AFTER_SUPERNODE
3524 : : exploded nodes, looking at supernode exit events.
3525 : :
3526 : : We use exit rather than entry since there can be multiple
3527 : : entry ENs, one per phi; the number of PK_AFTER_SUPERNODE ought
3528 : : to be equivalent to the number of supernodes multiplied by the
3529 : : number of states. */
3530 : 391971 : const int limit = m_sg.num_nodes () * param_analyzer_bb_explosion_factor;
3531 : 391971 : if (m_global_stats.m_num_nodes[PK_AFTER_SUPERNODE] > limit)
3532 : : {
3533 : 70 : if (logger)
3534 : 0 : logger->log ("bailing out; too many nodes");
3535 : 140 : warning_at (node->get_point ().get_location (),
3536 : : OPT_Wanalyzer_too_complex,
3537 : : "analysis bailed out early"
3538 : : " (%i 'after-snode' enodes; %i enodes)",
3539 : : m_global_stats.m_num_nodes[PK_AFTER_SUPERNODE],
3540 : : m_nodes.length ());
3541 : 70 : return;
3542 : : }
3543 : : }
3544 : 3783 : }
3545 : :
3546 : : /* Attempt to process a consecutive run of sufficiently-similar nodes in
3547 : : the worklist at a CFG join-point (having already popped ENODE from the
3548 : : head of the worklist).
3549 : :
3550 : : If ENODE's point is of the form (before-supernode, SNODE) and the next
3551 : : nodes in the worklist are a consecutive run of enodes of the same form,
3552 : : for the same supernode as ENODE (but potentially from different in-edges),
3553 : : process them all together, setting their status to STATUS_BULK_MERGED,
3554 : : and return true.
3555 : : Otherwise, return false, in which case ENODE must be processed in the
3556 : : normal way.
3557 : :
3558 : : When processing them all together, generate successor states based
3559 : : on phi nodes for the appropriate CFG edges, and then attempt to merge
3560 : : these states into a minimal set of merged successor states, partitioning
3561 : : the inputs by merged successor state.
3562 : :
3563 : : Create new exploded nodes for all of the merged states, and add edges
3564 : : connecting the input enodes to the corresponding merger exploded nodes.
3565 : :
3566 : : We hope we have a much smaller number of merged successor states
3567 : : compared to the number of input enodes - ideally just one,
3568 : : if all successor states can be merged.
3569 : :
3570 : : Processing and merging many together as one operation rather than as
3571 : : pairs avoids scaling issues where per-pair mergers could bloat the
3572 : : graph with merger nodes (especially so after switch statements). */
3573 : :
3574 : : bool
3575 : 385875 : exploded_graph::
3576 : : maybe_process_run_of_before_supernode_enodes (exploded_node *enode)
3577 : : {
3578 : : /* A struct for tracking per-input state. */
3579 : 51284 : struct item
3580 : : {
3581 : 51284 : item (exploded_node *input_enode)
3582 : 51284 : : m_input_enode (input_enode),
3583 : 51284 : m_processed_state (input_enode->get_state ()),
3584 : 51284 : m_merger_idx (-1)
3585 : : {}
3586 : :
3587 : : exploded_node *m_input_enode;
3588 : : program_state m_processed_state;
3589 : : int m_merger_idx;
3590 : : };
3591 : :
3592 : 385875 : gcc_assert (enode->get_status () == exploded_node::STATUS_WORKLIST);
3593 : 385875 : gcc_assert (enode->m_succs.length () == 0);
3594 : :
3595 : 385875 : const program_point &point = enode->get_point ();
3596 : :
3597 : 385875 : if (point.get_kind () != PK_BEFORE_SUPERNODE)
3598 : : return false;
3599 : :
3600 : 116190 : const supernode *snode = point.get_supernode ();
3601 : :
3602 : 116190 : logger * const logger = get_logger ();
3603 : 116190 : LOG_SCOPE (logger);
3604 : :
3605 : : /* Find a run of enodes in the worklist that are before the same supernode,
3606 : : but potentially from different in-edges. */
3607 : 116190 : auto_vec <exploded_node *> enodes;
3608 : 116190 : enodes.safe_push (enode);
3609 : 151423 : while (exploded_node *enode_2 = m_worklist.peek_next ())
3610 : : {
3611 : 131678 : gcc_assert (enode_2->get_status ()
3612 : : == exploded_node::STATUS_WORKLIST);
3613 : 131678 : gcc_assert (enode_2->m_succs.length () == 0);
3614 : :
3615 : 131678 : const program_point &point_2 = enode_2->get_point ();
3616 : :
3617 : 131678 : if (point_2.get_kind () == PK_BEFORE_SUPERNODE
3618 : 125060 : && point_2.get_supernode () == snode
3619 : 167217 : && &point_2.get_call_string () == &point.get_call_string ())
3620 : : {
3621 : 35233 : enodes.safe_push (enode_2);
3622 : 35233 : m_worklist.take_next ();
3623 : : }
3624 : : else
3625 : : break;
3626 : 35233 : }
3627 : :
3628 : : /* If the only node is ENODE, then give up. */
3629 : 116190 : if (enodes.length () == 1)
3630 : : return false;
3631 : :
3632 : 16051 : if (logger)
3633 : 2 : logger->log ("got run of %i enodes for SN: %i",
3634 : 2 : enodes.length (), snode->m_index);
3635 : :
3636 : : /* All of these enodes have a shared successor point (even if they
3637 : : were for different in-edges). */
3638 : 16051 : program_point next_point (point.get_next ());
3639 : :
3640 : : /* Calculate the successor state for each enode in enodes. */
3641 : 32102 : auto_delete_vec<item> items (enodes.length ());
3642 : 16051 : unsigned i;
3643 : 16051 : exploded_node *iter_enode;
3644 : 67335 : FOR_EACH_VEC_ELT (enodes, i, iter_enode)
3645 : : {
3646 : 51284 : item *it = new item (iter_enode);
3647 : 51284 : items.quick_push (it);
3648 : 51284 : const program_state &state = iter_enode->get_state ();
3649 : 51284 : program_state *next_state = &it->m_processed_state;
3650 : 51284 : next_state->validate (m_ext_state);
3651 : 51284 : const program_point &iter_point = iter_enode->get_point ();
3652 : 51284 : if (const superedge *iter_sedge = iter_point.get_from_edge ())
3653 : : {
3654 : 47493 : uncertainty_t uncertainty;
3655 : 47493 : impl_region_model_context ctxt (*this, iter_enode,
3656 : : &state, next_state,
3657 : 47493 : &uncertainty, NULL, NULL);
3658 : 47493 : const cfg_superedge *last_cfg_superedge
3659 : 47493 : = iter_sedge->dyn_cast_cfg_superedge ();
3660 : 47493 : if (last_cfg_superedge)
3661 : 47493 : next_state->m_region_model->update_for_phis
3662 : 47493 : (snode, last_cfg_superedge, &ctxt);
3663 : 94986 : }
3664 : 51284 : next_state->validate (m_ext_state);
3665 : : }
3666 : :
3667 : : /* Attempt to partition the items into a set of merged states.
3668 : : We hope we have a much smaller number of merged states
3669 : : compared to the number of input enodes - ideally just one,
3670 : : if all can be merged. */
3671 : 16051 : auto_delete_vec <program_state> merged_states;
3672 : 16051 : auto_vec<item *> first_item_for_each_merged_state;
3673 : 16051 : item *it;
3674 : 67335 : FOR_EACH_VEC_ELT (items, i, it)
3675 : : {
3676 : 51284 : const program_state &it_state = it->m_processed_state;
3677 : 51284 : program_state *merged_state;
3678 : 51284 : unsigned iter_merger_idx;
3679 : 93612 : FOR_EACH_VEC_ELT (merged_states, iter_merger_idx, merged_state)
3680 : : {
3681 : 58344 : merged_state->validate (m_ext_state);
3682 : 58344 : program_state merge (m_ext_state);
3683 : 58344 : if (it_state.can_merge_with_p (*merged_state, m_ext_state,
3684 : : next_point, &merge))
3685 : : {
3686 : 16016 : *merged_state = merge;
3687 : 16016 : merged_state->validate (m_ext_state);
3688 : 16016 : it->m_merger_idx = iter_merger_idx;
3689 : 16016 : if (logger)
3690 : 4 : logger->log ("reusing merger state %i for item %i (EN: %i)",
3691 : 4 : it->m_merger_idx, i, it->m_input_enode->m_index);
3692 : 16016 : goto got_merger;
3693 : : }
3694 : 58344 : }
3695 : : /* If it couldn't be merged with any existing merged_states,
3696 : : create a new one. */
3697 : 35268 : if (it->m_merger_idx == -1)
3698 : : {
3699 : 35268 : it->m_merger_idx = merged_states.length ();
3700 : 35268 : merged_states.safe_push (new program_state (it_state));
3701 : 35268 : first_item_for_each_merged_state.safe_push (it);
3702 : 35268 : if (logger)
3703 : 3 : logger->log ("using new merger state %i for item %i (EN: %i)",
3704 : 3 : it->m_merger_idx, i, it->m_input_enode->m_index);
3705 : : }
3706 : 0 : got_merger:
3707 : 51284 : gcc_assert (it->m_merger_idx >= 0);
3708 : 51284 : gcc_assert ((unsigned)it->m_merger_idx < merged_states.length ());
3709 : : }
3710 : :
3711 : : /* Create merger nodes. */
3712 : 48153 : auto_vec<exploded_node *> next_enodes (merged_states.length ());
3713 : 16051 : program_state *merged_state;
3714 : 51319 : FOR_EACH_VEC_ELT (merged_states, i, merged_state)
3715 : : {
3716 : 35268 : exploded_node *src_enode
3717 : 35268 : = first_item_for_each_merged_state[i]->m_input_enode;
3718 : 35268 : exploded_node *next
3719 : 35268 : = get_or_create_node (next_point, *merged_state, src_enode);
3720 : : /* "next" could be NULL; we handle that when adding the edges below. */
3721 : 35268 : next_enodes.quick_push (next);
3722 : 35268 : if (logger)
3723 : : {
3724 : 3 : if (next)
3725 : 3 : logger->log ("using EN: %i for merger state %i", next->m_index, i);
3726 : : else
3727 : 0 : logger->log ("using NULL enode for merger state %i", i);
3728 : : }
3729 : : }
3730 : :
3731 : : /* Create edges from each input enode to the appropriate successor enode.
3732 : : Update the status of the now-processed input enodes. */
3733 : 67335 : FOR_EACH_VEC_ELT (items, i, it)
3734 : : {
3735 : 51284 : exploded_node *next = next_enodes[it->m_merger_idx];
3736 : 51284 : if (next)
3737 : 51011 : add_edge (it->m_input_enode, next, NULL,
3738 : : false); /* no "work" is done during merger. */
3739 : 51284 : it->m_input_enode->set_status (exploded_node::STATUS_BULK_MERGED);
3740 : : }
3741 : :
3742 : 16051 : if (logger)
3743 : 4 : logger->log ("merged %i in-enodes into %i out-enode(s) at SN: %i",
3744 : 2 : items.length (), merged_states.length (), snode->m_index);
3745 : :
3746 : 16051 : return true;
3747 : 132241 : }
3748 : :
3749 : : /* Return true if STMT must appear at the start of its exploded node, and
3750 : : thus we can't consolidate its effects within a run of other statements,
3751 : : where PREV_STMT was the previous statement. */
3752 : :
3753 : : static bool
3754 : 155609 : stmt_requires_new_enode_p (const gimple *stmt,
3755 : : const gimple *prev_stmt)
3756 : : {
3757 : 155609 : if (const gcall *call = dyn_cast <const gcall *> (stmt))
3758 : : {
3759 : : /* Stop consolidating at calls to
3760 : : "__analyzer_dump_exploded_nodes", so they always appear at the
3761 : : start of an exploded_node. */
3762 : 26141 : if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes",
3763 : : 1))
3764 : : return true;
3765 : :
3766 : : /* sm-signal.cc injects an additional custom eedge at "signal" calls
3767 : : from the registration enode to the handler enode, separate from the
3768 : : regular next state, which defeats the "detect state change" logic
3769 : : in process_node. Work around this via special-casing, to ensure
3770 : : we split the enode immediately before any "signal" call. */
3771 : 25767 : if (is_special_named_call_p (call, "signal", 2))
3772 : : return true;
3773 : : }
3774 : :
3775 : : /* If we had a PREV_STMT with an unknown location, and this stmt
3776 : : has a known location, then if a state change happens here, it
3777 : : could be consolidated into PREV_STMT, giving us an event with
3778 : : no location. Ensure that STMT gets its own exploded_node to
3779 : : avoid this. */
3780 : 155234 : if (get_pure_location (prev_stmt->location) == UNKNOWN_LOCATION
3781 : 155234 : && get_pure_location (stmt->location) != UNKNOWN_LOCATION)
3782 : : return true;
3783 : :
3784 : : return false;
3785 : : }
3786 : :
3787 : : /* Return true if OLD_STATE and NEW_STATE are sufficiently different that
3788 : : we should split enodes and create an exploded_edge separating them
3789 : : (which makes it easier to identify state changes of intereset when
3790 : : constructing checker_paths). */
3791 : :
3792 : : static bool
3793 : 284686 : state_change_requires_new_enode_p (const program_state &old_state,
3794 : : const program_state &new_state)
3795 : : {
3796 : : /* Changes in dynamic extents signify creations of heap/alloca regions
3797 : : and resizings of heap regions; likely to be of interest in
3798 : : diagnostic paths. */
3799 : 569372 : if (old_state.m_region_model->get_dynamic_extents ()
3800 : 284686 : != new_state.m_region_model->get_dynamic_extents ())
3801 : : return true;
3802 : :
3803 : : /* Changes in sm-state are of interest. */
3804 : : int sm_idx;
3805 : : sm_state_map *smap;
3806 : 1996277 : FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
3807 : : {
3808 : 1750993 : const sm_state_map *old_smap = old_state.m_checker_states[sm_idx];
3809 : 1750993 : const sm_state_map *new_smap = new_state.m_checker_states[sm_idx];
3810 : 1750993 : if (*old_smap != *new_smap)
3811 : : return true;
3812 : : }
3813 : :
3814 : : return false;
3815 : : }
3816 : :
3817 : : /* Create enodes and eedges for the function calls that doesn't have an
3818 : : underlying call superedge.
3819 : :
3820 : : Such case occurs when GCC's middle end didn't know which function to
3821 : : call but the analyzer does (with the help of current state).
3822 : :
3823 : : Some example such calls are dynamically dispatched calls to virtual
3824 : : functions or calls that happen via function pointer. */
3825 : :
3826 : : bool
3827 : 190 : exploded_graph::maybe_create_dynamic_call (const gcall *call,
3828 : : tree fn_decl,
3829 : : exploded_node *node,
3830 : : program_state next_state,
3831 : : program_point &next_point,
3832 : : uncertainty_t *uncertainty,
3833 : : logger *logger)
3834 : : {
3835 : 190 : LOG_FUNC (logger);
3836 : :
3837 : 190 : const program_point *this_point = &node->get_point ();
3838 : 190 : function *fun = DECL_STRUCT_FUNCTION (fn_decl);
3839 : 190 : if (fun)
3840 : : {
3841 : 101 : const supergraph &sg = this->get_supergraph ();
3842 : 101 : supernode *sn_entry = sg.get_node_for_function_entry (*fun);
3843 : 101 : supernode *sn_exit = sg.get_node_for_function_exit (*fun);
3844 : :
3845 : 101 : program_point new_point
3846 : 101 : = program_point::before_supernode (sn_entry,
3847 : : NULL,
3848 : : this_point->get_call_string ());
3849 : :
3850 : 101 : new_point.push_to_call_stack (sn_exit,
3851 : : next_point.get_supernode());
3852 : :
3853 : : /* Impose a maximum recursion depth and don't analyze paths
3854 : : that exceed it further.
3855 : : This is something of a blunt workaround, but it only
3856 : : applies to recursion (and mutual recursion), not to
3857 : : general call stacks. */
3858 : 101 : if (new_point.get_call_string ().calc_recursion_depth ()
3859 : 101 : > param_analyzer_max_recursion_depth)
3860 : : {
3861 : 4 : if (logger)
3862 : 0 : logger->log ("rejecting call edge: recursion limit exceeded");
3863 : 101 : return false;
3864 : : }
3865 : :
3866 : 97 : next_state.push_call (*this, node, call, uncertainty);
3867 : :
3868 : 97 : if (next_state.m_valid)
3869 : : {
3870 : 97 : if (logger)
3871 : 0 : logger->log ("Discovered call to %s [SN: %i -> SN: %i]",
3872 : : function_name(fun),
3873 : 0 : this_point->get_supernode ()->m_index,
3874 : 0 : sn_entry->m_index);
3875 : :
3876 : 97 : exploded_node *enode = get_or_create_node (new_point,
3877 : : next_state,
3878 : : node);
3879 : 97 : if (enode)
3880 : 97 : add_edge (node,enode, NULL,
3881 : : false, /* No work is done by the call itself. */
3882 : 194 : make_unique<dynamic_call_info_t> (call));
3883 : 97 : return true;
3884 : : }
3885 : : }
3886 : : return false;
3887 : 190 : }
3888 : :
3889 : : /* Subclass of path_context for use within exploded_graph::process_node,
3890 : : so that we can split states e.g. at "realloc" calls. */
3891 : :
3892 : : class impl_path_context : public path_context
3893 : : {
3894 : : public:
3895 : 139191 : impl_path_context (const program_state *cur_state,
3896 : : logger *logger)
3897 : 139191 : : m_cur_state (cur_state),
3898 : 139191 : m_logger (logger),
3899 : 139191 : m_terminate_path (false)
3900 : : {
3901 : : }
3902 : :
3903 : 245284 : bool bifurcation_p () const
3904 : : {
3905 : 245284 : return m_custom_eedge_infos.length () > 0;
3906 : : }
3907 : :
3908 : 10502 : const program_state &get_state_at_bifurcation () const
3909 : : {
3910 : 10502 : gcc_assert (m_state_at_bifurcation);
3911 : 10502 : return *m_state_at_bifurcation;
3912 : : }
3913 : :
3914 : : void
3915 : 7979 : bifurcate (std::unique_ptr<custom_edge_info> info) final override
3916 : : {
3917 : 7979 : if (m_logger)
3918 : 0 : m_logger->log ("bifurcating path");
3919 : :
3920 : 7979 : if (m_state_at_bifurcation)
3921 : : /* Verify that the state at bifurcation is consistent when we
3922 : : split into multiple out-edges. */
3923 : 4655 : gcc_assert (*m_state_at_bifurcation == *m_cur_state);
3924 : : else
3925 : : /* Take a copy of the cur_state at the moment when bifurcation
3926 : : happens. */
3927 : 3324 : m_state_at_bifurcation
3928 : 3324 : = std::unique_ptr<program_state> (new program_state (*m_cur_state));
3929 : :
3930 : : /* Take ownership of INFO. */
3931 : 7979 : m_custom_eedge_infos.safe_push (info.release ());
3932 : 7979 : }
3933 : :
3934 : 4127 : void terminate_path () final override
3935 : : {
3936 : 4127 : if (m_logger)
3937 : 0 : m_logger->log ("terminating path");
3938 : 4127 : m_terminate_path = true;
3939 : 4127 : }
3940 : :
3941 : 657950 : bool terminate_path_p () const final override
3942 : : {
3943 : 657950 : return m_terminate_path;
3944 : : }
3945 : :
3946 : : const vec<custom_edge_info *> & get_custom_eedge_infos ()
3947 : : {
3948 : : return m_custom_eedge_infos;
3949 : : }
3950 : :
3951 : : private:
3952 : : const program_state *m_cur_state;
3953 : :
3954 : : logger *m_logger;
3955 : :
3956 : : /* Lazily-created copy of the state before the split. */
3957 : : std::unique_ptr<program_state> m_state_at_bifurcation;
3958 : :
3959 : : auto_vec <custom_edge_info *> m_custom_eedge_infos;
3960 : :
3961 : : bool m_terminate_path;
3962 : : };
3963 : :
3964 : : /* A subclass of pending_diagnostic for complaining about jumps through NULL
3965 : : function pointers. */
3966 : :
3967 : : class jump_through_null : public pending_diagnostic_subclass<jump_through_null>
3968 : : {
3969 : : public:
3970 : 20 : jump_through_null (const gcall *call)
3971 : 20 : : m_call (call)
3972 : : {}
3973 : :
3974 : 80 : const char *get_kind () const final override
3975 : : {
3976 : 80 : return "jump_through_null";
3977 : : }
3978 : :
3979 : 20 : bool operator== (const jump_through_null &other) const
3980 : : {
3981 : 20 : return m_call == other.m_call;
3982 : : }
3983 : :
3984 : 40 : int get_controlling_option () const final override
3985 : : {
3986 : 40 : return OPT_Wanalyzer_jump_through_null;
3987 : : }
3988 : :
3989 : 20 : bool emit (diagnostic_emission_context &ctxt) final override
3990 : : {
3991 : 20 : return ctxt.warn ("jump through null pointer");
3992 : : }
3993 : :
3994 : 40 : label_text describe_final_event (const evdesc::final_event &ev) final override
3995 : : {
3996 : 40 : return ev.formatted_print ("jump through null pointer here");
3997 : : }
3998 : :
3999 : : private:
4000 : : const gcall *m_call;
4001 : : };
4002 : :
4003 : : /* The core of exploded_graph::process_worklist (the main analysis loop),
4004 : : handling one node in the worklist.
4005 : :
4006 : : Get successor <point, state> pairs for NODE, calling get_or_create on
4007 : : them, and adding an exploded_edge to each successors.
4008 : :
4009 : : Freshly-created nodes will be added to the worklist. */
4010 : :
4011 : : void
4012 : 375920 : exploded_graph::process_node (exploded_node *node)
4013 : : {
4014 : 375920 : logger * const logger = get_logger ();
4015 : 375920 : LOG_FUNC_1 (logger, "EN: %i", node->m_index);
4016 : :
4017 : 375920 : node->set_status (exploded_node::STATUS_PROCESSED);
4018 : :
4019 : 375920 : const program_point &point = node->get_point ();
4020 : :
4021 : : /* Update cfun and input_location in case of an ICE: make it easier to
4022 : : track down which source construct we're failing to handle. */
4023 : 375920 : auto_cfun sentinel (node->get_function ());
4024 : 375920 : const gimple *stmt = point.get_stmt ();
4025 : 375920 : if (stmt)
4026 : 230557 : input_location = stmt->location;
4027 : :
4028 : 375920 : const program_state &state = node->get_state ();
4029 : 375920 : if (logger)
4030 : : {
4031 : 108 : pretty_printer *pp = logger->get_printer ();
4032 : 108 : logger->start_log_line ();
4033 : 108 : pp_string (pp, "point: ");
4034 : 108 : point.print (pp, format (false));
4035 : 108 : pp_string (pp, ", state: ");
4036 : 108 : state.dump_to_pp (m_ext_state, true, false, pp);
4037 : 108 : logger->end_log_line ();
4038 : : }
4039 : :
4040 : 375920 : switch (point.get_kind ())
4041 : : {
4042 : 0 : default:
4043 : 0 : gcc_unreachable ();
4044 : : case PK_ORIGIN:
4045 : : /* This node exists to simplify finding the shortest path
4046 : : to an exploded_node. */
4047 : : break;
4048 : :
4049 : 101193 : case PK_BEFORE_SUPERNODE:
4050 : 101193 : {
4051 : 101193 : program_state next_state (state);
4052 : 101193 : uncertainty_t uncertainty;
4053 : :
4054 : 101193 : if (point.get_from_edge ())
4055 : : {
4056 : 78163 : impl_region_model_context ctxt (*this, node,
4057 : : &state, &next_state,
4058 : 78163 : &uncertainty, NULL, NULL);
4059 : 78163 : const cfg_superedge *last_cfg_superedge
4060 : 78163 : = point.get_from_edge ()->dyn_cast_cfg_superedge ();
4061 : 78163 : if (last_cfg_superedge)
4062 : 78163 : next_state.m_region_model->update_for_phis
4063 : 78163 : (node->get_supernode (),
4064 : : last_cfg_superedge,
4065 : : &ctxt);
4066 : 78163 : program_state::detect_leaks (state, next_state, NULL,
4067 : : get_ext_state (), &ctxt);
4068 : 78163 : }
4069 : :
4070 : 101193 : program_point next_point (point.get_next ());
4071 : 101193 : exploded_node *next = get_or_create_node (next_point, next_state, node);
4072 : 101193 : if (next)
4073 : 100532 : add_edge (node, next, NULL,
4074 : : false); /* Assume no work is done at phi nodes. */
4075 : 101193 : }
4076 : 101193 : break;
4077 : 139191 : case PK_BEFORE_STMT:
4078 : 139191 : {
4079 : : /* Determine the effect of a run of one or more statements
4080 : : within one supernode, generating an edge to the program_point
4081 : : after the last statement that's processed.
4082 : :
4083 : : Stop iterating statements and thus consolidating into one enode
4084 : : when:
4085 : : - reaching the end of the statements in the supernode
4086 : : - if an sm-state-change occurs (so that it gets its own
4087 : : exploded_node)
4088 : : - if "-fanalyzer-fine-grained" is active
4089 : : - encountering certain statements must appear at the start of
4090 : : their enode (for which stmt_requires_new_enode_p returns true)
4091 : :
4092 : : Update next_state in-place, to get the result of the one
4093 : : or more stmts that are processed.
4094 : :
4095 : : Split the node in-place if an sm-state-change occurs, so that
4096 : : the sm-state-change occurs on an edge where the src enode has
4097 : : exactly one stmt, the one that caused the change. */
4098 : 139191 : program_state next_state (state);
4099 : :
4100 : 139191 : impl_path_context path_ctxt (&next_state, logger);
4101 : :
4102 : 139191 : bool could_have_done_work = false;
4103 : 139191 : uncertainty_t uncertainty;
4104 : 139191 : const supernode *snode = point.get_supernode ();
4105 : 139191 : unsigned stmt_idx;
4106 : 139191 : const gimple *prev_stmt = NULL;
4107 : 381451 : for (stmt_idx = point.get_stmt_idx ();
4108 : 762902 : stmt_idx < snode->m_stmts.length ();
4109 : : stmt_idx++)
4110 : : {
4111 : 294800 : const gimple *stmt = snode->m_stmts[stmt_idx];
4112 : :
4113 : 294800 : if (stmt_idx > point.get_stmt_idx ())
4114 : 155609 : if (stmt_requires_new_enode_p (stmt, prev_stmt))
4115 : : {
4116 : 8218 : stmt_idx--;
4117 : 43605 : break;
4118 : : }
4119 : 286582 : prev_stmt = stmt;
4120 : :
4121 : 286582 : program_state old_state (next_state);
4122 : :
4123 : : /* Process the stmt. */
4124 : 286582 : exploded_node::on_stmt_flags flags
4125 : 286582 : = node->on_stmt (*this, snode, stmt, &next_state, &uncertainty,
4126 : : &could_have_done_work, &path_ctxt);
4127 : 286582 : node->m_num_processed_stmts++;
4128 : :
4129 : : /* If flags.m_terminate_path, stop analyzing; any nodes/edges
4130 : : will have been added by on_stmt (e.g. for handling longjmp). */
4131 : 286582 : if (flags.m_terminate_path)
4132 : : return;
4133 : :
4134 : 285613 : if (next_state.m_region_model)
4135 : : {
4136 : 285613 : impl_region_model_context ctxt (*this, node,
4137 : : &old_state, &next_state,
4138 : 285613 : &uncertainty, NULL, stmt);
4139 : 285613 : program_state::detect_leaks (old_state, next_state, NULL,
4140 : : get_ext_state (), &ctxt);
4141 : 285613 : }
4142 : :
4143 : 285613 : unsigned next_idx = stmt_idx + 1;
4144 : 285613 : program_point next_point
4145 : 379927 : = (next_idx < point.get_supernode ()->m_stmts.length ()
4146 : 285613 : ? program_point::before_stmt (point.get_supernode (), next_idx,
4147 : : point.get_call_string ())
4148 : 94314 : : program_point::after_supernode (point.get_supernode (),
4149 : : point.get_call_string ()));
4150 : 571226 : next_state = next_state.prune_for_point (*this, next_point, node,
4151 : 285613 : &uncertainty);
4152 : :
4153 : 285613 : if (flag_analyzer_fine_grained
4154 : 284686 : || state_change_requires_new_enode_p (old_state, next_state)
4155 : 2940 : || path_ctxt.bifurcation_p ()
4156 : 527957 : || path_ctxt.terminate_path_p ())
4157 : : {
4158 : 43353 : program_point split_point
4159 : 43353 : = program_point::before_stmt (point.get_supernode (),
4160 : : stmt_idx,
4161 : : point.get_call_string ());
4162 : 43353 : if (split_point != node->get_point ())
4163 : : {
4164 : : /* If we're not at the start of NODE, split the enode at
4165 : : this stmt, so we have:
4166 : : node -> split_enode
4167 : : so that when split_enode is processed the next edge
4168 : : we add will be:
4169 : : split_enode -> next
4170 : : and any state change will effectively occur on that
4171 : : latter edge, and split_enode will contain just stmt. */
4172 : 7966 : if (logger)
4173 : 5 : logger->log ("getting split_enode");
4174 : 7966 : exploded_node *split_enode
4175 : 7966 : = get_or_create_node (split_point, old_state, node);
4176 : 7966 : if (!split_enode)
4177 : 7966 : return;
4178 : : /* "stmt" will be reprocessed when split_enode is
4179 : : processed. */
4180 : 7966 : node->m_num_processed_stmts--;
4181 : 7966 : if (logger)
4182 : 5 : logger->log ("creating edge to split_enode");
4183 : 7966 : add_edge (node, split_enode, NULL, could_have_done_work);
4184 : 7966 : return;
4185 : : }
4186 : : else
4187 : : /* If we're at the start of NODE, stop iterating,
4188 : : so that an edge will be created from NODE to
4189 : : (next_point, next_state) below. */
4190 : : break;
4191 : : }
4192 : 286582 : }
4193 : 130256 : unsigned next_idx = stmt_idx + 1;
4194 : 130256 : program_point next_point
4195 : 222746 : = (next_idx < point.get_supernode ()->m_stmts.length ()
4196 : 130256 : ? program_point::before_stmt (point.get_supernode (), next_idx,
4197 : : point.get_call_string ())
4198 : 92490 : : program_point::after_supernode (point.get_supernode (),
4199 : : point.get_call_string ()));
4200 : 130256 : if (path_ctxt.terminate_path_p ())
4201 : : {
4202 : 2150 : if (logger)
4203 : 0 : logger->log ("not adding node: terminating path");
4204 : : }
4205 : : else
4206 : : {
4207 : 128106 : exploded_node *next
4208 : 128106 : = get_or_create_node (next_point, next_state, node);
4209 : 128106 : if (next)
4210 : 128106 : add_edge (node, next, NULL, could_have_done_work);
4211 : : }
4212 : :
4213 : : /* If we have custom edge infos, "bifurcate" the state
4214 : : accordingly, potentially creating a new state/enode/eedge
4215 : : instances. For example, to handle a "realloc" call, we
4216 : : might split into 3 states, for the "failure",
4217 : : "resizing in place", and "moving to a new buffer" cases. */
4218 : 139895 : for (auto edge_info_iter : path_ctxt.get_custom_eedge_infos ())
4219 : : {
4220 : : /* Take ownership of the edge infos from the path_ctxt. */
4221 : 5251 : std::unique_ptr<custom_edge_info> edge_info (edge_info_iter);
4222 : 5251 : if (logger)
4223 : : {
4224 : 0 : logger->start_log_line ();
4225 : 0 : logger->log_partial ("bifurcating for edge: ");
4226 : 0 : edge_info->print (logger->get_printer ());
4227 : 0 : logger->end_log_line ();
4228 : : }
4229 : 5251 : program_state bifurcated_new_state
4230 : 5251 : (path_ctxt.get_state_at_bifurcation ());
4231 : :
4232 : : /* Apply edge_info to state. */
4233 : 5251 : impl_region_model_context
4234 : : bifurcation_ctxt (*this,
4235 : : node, // enode_for_diag
4236 : 5251 : &path_ctxt.get_state_at_bifurcation (),
4237 : : &bifurcated_new_state,
4238 : : NULL, // uncertainty_t *uncertainty
4239 : : NULL, // path_context *path_ctxt
4240 : 5251 : stmt);
4241 : 5251 : if (edge_info->update_state (&bifurcated_new_state,
4242 : : NULL, /* no exploded_edge yet. */
4243 : : &bifurcation_ctxt))
4244 : : {
4245 : 4718 : exploded_node *next2
4246 : 4718 : = get_or_create_node (next_point, bifurcated_new_state, node);
4247 : 4718 : if (next2)
4248 : 3779 : add_edge (node, next2, NULL,
4249 : : true /* assume that work could be done */,
4250 : : std::move (edge_info));
4251 : : }
4252 : : else
4253 : : {
4254 : 533 : if (logger)
4255 : 0 : logger->log ("infeasible state, not adding node");
4256 : : }
4257 : 5251 : }
4258 : 139191 : }
4259 : 130256 : break;
4260 : 131758 : case PK_AFTER_SUPERNODE:
4261 : 131758 : {
4262 : 131758 : bool found_a_superedge = false;
4263 : 131758 : bool is_an_exit_block = false;
4264 : : /* If this is an EXIT BB, detect leaks, and potentially
4265 : : create a function summary. */
4266 : 131758 : if (point.get_supernode ()->return_p ())
4267 : : {
4268 : 18904 : is_an_exit_block = true;
4269 : 18904 : node->detect_leaks (*this);
4270 : 18904 : if (flag_analyzer_call_summaries
4271 : 18904 : && point.get_call_string ().empty_p ())
4272 : : {
4273 : : /* TODO: create function summary
4274 : : There can be more than one; each corresponds to a different
4275 : : final enode in the function. */
4276 : 11619 : if (logger)
4277 : : {
4278 : 1 : pretty_printer *pp = logger->get_printer ();
4279 : 1 : logger->start_log_line ();
4280 : 1 : logger->log_partial
4281 : 1 : ("would create function summary for %qE; state: ",
4282 : : point.get_fndecl ());
4283 : 1 : state.dump_to_pp (m_ext_state, true, false, pp);
4284 : 1 : logger->end_log_line ();
4285 : : }
4286 : 11619 : per_function_data *per_fn_data
4287 : 11619 : = get_or_create_per_function_data (point.get_function ());
4288 : 11619 : per_fn_data->add_call_summary (node);
4289 : : }
4290 : : }
4291 : : /* Traverse into successors of the supernode. */
4292 : 131758 : int i;
4293 : 131758 : superedge *succ;
4294 : 305500 : FOR_EACH_VEC_ELT (point.get_supernode ()->m_succs, i, succ)
4295 : : {
4296 : 173742 : found_a_superedge = true;
4297 : 173742 : if (logger)
4298 : : {
4299 : 41 : label_text succ_desc (succ->get_description (false));
4300 : 41 : logger->log ("considering SN: %i -> SN: %i (%s)",
4301 : 41 : succ->m_src->m_index, succ->m_dest->m_index,
4302 : : succ_desc.get ());
4303 : 41 : }
4304 : :
4305 : 173742 : program_point next_point
4306 : 173742 : = program_point::before_supernode (succ->m_dest, succ,
4307 : : point.get_call_string ());
4308 : 173742 : program_state next_state (state);
4309 : 173742 : uncertainty_t uncertainty;
4310 : :
4311 : : /* Make use the current state and try to discover and analyse
4312 : : indirect function calls (a call that doesn't have an underlying
4313 : : cgraph edge representing call).
4314 : :
4315 : : Some examples of such calls are virtual function calls
4316 : : and calls that happen via a function pointer. */
4317 : 173742 : if (succ->m_kind == SUPEREDGE_INTRAPROCEDURAL_CALL
4318 : 173742 : && !(succ->get_any_callgraph_edge ()))
4319 : : {
4320 : 1571 : const gcall *call
4321 : 1571 : = point.get_supernode ()->get_final_call ();
4322 : :
4323 : 1571 : impl_region_model_context ctxt (*this,
4324 : : node,
4325 : : &state,
4326 : : &next_state,
4327 : : &uncertainty,
4328 : : NULL,
4329 : 1571 : point.get_stmt());
4330 : :
4331 : 1571 : region_model *model = state.m_region_model;
4332 : 1571 : bool call_discovered = false;
4333 : :
4334 : 1571 : if (tree fn_decl = model->get_fndecl_for_call (call, &ctxt))
4335 : 190 : call_discovered = maybe_create_dynamic_call (call,
4336 : : fn_decl,
4337 : : node,
4338 : : next_state,
4339 : : next_point,
4340 : : &uncertainty,
4341 : : logger);
4342 : 190 : if (!call_discovered)
4343 : : {
4344 : : /* Check for jump through NULL. */
4345 : 1474 : if (tree fn_ptr = gimple_call_fn (call))
4346 : : {
4347 : 527 : const svalue *fn_ptr_sval
4348 : 527 : = model->get_rvalue (fn_ptr, &ctxt);
4349 : 527 : if (fn_ptr_sval->all_zeroes_p ())
4350 : 20 : ctxt.warn (make_unique<jump_through_null> (call));
4351 : : }
4352 : :
4353 : : /* An unknown function or a special function was called
4354 : : at this point, in such case, don't terminate the
4355 : : analysis of the current function.
4356 : :
4357 : : The analyzer handles calls to such functions while
4358 : : analysing the stmt itself, so the function call
4359 : : must have been handled by the anlyzer till now. */
4360 : 1474 : exploded_node *next
4361 : 1474 : = get_or_create_node (next_point,
4362 : : next_state,
4363 : : node);
4364 : 1474 : if (next)
4365 : 1474 : add_edge (node, next, succ,
4366 : : true /* assume that work is done */);
4367 : : }
4368 : 1571 : }
4369 : :
4370 : 173742 : if (!node->on_edge (*this, succ, &next_point, &next_state,
4371 : : &uncertainty))
4372 : : {
4373 : 32072 : if (logger)
4374 : 0 : logger->log ("skipping impossible edge to SN: %i",
4375 : 0 : succ->m_dest->m_index);
4376 : 32072 : continue;
4377 : : }
4378 : 141670 : exploded_node *next = get_or_create_node (next_point, next_state,
4379 : : node);
4380 : 141670 : if (next)
4381 : : {
4382 : 141666 : add_edge (node, next, succ, false);
4383 : :
4384 : : /* We might have a function entrypoint. */
4385 : 141666 : detect_infinite_recursion (next);
4386 : : }
4387 : 173742 : }
4388 : :
4389 : : /* Return from the calls which doesn't have a return superedge.
4390 : : Such case occurs when GCC's middle end didn't knew which function to
4391 : : call but analyzer did. */
4392 : 131758 : if ((is_an_exit_block && !found_a_superedge)
4393 : 367069 : && (!point.get_call_string ().empty_p ()))
4394 : : {
4395 : 84 : const call_string &cs = point.get_call_string ();
4396 : 84 : program_point next_point
4397 : 84 : = program_point::before_supernode (cs.get_caller_node (),
4398 : : NULL,
4399 : : cs);
4400 : 84 : program_state next_state (state);
4401 : 84 : uncertainty_t uncertainty;
4402 : :
4403 : 84 : const gcall *call
4404 : 84 : = next_point.get_supernode ()->get_returning_call ();
4405 : :
4406 : 84 : if (call)
4407 : 84 : next_state.returning_call (*this, node, call, &uncertainty);
4408 : :
4409 : 84 : if (next_state.m_valid)
4410 : : {
4411 : 84 : next_point.pop_from_call_stack ();
4412 : 84 : exploded_node *enode = get_or_create_node (next_point,
4413 : : next_state,
4414 : : node);
4415 : 84 : if (enode)
4416 : 84 : add_edge (node, enode, NULL, false,
4417 : 168 : make_unique<dynamic_call_info_t> (call, true));
4418 : : }
4419 : 84 : }
4420 : : }
4421 : : break;
4422 : : }
4423 : 375920 : }
4424 : :
4425 : : /* Ensure that this graph has a stats instance for FN, return it.
4426 : : FN can be NULL, in which case a stats instances is returned covering
4427 : : "functionless" parts of the graph (the origin node). */
4428 : :
4429 : : stats *
4430 : 435762 : exploded_graph::get_or_create_function_stats (function *fn)
4431 : : {
4432 : 435762 : if (!fn)
4433 : 3783 : return &m_functionless_stats;
4434 : :
4435 : 431979 : if (stats **slot = m_per_function_stats.get (fn))
4436 : 420520 : return *slot;
4437 : : else
4438 : : {
4439 : 11459 : int num_supernodes = fn ? n_basic_blocks_for_fn (fn) : 0;
4440 : : /* not quite the num supernodes, but nearly. */
4441 : 11459 : stats *new_stats = new stats (num_supernodes);
4442 : 11459 : m_per_function_stats.put (fn, new_stats);
4443 : 11459 : return new_stats;
4444 : : }
4445 : : }
4446 : :
4447 : : /* Print bar charts to PP showing:
4448 : : - the number of enodes per function, and
4449 : : - for each function:
4450 : : - the number of enodes per supernode/BB
4451 : : - the number of excess enodes per supernode/BB beyond the
4452 : : per-program-point limit, if there were any. */
4453 : :
4454 : : void
4455 : 2 : exploded_graph::print_bar_charts (pretty_printer *pp) const
4456 : : {
4457 : 2 : cgraph_node *cgnode;
4458 : :
4459 : 2 : pp_string (pp, "enodes per function:");
4460 : 2 : pp_newline (pp);
4461 : 2 : bar_chart enodes_per_function;
4462 : 4 : FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cgnode)
4463 : : {
4464 : 2 : function *fn = cgnode->get_fun ();
4465 : 2 : const stats * const *s_ptr
4466 : 2 : = const_cast <function_stat_map_t &> (m_per_function_stats).get (fn);
4467 : 4 : enodes_per_function.add_item (function_name (fn),
4468 : 2 : s_ptr ? (*s_ptr)->get_total_enodes () : 0);
4469 : : }
4470 : 2 : enodes_per_function.print (pp);
4471 : :
4472 : : /* Accumulate number of enodes per supernode. */
4473 : 4 : auto_vec<unsigned> enodes_per_supernode (m_sg.num_nodes ());
4474 : 30 : for (int i = 0; i < m_sg.num_nodes (); i++)
4475 : 13 : enodes_per_supernode.quick_push (0);
4476 : : int i;
4477 : : exploded_node *enode;
4478 : 117 : FOR_EACH_VEC_ELT (m_nodes, i, enode)
4479 : : {
4480 : 115 : const supernode *iter_snode = enode->get_supernode ();
4481 : 115 : if (!iter_snode)
4482 : 2 : continue;
4483 : 113 : enodes_per_supernode[iter_snode->m_index]++;
4484 : : }
4485 : :
4486 : : /* Accumulate excess enodes per supernode. */
4487 : 4 : auto_vec<unsigned> excess_enodes_per_supernode (m_sg.num_nodes ());
4488 : 30 : for (int i = 0; i < m_sg.num_nodes (); i++)
4489 : 13 : excess_enodes_per_supernode.quick_push (0);
4490 : 46 : for (point_map_t::iterator iter = m_per_point_data.begin ();
4491 : 90 : iter != m_per_point_data.end (); ++iter)
4492 : : {
4493 : 44 : const program_point *point = (*iter).first;
4494 : 44 : const supernode *iter_snode = point->get_supernode ();
4495 : 44 : if (!iter_snode)
4496 : 2 : continue;
4497 : 42 : const per_program_point_data *point_data = (*iter).second;
4498 : 42 : excess_enodes_per_supernode[iter_snode->m_index]
4499 : 42 : += point_data->m_excess_enodes;
4500 : : }
4501 : :
4502 : : /* Show per-function bar_charts of enodes per supernode/BB. */
4503 : 2 : pp_string (pp, "per-function enodes per supernode/BB:");
4504 : 2 : pp_newline (pp);
4505 : 4 : FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cgnode)
4506 : : {
4507 : 2 : function *fn = cgnode->get_fun ();
4508 : 2 : pp_printf (pp, "function: %qs", function_name (fn));
4509 : 2 : pp_newline (pp);
4510 : :
4511 : 2 : bar_chart enodes_per_snode;
4512 : 2 : bar_chart excess_enodes_per_snode;
4513 : 2 : bool have_excess_enodes = false;
4514 : 30 : for (int i = 0; i < m_sg.num_nodes (); i++)
4515 : : {
4516 : 13 : const supernode *iter_snode = m_sg.get_node_by_index (i);
4517 : 13 : if (iter_snode->get_function () != fn)
4518 : 0 : continue;
4519 : 13 : pretty_printer tmp_pp;
4520 : 13 : pp_printf (&tmp_pp, "sn %i (bb %i)",
4521 : 13 : iter_snode->m_index, iter_snode->m_bb->index);
4522 : 13 : enodes_per_snode.add_item (pp_formatted_text (&tmp_pp),
4523 : 13 : enodes_per_supernode[iter_snode->m_index]);
4524 : 13 : const int num_excess
4525 : 13 : = excess_enodes_per_supernode[iter_snode->m_index];
4526 : 13 : excess_enodes_per_snode.add_item (pp_formatted_text (&tmp_pp),
4527 : : num_excess);
4528 : 13 : if (num_excess)
4529 : 0 : have_excess_enodes = true;
4530 : 13 : }
4531 : 2 : enodes_per_snode.print (pp);
4532 : 2 : if (have_excess_enodes)
4533 : : {
4534 : 0 : pp_printf (pp, "EXCESS ENODES:");
4535 : 0 : pp_newline (pp);
4536 : 0 : excess_enodes_per_snode.print (pp);
4537 : : }
4538 : 2 : }
4539 : 2 : }
4540 : :
4541 : : /* Write all stats information to this graph's logger, if any. */
4542 : :
4543 : : void
4544 : 3783 : exploded_graph::log_stats () const
4545 : : {
4546 : 3783 : logger * const logger = get_logger ();
4547 : 3783 : if (!logger)
4548 : 3781 : return;
4549 : :
4550 : 2 : LOG_SCOPE (logger);
4551 : :
4552 : 2 : m_ext_state.get_engine ()->log_stats (logger);
4553 : :
4554 : 4 : logger->log ("m_sg.num_nodes (): %i", m_sg.num_nodes ());
4555 : 4 : logger->log ("m_nodes.length (): %i", m_nodes.length ());
4556 : 4 : logger->log ("m_edges.length (): %i", m_edges.length ());
4557 : 2 : logger->log ("remaining enodes in worklist: %i", m_worklist.length ());
4558 : :
4559 : 2 : logger->log ("global stats:");
4560 : 2 : m_global_stats.log (logger);
4561 : :
4562 : 2 : for (function_stat_map_t::iterator iter = m_per_function_stats.begin ();
4563 : 8 : iter != m_per_function_stats.end ();
4564 : 2 : ++iter)
4565 : : {
4566 : 2 : function *fn = (*iter).first;
4567 : 2 : log_scope s (logger, function_name (fn));
4568 : 2 : (*iter).second->log (logger);
4569 : 2 : }
4570 : :
4571 : 2 : print_bar_charts (logger->get_printer ());
4572 : 2 : }
4573 : :
4574 : : /* Dump all stats information to OUT. */
4575 : :
4576 : : void
4577 : 0 : exploded_graph::dump_stats (FILE *out) const
4578 : : {
4579 : 0 : fprintf (out, "m_sg.num_nodes (): %i\n", m_sg.num_nodes ());
4580 : 0 : fprintf (out, "m_nodes.length (): %i\n", m_nodes.length ());
4581 : 0 : fprintf (out, "m_edges.length (): %i\n", m_edges.length ());
4582 : 0 : fprintf (out, "remaining enodes in worklist: %i", m_worklist.length ());
4583 : :
4584 : 0 : fprintf (out, "global stats:\n");
4585 : 0 : m_global_stats.dump (out);
4586 : :
4587 : 0 : for (function_stat_map_t::iterator iter = m_per_function_stats.begin ();
4588 : 0 : iter != m_per_function_stats.end ();
4589 : 0 : ++iter)
4590 : : {
4591 : 0 : function *fn = (*iter).first;
4592 : 0 : fprintf (out, "function: %s\n", function_name (fn));
4593 : 0 : (*iter).second->dump (out);
4594 : : }
4595 : :
4596 : 0 : fprintf (out, "PK_AFTER_SUPERNODE per supernode:\n");
4597 : 0 : for (unsigned i = 0; i < m_PK_AFTER_SUPERNODE_per_snode.length (); i++)
4598 : 0 : fprintf (out, " SN %i: %3i\n", i, m_PK_AFTER_SUPERNODE_per_snode[i]);
4599 : 0 : }
4600 : :
4601 : : void
4602 : 0 : exploded_graph::dump_states_for_supernode (FILE *out,
4603 : : const supernode *snode) const
4604 : : {
4605 : 0 : fprintf (out, "PK_AFTER_SUPERNODE nodes for SN: %i\n", snode->m_index);
4606 : 0 : int i;
4607 : 0 : exploded_node *enode;
4608 : 0 : int state_idx = 0;
4609 : 0 : FOR_EACH_VEC_ELT (m_nodes, i, enode)
4610 : : {
4611 : 0 : const supernode *iter_snode = enode->get_supernode ();
4612 : 0 : if (enode->get_point ().get_kind () == PK_AFTER_SUPERNODE
4613 : 0 : && iter_snode == snode)
4614 : : {
4615 : 0 : pretty_printer pp;
4616 : 0 : pp_format_decoder (&pp) = default_tree_printer;
4617 : 0 : enode->get_state ().dump_to_pp (m_ext_state, true, false, &pp);
4618 : 0 : fprintf (out, "state %i: EN: %i\n %s\n",
4619 : 0 : state_idx++, enode->m_index,
4620 : : pp_formatted_text (&pp));
4621 : 0 : }
4622 : : }
4623 : 0 : fprintf (out, "#exploded_node for PK_AFTER_SUPERNODE for SN: %i = %i\n",
4624 : 0 : snode->m_index, state_idx);
4625 : 0 : }
4626 : :
4627 : : /* Return a new json::object of the form
4628 : : {"nodes" : [objs for enodes],
4629 : : "edges" : [objs for eedges],
4630 : : "ext_state": object for extrinsic_state,
4631 : : "diagnostic_manager": object for diagnostic_manager}. */
4632 : :
4633 : : json::object *
4634 : 0 : exploded_graph::to_json () const
4635 : : {
4636 : 0 : json::object *egraph_obj = new json::object ();
4637 : :
4638 : : /* Nodes. */
4639 : 0 : {
4640 : 0 : json::array *nodes_arr = new json::array ();
4641 : 0 : unsigned i;
4642 : 0 : exploded_node *n;
4643 : 0 : FOR_EACH_VEC_ELT (m_nodes, i, n)
4644 : 0 : nodes_arr->append (n->to_json (m_ext_state));
4645 : 0 : egraph_obj->set ("nodes", nodes_arr);
4646 : : }
4647 : :
4648 : : /* Edges. */
4649 : 0 : {
4650 : 0 : json::array *edges_arr = new json::array ();
4651 : 0 : unsigned i;
4652 : 0 : exploded_edge *n;
4653 : 0 : FOR_EACH_VEC_ELT (m_edges, i, n)
4654 : 0 : edges_arr->append (n->to_json ());
4655 : 0 : egraph_obj->set ("edges", edges_arr);
4656 : : }
4657 : :
4658 : : /* m_sg is JSONified at the top-level. */
4659 : :
4660 : 0 : egraph_obj->set ("ext_state", m_ext_state.to_json ());
4661 : 0 : egraph_obj->set ("worklist", m_worklist.to_json ());
4662 : 0 : egraph_obj->set ("diagnostic_manager", m_diagnostic_manager.to_json ());
4663 : :
4664 : : /* The following fields aren't yet being JSONified:
4665 : : const state_purge_map *const m_purge_map;
4666 : : const analysis_plan &m_plan;
4667 : : stats m_global_stats;
4668 : : function_stat_map_t m_per_function_stats;
4669 : : stats m_functionless_stats;
4670 : : call_string_data_map_t m_per_call_string_data;
4671 : : auto_vec<int> m_PK_AFTER_SUPERNODE_per_snode; */
4672 : :
4673 : 0 : return egraph_obj;
4674 : : }
4675 : :
4676 : : /* class exploded_path. */
4677 : :
4678 : : /* Copy ctor. */
4679 : :
4680 : 5 : exploded_path::exploded_path (const exploded_path &other)
4681 : 10 : : m_edges (other.m_edges.length ())
4682 : : {
4683 : 5 : int i;
4684 : 5 : const exploded_edge *eedge;
4685 : 90 : FOR_EACH_VEC_ELT (other.m_edges, i, eedge)
4686 : 80 : m_edges.quick_push (eedge);
4687 : 5 : }
4688 : :
4689 : : /* Look for the last use of SEARCH_STMT within this path.
4690 : : If found write the edge's index to *OUT_IDX and return true, otherwise
4691 : : return false. */
4692 : :
4693 : : bool
4694 : 932 : exploded_path::find_stmt_backwards (const gimple *search_stmt,
4695 : : int *out_idx) const
4696 : : {
4697 : 932 : int i;
4698 : 932 : const exploded_edge *eedge;
4699 : 21212 : FOR_EACH_VEC_ELT_REVERSE (m_edges, i, eedge)
4700 : : {
4701 : 20222 : const exploded_node *dst_node = eedge->m_dest;
4702 : 20222 : const program_point &dst_point = dst_node->get_point ();
4703 : 20222 : const gimple *stmt = dst_point.get_stmt ();
4704 : 20222 : if (stmt == search_stmt)
4705 : : {
4706 : 874 : *out_idx = i;
4707 : 874 : return true;
4708 : : }
4709 : : }
4710 : : return false;
4711 : : }
4712 : :
4713 : : /* Get the final exploded_node in this path, which must be non-empty. */
4714 : :
4715 : : exploded_node *
4716 : 13533 : exploded_path::get_final_enode () const
4717 : : {
4718 : 13533 : gcc_assert (m_edges.length () > 0);
4719 : 13533 : return m_edges[m_edges.length () - 1]->m_dest;
4720 : : }
4721 : :
4722 : : /* Check state along this path, returning true if it is feasible.
4723 : : If OUT is non-NULL, and the path is infeasible, write a new
4724 : : feasibility_problem to *OUT. */
4725 : :
4726 : : bool
4727 : 5 : exploded_path::feasible_p (logger *logger,
4728 : : std::unique_ptr<feasibility_problem> *out,
4729 : : engine *eng, const exploded_graph *eg) const
4730 : : {
4731 : 5 : LOG_SCOPE (logger);
4732 : :
4733 : 5 : feasibility_state state (eng->get_model_manager (),
4734 : 5 : eg->get_supergraph ());
4735 : :
4736 : : /* Traverse the path, updating this state. */
4737 : 150 : for (unsigned edge_idx = 0; edge_idx < m_edges.length (); edge_idx++)
4738 : : {
4739 : 75 : const exploded_edge *eedge = m_edges[edge_idx];
4740 : 75 : if (logger)
4741 : 0 : logger->log ("considering edge %i: EN:%i -> EN:%i",
4742 : : edge_idx,
4743 : 0 : eedge->m_src->m_index,
4744 : 0 : eedge->m_dest->m_index);
4745 : :
4746 : 75 : std::unique_ptr <rejected_constraint> rc;
4747 : 75 : if (!state.maybe_update_for_edge (logger, eedge, nullptr, &rc))
4748 : : {
4749 : 5 : gcc_assert (rc);
4750 : 5 : if (out)
4751 : : {
4752 : 5 : const exploded_node &src_enode = *eedge->m_src;
4753 : 5 : const program_point &src_point = src_enode.get_point ();
4754 : 5 : const gimple *last_stmt
4755 : 5 : = src_point.get_supernode ()->get_last_stmt ();
4756 : 10 : *out = ::make_unique<feasibility_problem> (edge_idx, *eedge,
4757 : : last_stmt,
4758 : 5 : std::move (rc));
4759 : : }
4760 : 5 : return false;
4761 : : }
4762 : :
4763 : 70 : if (logger)
4764 : : {
4765 : 0 : logger->log ("state after edge %i: EN:%i -> EN:%i",
4766 : : edge_idx,
4767 : 0 : eedge->m_src->m_index,
4768 : 0 : eedge->m_dest->m_index);
4769 : 0 : logger->start_log_line ();
4770 : 0 : state.get_model ().dump_to_pp (logger->get_printer (), true, false);
4771 : 0 : logger->end_log_line ();
4772 : : }
4773 : 75 : }
4774 : :
4775 : 0 : return true;
4776 : 5 : }
4777 : :
4778 : : /* Dump this path in multiline form to PP.
4779 : : If EXT_STATE is non-NULL, then show the nodes. */
4780 : :
4781 : : void
4782 : 0 : exploded_path::dump_to_pp (pretty_printer *pp,
4783 : : const extrinsic_state *ext_state) const
4784 : : {
4785 : 0 : for (unsigned i = 0; i < m_edges.length (); i++)
4786 : : {
4787 : 0 : const exploded_edge *eedge = m_edges[i];
4788 : 0 : pp_printf (pp, "m_edges[%i]: EN %i -> EN %i",
4789 : : i,
4790 : 0 : eedge->m_src->m_index,
4791 : 0 : eedge->m_dest->m_index);
4792 : 0 : pp_newline (pp);
4793 : :
4794 : 0 : if (ext_state)
4795 : 0 : eedge->m_dest->dump_to_pp (pp, *ext_state);
4796 : : }
4797 : 0 : }
4798 : :
4799 : : /* Dump this path in multiline form to FP. */
4800 : :
4801 : : void
4802 : 0 : exploded_path::dump (FILE *fp, const extrinsic_state *ext_state) const
4803 : : {
4804 : 0 : pretty_printer pp;
4805 : 0 : pp_format_decoder (&pp) = default_tree_printer;
4806 : 0 : pp_show_color (&pp) = pp_show_color (global_dc->printer);
4807 : 0 : pp.buffer->stream = fp;
4808 : 0 : dump_to_pp (&pp, ext_state);
4809 : 0 : pp_flush (&pp);
4810 : 0 : }
4811 : :
4812 : : /* Dump this path in multiline form to stderr. */
4813 : :
4814 : : DEBUG_FUNCTION void
4815 : 0 : exploded_path::dump (const extrinsic_state *ext_state) const
4816 : : {
4817 : 0 : dump (stderr, ext_state);
4818 : 0 : }
4819 : :
4820 : : /* Dump this path verbosely to FILENAME. */
4821 : :
4822 : : void
4823 : 0 : exploded_path::dump_to_file (const char *filename,
4824 : : const extrinsic_state &ext_state) const
4825 : : {
4826 : 0 : FILE *fp = fopen (filename, "w");
4827 : 0 : if (!fp)
4828 : 0 : return;
4829 : 0 : pretty_printer pp;
4830 : 0 : pp_format_decoder (&pp) = default_tree_printer;
4831 : 0 : pp.buffer->stream = fp;
4832 : 0 : dump_to_pp (&pp, &ext_state);
4833 : 0 : pp_flush (&pp);
4834 : 0 : fclose (fp);
4835 : 0 : }
4836 : :
4837 : : /* class feasibility_problem. */
4838 : :
4839 : : void
4840 : 5 : feasibility_problem::dump_to_pp (pretty_printer *pp) const
4841 : : {
4842 : 5 : pp_printf (pp, "edge from EN: %i to EN: %i",
4843 : 5 : m_eedge.m_src->m_index, m_eedge.m_dest->m_index);
4844 : 5 : if (m_rc)
4845 : : {
4846 : 5 : pp_string (pp, "; rejected constraint: ");
4847 : 5 : m_rc->dump_to_pp (pp);
4848 : 5 : pp_string (pp, "; rmodel: ");
4849 : 5 : m_rc->get_model ().dump_to_pp (pp, true, false);
4850 : : }
4851 : 5 : }
4852 : :
4853 : : /* class feasibility_state. */
4854 : :
4855 : : /* Ctor for feasibility_state, at the beginning of a path. */
4856 : :
4857 : 7773 : feasibility_state::feasibility_state (region_model_manager *manager,
4858 : 7773 : const supergraph &sg)
4859 : 7773 : : m_model (manager),
4860 : 15546 : m_snodes_visited (sg.m_nodes.length ())
4861 : : {
4862 : 7773 : bitmap_clear (m_snodes_visited);
4863 : 7773 : }
4864 : :
4865 : : /* Copy ctor for feasibility_state, for extending a path. */
4866 : :
4867 : 446857 : feasibility_state::feasibility_state (const feasibility_state &other)
4868 : 446857 : : m_model (other.m_model),
4869 : 446857 : m_snodes_visited (const_sbitmap (other.m_snodes_visited)->n_bits)
4870 : : {
4871 : 446857 : bitmap_copy (m_snodes_visited, other.m_snodes_visited);
4872 : 446857 : }
4873 : :
4874 : 5955 : feasibility_state::feasibility_state (const region_model &model,
4875 : 5955 : const supergraph &sg)
4876 : 5955 : : m_model (model),
4877 : 11910 : m_snodes_visited (sg.m_nodes.length ())
4878 : : {
4879 : 5955 : bitmap_clear (m_snodes_visited);
4880 : 5955 : }
4881 : :
4882 : : feasibility_state &
4883 : 18853 : feasibility_state::operator= (const feasibility_state &other)
4884 : : {
4885 : 18853 : m_model = other.m_model;
4886 : 18853 : bitmap_copy (m_snodes_visited, other.m_snodes_visited);
4887 : 18853 : return *this;
4888 : : }
4889 : :
4890 : : /* The heart of feasibility-checking.
4891 : :
4892 : : Attempt to update this state in-place based on traversing EEDGE
4893 : : in a path.
4894 : : Update the model for the stmts in the src enode.
4895 : : Attempt to add constraints for EEDGE.
4896 : :
4897 : : If feasible, return true.
4898 : : Otherwise, return false and write to *OUT_RC. */
4899 : :
4900 : : bool
4901 : 211932 : feasibility_state::
4902 : : maybe_update_for_edge (logger *logger,
4903 : : const exploded_edge *eedge,
4904 : : region_model_context *ctxt,
4905 : : std::unique_ptr<rejected_constraint> *out_rc)
4906 : : {
4907 : 211932 : const exploded_node &src_enode = *eedge->m_src;
4908 : 211932 : const program_point &src_point = src_enode.get_point ();
4909 : 211932 : if (logger)
4910 : : {
4911 : 27 : logger->start_log_line ();
4912 : 27 : src_point.print (logger->get_printer (), format (false));
4913 : 27 : logger->end_log_line ();
4914 : : }
4915 : :
4916 : : /* Update state for the stmts that were processed in each enode. */
4917 : 342792 : for (unsigned stmt_idx = 0; stmt_idx < src_enode.m_num_processed_stmts;
4918 : : stmt_idx++)
4919 : : {
4920 : 130860 : const gimple *stmt = src_enode.get_processed_stmt (stmt_idx);
4921 : :
4922 : : /* Update cfun and input_location in case of ICE: make it easier to
4923 : : track down which source construct we're failing to handle. */
4924 : 130860 : auto_cfun sentinel (src_point.get_function ());
4925 : 130860 : input_location = stmt->location;
4926 : :
4927 : 130860 : update_for_stmt (stmt);
4928 : : }
4929 : :
4930 : 211932 : const superedge *sedge = eedge->m_sedge;
4931 : 211932 : if (sedge)
4932 : : {
4933 : 66190 : if (logger)
4934 : : {
4935 : 6 : label_text desc (sedge->get_description (false));
4936 : 6 : logger->log (" sedge: SN:%i -> SN:%i %s",
4937 : 6 : sedge->m_src->m_index,
4938 : 6 : sedge->m_dest->m_index,
4939 : : desc.get ());
4940 : 6 : }
4941 : :
4942 : 66190 : const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
4943 : 66190 : if (!m_model.maybe_update_for_edge (*sedge, last_stmt, ctxt, out_rc))
4944 : : {
4945 : 6829 : if (logger)
4946 : : {
4947 : 6 : logger->start_log_line ();
4948 : 6 : logger->log_partial ("rejecting due to region model: ");
4949 : 6 : m_model.dump_to_pp (logger->get_printer (), true, false);
4950 : 6 : logger->end_log_line ();
4951 : : }
4952 : 6829 : return false;
4953 : : }
4954 : : }
4955 : : else
4956 : : {
4957 : : /* Special-case the initial eedge from the origin node to the
4958 : : initial function by pushing a frame for it. */
4959 : 145742 : if (src_point.get_kind () == PK_ORIGIN)
4960 : : {
4961 : 7773 : gcc_assert (eedge->m_src->m_index == 0);
4962 : 7773 : gcc_assert (eedge->m_dest->get_point ().get_kind ()
4963 : : == PK_BEFORE_SUPERNODE);
4964 : 7773 : function *fun = eedge->m_dest->get_function ();
4965 : 7773 : gcc_assert (fun);
4966 : 7773 : m_model.push_frame (*fun, NULL, ctxt);
4967 : 7773 : if (logger)
4968 : 0 : logger->log (" pushing frame for %qD", fun->decl);
4969 : : }
4970 : 137969 : else if (eedge->m_custom_info)
4971 : : {
4972 : 3274 : eedge->m_custom_info->update_model (&m_model, eedge, ctxt);
4973 : : }
4974 : : }
4975 : :
4976 : : /* Handle phi nodes on an edge leaving a PK_BEFORE_SUPERNODE (to
4977 : : a PK_BEFORE_STMT, or a PK_AFTER_SUPERNODE if no stmts).
4978 : : This will typically not be associated with a superedge. */
4979 : 205103 : if (src_point.get_from_edge ())
4980 : : {
4981 : 53491 : const cfg_superedge *last_cfg_superedge
4982 : 53491 : = src_point.get_from_edge ()->dyn_cast_cfg_superedge ();
4983 : 53491 : const exploded_node &dst_enode = *eedge->m_dest;
4984 : 53491 : const unsigned dst_snode_idx = dst_enode.get_supernode ()->m_index;
4985 : 53491 : if (last_cfg_superedge)
4986 : : {
4987 : 53491 : if (logger)
4988 : 9 : logger->log (" update for phis");
4989 : 53491 : m_model.update_for_phis (src_enode.get_supernode (),
4990 : : last_cfg_superedge,
4991 : : ctxt);
4992 : : /* If we've entering an snode that we've already visited on this
4993 : : epath, then we need do fix things up for loops; see the
4994 : : comment for store::loop_replay_fixup.
4995 : : Perhaps we should probably also verify the callstring,
4996 : : and track program_points, but hopefully doing it by supernode
4997 : : is good enough. */
4998 : 53491 : if (bitmap_bit_p (m_snodes_visited, dst_snode_idx))
4999 : 11085 : m_model.loop_replay_fixup (dst_enode.get_state ().m_region_model);
5000 : : }
5001 : 53491 : bitmap_set_bit (m_snodes_visited, dst_snode_idx);
5002 : : }
5003 : : return true;
5004 : : }
5005 : :
5006 : : /* Update this object for the effects of STMT. */
5007 : :
5008 : : void
5009 : 132514 : feasibility_state::update_for_stmt (const gimple *stmt)
5010 : : {
5011 : 132514 : if (const gassign *assign = dyn_cast <const gassign *> (stmt))
5012 : 69938 : m_model.on_assignment (assign, NULL);
5013 : 62576 : else if (const gasm *asm_stmt = dyn_cast <const gasm *> (stmt))
5014 : 42 : m_model.on_asm_stmt (asm_stmt, NULL);
5015 : 62534 : else if (const gcall *call = dyn_cast <const gcall *> (stmt))
5016 : : {
5017 : 30439 : bool unknown_side_effects = m_model.on_call_pre (call, NULL);
5018 : 30439 : m_model.on_call_post (call, unknown_side_effects, NULL);
5019 : : }
5020 : 32095 : else if (const greturn *return_ = dyn_cast <const greturn *> (stmt))
5021 : 3516 : m_model.on_return (return_, NULL);
5022 : 132514 : }
5023 : :
5024 : : /* Dump this object to PP. */
5025 : :
5026 : : void
5027 : 145 : feasibility_state::dump_to_pp (pretty_printer *pp,
5028 : : bool simple, bool multiline) const
5029 : : {
5030 : 145 : m_model.dump_to_pp (pp, simple, multiline);
5031 : 145 : }
5032 : :
5033 : : /* A family of cluster subclasses for use when generating .dot output for
5034 : : exploded graphs (-fdump-analyzer-exploded-graph), for grouping the
5035 : : enodes into hierarchical boxes.
5036 : :
5037 : : All functionless enodes appear in the top-level graph.
5038 : : Every (function, call_string) pair gets its own cluster. Within that
5039 : : cluster, each supernode gets its own cluster.
5040 : :
5041 : : Hence all enodes relating to a particular function with a particular
5042 : : callstring will be in a cluster together; all enodes for the same
5043 : : function but with a different callstring will be in a different
5044 : : cluster. */
5045 : :
5046 : : /* Base class of cluster for clustering exploded_node instances in .dot
5047 : : output, based on various subclass-specific criteria. */
5048 : :
5049 : 1745 : class exploded_cluster : public cluster<eg_traits>
5050 : : {
5051 : : };
5052 : :
5053 : : /* Cluster containing all exploded_node instances for one supernode. */
5054 : :
5055 : : class supernode_cluster : public exploded_cluster
5056 : : {
5057 : : public:
5058 : 580 : supernode_cluster (const supernode *supernode) : m_supernode (supernode) {}
5059 : :
5060 : : // TODO: dtor?
5061 : :
5062 : 580 : void dump_dot (graphviz_out *gv, const dump_args_t &args) const final override
5063 : : {
5064 : 580 : gv->println ("subgraph \"cluster_supernode_%i\" {", m_supernode->m_index);
5065 : 580 : gv->indent ();
5066 : 580 : gv->println ("style=\"dashed\";");
5067 : 1160 : gv->println ("label=\"SN: %i (bb: %i; scc: %i)\";",
5068 : 580 : m_supernode->m_index, m_supernode->m_bb->index,
5069 : 580 : args.m_eg.get_scc_id (*m_supernode));
5070 : :
5071 : 580 : int i;
5072 : 580 : exploded_node *enode;
5073 : 1740 : FOR_EACH_VEC_ELT (m_enodes, i, enode)
5074 : 580 : enode->dump_dot (gv, args);
5075 : :
5076 : : /* Terminate subgraph. */
5077 : 580 : gv->outdent ();
5078 : 580 : gv->println ("}");
5079 : 580 : }
5080 : :
5081 : 580 : void add_node (exploded_node *en) final override
5082 : : {
5083 : 0 : m_enodes.safe_push (en);
5084 : 0 : }
5085 : :
5086 : : /* Comparator for use by auto_vec<supernode_cluster *>::qsort. */
5087 : :
5088 : 0 : static int cmp_ptr_ptr (const void *p1, const void *p2)
5089 : : {
5090 : 0 : const supernode_cluster *c1
5091 : : = *(const supernode_cluster * const *)p1;
5092 : 0 : const supernode_cluster *c2
5093 : : = *(const supernode_cluster * const *)p2;
5094 : 0 : return c1->m_supernode->m_index - c2->m_supernode->m_index;
5095 : : }
5096 : :
5097 : : private:
5098 : : const supernode *m_supernode;
5099 : : auto_vec <exploded_node *> m_enodes;
5100 : : };
5101 : :
5102 : : /* Cluster containing all supernode_cluster instances for one
5103 : : (function, call_string) pair. */
5104 : :
5105 : : class function_call_string_cluster : public exploded_cluster
5106 : : {
5107 : : public:
5108 : 580 : function_call_string_cluster (function *fun, const call_string &cs)
5109 : 580 : : m_fun (fun), m_cs (cs) {}
5110 : :
5111 : 1160 : ~function_call_string_cluster ()
5112 : 580 : {
5113 : 580 : for (map_t::iterator iter = m_map.begin ();
5114 : 2320 : iter != m_map.end ();
5115 : 580 : ++iter)
5116 : 580 : delete (*iter).second;
5117 : 1160 : }
5118 : :
5119 : 580 : void dump_dot (graphviz_out *gv, const dump_args_t &args) const final override
5120 : : {
5121 : 580 : const char *funcname = function_name (m_fun);
5122 : :
5123 : 1160 : gv->println ("subgraph \"cluster_function_%s\" {",
5124 : 580 : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (m_fun->decl)));
5125 : 580 : gv->indent ();
5126 : 580 : gv->write_indent ();
5127 : 580 : gv->print ("label=\"call string: ");
5128 : 580 : m_cs.print (gv->get_pp ());
5129 : 580 : gv->print (" function: %s \";", funcname);
5130 : 580 : gv->print ("\n");
5131 : :
5132 : : /* Dump m_map, sorting it to avoid churn when comparing dumps. */
5133 : 580 : auto_vec<supernode_cluster *> child_clusters (m_map.elements ());
5134 : 580 : for (map_t::iterator iter = m_map.begin ();
5135 : 2320 : iter != m_map.end ();
5136 : 580 : ++iter)
5137 : 580 : child_clusters.quick_push ((*iter).second);
5138 : :
5139 : 580 : child_clusters.qsort (supernode_cluster::cmp_ptr_ptr);
5140 : :
5141 : : unsigned i;
5142 : : supernode_cluster *child_cluster;
5143 : 1160 : FOR_EACH_VEC_ELT (child_clusters, i, child_cluster)
5144 : 580 : child_cluster->dump_dot (gv, args);
5145 : :
5146 : : /* Terminate subgraph. */
5147 : 580 : gv->outdent ();
5148 : 580 : gv->println ("}");
5149 : 580 : }
5150 : :
5151 : 580 : void add_node (exploded_node *en) final override
5152 : : {
5153 : 580 : const supernode *supernode = en->get_supernode ();
5154 : 580 : gcc_assert (supernode);
5155 : 580 : supernode_cluster **slot = m_map.get (supernode);
5156 : 580 : if (slot)
5157 : 0 : (*slot)->add_node (en);
5158 : : else
5159 : : {
5160 : 580 : supernode_cluster *child = new supernode_cluster (supernode);
5161 : 580 : m_map.put (supernode, child);
5162 : 580 : child->add_node (en);
5163 : : }
5164 : 580 : }
5165 : :
5166 : : /* Comparator for use by auto_vec<function_call_string_cluster *>. */
5167 : :
5168 : 24680 : static int cmp_ptr_ptr (const void *p1, const void *p2)
5169 : : {
5170 : 24680 : const function_call_string_cluster *c1
5171 : : = *(const function_call_string_cluster * const *)p1;
5172 : 24680 : const function_call_string_cluster *c2
5173 : : = *(const function_call_string_cluster * const *)p2;
5174 : 49360 : if (int cmp_names
5175 : 24680 : = strcmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (c1->m_fun->decl)),
5176 : 24680 : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (c2->m_fun->decl))))
5177 : : return cmp_names;
5178 : 9085 : return call_string::cmp (c1->m_cs, c2->m_cs);
5179 : : }
5180 : :
5181 : : private:
5182 : : function *m_fun;
5183 : : const call_string &m_cs;
5184 : : typedef ordered_hash_map<const supernode *, supernode_cluster *> map_t;
5185 : : map_t m_map;
5186 : : };
5187 : :
5188 : : /* Keys for root_cluster. */
5189 : :
5190 : : struct function_call_string
5191 : : {
5192 : 580 : function_call_string (function *fun, const call_string *cs)
5193 : 580 : : m_fun (fun), m_cs (cs)
5194 : : {
5195 : 580 : gcc_assert (fun);
5196 : 580 : gcc_assert (cs);
5197 : 580 : }
5198 : :
5199 : : function *m_fun;
5200 : : const call_string *m_cs;
5201 : : };
5202 : :
5203 : : } // namespace ana
5204 : :
5205 : : template <> struct default_hash_traits<function_call_string>
5206 : : : public pod_hash_traits<function_call_string>
5207 : : {
5208 : : static const bool empty_zero_p = false;
5209 : : };
5210 : :
5211 : : template <>
5212 : : inline hashval_t
5213 : 8478 : pod_hash_traits<function_call_string>::hash (value_type v)
5214 : : {
5215 : 8478 : return (pointer_hash <function>::hash (v.m_fun)
5216 : 8478 : ^ pointer_hash <const call_string>::hash (v.m_cs));
5217 : : }
5218 : :
5219 : : template <>
5220 : : inline bool
5221 : 34035 : pod_hash_traits<function_call_string>::equal (const value_type &existing,
5222 : : const value_type &candidate)
5223 : : {
5224 : 34035 : return existing.m_fun == candidate.m_fun && &existing.m_cs == &candidate.m_cs;
5225 : : }
5226 : : template <>
5227 : : inline void
5228 : : pod_hash_traits<function_call_string>::mark_deleted (value_type &v)
5229 : : {
5230 : : v.m_fun = reinterpret_cast<function *> (1);
5231 : : }
5232 : : template <>
5233 : : inline void
5234 : 2415 : pod_hash_traits<function_call_string>::mark_empty (value_type &v)
5235 : : {
5236 : 2415 : v.m_fun = NULL;
5237 : : }
5238 : : template <>
5239 : : inline bool
5240 : 54966 : pod_hash_traits<function_call_string>::is_deleted (value_type v)
5241 : : {
5242 : 54966 : return v.m_fun == reinterpret_cast<function *> (1);
5243 : : }
5244 : : template <>
5245 : : inline bool
5246 : 122339 : pod_hash_traits<function_call_string>::is_empty (value_type v)
5247 : : {
5248 : 121759 : return v.m_fun == NULL;
5249 : : }
5250 : :
5251 : : namespace ana {
5252 : :
5253 : : /* Top-level cluster for generating .dot output for exploded graphs,
5254 : : handling the functionless nodes, and grouping the remaining nodes by
5255 : : callstring. */
5256 : :
5257 : : class root_cluster : public exploded_cluster
5258 : : {
5259 : : public:
5260 : 5 : ~root_cluster ()
5261 : 5 : {
5262 : 585 : for (map_t::iterator iter = m_map.begin ();
5263 : 585 : iter != m_map.end ();
5264 : 580 : ++iter)
5265 : 580 : delete (*iter).second;
5266 : 5 : }
5267 : :
5268 : 5 : void dump_dot (graphviz_out *gv, const dump_args_t &args) const final override
5269 : : {
5270 : 5 : int i;
5271 : 5 : exploded_node *enode;
5272 : 10 : FOR_EACH_VEC_ELT (m_functionless_enodes, i, enode)
5273 : 5 : enode->dump_dot (gv, args);
5274 : :
5275 : : /* Dump m_map, sorting it to avoid churn when comparing dumps. */
5276 : 5 : auto_vec<function_call_string_cluster *> child_clusters (m_map.elements ());
5277 : 5 : for (map_t::iterator iter = m_map.begin ();
5278 : 585 : iter != m_map.end ();
5279 : 580 : ++iter)
5280 : 580 : child_clusters.quick_push ((*iter).second);
5281 : :
5282 : 5 : child_clusters.qsort (function_call_string_cluster::cmp_ptr_ptr);
5283 : :
5284 : : function_call_string_cluster *child_cluster;
5285 : 590 : FOR_EACH_VEC_ELT (child_clusters, i, child_cluster)
5286 : 580 : child_cluster->dump_dot (gv, args);
5287 : 5 : }
5288 : :
5289 : 585 : void add_node (exploded_node *en) final override
5290 : : {
5291 : 585 : function *fun = en->get_function ();
5292 : 585 : if (!fun)
5293 : : {
5294 : 5 : m_functionless_enodes.safe_push (en);
5295 : 5 : return;
5296 : : }
5297 : :
5298 : 580 : const call_string &cs = en->get_point ().get_call_string ();
5299 : 580 : function_call_string key (fun, &cs);
5300 : 580 : function_call_string_cluster **slot = m_map.get (key);
5301 : 580 : if (slot)
5302 : 0 : (*slot)->add_node (en);
5303 : : else
5304 : : {
5305 : 580 : function_call_string_cluster *child
5306 : 580 : = new function_call_string_cluster (fun, cs);
5307 : 580 : m_map.put (key, child);
5308 : 580 : child->add_node (en);
5309 : : }
5310 : : }
5311 : :
5312 : : private:
5313 : : typedef hash_map<function_call_string, function_call_string_cluster *> map_t;
5314 : : map_t m_map;
5315 : :
5316 : : /* This should just be the origin exploded_node. */
5317 : : auto_vec <exploded_node *> m_functionless_enodes;
5318 : : };
5319 : :
5320 : : /* Subclass of range_label for use within
5321 : : exploded_graph::dump_exploded_nodes for implementing
5322 : : -fdump-analyzer-exploded-nodes: a label for a specific
5323 : : exploded_node. */
5324 : :
5325 : : class enode_label : public range_label
5326 : : {
5327 : : public:
5328 : 0 : enode_label (const extrinsic_state &ext_state,
5329 : : exploded_node *enode)
5330 : 0 : : m_ext_state (ext_state), m_enode (enode) {}
5331 : :
5332 : 0 : label_text get_text (unsigned) const final override
5333 : : {
5334 : 0 : pretty_printer pp;
5335 : 0 : pp_format_decoder (&pp) = default_tree_printer;
5336 : 0 : m_enode->get_state ().dump_to_pp (m_ext_state, true, false, &pp);
5337 : 0 : return make_label_text (false, "EN: %i: %s",
5338 : 0 : m_enode->m_index, pp_formatted_text (&pp));
5339 : 0 : }
5340 : :
5341 : : private:
5342 : : const extrinsic_state &m_ext_state;
5343 : : exploded_node *m_enode;
5344 : : };
5345 : :
5346 : : /* Postprocessing support for dumping the exploded nodes.
5347 : : Handle -fdump-analyzer-exploded-nodes,
5348 : : -fdump-analyzer-exploded-nodes-2, and the
5349 : : "__analyzer_dump_exploded_nodes" builtin. */
5350 : :
5351 : : void
5352 : 3783 : exploded_graph::dump_exploded_nodes () const
5353 : : {
5354 : : // TODO
5355 : : /* Locate calls to __analyzer_dump_exploded_nodes. */
5356 : : // Print how many egs there are for them?
5357 : : /* Better: log them as we go, and record the exploded nodes
5358 : : in question. */
5359 : :
5360 : : /* Show every enode. */
5361 : :
5362 : : /* Gather them by stmt, so that we can more clearly see the
5363 : : "hotspots" requiring numerous exploded nodes. */
5364 : :
5365 : : /* Alternatively, simply throw them all into one big rich_location
5366 : : and see if the label-printing will sort it out...
5367 : : This requires them all to be in the same source file. */
5368 : :
5369 : 3783 : if (flag_dump_analyzer_exploded_nodes)
5370 : : {
5371 : 0 : auto_timevar tv (TV_ANALYZER_DUMP);
5372 : 0 : gcc_rich_location richloc (UNKNOWN_LOCATION);
5373 : 0 : unsigned i;
5374 : 0 : exploded_node *enode;
5375 : 0 : FOR_EACH_VEC_ELT (m_nodes, i, enode)
5376 : : {
5377 : 0 : if (const gimple *stmt = enode->get_stmt ())
5378 : : {
5379 : 0 : if (get_pure_location (richloc.get_loc ()) == UNKNOWN_LOCATION)
5380 : 0 : richloc.set_range (0, stmt->location, SHOW_RANGE_WITH_CARET);
5381 : : else
5382 : 0 : richloc.add_range (stmt->location,
5383 : : SHOW_RANGE_WITHOUT_CARET,
5384 : 0 : new enode_label (m_ext_state, enode));
5385 : : }
5386 : : }
5387 : 0 : warning_at (&richloc, 0, "%i exploded nodes", m_nodes.length ());
5388 : :
5389 : : /* Repeat the warning without all the labels, so that message is visible
5390 : : (the other one may well have scrolled past the terminal limit). */
5391 : 0 : warning_at (richloc.get_loc (), 0,
5392 : : "%i exploded nodes", m_nodes.length ());
5393 : :
5394 : 0 : if (m_worklist.length () > 0)
5395 : 0 : warning_at (richloc.get_loc (), 0,
5396 : : "worklist still contains %i nodes", m_worklist.length ());
5397 : 0 : }
5398 : :
5399 : : /* Dump the egraph in textual form to a dump file. */
5400 : 3783 : if (flag_dump_analyzer_exploded_nodes_2)
5401 : : {
5402 : 0 : auto_timevar tv (TV_ANALYZER_DUMP);
5403 : 0 : char *filename
5404 : 0 : = concat (dump_base_name, ".eg.txt", NULL);
5405 : 0 : FILE *outf = fopen (filename, "w");
5406 : 0 : if (!outf)
5407 : 0 : error_at (UNKNOWN_LOCATION, "unable to open %qs for writing", filename);
5408 : 0 : free (filename);
5409 : :
5410 : 0 : fprintf (outf, "exploded graph for %s\n", dump_base_name);
5411 : 0 : fprintf (outf, " nodes: %i\n", m_nodes.length ());
5412 : 0 : fprintf (outf, " edges: %i\n", m_edges.length ());
5413 : :
5414 : 0 : unsigned i;
5415 : 0 : exploded_node *enode;
5416 : 0 : FOR_EACH_VEC_ELT (m_nodes, i, enode)
5417 : : {
5418 : 0 : fprintf (outf, "\nEN %i:\n", enode->m_index);
5419 : 0 : enode->dump_succs_and_preds (outf);
5420 : 0 : pretty_printer pp;
5421 : 0 : enode->get_point ().print (&pp, format (true));
5422 : 0 : fprintf (outf, "%s\n", pp_formatted_text (&pp));
5423 : 0 : enode->get_state ().dump_to_file (m_ext_state, false, true, outf);
5424 : 0 : }
5425 : :
5426 : 0 : fclose (outf);
5427 : 0 : }
5428 : :
5429 : : /* Dump the egraph in textual form to multiple dump files, one per enode. */
5430 : 3783 : if (flag_dump_analyzer_exploded_nodes_3)
5431 : : {
5432 : 0 : auto_timevar tv (TV_ANALYZER_DUMP);
5433 : :
5434 : 0 : unsigned i;
5435 : 0 : exploded_node *enode;
5436 : 0 : FOR_EACH_VEC_ELT (m_nodes, i, enode)
5437 : : {
5438 : 0 : char *filename
5439 : 0 : = xasprintf ("%s.en-%i.txt", dump_base_name, i);
5440 : 0 : FILE *outf = fopen (filename, "w");
5441 : 0 : if (!outf)
5442 : 0 : error_at (UNKNOWN_LOCATION, "unable to open %qs for writing", filename);
5443 : 0 : free (filename);
5444 : :
5445 : 0 : fprintf (outf, "EN %i:\n", enode->m_index);
5446 : 0 : enode->dump_succs_and_preds (outf);
5447 : 0 : pretty_printer pp;
5448 : 0 : enode->get_point ().print (&pp, format (true));
5449 : 0 : fprintf (outf, "%s\n", pp_formatted_text (&pp));
5450 : 0 : enode->get_state ().dump_to_file (m_ext_state, false, true, outf);
5451 : :
5452 : 0 : fclose (outf);
5453 : 0 : }
5454 : 0 : }
5455 : :
5456 : : /* Emit a warning at any call to "__analyzer_dump_exploded_nodes",
5457 : : giving the number of processed exploded nodes for "before-stmt",
5458 : : and the IDs of processed, merger, and worklist enodes.
5459 : :
5460 : : We highlight the count of *processed* enodes since this is of most
5461 : : interest in DejaGnu tests for ensuring that state merger has
5462 : : happened.
5463 : :
5464 : : We don't show the count of merger and worklist enodes, as this is
5465 : : more of an implementation detail of the merging/worklist that we
5466 : : don't want to bake into our expected DejaGnu messages. */
5467 : :
5468 : 3783 : unsigned i;
5469 : 3783 : exploded_node *enode;
5470 : 3783 : hash_set<const gimple *> seen;
5471 : 436310 : FOR_EACH_VEC_ELT (m_nodes, i, enode)
5472 : : {
5473 : 428749 : if (enode->get_point ().get_kind () != PK_BEFORE_STMT)
5474 : 289313 : continue;
5475 : :
5476 : 139436 : if (const gimple *stmt = enode->get_stmt ())
5477 : 181686 : if (const gcall *call = dyn_cast <const gcall *> (stmt))
5478 : 42715 : if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes",
5479 : : 1))
5480 : : {
5481 : 1302 : if (seen.contains (stmt))
5482 : 465 : continue;
5483 : :
5484 : 837 : auto_vec<exploded_node *> processed_enodes;
5485 : 837 : auto_vec<exploded_node *> merger_enodes;
5486 : 837 : auto_vec<exploded_node *> worklist_enodes;
5487 : : /* This is O(N^2). */
5488 : 837 : unsigned j;
5489 : 837 : exploded_node *other_enode;
5490 : 167005 : FOR_EACH_VEC_ELT (m_nodes, j, other_enode)
5491 : : {
5492 : 166168 : if (other_enode->get_point ().get_kind () != PK_BEFORE_STMT)
5493 : 112862 : continue;
5494 : 53306 : if (other_enode->get_stmt () == stmt)
5495 : 1302 : switch (other_enode->get_status ())
5496 : : {
5497 : 0 : default:
5498 : 0 : gcc_unreachable ();
5499 : 0 : case exploded_node::STATUS_WORKLIST:
5500 : 0 : worklist_enodes.safe_push (other_enode);
5501 : 0 : break;
5502 : 1286 : case exploded_node::STATUS_PROCESSED:
5503 : 1286 : processed_enodes.safe_push (other_enode);
5504 : 1286 : break;
5505 : 16 : case exploded_node::STATUS_MERGER:
5506 : 16 : merger_enodes.safe_push (other_enode);
5507 : 16 : break;
5508 : : }
5509 : : }
5510 : :
5511 : 1674 : pretty_printer pp;
5512 : 837 : pp_character (&pp, '[');
5513 : 837 : print_enode_indices (&pp, processed_enodes);
5514 : 837 : if (merger_enodes.length () > 0)
5515 : : {
5516 : 16 : pp_string (&pp, "] merger(s): [");
5517 : 16 : print_enode_indices (&pp, merger_enodes);
5518 : : }
5519 : 837 : if (worklist_enodes.length () > 0)
5520 : : {
5521 : 0 : pp_string (&pp, "] worklist: [");
5522 : 0 : print_enode_indices (&pp, worklist_enodes);
5523 : : }
5524 : 837 : pp_character (&pp, ']');
5525 : :
5526 : 1674 : warning_n (stmt->location, 0, processed_enodes.length (),
5527 : : "%i processed enode: %s",
5528 : : "%i processed enodes: %s",
5529 : : processed_enodes.length (), pp_formatted_text (&pp));
5530 : 837 : seen.add (stmt);
5531 : :
5532 : : /* If the argument is non-zero, then print all of the states
5533 : : of the various enodes. */
5534 : 837 : tree t_arg = fold (gimple_call_arg (call, 0));
5535 : 837 : if (TREE_CODE (t_arg) != INTEGER_CST)
5536 : : {
5537 : 0 : error_at (call->location,
5538 : : "integer constant required for arg 1");
5539 : 0 : return;
5540 : : }
5541 : 837 : int i_arg = TREE_INT_CST_LOW (t_arg);
5542 : 837 : if (i_arg)
5543 : : {
5544 : : exploded_node *other_enode;
5545 : 837 : FOR_EACH_VEC_ELT (processed_enodes, j, other_enode)
5546 : : {
5547 : 0 : fprintf (stderr, "%i of %i: EN %i:\n",
5548 : : j + 1, processed_enodes.length (),
5549 : 0 : other_enode->m_index);
5550 : 0 : other_enode->dump_succs_and_preds (stderr);
5551 : : /* Dump state. */
5552 : 0 : other_enode->get_state ().dump (m_ext_state, false);
5553 : : }
5554 : : }
5555 : 837 : }
5556 : : }
5557 : 3783 : }
5558 : :
5559 : : DEBUG_FUNCTION exploded_node *
5560 : 0 : exploded_graph::get_node_by_index (int idx) const
5561 : : {
5562 : 0 : exploded_node *enode = m_nodes[idx];
5563 : 0 : gcc_assert (enode->m_index == idx);
5564 : 0 : return enode;
5565 : : }
5566 : :
5567 : : /* Ensure that there is an exploded_node for a top-level call to FNDECL. */
5568 : :
5569 : : void
5570 : 209 : exploded_graph::on_escaped_function (tree fndecl)
5571 : : {
5572 : 209 : logger * const logger = get_logger ();
5573 : 209 : LOG_FUNC_1 (logger, "%qE", fndecl);
5574 : :
5575 : 209 : cgraph_node *cgnode = cgraph_node::get (fndecl);
5576 : 209 : if (!cgnode)
5577 : : return;
5578 : :
5579 : 209 : function *fun = cgnode->get_fun ();
5580 : 209 : if (!fun)
5581 : : return;
5582 : :
5583 : 204 : if (!gimple_has_body_p (fndecl))
5584 : : return;
5585 : :
5586 : 204 : exploded_node *enode = add_function_entry (*fun);
5587 : 204 : if (logger)
5588 : : {
5589 : 0 : if (enode)
5590 : 0 : logger->log ("created EN %i for %qE entrypoint",
5591 : 0 : enode->m_index, fun->decl);
5592 : : else
5593 : 0 : logger->log ("did not create enode for %qE entrypoint", fun->decl);
5594 : : }
5595 : 209 : }
5596 : :
5597 : : /* A collection of classes for visualizing the callgraph in .dot form
5598 : : (as represented in the supergraph). */
5599 : :
5600 : : /* Forward decls. */
5601 : : class viz_callgraph_node;
5602 : : class viz_callgraph_edge;
5603 : : class viz_callgraph;
5604 : : class viz_callgraph_cluster;
5605 : :
5606 : : /* Traits for using "digraph.h" to visualize the callgraph. */
5607 : :
5608 : : struct viz_callgraph_traits
5609 : : {
5610 : : typedef viz_callgraph_node node_t;
5611 : : typedef viz_callgraph_edge edge_t;
5612 : : typedef viz_callgraph graph_t;
5613 : : struct dump_args_t
5614 : : {
5615 : 5 : dump_args_t (const exploded_graph *eg) : m_eg (eg) {}
5616 : : const exploded_graph *m_eg;
5617 : : };
5618 : : typedef viz_callgraph_cluster cluster_t;
5619 : : };
5620 : :
5621 : : /* Subclass of dnode representing a function within the callgraph. */
5622 : :
5623 : : class viz_callgraph_node : public dnode<viz_callgraph_traits>
5624 : : {
5625 : : friend class viz_callgraph;
5626 : :
5627 : : public:
5628 : 15 : viz_callgraph_node (function *fun, int index)
5629 : 15 : : m_fun (fun), m_index (index), m_num_supernodes (0), m_num_superedges (0)
5630 : : {
5631 : 15 : gcc_assert (fun);
5632 : 15 : }
5633 : :
5634 : 15 : void dump_dot (graphviz_out *gv, const dump_args_t &args) const final override
5635 : : {
5636 : 15 : pretty_printer *pp = gv->get_pp ();
5637 : :
5638 : 30 : dump_dot_id (pp);
5639 : 15 : pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
5640 : : "lightgrey");
5641 : 15 : pp_write_text_to_stream (pp);
5642 : :
5643 : 15 : pp_printf (pp, "VCG: %i: %s", m_index, function_name (m_fun));
5644 : 15 : pp_newline (pp);
5645 : :
5646 : 15 : pp_printf (pp, "supernodes: %i\n", m_num_supernodes);
5647 : 15 : pp_newline (pp);
5648 : :
5649 : 15 : pp_printf (pp, "superedges: %i\n", m_num_superedges);
5650 : 15 : pp_newline (pp);
5651 : :
5652 : 15 : if (args.m_eg)
5653 : : {
5654 : : unsigned i;
5655 : : exploded_node *enode;
5656 : : unsigned num_enodes = 0;
5657 : 1770 : FOR_EACH_VEC_ELT (args.m_eg->m_nodes, i, enode)
5658 : : {
5659 : 1755 : if (enode->get_point ().get_function () == m_fun)
5660 : 580 : num_enodes++;
5661 : : }
5662 : 15 : pp_printf (pp, "enodes: %i\n", num_enodes);
5663 : 15 : pp_newline (pp);
5664 : :
5665 : : // TODO: also show the per-callstring breakdown
5666 : 15 : const exploded_graph::call_string_data_map_t *per_cs_data
5667 : 15 : = args.m_eg->get_per_call_string_data ();
5668 : 45 : for (exploded_graph::call_string_data_map_t::iterator iter
5669 : 15 : = per_cs_data->begin ();
5670 : 45 : iter != per_cs_data->end ();
5671 : 30 : ++iter)
5672 : : {
5673 : 30 : const call_string *cs = (*iter).first;
5674 : : //per_call_string_data *data = (*iter).second;
5675 : 30 : num_enodes = 0;
5676 : 3540 : FOR_EACH_VEC_ELT (args.m_eg->m_nodes, i, enode)
5677 : : {
5678 : 3510 : if (enode->get_point ().get_function () == m_fun
5679 : 3510 : && &enode->get_point ().get_call_string () == cs)
5680 : 580 : num_enodes++;
5681 : : }
5682 : 30 : if (num_enodes > 0)
5683 : : {
5684 : 20 : cs->print (pp);
5685 : 20 : pp_printf (pp, ": %i\n", num_enodes);
5686 : : }
5687 : : }
5688 : :
5689 : : /* Show any summaries. */
5690 : 15 : per_function_data *data = args.m_eg->get_per_function_data (m_fun);
5691 : 15 : if (data)
5692 : : {
5693 : 15 : pp_newline (pp);
5694 : 30 : pp_printf (pp, "summaries: %i\n", data->m_summaries.length ());
5695 : 65 : for (auto summary : data->m_summaries)
5696 : : {
5697 : 20 : pp_printf (pp, "\nsummary: %s:\n", summary->get_desc ().get ());
5698 : 20 : const extrinsic_state &ext_state = args.m_eg->get_ext_state ();
5699 : 20 : const program_state &state = summary->get_state ();
5700 : 20 : state.dump_to_pp (ext_state, false, true, pp);
5701 : 20 : pp_newline (pp);
5702 : : }
5703 : : }
5704 : : }
5705 : :
5706 : 15 : pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
5707 : 15 : pp_string (pp, "\"];\n\n");
5708 : 15 : pp_flush (pp);
5709 : 15 : }
5710 : :
5711 : 25 : void dump_dot_id (pretty_printer *pp) const
5712 : : {
5713 : 15 : pp_printf (pp, "vcg_%i", m_index);
5714 : : }
5715 : :
5716 : : private:
5717 : : function *m_fun;
5718 : : int m_index;
5719 : : int m_num_supernodes;
5720 : : int m_num_superedges;
5721 : : };
5722 : :
5723 : : /* Subclass of dedge representing a callgraph edge. */
5724 : :
5725 : : class viz_callgraph_edge : public dedge<viz_callgraph_traits>
5726 : : {
5727 : : public:
5728 : 5 : viz_callgraph_edge (viz_callgraph_node *src, viz_callgraph_node *dest)
5729 : 5 : : dedge<viz_callgraph_traits> (src, dest)
5730 : : {}
5731 : :
5732 : 5 : void dump_dot (graphviz_out *gv, const dump_args_t &) const
5733 : : final override
5734 : : {
5735 : 5 : pretty_printer *pp = gv->get_pp ();
5736 : :
5737 : 5 : const char *style = "\"solid,bold\"";
5738 : 5 : const char *color = "black";
5739 : 5 : int weight = 10;
5740 : 5 : const char *constraint = "true";
5741 : :
5742 : 5 : m_src->dump_dot_id (pp);
5743 : 5 : pp_string (pp, " -> ");
5744 : 5 : m_dest->dump_dot_id (pp);
5745 : 5 : pp_printf (pp,
5746 : : (" [style=%s, color=%s, weight=%d, constraint=%s,"
5747 : : " headlabel=\""),
5748 : : style, color, weight, constraint);
5749 : 5 : pp_printf (pp, "\"];\n");
5750 : 5 : }
5751 : : };
5752 : :
5753 : : /* Subclass of digraph representing the callgraph. */
5754 : :
5755 : : class viz_callgraph : public digraph<viz_callgraph_traits>
5756 : : {
5757 : : public:
5758 : : viz_callgraph (const supergraph &sg);
5759 : :
5760 : 310 : viz_callgraph_node *get_vcg_node_for_function (function *fun)
5761 : : {
5762 : 620 : return *m_map.get (fun);
5763 : : }
5764 : :
5765 : 110 : viz_callgraph_node *get_vcg_node_for_snode (supernode *snode)
5766 : : {
5767 : 220 : return get_vcg_node_for_function (snode->m_fun);
5768 : : }
5769 : :
5770 : : private:
5771 : : hash_map<function *, viz_callgraph_node *> m_map;
5772 : : };
5773 : :
5774 : : /* Placeholder subclass of cluster. */
5775 : :
5776 : : class viz_callgraph_cluster : public cluster<viz_callgraph_traits>
5777 : : {
5778 : : };
5779 : :
5780 : : /* viz_callgraph's ctor. */
5781 : :
5782 : 5 : viz_callgraph::viz_callgraph (const supergraph &sg)
5783 : : {
5784 : 5 : cgraph_node *node;
5785 : 20 : FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
5786 : : {
5787 : 15 : function *fun = node->get_fun ();
5788 : 15 : viz_callgraph_node *vcg_node
5789 : 25 : = new viz_callgraph_node (fun, m_nodes.length ());
5790 : 15 : m_map.put (fun, vcg_node);
5791 : 15 : add_node (vcg_node);
5792 : : }
5793 : :
5794 : : unsigned i;
5795 : : superedge *sedge;
5796 : 110 : FOR_EACH_VEC_ELT (sg.m_edges, i, sedge)
5797 : : {
5798 : 105 : viz_callgraph_node *vcg_src = get_vcg_node_for_snode (sedge->m_src);
5799 : 105 : if (vcg_src->m_fun)
5800 : 105 : get_vcg_node_for_function (vcg_src->m_fun)->m_num_superedges++;
5801 : 105 : if (sedge->dyn_cast_call_superedge ())
5802 : : {
5803 : 5 : viz_callgraph_node *vcg_dest = get_vcg_node_for_snode (sedge->m_dest);
5804 : 5 : viz_callgraph_edge *vcg_edge
5805 : 5 : = new viz_callgraph_edge (vcg_src, vcg_dest);
5806 : 5 : add_edge (vcg_edge);
5807 : : }
5808 : : }
5809 : :
5810 : : supernode *snode;
5811 : 100 : FOR_EACH_VEC_ELT (sg.m_nodes, i, snode)
5812 : : {
5813 : 95 : if (snode->m_fun)
5814 : 95 : get_vcg_node_for_function (snode->m_fun)->m_num_supernodes++;
5815 : : }
5816 : 5 : }
5817 : :
5818 : : /* Dump the callgraph to FILENAME. */
5819 : :
5820 : : static void
5821 : 5 : dump_callgraph (const supergraph &sg, const char *filename,
5822 : : const exploded_graph *eg)
5823 : : {
5824 : 5 : FILE *outf = fopen (filename, "w");
5825 : 5 : if (!outf)
5826 : 0 : return;
5827 : :
5828 : : // TODO
5829 : 5 : viz_callgraph vcg (sg);
5830 : 5 : vcg.dump_dot (filename, NULL, viz_callgraph_traits::dump_args_t (eg));
5831 : :
5832 : 5 : fclose (outf);
5833 : 5 : }
5834 : :
5835 : : /* Dump the callgraph to "<srcfile>.callgraph.dot". */
5836 : :
5837 : : static void
5838 : 5 : dump_callgraph (const supergraph &sg, const exploded_graph *eg)
5839 : : {
5840 : 5 : auto_timevar tv (TV_ANALYZER_DUMP);
5841 : 5 : char *filename = concat (dump_base_name, ".callgraph.dot", NULL);
5842 : 5 : dump_callgraph (sg, filename, eg);
5843 : 5 : free (filename);
5844 : 5 : }
5845 : :
5846 : : /* Subclass of dot_annotator for implementing
5847 : : DUMP_BASE_NAME.supergraph-eg.dot, a post-analysis dump of the supergraph.
5848 : :
5849 : : Annotate the supergraph nodes by printing the exploded nodes in concise
5850 : : form within them, next to their pertinent statements where appropriate,
5851 : : colorizing the exploded nodes based on sm-state.
5852 : : Also show saved diagnostics within the exploded nodes, giving information
5853 : : on whether they were feasible, and, if infeasible, where the problem
5854 : : was. */
5855 : :
5856 : 5 : class exploded_graph_annotator : public dot_annotator
5857 : : {
5858 : : public:
5859 : 5 : exploded_graph_annotator (const exploded_graph &eg)
5860 : 5 : : m_eg (eg)
5861 : : {
5862 : : /* Avoid O(N^2) by prepopulating m_enodes_per_snodes. */
5863 : 5 : unsigned i;
5864 : 5 : supernode *snode;
5865 : 100 : FOR_EACH_VEC_ELT (eg.get_supergraph ().m_nodes, i, snode)
5866 : 95 : m_enodes_per_snodes.safe_push (new auto_vec <exploded_node *> ());
5867 : : exploded_node *enode;
5868 : 590 : FOR_EACH_VEC_ELT (m_eg.m_nodes, i, enode)
5869 : 585 : if (enode->get_supernode ())
5870 : 580 : m_enodes_per_snodes[enode->get_supernode ()->m_index]->safe_push (enode);
5871 : 5 : }
5872 : :
5873 : : /* Show exploded nodes for BEFORE_SUPERNODE points before N. */
5874 : 190 : bool add_node_annotations (graphviz_out *gv, const supernode &n,
5875 : : bool within_table)
5876 : : const final override
5877 : : {
5878 : 190 : if (!within_table)
5879 : : return false;
5880 : 95 : gv->begin_tr ();
5881 : 95 : pretty_printer *pp = gv->get_pp ();
5882 : :
5883 : 95 : gv->begin_td ();
5884 : 95 : pp_string (pp, "BEFORE");
5885 : 95 : pp_printf (pp, " (scc: %i)", m_eg.get_scc_id (n));
5886 : 95 : gv->end_td ();
5887 : :
5888 : 95 : unsigned i;
5889 : 95 : exploded_node *enode;
5890 : 95 : bool had_enode = false;
5891 : 675 : FOR_EACH_VEC_ELT (*m_enodes_per_snodes[n.m_index], i, enode)
5892 : : {
5893 : 580 : gcc_assert (enode->get_supernode () == &n);
5894 : 580 : const program_point &point = enode->get_point ();
5895 : 580 : if (point.get_kind () != PK_BEFORE_SUPERNODE)
5896 : 380 : continue;
5897 : 200 : print_enode (gv, enode);
5898 : 200 : had_enode = true;
5899 : : }
5900 : 95 : if (!had_enode)
5901 : 0 : pp_string (pp, "<TD BGCOLOR=\"red\">UNREACHED</TD>");
5902 : 95 : pp_flush (pp);
5903 : 95 : gv->end_tr ();
5904 : 95 : return true;
5905 : : }
5906 : :
5907 : : /* Show exploded nodes for STMT. */
5908 : 338 : void add_stmt_annotations (graphviz_out *gv, const gimple *stmt,
5909 : : bool within_row)
5910 : : const final override
5911 : : {
5912 : 338 : if (!within_row)
5913 : 338 : return;
5914 : 169 : pretty_printer *pp = gv->get_pp ();
5915 : :
5916 : 169 : const supernode *snode
5917 : 169 : = m_eg.get_supergraph ().get_supernode_for_stmt (stmt);
5918 : 169 : unsigned i;
5919 : 169 : exploded_node *enode;
5920 : 169 : bool had_td = false;
5921 : 1769 : FOR_EACH_VEC_ELT (*m_enodes_per_snodes[snode->m_index], i, enode)
5922 : : {
5923 : 1600 : const program_point &point = enode->get_point ();
5924 : 1600 : if (point.get_kind () != PK_BEFORE_STMT)
5925 : 837 : continue;
5926 : 763 : if (point.get_stmt () != stmt)
5927 : 553 : continue;
5928 : 210 : print_enode (gv, enode);
5929 : 210 : had_td = true;
5930 : : }
5931 : 169 : pp_flush (pp);
5932 : 169 : if (!had_td)
5933 : : {
5934 : 54 : gv->begin_td ();
5935 : 54 : gv->end_td ();
5936 : : }
5937 : : }
5938 : :
5939 : : /* Show exploded nodes for AFTER_SUPERNODE points after N. */
5940 : 95 : bool add_after_node_annotations (graphviz_out *gv, const supernode &n)
5941 : : const final override
5942 : : {
5943 : 95 : gv->begin_tr ();
5944 : 95 : pretty_printer *pp = gv->get_pp ();
5945 : :
5946 : 95 : gv->begin_td ();
5947 : 95 : pp_string (pp, "AFTER");
5948 : 95 : gv->end_td ();
5949 : :
5950 : 95 : unsigned i;
5951 : 95 : exploded_node *enode;
5952 : 675 : FOR_EACH_VEC_ELT (*m_enodes_per_snodes[n.m_index], i, enode)
5953 : : {
5954 : 580 : gcc_assert (enode->get_supernode () == &n);
5955 : 580 : const program_point &point = enode->get_point ();
5956 : 580 : if (point.get_kind () != PK_AFTER_SUPERNODE)
5957 : 400 : continue;
5958 : 180 : print_enode (gv, enode);
5959 : : }
5960 : 95 : pp_flush (pp);
5961 : 95 : gv->end_tr ();
5962 : 95 : return true;
5963 : : }
5964 : :
5965 : : private:
5966 : : /* Concisely print a TD element for ENODE, showing the index, status,
5967 : : and any saved_diagnostics at the enode. Colorize it to show sm-state.
5968 : :
5969 : : Ideally we'd dump ENODE's state here, hidden behind some kind of
5970 : : interactive disclosure method like a tooltip, so that the states
5971 : : can be explored without overwhelming the graph.
5972 : : However, I wasn't able to get graphviz/xdot to show tooltips on
5973 : : individual elements within a HTML-like label. */
5974 : 590 : void print_enode (graphviz_out *gv, const exploded_node *enode) const
5975 : : {
5976 : 590 : pretty_printer *pp = gv->get_pp ();
5977 : 590 : pp_printf (pp, "<TD BGCOLOR=\"%s\">",
5978 : : enode->get_dot_fillcolor ());
5979 : 590 : pp_printf (pp, "<TABLE BORDER=\"0\">");
5980 : 590 : gv->begin_trtd ();
5981 : 590 : pp_printf (pp, "EN: %i", enode->m_index);
5982 : 590 : switch (enode->get_status ())
5983 : : {
5984 : 0 : default:
5985 : 0 : gcc_unreachable ();
5986 : 0 : case exploded_node::STATUS_WORKLIST:
5987 : 0 : pp_string (pp, "(W)");
5988 : 0 : break;
5989 : : case exploded_node::STATUS_PROCESSED:
5990 : : break;
5991 : 0 : case exploded_node::STATUS_MERGER:
5992 : 0 : pp_string (pp, "(M)");
5993 : 0 : break;
5994 : 50 : case exploded_node::STATUS_BULK_MERGED:
5995 : 50 : pp_string (pp, "(BM)");
5996 : 50 : break;
5997 : : }
5998 : 590 : gv->end_tdtr ();
5999 : :
6000 : : /* Dump any saved_diagnostics at this enode. */
6001 : 620 : for (unsigned i = 0; i < enode->get_num_diagnostics (); i++)
6002 : : {
6003 : 10 : const saved_diagnostic *sd = enode->get_saved_diagnostic (i);
6004 : 10 : print_saved_diagnostic (gv, sd);
6005 : : }
6006 : 590 : pp_printf (pp, "</TABLE>");
6007 : 590 : pp_printf (pp, "</TD>");
6008 : 590 : }
6009 : :
6010 : : /* Print a TABLE element for SD, showing the kind, the length of the
6011 : : exploded_path, whether the path was feasible, and if infeasible,
6012 : : what the problem was. */
6013 : 10 : void print_saved_diagnostic (graphviz_out *gv,
6014 : : const saved_diagnostic *sd) const
6015 : : {
6016 : 10 : pretty_printer *pp = gv->get_pp ();
6017 : 10 : gv->begin_trtd ();
6018 : 10 : pp_printf (pp, "<TABLE BORDER=\"0\">");
6019 : 10 : gv->begin_tr ();
6020 : 10 : pp_string (pp, "<TD BGCOLOR=\"green\">");
6021 : 10 : pp_printf (pp, "DIAGNOSTIC: %s", sd->m_d->get_kind ());
6022 : 10 : gv->end_tdtr ();
6023 : 10 : gv->begin_trtd ();
6024 : 10 : if (sd->get_best_epath ())
6025 : 10 : pp_printf (pp, "epath length: %i", sd->get_epath_length ());
6026 : : else
6027 : 0 : pp_printf (pp, "no best epath");
6028 : 10 : gv->end_tdtr ();
6029 : 10 : if (const feasibility_problem *p = sd->get_feasibility_problem ())
6030 : : {
6031 : 0 : gv->begin_trtd ();
6032 : 0 : pp_printf (pp, "INFEASIBLE at eedge %i: EN:%i -> EN:%i",
6033 : 0 : p->m_eedge_idx,
6034 : 0 : p->m_eedge.m_src->m_index,
6035 : 0 : p->m_eedge.m_dest->m_index);
6036 : 0 : pp_write_text_as_html_like_dot_to_stream (pp);
6037 : 0 : gv->end_tdtr ();
6038 : 0 : gv->begin_trtd ();
6039 : 0 : p->m_eedge.m_sedge->dump (pp);
6040 : 0 : pp_write_text_as_html_like_dot_to_stream (pp);
6041 : 0 : gv->end_tdtr ();
6042 : 0 : gv->begin_trtd ();
6043 : 0 : pp_gimple_stmt_1 (pp, p->m_last_stmt, 0, (dump_flags_t)0);
6044 : 0 : pp_write_text_as_html_like_dot_to_stream (pp);
6045 : 0 : gv->end_tdtr ();
6046 : : /* Ideally we'd print p->m_model here; see the notes above about
6047 : : tooltips. */
6048 : : }
6049 : 10 : pp_printf (pp, "</TABLE>");
6050 : 10 : gv->end_tdtr ();
6051 : 10 : }
6052 : :
6053 : : const exploded_graph &m_eg;
6054 : : auto_delete_vec<auto_vec <exploded_node *> > m_enodes_per_snodes;
6055 : : };
6056 : :
6057 : : /* Implement -fdump-analyzer-json. */
6058 : :
6059 : : static void
6060 : 0 : dump_analyzer_json (const supergraph &sg,
6061 : : const exploded_graph &eg)
6062 : : {
6063 : 0 : auto_timevar tv (TV_ANALYZER_DUMP);
6064 : 0 : char *filename = concat (dump_base_name, ".analyzer.json.gz", NULL);
6065 : 0 : gzFile output = gzopen (filename, "w");
6066 : 0 : if (!output)
6067 : : {
6068 : 0 : error_at (UNKNOWN_LOCATION, "unable to open %qs for writing", filename);
6069 : 0 : free (filename);
6070 : 0 : return;
6071 : : }
6072 : :
6073 : 0 : json::object *toplev_obj = new json::object ();
6074 : 0 : toplev_obj->set ("sgraph", sg.to_json ());
6075 : 0 : toplev_obj->set ("egraph", eg.to_json ());
6076 : :
6077 : 0 : pretty_printer pp;
6078 : 0 : toplev_obj->print (&pp, flag_diagnostics_json_formatting);
6079 : 0 : pp_formatted_text (&pp);
6080 : :
6081 : 0 : delete toplev_obj;
6082 : :
6083 : 0 : if (gzputs (output, pp_formatted_text (&pp)) == EOF
6084 : 0 : || gzclose (output))
6085 : 0 : error_at (UNKNOWN_LOCATION, "error writing %qs", filename);
6086 : :
6087 : 0 : free (filename);
6088 : 0 : }
6089 : :
6090 : : /* Concrete subclass of plugin_analyzer_init_iface, allowing plugins
6091 : : to register new state machines. */
6092 : :
6093 : : class plugin_analyzer_init_impl : public plugin_analyzer_init_iface
6094 : : {
6095 : : public:
6096 : 3783 : plugin_analyzer_init_impl (auto_delete_vec <state_machine> *checkers,
6097 : : known_function_manager *known_fn_mgr,
6098 : : logger *logger)
6099 : 3783 : : m_checkers (checkers),
6100 : 3783 : m_known_fn_mgr (known_fn_mgr),
6101 : 3783 : m_logger (logger)
6102 : : {}
6103 : :
6104 : 1 : void register_state_machine (std::unique_ptr<state_machine> sm) final override
6105 : : {
6106 : 1 : LOG_SCOPE (m_logger);
6107 : 1 : m_checkers->safe_push (sm.release ());
6108 : 1 : }
6109 : :
6110 : 107 : void register_known_function (const char *name,
6111 : : std::unique_ptr<known_function> kf) final override
6112 : : {
6113 : 107 : LOG_SCOPE (m_logger);
6114 : 107 : m_known_fn_mgr->add (name, std::move (kf));
6115 : 107 : }
6116 : :
6117 : 39 : logger *get_logger () const final override
6118 : : {
6119 : 39 : return m_logger;
6120 : : }
6121 : :
6122 : : private:
6123 : : auto_delete_vec <state_machine> *m_checkers;
6124 : : known_function_manager *m_known_fn_mgr;
6125 : : logger *m_logger;
6126 : : };
6127 : :
6128 : : /* Run the analysis "engine". */
6129 : :
6130 : : void
6131 : 3783 : impl_run_checkers (logger *logger)
6132 : : {
6133 : 3783 : LOG_SCOPE (logger);
6134 : :
6135 : 3783 : if (logger)
6136 : : {
6137 : 2 : logger->log ("BITS_BIG_ENDIAN: %i", BITS_BIG_ENDIAN ? 1 : 0);
6138 : 2 : logger->log ("BYTES_BIG_ENDIAN: %i", BYTES_BIG_ENDIAN ? 1 : 0);
6139 : 2 : logger->log ("WORDS_BIG_ENDIAN: %i", WORDS_BIG_ENDIAN ? 1 : 0);
6140 : 2 : log_stashed_constants (logger);
6141 : : }
6142 : :
6143 : : /* If using LTO, ensure that the cgraph nodes have function bodies. */
6144 : 3783 : cgraph_node *node;
6145 : 15247 : FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
6146 : 11464 : node->get_untransformed_body ();
6147 : :
6148 : : /* Create the supergraph. */
6149 : 3783 : supergraph sg (logger);
6150 : :
6151 : 3783 : engine eng (&sg, logger);
6152 : :
6153 : 3783 : state_purge_map *purge_map = NULL;
6154 : :
6155 : 3783 : if (flag_analyzer_state_purge)
6156 : 3773 : purge_map = new state_purge_map (sg, eng.get_model_manager (), logger);
6157 : :
6158 : 3783 : if (flag_dump_analyzer_supergraph)
6159 : : {
6160 : : /* Dump supergraph pre-analysis. */
6161 : 5 : auto_timevar tv (TV_ANALYZER_DUMP);
6162 : 5 : char *filename = concat (dump_base_name, ".supergraph.dot", NULL);
6163 : 5 : supergraph::dump_args_t args ((enum supergraph_dot_flags)0, NULL);
6164 : 5 : sg.dump_dot (filename, args);
6165 : 5 : free (filename);
6166 : 5 : }
6167 : :
6168 : 3783 : if (flag_dump_analyzer_state_purge)
6169 : : {
6170 : 5 : auto_timevar tv (TV_ANALYZER_DUMP);
6171 : 5 : state_purge_annotator a (purge_map);
6172 : 5 : char *filename = concat (dump_base_name, ".state-purge.dot", NULL);
6173 : 5 : supergraph::dump_args_t args ((enum supergraph_dot_flags)0, &a);
6174 : 5 : sg.dump_dot (filename, args);
6175 : 5 : free (filename);
6176 : 5 : }
6177 : :
6178 : 3783 : auto_delete_vec <state_machine> checkers;
6179 : 3783 : make_checkers (checkers, logger);
6180 : :
6181 : 3783 : register_known_functions (*eng.get_known_function_manager (),
6182 : 3783 : *eng.get_model_manager ());
6183 : :
6184 : 3783 : plugin_analyzer_init_impl data (&checkers,
6185 : : eng.get_known_function_manager (),
6186 : 3783 : logger);
6187 : 3783 : invoke_plugin_callbacks (PLUGIN_ANALYZER_INIT, &data);
6188 : :
6189 : 3783 : if (logger)
6190 : : {
6191 : : int i;
6192 : : state_machine *sm;
6193 : 16 : FOR_EACH_VEC_ELT (checkers, i, sm)
6194 : 14 : logger->log ("checkers[%i]: %s", i, sm->get_name ());
6195 : : }
6196 : :
6197 : : /* Extrinsic state shared by nodes in the graph. */
6198 : 3783 : const extrinsic_state ext_state (checkers, &eng, logger);
6199 : :
6200 : 3783 : const analysis_plan plan (sg, logger);
6201 : :
6202 : : /* The exploded graph. */
6203 : 3783 : exploded_graph eg (sg, logger, ext_state, purge_map, plan,
6204 : 3783 : analyzer_verbosity);
6205 : :
6206 : : /* Add entrypoints to the graph for externally-callable functions. */
6207 : 3783 : eg.build_initial_worklist ();
6208 : :
6209 : : /* Now process the worklist, exploring the <point, state> graph. */
6210 : 3783 : eg.process_worklist ();
6211 : :
6212 : 3783 : if (warn_analyzer_infinite_loop)
6213 : 3783 : eg.detect_infinite_loops ();
6214 : :
6215 : 3783 : if (flag_dump_analyzer_exploded_graph)
6216 : : {
6217 : 5 : auto_timevar tv (TV_ANALYZER_DUMP);
6218 : 5 : char *filename
6219 : 5 : = concat (dump_base_name, ".eg.dot", NULL);
6220 : 5 : exploded_graph::dump_args_t args (eg);
6221 : 5 : root_cluster c;
6222 : 5 : eg.dump_dot (filename, &c, args);
6223 : 5 : free (filename);
6224 : 5 : }
6225 : :
6226 : : /* Now emit any saved diagnostics. */
6227 : 3783 : eg.get_diagnostic_manager ().emit_saved_diagnostics (eg);
6228 : :
6229 : 3783 : eg.dump_exploded_nodes ();
6230 : :
6231 : 3783 : eg.log_stats ();
6232 : :
6233 : 3783 : if (flag_dump_analyzer_callgraph)
6234 : 5 : dump_callgraph (sg, &eg);
6235 : :
6236 : 3783 : if (flag_dump_analyzer_supergraph)
6237 : : {
6238 : : /* Dump post-analysis form of supergraph. */
6239 : 5 : auto_timevar tv (TV_ANALYZER_DUMP);
6240 : 5 : char *filename = concat (dump_base_name, ".supergraph-eg.dot", NULL);
6241 : 5 : exploded_graph_annotator a (eg);
6242 : 5 : supergraph::dump_args_t args ((enum supergraph_dot_flags)0, &a);
6243 : 5 : sg.dump_dot (filename, args);
6244 : 5 : free (filename);
6245 : 5 : }
6246 : :
6247 : 3783 : if (flag_dump_analyzer_json)
6248 : 0 : dump_analyzer_json (sg, eg);
6249 : :
6250 : 3783 : if (flag_dump_analyzer_untracked)
6251 : 28 : eng.get_model_manager ()->dump_untracked_regions ();
6252 : :
6253 : 3783 : delete purge_map;
6254 : :
6255 : : /* Free up any dominance info that we may have created. */
6256 : 15247 : FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
6257 : : {
6258 : 11464 : function *fun = node->get_fun ();
6259 : 11464 : free_dominance_info (fun, CDI_DOMINATORS);
6260 : : }
6261 : 3783 : }
6262 : :
6263 : : /* Handle -fdump-analyzer and -fdump-analyzer-stderr. */
6264 : : static FILE *dump_fout = NULL;
6265 : :
6266 : : /* Track if we're responsible for closing dump_fout. */
6267 : : static bool owns_dump_fout = false;
6268 : :
6269 : : /* If dumping is enabled, attempt to create dump_fout if it hasn't already
6270 : : been opened. Return it. */
6271 : :
6272 : : FILE *
6273 : 5179 : get_or_create_any_logfile ()
6274 : : {
6275 : 5179 : if (!dump_fout)
6276 : : {
6277 : 5177 : if (flag_dump_analyzer_stderr)
6278 : 0 : dump_fout = stderr;
6279 : 5177 : else if (flag_dump_analyzer)
6280 : : {
6281 : 2 : char *dump_filename = concat (dump_base_name, ".analyzer.txt", NULL);
6282 : 2 : dump_fout = fopen (dump_filename, "w");
6283 : 2 : free (dump_filename);
6284 : 2 : if (dump_fout)
6285 : 2 : owns_dump_fout = true;
6286 : : }
6287 : : }
6288 : 5179 : return dump_fout;
6289 : : }
6290 : :
6291 : : /* External entrypoint to the analysis "engine".
6292 : : Set up any dumps, then call impl_run_checkers. */
6293 : :
6294 : : void
6295 : 3783 : run_checkers ()
6296 : : {
6297 : : /* Save input_location. */
6298 : 3783 : location_t saved_input_location = input_location;
6299 : :
6300 : 3783 : {
6301 : 3783 : log_user the_logger (NULL);
6302 : 3783 : get_or_create_any_logfile ();
6303 : 3783 : if (dump_fout)
6304 : 2 : the_logger.set_logger (new logger (dump_fout, 0, 0,
6305 : 2 : *global_dc->printer));
6306 : 3783 : LOG_SCOPE (the_logger.get_logger ());
6307 : :
6308 : 3783 : impl_run_checkers (the_logger.get_logger ());
6309 : :
6310 : : /* end of lifetime of the_logger (so that dump file is closed after the
6311 : : various dtors run). */
6312 : 3783 : }
6313 : :
6314 : 3783 : if (owns_dump_fout)
6315 : : {
6316 : 2 : fclose (dump_fout);
6317 : 2 : owns_dump_fout = false;
6318 : 2 : dump_fout = NULL;
6319 : : }
6320 : :
6321 : : /* Restore input_location. Subsequent passes may assume that input_location
6322 : : is some arbitrary value *not* in the block tree, which might be violated
6323 : : if we didn't restore it. */
6324 : 3783 : input_location = saved_input_location;
6325 : 3783 : }
6326 : :
6327 : : } // namespace ana
6328 : :
6329 : : #endif /* #if ENABLE_ANALYZER */
|