1 /* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
2 Copyright (C) 2019-2021 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #ifndef GCC_ANALYZER_CHECKER_PATH_H
22 #define GCC_ANALYZER_CHECKER_PATH_H
26 /* An enum for discriminating between the concrete subclasses of
40 EK_START_CONSOLIDATED_CFG_EDGES
,
41 EK_END_CONSOLIDATED_CFG_EDGES
,
43 EK_REWIND_FROM_LONGJMP
,
48 extern const char *event_kind_to_string (enum event_kind ek
);
52 The class hierarchy looks like this (using indentation to show
53 inheritance, and with event_kinds shown for the concrete subclasses):
57 debug_event (EK_DEBUG)
58 custom_event (EK_CUSTOM)
59 precanned_custom_event
60 statement_event (EK_STMT)
61 function_entry_event (EK_FUNCTION_ENTRY)
62 state_change_event (EK_STATE_CHANGE)
65 start_cfg_edge_event (EK_START_CFG_EDGE)
66 end_cfg_edge_event (EK_END_CFG_EDGE)
67 call_event (EK_CALL_EDGE)
68 return_edge (EK_RETURN_EDGE)
69 start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
70 end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
71 setjmp_event (EK_SETJMP)
73 rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
74 rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
75 warning_event (EK_WARNING). */
77 /* Abstract subclass of diagnostic_event; the base class for use in
78 checker_path (the analyzer's diagnostic_path subclass). */
80 class checker_event
: public diagnostic_event
83 checker_event (enum event_kind kind
,
84 location_t loc
, tree fndecl
, int depth
)
85 : m_kind (kind
), m_loc (loc
), m_fndecl (fndecl
), m_depth (depth
),
86 m_pending_diagnostic (NULL
), m_emission_id ()
90 /* Implementation of diagnostic_event. */
92 location_t
get_location () const FINAL OVERRIDE
{ return m_loc
; }
93 tree
get_fndecl () const FINAL OVERRIDE
{ return m_fndecl
; }
94 int get_stack_depth () const FINAL OVERRIDE
{ return m_depth
; }
96 /* Additional functionality. */
98 virtual void prepare_for_emission (checker_path
*,
99 pending_diagnostic
*pd
,
100 diagnostic_event_id_t emission_id
);
101 virtual bool is_call_p () const { return false; }
102 virtual bool is_function_entry_p () const { return false; }
103 virtual bool is_return_p () const { return false; }
105 /* For use with %@. */
106 const diagnostic_event_id_t
*get_id_ptr () const
108 return &m_emission_id
;
111 void dump (pretty_printer
*pp
) const;
113 void set_location (location_t loc
) { m_loc
= loc
; }
116 const enum event_kind m_kind
;
121 pending_diagnostic
*m_pending_diagnostic
;
122 diagnostic_event_id_t m_emission_id
; // only set once all pruning has occurred
125 /* A concrete event subclass for a purely textual event, for use in
126 debugging path creation and filtering. */
128 class debug_event
: public checker_event
131 debug_event (location_t loc
, tree fndecl
, int depth
,
133 : checker_event (EK_DEBUG
, loc
, fndecl
, depth
),
134 m_desc (xstrdup (desc
))
142 label_text
get_desc (bool) const FINAL OVERRIDE
;
148 /* An abstract event subclass for custom events. These are not filtered,
149 as they are likely to be pertinent to the diagnostic. */
151 class custom_event
: public checker_event
154 custom_event (location_t loc
, tree fndecl
, int depth
)
155 : checker_event (EK_CUSTOM
, loc
, fndecl
, depth
)
160 /* A concrete custom_event subclass with a precanned message. */
162 class precanned_custom_event
: public custom_event
165 precanned_custom_event (location_t loc
, tree fndecl
, int depth
,
167 : custom_event (loc
, fndecl
, depth
),
168 m_desc (xstrdup (desc
))
171 ~precanned_custom_event ()
176 label_text
get_desc (bool) const FINAL OVERRIDE
;
182 /* A concrete event subclass describing the execution of a gimple statement,
183 for use at high verbosity levels when debugging paths. */
185 class statement_event
: public checker_event
188 statement_event (const gimple
*stmt
, tree fndecl
, int depth
,
189 const program_state
&dst_state
);
191 label_text
get_desc (bool) const FINAL OVERRIDE
;
193 const gimple
* const m_stmt
;
194 const program_state m_dst_state
;
197 /* An event subclass describing the entry to a function. */
199 class function_entry_event
: public checker_event
202 function_entry_event (location_t loc
, tree fndecl
, int depth
)
203 : checker_event (EK_FUNCTION_ENTRY
, loc
, fndecl
, depth
)
207 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
209 bool is_function_entry_p () const FINAL OVERRIDE
{ return true; }
212 /* Subclass of checker_event describing a state change. */
214 class state_change_event
: public checker_event
217 state_change_event (const supernode
*node
, const gimple
*stmt
,
219 const state_machine
&sm
,
221 state_machine::state_t from
,
222 state_machine::state_t to
,
223 const svalue
*origin
,
224 const program_state
&dst_state
);
226 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
228 function
*get_dest_function () const
230 return m_dst_state
.get_current_function ();
233 const supernode
*m_node
;
234 const gimple
*m_stmt
;
235 const state_machine
&m_sm
;
236 const svalue
*m_sval
;
237 state_machine::state_t m_from
;
238 state_machine::state_t m_to
;
239 const svalue
*m_origin
;
240 program_state m_dst_state
;
243 /* Subclass of checker_event; parent class for subclasses that relate to
246 class superedge_event
: public checker_event
249 /* Mark this edge event as being either an interprocedural call or
250 return in which VAR is in STATE, and that this is critical to the
251 diagnostic (so that get_desc can attempt to get a better description
252 from any pending_diagnostic). */
253 void record_critical_state (tree var
, state_machine::state_t state
)
256 m_critical_state
= state
;
259 const callgraph_superedge
& get_callgraph_superedge () const;
261 bool should_filter_p (int verbosity
) const;
264 superedge_event (enum event_kind kind
, const exploded_edge
&eedge
,
265 location_t loc
, tree fndecl
, int depth
);
268 const exploded_edge
&m_eedge
;
269 const superedge
*m_sedge
;
271 state_machine::state_t m_critical_state
;
274 /* An abstract event subclass for when a CFG edge is followed; it has two
275 subclasses, representing the start of the edge and the end of the
276 edge, which come in pairs. */
278 class cfg_edge_event
: public superedge_event
281 const cfg_superedge
& get_cfg_superedge () const;
284 cfg_edge_event (enum event_kind kind
, const exploded_edge
&eedge
,
285 location_t loc
, tree fndecl
, int depth
);
288 /* A concrete event subclass for the start of a CFG edge
289 e.g. "following 'false' branch...'. */
291 class start_cfg_edge_event
: public cfg_edge_event
294 start_cfg_edge_event (const exploded_edge
&eedge
,
295 location_t loc
, tree fndecl
, int depth
)
296 : cfg_edge_event (EK_START_CFG_EDGE
, eedge
, loc
, fndecl
, depth
)
300 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
303 label_text
maybe_describe_condition (bool can_colorize
) const;
305 static label_text
maybe_describe_condition (bool can_colorize
,
309 static bool should_print_expr_p (tree
);
312 /* A concrete event subclass for the end of a CFG edge
313 e.g. "...to here'. */
315 class end_cfg_edge_event
: public cfg_edge_event
318 end_cfg_edge_event (const exploded_edge
&eedge
,
319 location_t loc
, tree fndecl
, int depth
)
320 : cfg_edge_event (EK_END_CFG_EDGE
, eedge
, loc
, fndecl
, depth
)
324 label_text
get_desc (bool /*can_colorize*/) const FINAL OVERRIDE
326 return label_text::borrow ("...to here");
330 /* A concrete event subclass for an interprocedural call. */
332 class call_event
: public superedge_event
335 call_event (const exploded_edge
&eedge
,
336 location_t loc
, tree fndecl
, int depth
);
338 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
340 bool is_call_p () const FINAL OVERRIDE
;
342 const supernode
*m_src_snode
;
343 const supernode
*m_dest_snode
;
346 /* A concrete event subclass for an interprocedural return. */
348 class return_event
: public superedge_event
351 return_event (const exploded_edge
&eedge
,
352 location_t loc
, tree fndecl
, int depth
);
354 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
356 bool is_return_p () const FINAL OVERRIDE
;
358 const supernode
*m_src_snode
;
359 const supernode
*m_dest_snode
;
362 /* A concrete event subclass for the start of a consolidated run of CFG
363 edges all either TRUE or FALSE e.g. "following 'false' branch...'. */
365 class start_consolidated_cfg_edges_event
: public checker_event
368 start_consolidated_cfg_edges_event (location_t loc
, tree fndecl
, int depth
,
370 : checker_event (EK_START_CONSOLIDATED_CFG_EDGES
, loc
, fndecl
, depth
),
371 m_edge_sense (edge_sense
)
375 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
381 /* A concrete event subclass for the end of a consolidated run of
382 CFG edges e.g. "...to here'. */
384 class end_consolidated_cfg_edges_event
: public checker_event
387 end_consolidated_cfg_edges_event (location_t loc
, tree fndecl
, int depth
)
388 : checker_event (EK_END_CONSOLIDATED_CFG_EDGES
, loc
, fndecl
, depth
)
392 label_text
get_desc (bool /*can_colorize*/) const FINAL OVERRIDE
394 return label_text::borrow ("...to here");
398 /* A concrete event subclass for a setjmp or sigsetjmp call. */
400 class setjmp_event
: public checker_event
403 setjmp_event (location_t loc
, const exploded_node
*enode
,
404 tree fndecl
, int depth
, const gcall
*setjmp_call
)
405 : checker_event (EK_SETJMP
, loc
, fndecl
, depth
),
406 m_enode (enode
), m_setjmp_call (setjmp_call
)
410 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
412 void prepare_for_emission (checker_path
*path
,
413 pending_diagnostic
*pd
,
414 diagnostic_event_id_t emission_id
) FINAL OVERRIDE
;
417 const exploded_node
*m_enode
;
418 const gcall
*m_setjmp_call
;
421 /* An abstract event subclass for rewinding from a longjmp to a setjmp
422 (or siglongjmp to sigsetjmp).
424 Base class for two from/to subclasses, showing the two halves of the
427 class rewind_event
: public checker_event
430 tree
get_longjmp_caller () const;
431 tree
get_setjmp_caller () const;
432 const exploded_edge
*get_eedge () const { return m_eedge
; }
435 rewind_event (const exploded_edge
*eedge
,
436 enum event_kind kind
,
437 location_t loc
, tree fndecl
, int depth
,
438 const rewind_info_t
*rewind_info
);
439 const rewind_info_t
*m_rewind_info
;
442 const exploded_edge
*m_eedge
;
445 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
446 showing the longjmp (or siglongjmp). */
448 class rewind_from_longjmp_event
: public rewind_event
451 rewind_from_longjmp_event (const exploded_edge
*eedge
,
452 location_t loc
, tree fndecl
, int depth
,
453 const rewind_info_t
*rewind_info
)
454 : rewind_event (eedge
, EK_REWIND_FROM_LONGJMP
, loc
, fndecl
, depth
,
459 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
462 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
463 showing the setjmp (or sigsetjmp). */
465 class rewind_to_setjmp_event
: public rewind_event
468 rewind_to_setjmp_event (const exploded_edge
*eedge
,
469 location_t loc
, tree fndecl
, int depth
,
470 const rewind_info_t
*rewind_info
)
471 : rewind_event (eedge
, EK_REWIND_TO_SETJMP
, loc
, fndecl
, depth
,
476 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
478 void prepare_for_emission (checker_path
*path
,
479 pending_diagnostic
*pd
,
480 diagnostic_event_id_t emission_id
) FINAL OVERRIDE
;
483 diagnostic_event_id_t m_original_setjmp_event_id
;
486 /* Concrete subclass of checker_event for use at the end of a path:
487 a repeat of the warning message at the end of the path (perhaps with
488 references to pertinent events that occurred on the way), at the point
489 where the problem occurs. */
491 class warning_event
: public checker_event
494 warning_event (location_t loc
, tree fndecl
, int depth
,
495 const state_machine
*sm
,
496 tree var
, state_machine::state_t state
)
497 : checker_event (EK_WARNING
, loc
, fndecl
, depth
),
498 m_sm (sm
), m_var (var
), m_state (state
)
502 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
505 const state_machine
*m_sm
;
507 state_machine::state_t m_state
;
510 /* Subclass of diagnostic_path for analyzer diagnostics. */
512 class checker_path
: public diagnostic_path
515 checker_path () : diagnostic_path () {}
517 /* Implementation of diagnostic_path vfuncs. */
519 unsigned num_events () const FINAL OVERRIDE
521 return m_events
.length ();
524 const diagnostic_event
& get_event (int idx
) const FINAL OVERRIDE
526 return *m_events
[idx
];
529 checker_event
*get_checker_event (int idx
)
531 return m_events
[idx
];
534 void dump (pretty_printer
*pp
) const;
537 void maybe_log (logger
*logger
, const char *desc
) const;
539 void add_event (checker_event
*event
)
541 m_events
.safe_push (event
);
544 void delete_event (int idx
)
546 checker_event
*event
= m_events
[idx
];
547 m_events
.ordered_remove (idx
);
551 void delete_events (unsigned start_idx
, unsigned len
)
553 for (unsigned i
= start_idx
; i
< start_idx
+ len
; i
++)
555 m_events
.block_remove (start_idx
, len
);
558 void replace_event (unsigned idx
, checker_event
*new_event
)
560 delete m_events
[idx
];
561 m_events
[idx
] = new_event
;
564 void add_final_event (const state_machine
*sm
,
565 const exploded_node
*enode
, const gimple
*stmt
,
566 tree var
, state_machine::state_t state
);
568 /* After all event-pruning, a hook for notifying each event what
569 its ID will be. The events are notified in order, allowing
570 for later events to refer to the IDs of earlier events in
571 their descriptions. */
572 void prepare_for_emission (pending_diagnostic
*pd
)
576 FOR_EACH_VEC_ELT (m_events
, i
, e
)
577 e
->prepare_for_emission (this, pd
, diagnostic_event_id_t (i
));
580 void fixup_locations (pending_diagnostic
*pd
);
582 void record_setjmp_event (const exploded_node
*enode
,
583 diagnostic_event_id_t setjmp_emission_id
)
585 m_setjmp_event_ids
.put (enode
, setjmp_emission_id
);
588 bool get_setjmp_event (const exploded_node
*enode
,
589 diagnostic_event_id_t
*out_emission_id
)
591 if (diagnostic_event_id_t
*emission_id
= m_setjmp_event_ids
.get (enode
))
593 *out_emission_id
= *emission_id
;
599 bool cfg_edge_pair_at_p (unsigned idx
) const;
602 DISABLE_COPY_AND_ASSIGN(checker_path
);
604 /* The events that have occurred along this path. */
605 auto_delete_vec
<checker_event
> m_events
;
607 /* During prepare_for_emission (and after), the setjmp_event for each
608 exploded_node *, so that rewind events can refer to them in their
610 hash_map
<const exploded_node
*, diagnostic_event_id_t
> m_setjmp_event_ids
;
615 #endif /* GCC_ANALYZER_CHECKER_PATH_H */