Line data Source code
1 : /* Classes for managing a directed graph of <point, state> pairs.
2 : Copyright (C) 2019-2026 Free Software Foundation, Inc.
3 : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 :
5 : This file is part of GCC.
6 :
7 : GCC is free software; you can redistribute it and/or modify it
8 : under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3, or (at your option)
10 : any later version.
11 :
12 : GCC is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with GCC; see the file COPYING3. If not see
19 : <http://www.gnu.org/licenses/>. */
20 :
21 : #ifndef GCC_ANALYZER_EXPLODED_GRAPH_H
22 : #define GCC_ANALYZER_EXPLODED_GRAPH_H
23 :
24 : #include "alloc-pool.h"
25 : #include "fibonacci_heap.h"
26 : #include "supergraph.h"
27 : #include "sbitmap.h"
28 : #include "shortest-paths.h"
29 : #include "analyzer/sm.h"
30 : #include "analyzer/program-state.h"
31 : #include "analyzer/diagnostic-manager.h"
32 : #include "analyzer/region-model.h"
33 :
34 : namespace ana {
35 :
36 : /* Concrete implementation of region_model_context, wiring it up to the
37 : rest of the analysis engine. */
38 :
39 1442983 : class impl_region_model_context : public region_model_context
40 : {
41 : public:
42 : impl_region_model_context (exploded_graph &eg,
43 : exploded_node *enode_for_diag,
44 :
45 : /* TODO: should we be getting the ECs from the
46 : old state, rather than the new? */
47 : const program_state *old_state,
48 : program_state *new_state,
49 : uncertainty_t *uncertainty,
50 : path_context *path_ctxt,
51 : const gimple *stmt = nullptr,
52 : bool *out_could_have_done_work = nullptr);
53 :
54 : impl_region_model_context (program_state *state,
55 : const extrinsic_state &ext_state,
56 : uncertainty_t *uncertainty,
57 : logger *logger = nullptr);
58 :
59 : bool
60 : warn_at (std::unique_ptr<pending_diagnostic> d,
61 : pending_location &&ploc) final override;
62 : void add_note (std::unique_ptr<pending_note> pn) final override;
63 : void add_event (std::unique_ptr<checker_event> event) final override;
64 : void on_svalue_leak (const svalue *) override;
65 : void on_liveness_change (const svalue_set &live_svalues,
66 : const region_model *model) final override;
67 797261 : logger *get_logger () final override
68 : {
69 13706 : return m_logger.get_logger ();
70 : }
71 :
72 : void on_state_leak (const state_machine &sm,
73 : const svalue *sval,
74 : state_machine::state_t state);
75 :
76 : void on_condition (const svalue *lhs,
77 : enum tree_code op,
78 : const svalue *rhs) final override;
79 :
80 : void on_bounded_ranges (const svalue &sval,
81 : const bounded_ranges &ranges) final override;
82 :
83 : void on_pop_frame (const frame_region *frame_reg) final override;
84 :
85 : void on_unknown_change (const svalue *sval, bool is_mutable) final override;
86 :
87 : void on_phi (const gphi *phi, tree rhs) final override;
88 :
89 : void on_unexpected_tree_code (tree t,
90 : const dump_location_t &loc) final override;
91 :
92 : void on_escaped_function (tree fndecl) final override;
93 :
94 : uncertainty_t *get_uncertainty () final override;
95 :
96 : void purge_state_involving (const svalue *sval) final override;
97 :
98 : void bifurcate (std::unique_ptr<custom_edge_info> info) final override;
99 : void terminate_path () final override;
100 1162544 : const extrinsic_state *get_ext_state () const final override
101 : {
102 1162544 : return &m_ext_state;
103 : }
104 : bool
105 : get_state_map_by_name (const char *name,
106 : sm_state_map **out_smap,
107 : const state_machine **out_sm,
108 : unsigned *out_sm_idx,
109 : std::unique_ptr<sm_context> *out_sm_context) override;
110 :
111 441038 : const gimple *get_stmt () const override { return m_stmt; }
112 0 : const exploded_graph *get_eg () const override { return m_eg; }
113 :
114 315 : const program_state *get_state () const override { return m_new_state; }
115 :
116 : void maybe_did_work () override;
117 52950 : bool checking_for_infinite_loop_p () const override { return false; }
118 0 : void on_unusable_in_infinite_loop () override {}
119 :
120 : pending_location
121 : get_pending_location_for_diag () const override;
122 :
123 : exploded_graph *m_eg;
124 : log_user m_logger;
125 : exploded_node *m_enode_for_diag;
126 : const program_state *m_old_state;
127 : program_state *m_new_state;
128 : const gimple *m_stmt;
129 : const extrinsic_state &m_ext_state;
130 : uncertainty_t *m_uncertainty;
131 : path_context *m_path_ctxt;
132 : bool *m_out_could_have_done_work;
133 : };
134 :
135 : /* A <program_point, program_state> pair, used internally by
136 : exploded_node as its immutable data, and as a key for identifying
137 : exploded_nodes we've already seen in the graph. */
138 :
139 436091 : class point_and_state
140 : {
141 : public:
142 436091 : point_and_state (const program_point &point,
143 : const program_state &state)
144 436091 : : m_point (point),
145 436091 : m_state (state),
146 436091 : m_hash (m_point.hash () ^ m_state.hash ())
147 : {
148 : /* We shouldn't be building point_and_states and thus exploded_nodes
149 : for states that aren't valid. */
150 436091 : gcc_assert (state.m_valid);
151 436091 : }
152 :
153 0 : point_and_state (const point_and_state &other) = default;
154 :
155 428720 : point_and_state (point_and_state &&other)
156 428720 : : m_point (other.m_point),
157 428720 : m_state (std::move (other.m_state)),
158 428720 : m_hash (other.m_hash)
159 : {
160 : }
161 :
162 6083017 : hashval_t hash () const
163 : {
164 6083017 : return m_hash;
165 : }
166 5776293 : bool operator== (const point_and_state &other) const
167 : {
168 5817789 : return m_point == other.m_point && m_state == other.m_state;
169 : }
170 :
171 210779 : const program_point &get_point () const { return m_point; }
172 1893905 : const program_state &get_state () const { return m_state; }
173 :
174 : void set_state (const program_state &state)
175 : {
176 : m_state = state;
177 : m_hash = m_point.hash () ^ m_state.hash ();
178 : }
179 :
180 27702 : void set_state (program_state &&state)
181 : {
182 27702 : m_state = std::move (state);
183 27702 : m_hash = m_point.hash () ^ m_state.hash ();
184 27702 : }
185 :
186 : void validate (const extrinsic_state &ext_state) const;
187 :
188 : private:
189 : program_point m_point;
190 : program_state m_state;
191 : hashval_t m_hash;
192 : };
193 :
194 : /* A traits class for exploded graphs and their nodes and edges. */
195 :
196 : struct eg_traits
197 : {
198 : typedef exploded_node node_t;
199 : typedef exploded_edge edge_t;
200 : typedef exploded_graph graph_t;
201 : struct dump_args_t
202 : {
203 12 : dump_args_t (const exploded_graph &eg) : m_eg (eg) {}
204 :
205 : bool show_enode_details_p (const exploded_node &enode) const;
206 :
207 : virtual void
208 433 : dump_extra_info (const exploded_node *, pretty_printer *) const {}
209 :
210 : const exploded_graph &m_eg;
211 : };
212 : typedef exploded_cluster cluster_t;
213 : };
214 :
215 : /* An exploded_node is a unique, immutable <point, state> pair within the
216 : exploded_graph.
217 : Each exploded_node has a unique index within the graph
218 : (for ease of debugging). */
219 :
220 : class exploded_node : public dnode<eg_traits>
221 : {
222 : public:
223 : /* Has this enode had exploded_graph::process_node called on it?
224 : This allows us to distinguish enodes that were merged during
225 : worklist-handling, and thus never had process_node called on them
226 : (in favor of processing the merged node). */
227 : enum class status
228 : {
229 : /* Node is in the worklist. */
230 : worklist,
231 :
232 : /* Node has had exploded_graph::process_node called on it. */
233 : processed,
234 :
235 : /* Node was excluded from worklist on creation.
236 : e.g. for handling exception-unwinding. */
237 : special,
238 :
239 : /* Node was left unprocessed due to merger; it won't have had
240 : exploded_graph::process_node called on it. */
241 : merger,
242 :
243 : /* Node was processed by maybe_process_run_of_enodes. */
244 : bulk_merged
245 : };
246 : static const char * status_to_str (enum status s);
247 :
248 : exploded_node (const point_and_state &ps, int index);
249 : exploded_node (point_and_state &&ps, int index);
250 :
251 : hashval_t hash () const { return m_ps.hash (); }
252 :
253 : const char * get_dot_fillcolor () const;
254 : void dump_dot (graphviz_out *gv, const dump_args_t &args)
255 : const final override;
256 : void dump_dot_id (pretty_printer *pp) const;
257 :
258 : void dump_to_pp (pretty_printer *pp, const extrinsic_state &ext_state) const;
259 : void dump (FILE *fp, const extrinsic_state &ext_state) const;
260 : void dump (const extrinsic_state &ext_state) const;
261 :
262 : void dump_processed_stmts (pretty_printer *pp) const;
263 : void dump_saved_diagnostics (pretty_printer *pp) const;
264 :
265 : std::unique_ptr<json::object> to_json (const extrinsic_state &ext_state) const;
266 :
267 : void on_longjmp (exploded_graph &eg,
268 : const gcall &call,
269 : program_state *new_state,
270 : region_model_context *ctxt);
271 : void on_throw (exploded_graph &eg,
272 : const gcall &call,
273 : const program_point &after_throw_point,
274 : program_state *new_state,
275 : bool is_rethrow,
276 : region_model_context *ctxt);
277 :
278 : void detect_leaks (exploded_graph &eg);
279 :
280 4047535 : const program_point &get_point () const { return m_ps.get_point (); }
281 5299635 : const supernode *get_supernode () const
282 : {
283 1629059 : return get_point ().get_supernode ();
284 : }
285 411329 : location_t get_location () const
286 : {
287 819113 : return get_point ().get_location ();
288 : }
289 422576 : function *get_function () const
290 : {
291 840678 : return get_point ().get_function ();
292 : }
293 37055 : int get_stack_depth () const
294 : {
295 85188 : return get_point ().get_stack_depth ();
296 : }
297 :
298 1038530 : const program_state &get_state () const { return m_ps.get_state (); }
299 :
300 428720 : const point_and_state *get_ps_key () const { return &m_ps; }
301 : const program_point *get_point_key () const { return &m_ps.get_point (); }
302 :
303 : void dump_succs_and_preds (FILE *outf) const;
304 :
305 1411513 : enum status get_status () const { return m_status; }
306 427514 : void set_status (enum status s)
307 : {
308 427514 : gcc_assert (m_status == status::worklist);
309 427514 : m_status = s;
310 427514 : }
311 :
312 6663 : void add_diagnostic (const saved_diagnostic *sd)
313 : {
314 6663 : m_saved_diagnostics.safe_push (sd);
315 : }
316 437 : unsigned get_num_diagnostics () const
317 : {
318 437 : return m_saved_diagnostics.length ();
319 : }
320 4 : const saved_diagnostic *get_saved_diagnostic (unsigned idx) const
321 : {
322 4 : return m_saved_diagnostics[idx];
323 : }
324 :
325 : private:
326 : DISABLE_COPY_AND_ASSIGN (exploded_node);
327 :
328 : /* The <program_point, program_state> pair. This is const, as it
329 : is immutable once the exploded_node has been created. */
330 : const point_and_state m_ps;
331 :
332 : enum status m_status;
333 :
334 : /* The saved_diagnostics at this enode, borrowed from the
335 : diagnostic_manager. */
336 : auto_vec <const saved_diagnostic *> m_saved_diagnostics;
337 :
338 : public:
339 : /* The index of this exploded_node. */
340 : const int m_index;
341 : };
342 :
343 : /* An edge within the exploded graph.
344 : Some exploded_edges have an underlying superedge; others don't. */
345 :
346 : class exploded_edge : public dedge<eg_traits>
347 : {
348 : public:
349 : exploded_edge (exploded_node *src, exploded_node *dest,
350 : const superedge *sedge, bool could_do_work,
351 : std::unique_ptr<custom_edge_info> custom_info);
352 : void dump_dot (graphviz_out *gv, const dump_args_t &args)
353 : const final override;
354 : void dump_dot_label (pretty_printer *pp) const;
355 :
356 : std::unique_ptr<json::object> to_json () const;
357 :
358 : //private:
359 : const superedge *const m_sedge;
360 :
361 : /* nullptr for most edges; will be non-NULL for special cases
362 : such as an unwind from a longjmp to a setjmp, or when
363 : a signal is delivered to a signal-handler. */
364 : std::unique_ptr<custom_edge_info> m_custom_info;
365 :
366 59987 : bool could_do_work_p () const { return m_could_do_work_p; }
367 :
368 : const gimple *maybe_get_stmt () const;
369 : const operation *maybe_get_op () const;
370 :
371 : private:
372 : DISABLE_COPY_AND_ASSIGN (exploded_edge);
373 :
374 : /* For -Wanalyzer-infinite-loop.
375 : Set to true during processing if any of the activity along
376 : this edge is "externally-visible work" (and thus ruling this
377 : out as being part of an infinite loop.
378 :
379 : For example, given:
380 :
381 : while (1)
382 : do_something ();
383 :
384 : although it is an infinite loop, presumably the point of the
385 : program is the loop body, and thus reporting this as an infinite
386 : loop is likely to be unhelpful to the user. */
387 : bool m_could_do_work_p;
388 : };
389 :
390 : /* Extra data for an exploded_edge that represents an interprocedural
391 : call. */
392 :
393 : class interprocedural_call : public custom_edge_info
394 : {
395 : public:
396 9355 : interprocedural_call (const call_and_return_op &op,
397 : function &callee_fun)
398 9355 : : m_op (op),
399 9355 : m_callee_fun (callee_fun)
400 : {}
401 :
402 : void print (pretty_printer *pp) const final override;
403 :
404 : void get_dot_attrs (const char *&out_style,
405 : const char *&out_color) const final override;
406 :
407 : bool update_state (program_state *state,
408 : const exploded_edge *eedge,
409 : region_model_context *ctxt) const final override;
410 :
411 : bool update_model (region_model *model,
412 : const exploded_edge *eedge,
413 : region_model_context *ctxt) const final override;
414 :
415 : void add_events_to_path (checker_path *emission_path,
416 : const exploded_edge &eedge,
417 : pending_diagnostic &pd,
418 : const state_transition *state_trans) const final override;
419 :
420 : bool
421 : try_to_rewind_data_flow (rewind_context &) const final override;
422 :
423 : const gcall &get_gcall () const;
424 :
425 : private:
426 : const call_and_return_op &m_op;
427 : function &m_callee_fun;
428 : };
429 :
430 : /* Extra data for an exploded_edge that represents an interprocedural
431 : return. */
432 :
433 : class interprocedural_return : public custom_edge_info
434 : {
435 : public:
436 8426 : interprocedural_return (const gcall &call_stmt)
437 8426 : : m_call_stmt (call_stmt)
438 : {}
439 :
440 : void print (pretty_printer *pp) const final override;
441 :
442 : void get_dot_attrs (const char *&out_style,
443 : const char *&out_color) const final override;
444 :
445 : bool update_state (program_state *state,
446 : const exploded_edge *eedge,
447 : region_model_context *ctxt) const final override;
448 :
449 : bool update_model (region_model *model,
450 : const exploded_edge *eedge,
451 : region_model_context *ctxt) const final override;
452 :
453 : void add_events_to_path (checker_path *emission_path,
454 : const exploded_edge &eedge,
455 : pending_diagnostic &pd,
456 : const state_transition *state_trans) const final override;
457 :
458 : bool
459 : try_to_rewind_data_flow (rewind_context &) const final override;
460 :
461 : private:
462 : const gcall &m_call_stmt;
463 : };
464 :
465 : /* Extra data for an exploded_edge that represents a rewind from a
466 : longjmp to a setjmp (or from a siglongjmp to a sigsetjmp). */
467 :
468 25 : class rewind_info_t : public custom_edge_info
469 : {
470 : public:
471 45 : rewind_info_t (const setjmp_record &setjmp_record,
472 : const gcall &longjmp_call)
473 25 : : m_setjmp_record (setjmp_record),
474 25 : m_longjmp_call (longjmp_call)
475 : {}
476 :
477 0 : void print (pretty_printer *pp) const final override
478 : {
479 0 : pp_string (pp, "rewind");
480 0 : }
481 :
482 : bool update_model (region_model *model,
483 : const exploded_edge *eedge,
484 : region_model_context *ctxt) const final override;
485 :
486 : void add_events_to_path (checker_path *emission_path,
487 : const exploded_edge &eedge,
488 : pending_diagnostic &pd,
489 : const state_transition *state_trans) const final override;
490 :
491 : program_point
492 25 : get_point_before_setjmp () const
493 : {
494 25 : return get_enode_origin ()->get_point ();
495 : }
496 :
497 : program_point
498 25 : get_point_after_setjmp () const
499 : {
500 25 : const program_point &origin_point = get_enode_origin ()->get_point ();
501 25 : return program_point (m_setjmp_record.m_sedge->m_dest,
502 25 : origin_point.get_call_string ());
503 : }
504 :
505 68 : const gcall &get_setjmp_call () const
506 : {
507 46 : return *m_setjmp_record.m_setjmp_call;
508 : }
509 :
510 68 : const gcall &get_longjmp_call () const
511 : {
512 68 : return m_longjmp_call;
513 : }
514 :
515 40 : const exploded_node *get_enode_origin () const
516 : {
517 40 : return m_setjmp_record.m_enode;
518 : }
519 :
520 : private:
521 : setjmp_record m_setjmp_record;
522 : const gcall &m_longjmp_call;
523 : };
524 :
525 : /* Statistics about aspects of an exploded_graph. */
526 :
527 : struct stats
528 : {
529 : stats (int num_supernodes);
530 : void log (logger *logger) const;
531 : void dump (FILE *out) const;
532 :
533 : int get_total_enodes () const;
534 :
535 : int m_num_nodes;
536 : int m_node_reuse_count;
537 : int m_node_reuse_after_merge_count;
538 : int m_num_supernodes;
539 : };
540 :
541 : /* Traits class for ensuring uniqueness of point_and_state data within
542 : an exploded_graph. */
543 :
544 : struct eg_hash_map_traits
545 : {
546 : typedef const point_and_state *key_type;
547 : typedef exploded_node *value_type;
548 : typedef exploded_node *compare_type;
549 :
550 6083017 : static inline hashval_t hash (const key_type &k)
551 : {
552 6083017 : gcc_assert (k != nullptr);
553 6083017 : gcc_assert (k != reinterpret_cast<key_type> (1));
554 6083017 : return k->hash ();
555 : }
556 5776293 : static inline bool equal_keys (const key_type &k1, const key_type &k2)
557 : {
558 5776293 : gcc_assert (k1 != nullptr);
559 5776293 : gcc_assert (k2 != nullptr);
560 5776293 : gcc_assert (k1 != reinterpret_cast<key_type> (1));
561 5776293 : gcc_assert (k2 != reinterpret_cast<key_type> (1));
562 5776293 : if (k1 && k2)
563 5776293 : return *k1 == *k2;
564 : else
565 : /* Otherwise they must both be non-NULL. */
566 : return k1 == k2;
567 : }
568 : template <typename T>
569 : static inline void remove (T &)
570 : {
571 : /* empty; the nodes are handled elsewhere. */
572 : }
573 : template <typename T>
574 : static inline void mark_deleted (T &entry)
575 : {
576 : entry.m_key = reinterpret_cast<key_type> (1);
577 : }
578 : template <typename T>
579 1546517 : static inline void mark_empty (T &entry)
580 : {
581 1546517 : entry.m_key = nullptr;
582 : }
583 : template <typename T>
584 6904974 : static inline bool is_deleted (const T &entry)
585 : {
586 6904974 : return entry.m_key == reinterpret_cast<key_type> (1);
587 : }
588 : template <typename T>
589 21858583 : static inline bool is_empty (const T &entry)
590 : {
591 21858583 : return entry.m_key == nullptr;
592 : }
593 : static const bool empty_zero_p = false;
594 : };
595 :
596 : /* Per-program_point data for an exploded_graph. */
597 :
598 267456 : struct per_program_point_data
599 : {
600 267456 : per_program_point_data (const program_point &key)
601 267456 : : m_key (key), m_excess_enodes (0)
602 : {}
603 :
604 : const program_point m_key;
605 : auto_vec<exploded_node *> m_enodes;
606 : /* The number of attempts to create an enode for this point
607 : after exceeding --param=analyzer-max-enodes-per-program-point. */
608 : int m_excess_enodes;
609 : };
610 :
611 : /* Traits class for storing per-program_point data within
612 : an exploded_graph. */
613 :
614 : struct eg_point_hash_map_traits
615 : {
616 : typedef const program_point *key_type;
617 : typedef per_program_point_data *value_type;
618 : typedef per_program_point_data *compare_type;
619 :
620 4662600 : static inline hashval_t hash (const key_type &k)
621 : {
622 4662600 : gcc_assert (k != nullptr);
623 4662600 : gcc_assert (k != reinterpret_cast<key_type> (1));
624 4662600 : return k->hash ();
625 : }
626 4561702 : static inline bool equal_keys (const key_type &k1, const key_type &k2)
627 : {
628 4561702 : gcc_assert (k1 != nullptr);
629 4561702 : gcc_assert (k2 != nullptr);
630 4561702 : gcc_assert (k1 != reinterpret_cast<key_type> (1));
631 4561702 : gcc_assert (k2 != reinterpret_cast<key_type> (1));
632 4561702 : if (k1 && k2)
633 4561702 : return *k1 == *k2;
634 : else
635 : /* Otherwise they must both be non-NULL. */
636 : return k1 == k2;
637 : }
638 : template <typename T>
639 : static inline void remove (T &)
640 : {
641 : /* empty; the nodes are handled elsewhere. */
642 : }
643 : template <typename T>
644 : static inline void mark_deleted (T &entry)
645 : {
646 : entry.m_key = reinterpret_cast<key_type> (1);
647 : }
648 : template <typename T>
649 948916 : static inline void mark_empty (T &entry)
650 : {
651 948916 : entry.m_key = nullptr;
652 : }
653 : template <typename T>
654 5522227 : static inline bool is_deleted (const T &entry)
655 : {
656 5522227 : return entry.m_key == reinterpret_cast<key_type> (1);
657 : }
658 : template <typename T>
659 17109741 : static inline bool is_empty (const T &entry)
660 : {
661 17109741 : return entry.m_key == nullptr;
662 : }
663 : static const bool empty_zero_p = false;
664 : };
665 :
666 : /* Data about a particular call_string within an exploded_graph. */
667 :
668 : struct per_call_string_data
669 : {
670 11052 : per_call_string_data (const call_string &key, int num_supernodes)
671 11052 : : m_key (key), m_stats (num_supernodes)
672 : {}
673 :
674 : const call_string &m_key;
675 : stats m_stats;
676 : };
677 :
678 : /* Data about a particular function within an exploded_graph. */
679 :
680 : struct per_function_data
681 : {
682 368 : per_function_data () {}
683 : ~per_function_data ();
684 :
685 : void add_call_summary (exploded_node *node);
686 :
687 : auto_vec<call_summary *> m_summaries;
688 : };
689 :
690 : /* The strongly connected components of a supergraph.
691 : In particular, this allows us to compute a partial ordering
692 : of supernodes. */
693 :
694 : class strongly_connected_components
695 : {
696 : public:
697 : strongly_connected_components (const supergraph &sg, logger *logger);
698 :
699 3569853 : int get_scc_id (int node_index) const
700 : {
701 382 : return m_per_node[node_index].m_lowlink;
702 : }
703 :
704 : void dump () const;
705 :
706 : std::unique_ptr<json::array> to_json () const;
707 :
708 : private:
709 : struct per_node_data
710 : {
711 197108 : per_node_data ()
712 197108 : : m_id (-1), m_lowlink (-1), m_on_stack (false)
713 : {}
714 :
715 : int m_id;
716 : int m_lowlink;
717 : bool m_on_stack;
718 : };
719 :
720 : void strong_connect (unsigned index, logger *logger);
721 :
722 : const supergraph &m_sg;
723 : auto_vec<unsigned> m_stack;
724 : auto_vec<per_node_data> m_per_node;
725 : };
726 :
727 : /* The worklist of exploded_node instances that have been added to
728 : an exploded_graph, but that haven't yet been processed to find
729 : their successors (or warnings).
730 :
731 : The enodes are stored in a priority queue, ordered by a topological
732 : sort of the SCCs in the supergraph, so that enodes for the same
733 : program_point should appear at the front of the queue together.
734 : This allows for state-merging at CFG join-points, so that
735 : sufficiently-similar enodes can be merged into one. */
736 :
737 : class worklist
738 : {
739 : public:
740 : worklist (const exploded_graph &eg, const analysis_plan &plan);
741 : unsigned length () const;
742 : exploded_node *take_next ();
743 : exploded_node *peek_next ();
744 : void add_node (exploded_node *enode);
745 620 : int get_scc_id (const supernode &snode) const
746 : {
747 1240 : return m_scc.get_scc_id (snode.m_id);
748 : }
749 :
750 : std::unique_ptr<json::object> to_json () const;
751 :
752 : private:
753 : class key_t
754 : {
755 : public:
756 424703 : key_t (const worklist &w, exploded_node *enode)
757 424703 : : m_worklist (w), m_enode (enode)
758 : {}
759 :
760 1596670 : bool operator< (const key_t &other) const
761 : {
762 1596670 : return cmp (*this, other) < 0;
763 : }
764 :
765 457246 : bool operator== (const key_t &other) const
766 : {
767 457246 : return cmp (*this, other) == 0;
768 : }
769 :
770 457246 : bool operator> (const key_t &other) const
771 : {
772 914492 : return !(*this == other || *this < other);
773 : }
774 :
775 : private:
776 : static int cmp (const key_t &ka, const key_t &kb);
777 :
778 3580362 : int get_scc_id (const exploded_node *enode) const
779 : {
780 3580362 : const supernode *snode = enode->get_supernode ();
781 3580362 : if (snode == nullptr)
782 : return 0;
783 3569233 : return m_worklist.m_scc.get_scc_id (snode->m_id);
784 : }
785 :
786 : const worklist &m_worklist;
787 : exploded_node *m_enode;
788 : };
789 :
790 : /* The order is important here: m_scc needs to stick around
791 : until after m_queue has finished being cleaned up (the dtor
792 : calls the ordering fns). */
793 : strongly_connected_components m_scc;
794 : const analysis_plan &m_plan;
795 :
796 : /* Priority queue, backed by a fibonacci_heap. */
797 : typedef fibonacci_heap<key_t, exploded_node> queue_t;
798 : queue_t m_queue;
799 : };
800 :
801 : /* An exploded_graph is a directed graph of unique <point, state> pairs.
802 : It also has a worklist of nodes that are waiting for their successors
803 : to be added to the graph. */
804 :
805 : class exploded_graph : public digraph<eg_traits>
806 : {
807 : public:
808 : typedef hash_map <const call_string *,
809 : per_call_string_data *> call_string_data_map_t;
810 :
811 : exploded_graph (const supergraph &sg, logger *logger,
812 : const extrinsic_state &ext_state,
813 : const state_purge_map *purge_map,
814 : const analysis_plan &plan,
815 : int verbosity);
816 : ~exploded_graph ();
817 :
818 6938192 : logger *get_logger () const { return m_logger.get_logger (); }
819 :
820 70117 : const supergraph &get_supergraph () const { return m_sg; }
821 4036834 : const extrinsic_state &get_ext_state () const { return m_ext_state; }
822 6663 : engine *get_engine () const { return m_ext_state.get_engine (); }
823 432588 : const state_purge_map *get_purge_map () const { return m_purge_map; }
824 10108 : const analysis_plan &get_analysis_plan () const { return m_plan; }
825 :
826 6673 : exploded_node *get_origin () const { return m_origin; }
827 :
828 : exploded_node *add_function_entry (const function &fun);
829 :
830 : void build_initial_worklist ();
831 : void process_worklist ();
832 : bool maybe_process_run_of_enodes (exploded_node *node);
833 : void process_node (exploded_node *node);
834 :
835 : exploded_node *get_or_create_node (const program_point &point,
836 : const program_state &state,
837 : exploded_node *enode_for_diag,
838 : bool add_to_worklist = true);
839 : exploded_edge *add_edge (exploded_node *src, exploded_node *dest,
840 : const superedge *sedge, bool could_do_work,
841 : std::unique_ptr<custom_edge_info> custom = nullptr);
842 :
843 : per_program_point_data *
844 : get_or_create_per_program_point_data (const program_point &);
845 : per_program_point_data *
846 : get_per_program_point_data (const program_point &) const;
847 :
848 : per_call_string_data *
849 : get_or_create_per_call_string_data (const call_string &);
850 :
851 : per_function_data *
852 : get_or_create_per_function_data (function *);
853 : per_function_data *get_per_function_data (function *) const;
854 :
855 : void save_diagnostic (const state_machine &sm,
856 : const exploded_node *enode,
857 : const supernode *node, const gimple *stmt,
858 : tree var, state_machine::state_t state,
859 : pending_diagnostic *d);
860 :
861 14636 : diagnostic_manager &get_diagnostic_manager ()
862 : {
863 14656 : return m_diagnostic_manager;
864 : }
865 : const diagnostic_manager &get_diagnostic_manager () const
866 : {
867 : return m_diagnostic_manager;
868 : }
869 :
870 : stats *get_global_stats () { return &m_global_stats; }
871 : stats *get_or_create_function_stats (function *fn);
872 : void log_stats () const;
873 : void dump_stats (FILE *) const;
874 : void dump_exploded_nodes () const;
875 :
876 : std::unique_ptr<json::object> to_json () const;
877 :
878 : exploded_node *get_node_by_index (int idx) const;
879 :
880 : const call_string_data_map_t *get_per_call_string_data () const
881 : { return &m_per_call_string_data; }
882 :
883 620 : int get_scc_id (const supernode &node) const
884 : {
885 620 : return m_worklist.get_scc_id (node);
886 : }
887 :
888 : void on_escaped_function (tree fndecl);
889 :
890 : void unwind_from_exception (exploded_node &enode,
891 : const gimple *stmt,
892 : region_model_context *ctxt);
893 :
894 : /* In infinite-loop.cc */
895 : void detect_infinite_loops ();
896 :
897 : /* In infinite-recursion.cc */
898 : void detect_infinite_recursion (exploded_node *enode);
899 : exploded_node *find_previous_entry_to (function *top_of_stack_fun,
900 : exploded_node *enode) const;
901 :
902 : private:
903 : void print_bar_charts (pretty_printer *pp) const;
904 :
905 : DISABLE_COPY_AND_ASSIGN (exploded_graph);
906 :
907 : const supergraph &m_sg;
908 :
909 : log_user m_logger;
910 :
911 : /* Map from point/state to exploded node.
912 : To avoid duplication we store point_and_state
913 : *pointers* as keys, rather than point_and_state, using the
914 : instance from within the exploded_node, with a custom hasher. */
915 : typedef hash_map <const point_and_state *, exploded_node *,
916 : eg_hash_map_traits> map_t;
917 : map_t m_point_and_state_to_node;
918 :
919 : /* Map from program_point to per-program_point data. */
920 : typedef hash_map <const program_point *, per_program_point_data *,
921 : eg_point_hash_map_traits> point_map_t;
922 : point_map_t m_per_point_data;
923 :
924 : worklist m_worklist;
925 :
926 : exploded_node *m_origin;
927 :
928 : const extrinsic_state &m_ext_state;
929 :
930 : const state_purge_map *const m_purge_map;
931 :
932 : const analysis_plan &m_plan;
933 :
934 : typedef hash_map<function *, per_function_data *> per_function_data_t;
935 : per_function_data_t m_per_function_data;
936 :
937 : diagnostic_manager m_diagnostic_manager;
938 :
939 : /* Stats. */
940 : stats m_global_stats;
941 : typedef ordered_hash_map<function *, stats *> function_stat_map_t;
942 : function_stat_map_t m_per_function_stats;
943 : stats m_functionless_stats;
944 :
945 : call_string_data_map_t m_per_call_string_data;
946 :
947 : /* Functions with a top-level enode, to make add_function_entry
948 : be idempotent, for use in handling callbacks. */
949 : hash_set<function *> m_functions_with_enodes;
950 : };
951 :
952 : /* A reason why a particular exploded_path is infeasible. */
953 :
954 4 : class feasibility_problem
955 : {
956 : public:
957 4 : feasibility_problem (unsigned eedge_idx,
958 : const exploded_edge &eedge,
959 : std::unique_ptr<rejected_constraint> rc)
960 4 : : m_eedge_idx (eedge_idx), m_eedge (eedge),
961 4 : m_rc (std::move (rc))
962 : {}
963 :
964 : void dump_to_pp (pretty_printer *pp) const;
965 :
966 : unsigned m_eedge_idx;
967 : const exploded_edge &m_eedge;
968 : std::unique_ptr<rejected_constraint> m_rc;
969 : };
970 :
971 : /* A class for capturing the state of a node when checking a path
972 : through the exploded_graph for feasibility. */
973 :
974 : class feasibility_state
975 : {
976 : public:
977 : feasibility_state (region_model_manager *manager,
978 : const supergraph &sg);
979 : feasibility_state (const region_model &model,
980 : const supergraph &sg);
981 : feasibility_state (const feasibility_state &other);
982 :
983 : feasibility_state &operator= (const feasibility_state &other);
984 :
985 : bool maybe_update_for_edge (logger *logger,
986 : const exploded_edge *eedge,
987 : region_model_context *ctxt,
988 : std::unique_ptr<rejected_constraint> *out_rc);
989 :
990 202175 : region_model &get_model () { return m_model; }
991 1790 : const region_model &get_model () const { return m_model; }
992 : auto_sbitmap &get_snodes_visited () { return m_snodes_visited; }
993 : const auto_sbitmap &get_snodes_visited () const { return m_snodes_visited; }
994 :
995 : void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
996 :
997 : private:
998 : region_model m_model;
999 : auto_sbitmap m_snodes_visited;
1000 : };
1001 :
1002 : // TODO: split the above up?
1003 :
1004 : } // namespace ana
1005 :
1006 : #endif /* GCC_ANALYZER_EXPLODED_GRAPH_H */
|