1/* Subclasses of diagnostic_event for analyzer diagnostics.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc.
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#ifndef GCC_ANALYZER_CHECKER_EVENT_H
22#define GCC_ANALYZER_CHECKER_EVENT_H
23
24#include "tree-logical-location.h"
25#include "analyzer/program-state.h"
26
27namespace ana {
28
29/* A bundle of location information for a checker_event. */
30
31struct event_loc_info
32{
33 event_loc_info (location_t loc, tree fndecl, int depth)
34 : m_loc (loc), m_fndecl (fndecl), m_depth (depth)
35 {}
36
37 location_t m_loc;
38 tree m_fndecl;
39 int m_depth;
40};
41
42/* An enum for discriminating between the concrete subclasses of
43 checker_event. */
44
45enum event_kind
46{
47 EK_DEBUG,
48 EK_CUSTOM,
49 EK_STMT,
50 EK_REGION_CREATION,
51 EK_FUNCTION_ENTRY,
52 EK_STATE_CHANGE,
53 EK_START_CFG_EDGE,
54 EK_END_CFG_EDGE,
55 EK_CALL_EDGE,
56 EK_RETURN_EDGE,
57 EK_START_CONSOLIDATED_CFG_EDGES,
58 EK_END_CONSOLIDATED_CFG_EDGES,
59 EK_INLINED_CALL,
60 EK_SETJMP,
61 EK_REWIND_FROM_LONGJMP,
62 EK_REWIND_TO_SETJMP,
63 EK_WARNING
64};
65
66extern const char *event_kind_to_string (enum event_kind ek);
67
68/* Event subclasses.
69
70 The class hierarchy looks like this (using indentation to show
71 inheritance, and with event_kinds shown for the concrete subclasses):
72
73 diagnostic_event
74 checker_event
75 debug_event (EK_DEBUG)
76 custom_event (EK_CUSTOM)
77 precanned_custom_event
78 statement_event (EK_STMT)
79 region_creation_event (EK_REGION_CREATION)
80 function_entry_event (EK_FUNCTION_ENTRY)
81 state_change_event (EK_STATE_CHANGE)
82 superedge_event
83 cfg_edge_event
84 start_cfg_edge_event (EK_START_CFG_EDGE)
85 end_cfg_edge_event (EK_END_CFG_EDGE)
86 call_event (EK_CALL_EDGE)
87 return_edge (EK_RETURN_EDGE)
88 start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
89 end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
90 inlined_call_event (EK_INLINED_CALL)
91 setjmp_event (EK_SETJMP)
92 rewind_event
93 rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
94 rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
95 warning_event (EK_WARNING). */
96
97/* Abstract subclass of diagnostic_event; the base class for use in
98 checker_path (the analyzer's diagnostic_path subclass). */
99
100class checker_event : public diagnostic_event
101{
102public:
103 /* Implementation of diagnostic_event. */
104
105 location_t get_location () const final override { return m_loc; }
106 tree get_fndecl () const final override { return m_effective_fndecl; }
107 int get_stack_depth () const final override { return m_effective_depth; }
108 const logical_location *get_logical_location () const final override
109 {
110 if (m_effective_fndecl)
111 return &m_logical_loc;
112 else
113 return NULL;
114 }
115 meaning get_meaning () const override;
116 diagnostic_thread_id_t get_thread_id () const final override
117 {
118 return 0;
119 }
120
121 void
122 maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj) const override;
123
124 /* Additional functionality. */
125
126 int get_original_stack_depth () const { return m_original_depth; }
127
128 virtual void prepare_for_emission (checker_path *,
129 pending_diagnostic *pd,
130 diagnostic_event_id_t emission_id);
131 virtual bool is_call_p () const { return false; }
132 virtual bool is_function_entry_p () const { return false; }
133 virtual bool is_return_p () const { return false; }
134
135 /* For use with %@. */
136 const diagnostic_event_id_t *get_id_ptr () const
137 {
138 return &m_emission_id;
139 }
140
141 void dump (pretty_printer *pp) const;
142 void debug () const;
143
144 void set_location (location_t loc) { m_loc = loc; }
145
146protected:
147 checker_event (enum event_kind kind,
148 const event_loc_info &loc_info);
149
150 public:
151 const enum event_kind m_kind;
152 protected:
153 location_t m_loc;
154 tree m_original_fndecl;
155 tree m_effective_fndecl;
156 int m_original_depth;
157 int m_effective_depth;
158 pending_diagnostic *m_pending_diagnostic;
159 diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
160 tree_logical_location m_logical_loc;
161};
162
163/* A concrete event subclass for a purely textual event, for use in
164 debugging path creation and filtering. */
165
166class debug_event : public checker_event
167{
168public:
169
170 debug_event (const event_loc_info &loc_info,
171 const char *desc)
172 : checker_event (EK_DEBUG, loc_info),
173 m_desc (xstrdup (desc))
174 {
175 }
176 ~debug_event ()
177 {
178 free (ptr: m_desc);
179 }
180
181 label_text get_desc (bool) const final override;
182
183private:
184 char *m_desc;
185};
186
187/* An abstract event subclass for custom events. These are not filtered,
188 as they are likely to be pertinent to the diagnostic. */
189
190class custom_event : public checker_event
191{
192protected:
193 custom_event (const event_loc_info &loc_info)
194 : checker_event (EK_CUSTOM, loc_info)
195 {
196 }
197};
198
199/* A concrete custom_event subclass with a precanned message. */
200
201class precanned_custom_event : public custom_event
202{
203public:
204 precanned_custom_event (const event_loc_info &loc_info,
205 const char *desc)
206 : custom_event (loc_info),
207 m_desc (xstrdup (desc))
208 {
209 }
210 ~precanned_custom_event ()
211 {
212 free (ptr: m_desc);
213 }
214
215 label_text get_desc (bool) const final override;
216
217private:
218 char *m_desc;
219};
220
221/* A concrete event subclass describing the execution of a gimple statement,
222 for use at high verbosity levels when debugging paths. */
223
224class statement_event : public checker_event
225{
226public:
227 statement_event (const gimple *stmt, tree fndecl, int depth,
228 const program_state &dst_state);
229
230 label_text get_desc (bool) const final override;
231
232 const gimple * const m_stmt;
233 const program_state m_dst_state;
234};
235
236/* An abstract event subclass describing the creation of a region that
237 is significant for a diagnostic.
238
239 There are too many combinations to express region creation in one message,
240 so we emit multiple region_creation_event instances when each pertinent
241 region is created.
242
243 The events are created by pending_diagnostic's add_region_creation_events
244 vfunc, which by default creates a region_creation_event_memory_space, and
245 if a capacity is known, a region_creation_event_capacity, giving e.g.:
246 (1) region created on stack here
247 (2) capacity: 100 bytes
248 but this vfunc can be overridden to create other events if other wordings
249 are more appropriate foa a given pending_diagnostic. */
250
251class region_creation_event : public checker_event
252{
253protected:
254 region_creation_event (const event_loc_info &loc_info);
255};
256
257/* Concrete subclass of region_creation_event.
258 Generates a message based on the memory space of the region
259 e.g. "region created on stack here". */
260
261class region_creation_event_memory_space : public region_creation_event
262{
263public:
264 region_creation_event_memory_space (enum memory_space mem_space,
265 const event_loc_info &loc_info)
266 : region_creation_event (loc_info),
267 m_mem_space (mem_space)
268 {
269 }
270
271 label_text get_desc (bool can_colorize) const final override;
272
273private:
274 enum memory_space m_mem_space;
275};
276
277/* Concrete subclass of region_creation_event.
278 Generates a message based on the capacity of the region
279 e.g. "capacity: 100 bytes". */
280
281class region_creation_event_capacity : public region_creation_event
282{
283public:
284 region_creation_event_capacity (tree capacity,
285 const event_loc_info &loc_info)
286 : region_creation_event (loc_info),
287 m_capacity (capacity)
288 {
289 gcc_assert (m_capacity);
290 }
291
292 label_text get_desc (bool can_colorize) const final override;
293
294private:
295 tree m_capacity;
296};
297
298/* Concrete subclass of region_creation_event.
299 Generates a message based on the capacity of the region
300 e.g. "allocated 100 bytes here". */
301
302class region_creation_event_allocation_size : public region_creation_event
303{
304public:
305 region_creation_event_allocation_size (tree capacity,
306 const event_loc_info &loc_info)
307 : region_creation_event (loc_info),
308 m_capacity (capacity)
309 {}
310
311 label_text get_desc (bool can_colorize) const final override;
312
313private:
314 tree m_capacity;
315};
316
317/* Concrete subclass of region_creation_event.
318 Generates a debug message intended for analyzer developers. */
319
320class region_creation_event_debug : public region_creation_event
321{
322public:
323 region_creation_event_debug (const region *reg, tree capacity,
324 const event_loc_info &loc_info)
325 : region_creation_event (loc_info),
326 m_reg (reg), m_capacity (capacity)
327 {
328 }
329
330 label_text get_desc (bool can_colorize) const final override;
331
332private:
333 const region *m_reg;
334 tree m_capacity;
335};
336
337/* An event subclass describing the entry to a function. */
338
339class function_entry_event : public checker_event
340{
341public:
342 function_entry_event (const event_loc_info &loc_info)
343 : checker_event (EK_FUNCTION_ENTRY, loc_info)
344 {
345 }
346
347 function_entry_event (const program_point &dst_point);
348
349 label_text get_desc (bool can_colorize) const override;
350 meaning get_meaning () const override;
351
352 bool is_function_entry_p () const final override { return true; }
353};
354
355/* Subclass of checker_event describing a state change. */
356
357class state_change_event : public checker_event
358{
359public:
360 state_change_event (const supernode *node, const gimple *stmt,
361 int stack_depth,
362 const state_machine &sm,
363 const svalue *sval,
364 state_machine::state_t from,
365 state_machine::state_t to,
366 const svalue *origin,
367 const program_state &dst_state,
368 const exploded_node *enode);
369
370 label_text get_desc (bool can_colorize) const final override;
371 meaning get_meaning () const override;
372
373 const function *get_dest_function () const
374 {
375 return m_dst_state.get_current_function ();
376 }
377
378 const exploded_node *get_exploded_node () const { return m_enode; }
379
380 const supernode *m_node;
381 const gimple *m_stmt;
382 const state_machine &m_sm;
383 const svalue *m_sval;
384 state_machine::state_t m_from;
385 state_machine::state_t m_to;
386 const svalue *m_origin;
387 program_state m_dst_state;
388 const exploded_node *m_enode;
389};
390
391/* Subclass of checker_event; parent class for subclasses that relate to
392 a superedge. */
393
394class superedge_event : public checker_event
395{
396public:
397 void maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj)
398 const override;
399
400 /* Mark this edge event as being either an interprocedural call or
401 return in which VAR is in STATE, and that this is critical to the
402 diagnostic (so that get_desc can attempt to get a better description
403 from any pending_diagnostic). */
404 void record_critical_state (tree var, state_machine::state_t state)
405 {
406 m_var = var;
407 m_critical_state = state;
408 }
409
410 const callgraph_superedge& get_callgraph_superedge () const;
411
412 bool should_filter_p (int verbosity) const;
413
414 protected:
415 superedge_event (enum event_kind kind, const exploded_edge &eedge,
416 const event_loc_info &loc_info);
417
418 public:
419 const exploded_edge &m_eedge;
420 const superedge *m_sedge;
421 tree m_var;
422 state_machine::state_t m_critical_state;
423};
424
425/* An abstract event subclass for when a CFG edge is followed; it has two
426 subclasses, representing the start of the edge and the end of the
427 edge, which come in pairs. */
428
429class cfg_edge_event : public superedge_event
430{
431public:
432 meaning get_meaning () const override;
433
434 const cfg_superedge& get_cfg_superedge () const;
435
436 protected:
437 cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
438 const event_loc_info &loc_info);
439};
440
441/* A concrete event subclass for the start of a CFG edge
442 e.g. "following 'false' branch...'. */
443
444class start_cfg_edge_event : public cfg_edge_event
445{
446public:
447 start_cfg_edge_event (const exploded_edge &eedge,
448 const event_loc_info &loc_info)
449 : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc_info)
450 {
451 }
452
453 label_text get_desc (bool can_colorize) const override;
454
455protected:
456 label_text maybe_describe_condition (bool can_colorize) const;
457
458private:
459 static label_text maybe_describe_condition (bool can_colorize,
460 tree lhs,
461 enum tree_code op,
462 tree rhs);
463 static bool should_print_expr_p (tree);
464};
465
466/* A concrete event subclass for the end of a CFG edge
467 e.g. "...to here'. */
468
469class end_cfg_edge_event : public cfg_edge_event
470{
471public:
472 end_cfg_edge_event (const exploded_edge &eedge,
473 const event_loc_info &loc_info)
474 : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc_info)
475 {
476 }
477
478 label_text get_desc (bool /*can_colorize*/) const final override
479 {
480 return label_text::borrow (buffer: "...to here");
481 }
482};
483
484/* A concrete event subclass for an interprocedural call. */
485
486class call_event : public superedge_event
487{
488public:
489 call_event (const exploded_edge &eedge,
490 const event_loc_info &loc_info);
491
492 label_text get_desc (bool can_colorize) const override;
493 meaning get_meaning () const override;
494
495 bool is_call_p () const final override;
496
497protected:
498 tree get_caller_fndecl () const;
499 tree get_callee_fndecl () const;
500
501 const supernode *m_src_snode;
502 const supernode *m_dest_snode;
503};
504
505/* A concrete event subclass for an interprocedural return. */
506
507class return_event : public superedge_event
508{
509public:
510 return_event (const exploded_edge &eedge,
511 const event_loc_info &loc_info);
512
513 label_text get_desc (bool can_colorize) const final override;
514 meaning get_meaning () const override;
515
516 bool is_return_p () const final override;
517
518 const supernode *m_src_snode;
519 const supernode *m_dest_snode;
520};
521
522/* A concrete event subclass for the start of a consolidated run of CFG
523 edges all either TRUE or FALSE e.g. "following 'false' branch...'. */
524
525class start_consolidated_cfg_edges_event : public checker_event
526{
527public:
528 start_consolidated_cfg_edges_event (const event_loc_info &loc_info,
529 bool edge_sense)
530 : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc_info),
531 m_edge_sense (edge_sense)
532 {
533 }
534
535 label_text get_desc (bool can_colorize) const final override;
536 meaning get_meaning () const override;
537
538 private:
539 bool m_edge_sense;
540};
541
542/* A concrete event subclass for the end of a consolidated run of
543 CFG edges e.g. "...to here'. */
544
545class end_consolidated_cfg_edges_event : public checker_event
546{
547public:
548 end_consolidated_cfg_edges_event (const event_loc_info &loc_info)
549 : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc_info)
550 {
551 }
552
553 label_text get_desc (bool /*can_colorize*/) const final override
554 {
555 return label_text::borrow (buffer: "...to here");
556 }
557};
558
559/* A concrete event subclass for describing an inlined call event
560 e.g. "inlined call to 'callee' from 'caller'". */
561
562class inlined_call_event : public checker_event
563{
564public:
565 inlined_call_event (location_t loc,
566 tree apparent_callee_fndecl,
567 tree apparent_caller_fndecl,
568 int actual_depth,
569 int stack_depth_adjustment)
570 : checker_event (EK_INLINED_CALL,
571 event_loc_info (loc,
572 apparent_caller_fndecl,
573 actual_depth + stack_depth_adjustment)),
574 m_apparent_callee_fndecl (apparent_callee_fndecl),
575 m_apparent_caller_fndecl (apparent_caller_fndecl)
576 {
577 gcc_assert (LOCATION_BLOCK (loc) == NULL);
578 }
579
580 label_text get_desc (bool /*can_colorize*/) const final override;
581 meaning get_meaning () const override;
582
583private:
584 tree m_apparent_callee_fndecl;
585 tree m_apparent_caller_fndecl;
586};
587
588/* A concrete event subclass for a setjmp or sigsetjmp call. */
589
590class setjmp_event : public checker_event
591{
592public:
593 setjmp_event (const event_loc_info &loc_info,
594 const exploded_node *enode,
595 const gcall *setjmp_call)
596 : checker_event (EK_SETJMP, loc_info),
597 m_enode (enode), m_setjmp_call (setjmp_call)
598 {
599 }
600
601 label_text get_desc (bool can_colorize) const final override;
602
603 void prepare_for_emission (checker_path *path,
604 pending_diagnostic *pd,
605 diagnostic_event_id_t emission_id) final override;
606
607private:
608 const exploded_node *m_enode;
609 const gcall *m_setjmp_call;
610};
611
612/* An abstract event subclass for rewinding from a longjmp to a setjmp
613 (or siglongjmp to sigsetjmp).
614
615 Base class for two from/to subclasses, showing the two halves of the
616 rewind. */
617
618class rewind_event : public checker_event
619{
620public:
621 tree get_longjmp_caller () const;
622 tree get_setjmp_caller () const;
623 const exploded_edge *get_eedge () const { return m_eedge; }
624
625 protected:
626 rewind_event (const exploded_edge *eedge,
627 enum event_kind kind,
628 const event_loc_info &loc_info,
629 const rewind_info_t *rewind_info);
630 const rewind_info_t *m_rewind_info;
631
632 private:
633 const exploded_edge *m_eedge;
634};
635
636/* A concrete event subclass for rewinding from a longjmp to a setjmp,
637 showing the longjmp (or siglongjmp). */
638
639class rewind_from_longjmp_event : public rewind_event
640{
641public:
642 rewind_from_longjmp_event (const exploded_edge *eedge,
643 const event_loc_info &loc_info,
644 const rewind_info_t *rewind_info)
645 : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc_info,
646 rewind_info)
647 {
648 }
649
650 label_text get_desc (bool can_colorize) const final override;
651};
652
653/* A concrete event subclass for rewinding from a longjmp to a setjmp,
654 showing the setjmp (or sigsetjmp). */
655
656class rewind_to_setjmp_event : public rewind_event
657{
658public:
659 rewind_to_setjmp_event (const exploded_edge *eedge,
660 const event_loc_info &loc_info,
661 const rewind_info_t *rewind_info)
662 : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc_info,
663 rewind_info)
664 {
665 }
666
667 label_text get_desc (bool can_colorize) const final override;
668
669 void prepare_for_emission (checker_path *path,
670 pending_diagnostic *pd,
671 diagnostic_event_id_t emission_id) final override;
672
673private:
674 diagnostic_event_id_t m_original_setjmp_event_id;
675};
676
677/* Concrete subclass of checker_event for use at the end of a path:
678 a repeat of the warning message at the end of the path (perhaps with
679 references to pertinent events that occurred on the way), at the point
680 where the problem occurs. */
681
682class warning_event : public checker_event
683{
684public:
685 warning_event (const event_loc_info &loc_info,
686 const exploded_node *enode,
687 const state_machine *sm,
688 tree var, state_machine::state_t state)
689 : checker_event (EK_WARNING, loc_info),
690 m_enode (enode),
691 m_sm (sm), m_var (var), m_state (state)
692 {
693 }
694
695 label_text get_desc (bool can_colorize) const final override;
696 meaning get_meaning () const override;
697
698 const exploded_node *get_exploded_node () const { return m_enode; }
699
700private:
701 const exploded_node *m_enode;
702 const state_machine *m_sm;
703 tree m_var;
704 state_machine::state_t m_state;
705};
706
707} // namespace ana
708
709#endif /* GCC_ANALYZER_CHECKER_EVENT_H */
710

source code of gcc/analyzer/checker-event.h