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