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