f9885f5cfc37dd90eded7fc73172257d17f3e88c
[platform/upstream/gcc.git] / gcc / analyzer / checker-event.h
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>.
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 /* An enum for discriminating between the concrete subclasses of
30    checker_event.  */
31
32 enum event_kind
33 {
34   EK_DEBUG,
35   EK_CUSTOM,
36   EK_STMT,
37   EK_REGION_CREATION,
38   EK_FUNCTION_ENTRY,
39   EK_STATE_CHANGE,
40   EK_START_CFG_EDGE,
41   EK_END_CFG_EDGE,
42   EK_CALL_EDGE,
43   EK_RETURN_EDGE,
44   EK_START_CONSOLIDATED_CFG_EDGES,
45   EK_END_CONSOLIDATED_CFG_EDGES,
46   EK_INLINED_CALL,
47   EK_SETJMP,
48   EK_REWIND_FROM_LONGJMP,
49   EK_REWIND_TO_SETJMP,
50   EK_WARNING
51 };
52
53 extern const char *event_kind_to_string (enum event_kind ek);
54
55 /* Event subclasses.
56
57    The class hierarchy looks like this (using indentation to show
58    inheritance, and with event_kinds shown for the concrete subclasses):
59
60    diagnostic_event
61      checker_event
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)
69        superedge_event
70          cfg_edge_event
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)
79        rewind_event
80          rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
81          rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
82        warning_event (EK_WARNING).  */
83
84 /* Abstract subclass of diagnostic_event; the base class for use in
85    checker_path (the analyzer's diagnostic_path subclass).  */
86
87 class checker_event : public diagnostic_event
88 {
89 public:
90   /* Implementation of diagnostic_event.  */
91
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
96   {
97     if (m_effective_fndecl)
98       return &m_logical_loc;
99     else
100       return NULL;
101   }
102   meaning get_meaning () const override;
103
104   /* Additional functionality.  */
105
106   int get_original_stack_depth () const { return m_original_depth; }
107
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; }
114
115   /* For use with %@.  */
116   const diagnostic_event_id_t *get_id_ptr () const
117   {
118     return &m_emission_id;
119   }
120
121   void dump (pretty_printer *pp) const;
122   void debug () const;
123
124   void set_location (location_t loc) { m_loc = loc; }
125
126 protected:
127   checker_event (enum event_kind kind,
128                  location_t loc, tree fndecl, int depth);
129
130  public:
131   const enum event_kind m_kind;
132  protected:
133   location_t m_loc;
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;
141 };
142
143 /* A concrete event subclass for a purely textual event, for use in
144    debugging path creation and filtering.  */
145
146 class debug_event : public checker_event
147 {
148 public:
149   debug_event (location_t loc, tree fndecl, int depth,
150               const char *desc)
151   : checker_event (EK_DEBUG, loc, fndecl, depth),
152     m_desc (xstrdup (desc))
153   {
154   }
155   ~debug_event ()
156   {
157     free (m_desc);
158   }
159
160   label_text get_desc (bool) const final override;
161
162 private:
163   char *m_desc;
164 };
165
166 /* An abstract event subclass for custom events.  These are not filtered,
167    as they are likely to be pertinent to the diagnostic.  */
168
169 class custom_event : public checker_event
170 {
171 protected:
172   custom_event (location_t loc, tree fndecl, int depth)
173   : checker_event (EK_CUSTOM, loc, fndecl, depth)
174   {
175   }
176 };
177
178 /* A concrete custom_event subclass with a precanned message.  */
179
180 class precanned_custom_event : public custom_event
181 {
182 public:
183   precanned_custom_event (location_t loc, tree fndecl, int depth,
184                           const char *desc)
185   : custom_event (loc, fndecl, depth),
186     m_desc (xstrdup (desc))
187   {
188   }
189   ~precanned_custom_event ()
190   {
191     free (m_desc);
192   }
193
194   label_text get_desc (bool) const final override;
195
196 private:
197   char *m_desc;
198 };
199
200 /* A concrete event subclass describing the execution of a gimple statement,
201    for use at high verbosity levels when debugging paths.  */
202
203 class statement_event : public checker_event
204 {
205 public:
206   statement_event (const gimple *stmt, tree fndecl, int depth,
207                    const program_state &dst_state);
208
209   label_text get_desc (bool) const final override;
210
211   const gimple * const m_stmt;
212   const program_state m_dst_state;
213 };
214
215 /* An abstract event subclass describing the creation of a region that
216    is significant for a diagnostic.
217
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
220    region is created.
221
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.  */
229
230 class region_creation_event : public checker_event
231 {
232 protected:
233   region_creation_event (location_t loc, tree fndecl, int depth);
234 };
235
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".  */
239
240 class region_creation_event_memory_space : public region_creation_event
241 {
242 public:
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)
247   {
248   }
249
250   label_text get_desc (bool can_colorize) const final override;
251
252 private:
253   enum memory_space m_mem_space;
254 };
255
256 /* Concrete subclass of region_creation_event.
257    Generates a message based on the capacity of the region
258    e.g. "capacity: 100 bytes".  */
259
260 class region_creation_event_capacity : public region_creation_event
261 {
262 public:
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)
267   {
268     gcc_assert (m_capacity);
269   }
270
271   label_text get_desc (bool can_colorize) const final override;
272
273 private:
274   tree m_capacity;
275 };
276
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".  */
280
281 class region_creation_event_allocation_size : public region_creation_event
282 {
283 public:
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)
288   {}
289
290   label_text get_desc (bool can_colorize) const final override;
291
292 private:
293   tree m_capacity;
294 };
295
296 /* Concrete subclass of region_creation_event.
297    Generates a debug message intended for analyzer developers.  */
298
299 class region_creation_event_debug : public region_creation_event
300 {
301 public:
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)
306   {
307   }
308
309   label_text get_desc (bool can_colorize) const final override;
310
311 private:
312   const region *m_reg;
313   tree m_capacity;
314 };
315
316 /* An event subclass describing the entry to a function.  */
317
318 class function_entry_event : public checker_event
319 {
320 public:
321   function_entry_event (location_t loc, tree fndecl, int depth)
322   : checker_event (EK_FUNCTION_ENTRY, loc, fndecl, depth)
323   {
324   }
325
326   function_entry_event (const program_point &dst_point);
327
328   label_text get_desc (bool can_colorize) const override;
329   meaning get_meaning () const override;
330
331   bool is_function_entry_p () const final override { return true; }
332 };
333
334 /* Subclass of checker_event describing a state change.  */
335
336 class state_change_event : public checker_event
337 {
338 public:
339   state_change_event (const supernode *node, const gimple *stmt,
340                       int stack_depth,
341                       const state_machine &sm,
342                       const svalue *sval,
343                       state_machine::state_t from,
344                       state_machine::state_t to,
345                       const svalue *origin,
346                       const program_state &dst_state);
347
348   label_text get_desc (bool can_colorize) const final override;
349   meaning get_meaning () const override;
350
351   function *get_dest_function () const
352   {
353     return m_dst_state.get_current_function ();
354   }
355
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;
364 };
365
366 /* Subclass of checker_event; parent class for subclasses that relate to
367    a superedge.  */
368
369 class superedge_event : public checker_event
370 {
371 public:
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)
377   {
378     m_var = var;
379     m_critical_state = state;
380   }
381
382   const callgraph_superedge& get_callgraph_superedge () const;
383
384   bool should_filter_p (int verbosity) const;
385
386  protected:
387   superedge_event (enum event_kind kind, const exploded_edge &eedge,
388                    location_t loc, tree fndecl, int depth);
389
390  public:
391   const exploded_edge &m_eedge;
392   const superedge *m_sedge;
393   tree m_var;
394   state_machine::state_t m_critical_state;
395 };
396
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.  */
400
401 class cfg_edge_event : public superedge_event
402 {
403 public:
404   meaning get_meaning () const override;
405
406   const cfg_superedge& get_cfg_superedge () const;
407
408  protected:
409   cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
410                   location_t loc, tree fndecl, int depth);
411 };
412
413 /* A concrete event subclass for the start of a CFG edge
414    e.g. "following 'false' branch...'.  */
415
416 class start_cfg_edge_event : public cfg_edge_event
417 {
418 public:
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)
422   {
423   }
424
425   label_text get_desc (bool can_colorize) const final override;
426
427  private:
428   label_text maybe_describe_condition (bool can_colorize) const;
429
430   static label_text maybe_describe_condition (bool can_colorize,
431                                               tree lhs,
432                                               enum tree_code op,
433                                               tree rhs);
434   static bool should_print_expr_p (tree);
435 };
436
437 /* A concrete event subclass for the end of a CFG edge
438    e.g. "...to here'.  */
439
440 class end_cfg_edge_event : public cfg_edge_event
441 {
442 public:
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)
446   {
447   }
448
449   label_text get_desc (bool /*can_colorize*/) const final override
450   {
451     return label_text::borrow ("...to here");
452   }
453 };
454
455 /* A concrete event subclass for an interprocedural call.  */
456
457 class call_event : public superedge_event
458 {
459 public:
460   call_event (const exploded_edge &eedge,
461               location_t loc, tree fndecl, int depth);
462
463   label_text get_desc (bool can_colorize) const override;
464   meaning get_meaning () const override;
465
466   bool is_call_p () const final override;
467
468 protected:
469   tree get_caller_fndecl () const;
470   tree get_callee_fndecl () const;
471
472   const supernode *m_src_snode;
473   const supernode *m_dest_snode;
474 };
475
476 /* A concrete event subclass for an interprocedural return.  */
477
478 class return_event : public superedge_event
479 {
480 public:
481   return_event (const exploded_edge &eedge,
482                 location_t loc, tree fndecl, int depth);
483
484   label_text get_desc (bool can_colorize) const final override;
485   meaning get_meaning () const override;
486
487   bool is_return_p () const final override;
488
489   const supernode *m_src_snode;
490   const supernode *m_dest_snode;
491 };
492
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...'.  */
495
496 class start_consolidated_cfg_edges_event : public checker_event
497 {
498 public:
499   start_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth,
500                                       bool edge_sense)
501   : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth),
502     m_edge_sense (edge_sense)
503   {
504   }
505
506   label_text get_desc (bool can_colorize) const final override;
507   meaning get_meaning () const override;
508
509  private:
510   bool m_edge_sense;
511 };
512
513 /* A concrete event subclass for the end of a consolidated run of
514    CFG edges e.g. "...to here'.  */
515
516 class end_consolidated_cfg_edges_event : public checker_event
517 {
518 public:
519   end_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth)
520   : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth)
521   {
522   }
523
524   label_text get_desc (bool /*can_colorize*/) const final override
525   {
526     return label_text::borrow ("...to here");
527   }
528 };
529
530 /* A concrete event subclass for describing an inlined call event
531    e.g. "inlined call to 'callee' from 'caller'".  */
532
533 class inlined_call_event : public checker_event
534 {
535 public:
536   inlined_call_event (location_t loc,
537                       tree apparent_callee_fndecl,
538                       tree apparent_caller_fndecl,
539                       int actual_depth,
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)
546   {
547     gcc_assert (LOCATION_BLOCK (loc) == NULL);
548   }
549
550   label_text get_desc (bool /*can_colorize*/) const final override;
551   meaning get_meaning () const override;
552
553 private:
554   tree m_apparent_callee_fndecl;
555   tree m_apparent_caller_fndecl;
556 };
557
558 /* A concrete event subclass for a setjmp or sigsetjmp call.  */
559
560 class setjmp_event : public checker_event
561 {
562 public:
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)
567   {
568   }
569
570   label_text get_desc (bool can_colorize) const final override;
571
572   void prepare_for_emission (checker_path *path,
573                              pending_diagnostic *pd,
574                              diagnostic_event_id_t emission_id) final override;
575
576 private:
577   const exploded_node *m_enode;
578   const gcall *m_setjmp_call;
579 };
580
581 /* An abstract event subclass for rewinding from a longjmp to a setjmp
582    (or siglongjmp to sigsetjmp).
583
584    Base class for two from/to subclasses, showing the two halves of the
585    rewind.  */
586
587 class rewind_event : public checker_event
588 {
589 public:
590   tree get_longjmp_caller () const;
591   tree get_setjmp_caller () const;
592   const exploded_edge *get_eedge () const { return m_eedge; }
593
594  protected:
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;
600
601  private:
602   const exploded_edge *m_eedge;
603 };
604
605 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
606    showing the longjmp (or siglongjmp).  */
607
608 class rewind_from_longjmp_event : public rewind_event
609 {
610 public:
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,
615                   rewind_info)
616   {
617   }
618
619   label_text get_desc (bool can_colorize) const final override;
620 };
621
622 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
623    showing the setjmp (or sigsetjmp).  */
624
625 class rewind_to_setjmp_event : public rewind_event
626 {
627 public:
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,
632                   rewind_info)
633   {
634   }
635
636   label_text get_desc (bool can_colorize) const final override;
637
638   void prepare_for_emission (checker_path *path,
639                              pending_diagnostic *pd,
640                              diagnostic_event_id_t emission_id) final override;
641
642 private:
643   diagnostic_event_id_t m_original_setjmp_event_id;
644 };
645
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.  */
650
651 class warning_event : public checker_event
652 {
653 public:
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)
659   {
660   }
661
662   label_text get_desc (bool can_colorize) const final override;
663   meaning get_meaning () const override;
664
665 private:
666   const state_machine *m_sm;
667   tree m_var;
668   state_machine::state_t m_state;
669 };
670
671 } // namespace ana
672
673 #endif /* GCC_ANALYZER_CHECKER_EVENT_H */