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