1 /* Subclasses of diagnostic_event for analyzer diagnostics.
2 Copyright (C) 2019-2022 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_EVENT_H
22 #define GCC_ANALYZER_CHECKER_EVENT_H
24 #include "tree-logical-location.h"
25 #include "analyzer/program-state.h"
29 /* An enum for discriminating between the concrete subclasses of
44 EK_START_CONSOLIDATED_CFG_EDGES,
45 EK_END_CONSOLIDATED_CFG_EDGES,
48 EK_REWIND_FROM_LONGJMP,
53 extern const char *event_kind_to_string (enum event_kind ek);
57 The class hierarchy looks like this (using indentation to show
58 inheritance, and with event_kinds shown for the concrete subclasses):
62 debug_event (EK_DEBUG)
63 custom_event (EK_CUSTOM)
64 precanned_custom_event
65 statement_event (EK_STMT)
66 region_creation_event (EK_REGION_CREATION)
67 function_entry_event (EK_FUNCTION_ENTRY)
68 state_change_event (EK_STATE_CHANGE)
71 start_cfg_edge_event (EK_START_CFG_EDGE)
72 end_cfg_edge_event (EK_END_CFG_EDGE)
73 call_event (EK_CALL_EDGE)
74 return_edge (EK_RETURN_EDGE)
75 start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
76 end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
77 inlined_call_event (EK_INLINED_CALL)
78 setjmp_event (EK_SETJMP)
80 rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
81 rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
82 warning_event (EK_WARNING). */
84 /* Abstract subclass of diagnostic_event; the base class for use in
85 checker_path (the analyzer's diagnostic_path subclass). */
87 class checker_event : public diagnostic_event
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_effective_fndecl; }
94 int get_stack_depth () const final override { return m_effective_depth; }
95 const logical_location *get_logical_location () const final override
97 if (m_effective_fndecl)
98 return &m_logical_loc;
102 meaning get_meaning () const override;
104 /* Additional functionality. */
106 int get_original_stack_depth () const { return m_original_depth; }
108 virtual void prepare_for_emission (checker_path *,
109 pending_diagnostic *pd,
110 diagnostic_event_id_t emission_id);
111 virtual bool is_call_p () const { return false; }
112 virtual bool is_function_entry_p () const { return false; }
113 virtual bool is_return_p () const { return false; }
115 /* For use with %@. */
116 const diagnostic_event_id_t *get_id_ptr () const
118 return &m_emission_id;
121 void dump (pretty_printer *pp) const;
124 void set_location (location_t loc) { m_loc = loc; }
127 checker_event (enum event_kind kind,
128 location_t loc, tree fndecl, int depth);
131 const enum event_kind m_kind;
134 tree m_original_fndecl;
135 tree m_effective_fndecl;
136 int m_original_depth;
137 int m_effective_depth;
138 pending_diagnostic *m_pending_diagnostic;
139 diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
140 tree_logical_location m_logical_loc;
143 /* A concrete event subclass for a purely textual event, for use in
144 debugging path creation and filtering. */
146 class debug_event : public checker_event
149 debug_event (location_t loc, tree fndecl, int depth,
151 : checker_event (EK_DEBUG, loc, fndecl, depth),
152 m_desc (xstrdup (desc))
160 label_text get_desc (bool) const final override;
166 /* An abstract event subclass for custom events. These are not filtered,
167 as they are likely to be pertinent to the diagnostic. */
169 class custom_event : public checker_event
172 custom_event (location_t loc, tree fndecl, int depth)
173 : checker_event (EK_CUSTOM, loc, fndecl, depth)
178 /* A concrete custom_event subclass with a precanned message. */
180 class precanned_custom_event : public custom_event
183 precanned_custom_event (location_t loc, tree fndecl, int depth,
185 : custom_event (loc, fndecl, depth),
186 m_desc (xstrdup (desc))
189 ~precanned_custom_event ()
194 label_text get_desc (bool) const final override;
200 /* A concrete event subclass describing the execution of a gimple statement,
201 for use at high verbosity levels when debugging paths. */
203 class statement_event : public checker_event
206 statement_event (const gimple *stmt, tree fndecl, int depth,
207 const program_state &dst_state);
209 label_text get_desc (bool) const final override;
211 const gimple * const m_stmt;
212 const program_state m_dst_state;
215 /* An abstract event subclass describing the creation of a region that
216 is significant for a diagnostic.
218 There are too many combinations to express region creation in one message,
219 so we emit multiple region_creation_event instances when each pertinent
222 The events are created by pending_diagnostic's add_region_creation_events
223 vfunc, which by default creates a region_creation_event_memory_space, and
224 if a capacity is known, a region_creation_event_capacity, giving e.g.:
225 (1) region created on stack here
226 (2) capacity: 100 bytes
227 but this vfunc can be overridden to create other events if other wordings
228 are more appropriate foa a given pending_diagnostic. */
230 class region_creation_event : public checker_event
233 region_creation_event (location_t loc, tree fndecl, int depth);
236 /* Concrete subclass of region_creation_event.
237 Generates a message based on the memory space of the region
238 e.g. "region created on stack here". */
240 class region_creation_event_memory_space : public region_creation_event
243 region_creation_event_memory_space (enum memory_space mem_space,
244 location_t loc, tree fndecl, int depth)
245 : region_creation_event (loc, fndecl, depth),
246 m_mem_space (mem_space)
250 label_text get_desc (bool can_colorize) const final override;
253 enum memory_space m_mem_space;
256 /* Concrete subclass of region_creation_event.
257 Generates a message based on the capacity of the region
258 e.g. "capacity: 100 bytes". */
260 class region_creation_event_capacity : public region_creation_event
263 region_creation_event_capacity (tree capacity,
264 location_t loc, tree fndecl, int depth)
265 : region_creation_event (loc, fndecl, depth),
266 m_capacity (capacity)
268 gcc_assert (m_capacity);
271 label_text get_desc (bool can_colorize) const final override;
277 /* Concrete subclass of region_creation_event.
278 Generates a message based on the capacity of the region
279 e.g. "allocated 100 bytes here". */
281 class region_creation_event_allocation_size : public region_creation_event
284 region_creation_event_allocation_size (tree capacity,
285 location_t loc, tree fndecl, int depth)
286 : region_creation_event (loc, fndecl, depth),
287 m_capacity (capacity)
290 label_text get_desc (bool can_colorize) const final override;
296 /* Concrete subclass of region_creation_event.
297 Generates a debug message intended for analyzer developers. */
299 class region_creation_event_debug : public region_creation_event
302 region_creation_event_debug (const region *reg, tree capacity,
303 location_t loc, tree fndecl, int depth)
304 : region_creation_event (loc, fndecl, depth),
305 m_reg (reg), m_capacity (capacity)
309 label_text get_desc (bool can_colorize) const final override;
316 /* An event subclass describing the entry to a function. */
318 class function_entry_event : public checker_event
321 function_entry_event (location_t loc, tree fndecl, int depth)
322 : checker_event (EK_FUNCTION_ENTRY, loc, fndecl, depth)
326 function_entry_event (const program_point &dst_point);
328 label_text get_desc (bool can_colorize) const override;
329 meaning get_meaning () const override;
331 bool is_function_entry_p () const final override { return true; }
334 /* Subclass of checker_event describing a state change. */
336 class state_change_event : public checker_event
339 state_change_event (const supernode *node, const gimple *stmt,
341 const state_machine &sm,
343 state_machine::state_t from,
344 state_machine::state_t to,
345 const svalue *origin,
346 const program_state &dst_state);
348 label_text get_desc (bool can_colorize) const final override;
349 meaning get_meaning () const override;
351 function *get_dest_function () const
353 return m_dst_state.get_current_function ();
356 const supernode *m_node;
357 const gimple *m_stmt;
358 const state_machine &m_sm;
359 const svalue *m_sval;
360 state_machine::state_t m_from;
361 state_machine::state_t m_to;
362 const svalue *m_origin;
363 program_state m_dst_state;
366 /* Subclass of checker_event; parent class for subclasses that relate to
369 class superedge_event : public checker_event
372 /* Mark this edge event as being either an interprocedural call or
373 return in which VAR is in STATE, and that this is critical to the
374 diagnostic (so that get_desc can attempt to get a better description
375 from any pending_diagnostic). */
376 void record_critical_state (tree var, state_machine::state_t state)
379 m_critical_state = state;
382 const callgraph_superedge& get_callgraph_superedge () const;
384 bool should_filter_p (int verbosity) const;
387 superedge_event (enum event_kind kind, const exploded_edge &eedge,
388 location_t loc, tree fndecl, int depth);
391 const exploded_edge &m_eedge;
392 const superedge *m_sedge;
394 state_machine::state_t m_critical_state;
397 /* An abstract event subclass for when a CFG edge is followed; it has two
398 subclasses, representing the start of the edge and the end of the
399 edge, which come in pairs. */
401 class cfg_edge_event : public superedge_event
404 meaning get_meaning () const override;
406 const cfg_superedge& get_cfg_superedge () const;
409 cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
410 location_t loc, tree fndecl, int depth);
413 /* A concrete event subclass for the start of a CFG edge
414 e.g. "following 'false' branch...'. */
416 class start_cfg_edge_event : public cfg_edge_event
419 start_cfg_edge_event (const exploded_edge &eedge,
420 location_t loc, tree fndecl, int depth)
421 : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc, fndecl, depth)
425 label_text get_desc (bool can_colorize) const final override;
428 label_text maybe_describe_condition (bool can_colorize) const;
430 static label_text maybe_describe_condition (bool can_colorize,
434 static bool should_print_expr_p (tree);
437 /* A concrete event subclass for the end of a CFG edge
438 e.g. "...to here'. */
440 class end_cfg_edge_event : public cfg_edge_event
443 end_cfg_edge_event (const exploded_edge &eedge,
444 location_t loc, tree fndecl, int depth)
445 : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc, fndecl, depth)
449 label_text get_desc (bool /*can_colorize*/) const final override
451 return label_text::borrow ("...to here");
455 /* A concrete event subclass for an interprocedural call. */
457 class call_event : public superedge_event
460 call_event (const exploded_edge &eedge,
461 location_t loc, tree fndecl, int depth);
463 label_text get_desc (bool can_colorize) const override;
464 meaning get_meaning () const override;
466 bool is_call_p () const final override;
469 tree get_caller_fndecl () const;
470 tree get_callee_fndecl () const;
472 const supernode *m_src_snode;
473 const supernode *m_dest_snode;
476 /* A concrete event subclass for an interprocedural return. */
478 class return_event : public superedge_event
481 return_event (const exploded_edge &eedge,
482 location_t loc, tree fndecl, int depth);
484 label_text get_desc (bool can_colorize) const final override;
485 meaning get_meaning () const override;
487 bool is_return_p () const final override;
489 const supernode *m_src_snode;
490 const supernode *m_dest_snode;
493 /* A concrete event subclass for the start of a consolidated run of CFG
494 edges all either TRUE or FALSE e.g. "following 'false' branch...'. */
496 class start_consolidated_cfg_edges_event : public checker_event
499 start_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth,
501 : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth),
502 m_edge_sense (edge_sense)
506 label_text get_desc (bool can_colorize) const final override;
507 meaning get_meaning () const override;
513 /* A concrete event subclass for the end of a consolidated run of
514 CFG edges e.g. "...to here'. */
516 class end_consolidated_cfg_edges_event : public checker_event
519 end_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth)
520 : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth)
524 label_text get_desc (bool /*can_colorize*/) const final override
526 return label_text::borrow ("...to here");
530 /* A concrete event subclass for describing an inlined call event
531 e.g. "inlined call to 'callee' from 'caller'". */
533 class inlined_call_event : public checker_event
536 inlined_call_event (location_t loc,
537 tree apparent_callee_fndecl,
538 tree apparent_caller_fndecl,
540 int stack_depth_adjustment)
541 : checker_event (EK_INLINED_CALL, loc,
542 apparent_caller_fndecl,
543 actual_depth + stack_depth_adjustment),
544 m_apparent_callee_fndecl (apparent_callee_fndecl),
545 m_apparent_caller_fndecl (apparent_caller_fndecl)
547 gcc_assert (LOCATION_BLOCK (loc) == NULL);
550 label_text get_desc (bool /*can_colorize*/) const final override;
551 meaning get_meaning () const override;
554 tree m_apparent_callee_fndecl;
555 tree m_apparent_caller_fndecl;
558 /* A concrete event subclass for a setjmp or sigsetjmp call. */
560 class setjmp_event : public checker_event
563 setjmp_event (location_t loc, const exploded_node *enode,
564 tree fndecl, int depth, const gcall *setjmp_call)
565 : checker_event (EK_SETJMP, loc, fndecl, depth),
566 m_enode (enode), m_setjmp_call (setjmp_call)
570 label_text get_desc (bool can_colorize) const final override;
572 void prepare_for_emission (checker_path *path,
573 pending_diagnostic *pd,
574 diagnostic_event_id_t emission_id) final override;
577 const exploded_node *m_enode;
578 const gcall *m_setjmp_call;
581 /* An abstract event subclass for rewinding from a longjmp to a setjmp
582 (or siglongjmp to sigsetjmp).
584 Base class for two from/to subclasses, showing the two halves of the
587 class rewind_event : public checker_event
590 tree get_longjmp_caller () const;
591 tree get_setjmp_caller () const;
592 const exploded_edge *get_eedge () const { return m_eedge; }
595 rewind_event (const exploded_edge *eedge,
596 enum event_kind kind,
597 location_t loc, tree fndecl, int depth,
598 const rewind_info_t *rewind_info);
599 const rewind_info_t *m_rewind_info;
602 const exploded_edge *m_eedge;
605 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
606 showing the longjmp (or siglongjmp). */
608 class rewind_from_longjmp_event : public rewind_event
611 rewind_from_longjmp_event (const exploded_edge *eedge,
612 location_t loc, tree fndecl, int depth,
613 const rewind_info_t *rewind_info)
614 : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc, fndecl, depth,
619 label_text get_desc (bool can_colorize) const final override;
622 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
623 showing the setjmp (or sigsetjmp). */
625 class rewind_to_setjmp_event : public rewind_event
628 rewind_to_setjmp_event (const exploded_edge *eedge,
629 location_t loc, tree fndecl, int depth,
630 const rewind_info_t *rewind_info)
631 : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc, fndecl, depth,
636 label_text get_desc (bool can_colorize) const final override;
638 void prepare_for_emission (checker_path *path,
639 pending_diagnostic *pd,
640 diagnostic_event_id_t emission_id) final override;
643 diagnostic_event_id_t m_original_setjmp_event_id;
646 /* Concrete subclass of checker_event for use at the end of a path:
647 a repeat of the warning message at the end of the path (perhaps with
648 references to pertinent events that occurred on the way), at the point
649 where the problem occurs. */
651 class warning_event : public checker_event
654 warning_event (location_t loc, tree fndecl, int depth,
655 const state_machine *sm,
656 tree var, state_machine::state_t state)
657 : checker_event (EK_WARNING, loc, fndecl, depth),
658 m_sm (sm), m_var (var), m_state (state)
662 label_text get_desc (bool can_colorize) const final override;
663 meaning get_meaning () const override;
666 const state_machine *m_sm;
668 state_machine::state_t m_state;
673 #endif /* GCC_ANALYZER_CHECKER_EVENT_H */