4bc3080c049c33c03f4ff128497f3de7512c1d62
[platform/upstream/gcc.git] / gcc / analyzer / pending-diagnostic.h
1 /* Classes 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_PENDING_DIAGNOSTIC_H
22 #define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
23
24 #include "diagnostic-path.h"
25 #include "analyzer/sm.h"
26
27 namespace ana {
28
29 /* A bundle of information about things that are of interest to a
30    pending_diagnostic.
31
32    For now, merely the set of regions that are pertinent to the
33    diagnostic, so that we can notify the user about when they
34    were created.  */
35
36 struct interesting_t
37 {
38   void add_region_creation (const region *reg);
39
40   void dump_to_pp (pretty_printer *pp, bool simple) const;
41
42   auto_vec<const region *> m_region_creation;
43 };
44
45 /* Various bundles of information used for generating more precise
46    messages for events within a diagnostic_path, for passing to the
47    various "describe_*" vfuncs of pending_diagnostic.  See those
48    for more information.  */
49
50 namespace evdesc {
51
52 struct event_desc
53 {
54   event_desc (bool colorize) : m_colorize (colorize) {}
55
56   label_text formatted_print (const char *fmt, ...) const
57     ATTRIBUTE_GCC_DIAG(2,3);
58
59   bool m_colorize;
60 };
61
62 /* For use by pending_diagnostic::describe_state_change.  */
63
64 struct state_change : public event_desc
65 {
66   state_change (bool colorize,
67                 tree expr,
68                 tree origin,
69                 state_machine::state_t old_state,
70                 state_machine::state_t new_state,
71                 diagnostic_event_id_t event_id,
72                 const state_change_event &event)
73   : event_desc (colorize),
74     m_expr (expr), m_origin (origin),
75     m_old_state (old_state), m_new_state (new_state),
76     m_event_id (event_id), m_event (event)
77   {}
78
79   bool is_global_p () const { return m_expr == NULL_TREE; }
80
81   tree m_expr;
82   tree m_origin;
83   state_machine::state_t m_old_state;
84   state_machine::state_t m_new_state;
85   diagnostic_event_id_t m_event_id;
86   const state_change_event &m_event;
87 };
88
89 /* For use by pending_diagnostic::describe_call_with_state.  */
90
91 struct call_with_state : public event_desc
92 {
93   call_with_state (bool colorize,
94                    tree caller_fndecl, tree callee_fndecl,
95                    tree expr, state_machine::state_t state)
96   : event_desc (colorize),
97     m_caller_fndecl (caller_fndecl),
98     m_callee_fndecl (callee_fndecl),
99     m_expr (expr),
100     m_state (state)
101   {
102   }
103
104   tree m_caller_fndecl;
105   tree m_callee_fndecl;
106   tree m_expr;
107   state_machine::state_t m_state;
108 };
109
110 /* For use by pending_diagnostic::describe_return_of_state.  */
111
112 struct return_of_state : public event_desc
113 {
114   return_of_state (bool colorize,
115                    tree caller_fndecl, tree callee_fndecl,
116                    state_machine::state_t state)
117   : event_desc (colorize),
118     m_caller_fndecl (caller_fndecl),
119     m_callee_fndecl (callee_fndecl),
120     m_state (state)
121   {
122   }
123
124   tree m_caller_fndecl;
125   tree m_callee_fndecl;
126   state_machine::state_t m_state;
127 };
128
129 /* For use by pending_diagnostic::describe_final_event.  */
130
131 struct final_event : public event_desc
132 {
133   final_event (bool colorize,
134                tree expr, state_machine::state_t state)
135   : event_desc (colorize),
136     m_expr (expr), m_state (state)
137   {}
138
139   tree m_expr;
140   state_machine::state_t m_state;
141 };
142
143 } /* end of namespace evdesc */
144
145 /* An abstract base class for capturing information about a diagnostic in
146    a form that is ready to emit at a later point (or be rejected).
147    Each kind of diagnostic will have a concrete subclass of
148    pending_diagnostic.
149
150    Normally, gcc diagnostics are emitted using va_list, which can't be
151    portably stored for later use, so we have to use an "emit" virtual
152    function.
153
154    This class also supports comparison, so that multiple pending_diagnostic
155    instances can be de-duplicated.
156
157    As well as emitting a diagnostic, the class has various "precision of
158    wording" virtual functions, for generating descriptions for events
159    within a diagnostic_path.  These are optional, but implementing these
160    allows for more precise wordings than the more generic
161    implementation.  */
162
163 class pending_diagnostic
164 {
165  public:
166   virtual ~pending_diagnostic () {}
167
168   /* Vfunc to get the command-line option used when emitting the diagnostic,
169      or zero if there is none.
170      Used by diagnostic_manager for early rejection of diagnostics (to avoid
171      having to generate feasible execution paths for them).  */
172   virtual int get_controlling_option () const = 0;
173
174   /* Vfunc for emitting the diagnostic.  The rich_location will have been
175      populated with a diagnostic_path.
176      Return true if a diagnostic is actually emitted.  */
177   virtual bool emit (rich_location *) = 0;
178
179   /* Hand-coded RTTI: get an ID for the subclass.  */
180   virtual const char *get_kind () const = 0;
181
182   /* A vfunc for identifying "use of uninitialized value".  */
183   virtual bool use_of_uninit_p () const { return false; }
184
185   /* Compare for equality with OTHER, which might be of a different
186      subclass.  */
187
188   bool equal_p (const pending_diagnostic &other) const
189   {
190     /* Check for pointer equality on the IDs from get_kind.  */
191     if (get_kind () != other.get_kind ())
192       return false;
193     /* Call vfunc now we know they have the same ID: */
194     return subclass_equal_p (other);
195   }
196
197   /* A vfunc for testing for equality, where we've already
198      checked they have the same ID.  See pending_diagnostic_subclass
199      below for a convenience subclass for implementing this.  */
200   virtual bool subclass_equal_p (const pending_diagnostic &other) const = 0;
201
202   /* Return true if T1 and T2 are "the same" for the purposes of
203      diagnostic deduplication.  */
204   static bool same_tree_p (tree t1, tree t2);
205
206   /* Vfunc for fixing up locations, e.g. to avoid unwinding
207      inside specific macros.  PRIMARY is true for the primary location
208      for the diagnostic, and FALSE for events in their paths.  */
209   virtual location_t fixup_location (location_t loc, bool primary) const;
210
211   /* Precision-of-wording vfunc for describing a critical state change
212      within the diagnostic_path.
213
214      For example, a double-free diagnostic might use the descriptions:
215      - "first 'free' happens here"
216      - "second 'free' happens here"
217      for the pertinent events, whereas a use-after-free might use the
218      descriptions:
219      - "freed here"
220      - "use after free here"
221      Note how in both cases the first event is a "free": the best
222      description to use depends on the diagnostic.  */
223
224   virtual label_text describe_state_change (const evdesc::state_change &)
225   {
226     /* Default no-op implementation.  */
227     return label_text ();
228   }
229
230   /* Vfunc for implementing diagnostic_event::get_meaning for
231      state_change_event.  */
232   virtual diagnostic_event::meaning
233   get_meaning_for_state_change (const evdesc::state_change &) const
234   {
235     /* Default no-op implementation.  */
236     return diagnostic_event::meaning ();
237   }
238
239   /* Precision-of-wording vfunc for describing an interprocedural call
240      carrying critial state for the diagnostic, from caller to callee.
241
242      For example a double-free diagnostic might use:
243      - "passing freed pointer 'ptr' in call to 'deallocator' from 'test'"
244      to make it clearer how the freed value moves from caller to
245      callee.  */
246
247   virtual label_text describe_call_with_state (const evdesc::call_with_state &)
248   {
249     /* Default no-op implementation.  */
250     return label_text ();
251   }
252
253   /* Precision-of-wording vfunc for describing an interprocedural return
254      within the diagnostic_path that carries critial state for the
255      diagnostic, from callee back to caller.
256
257      For example, a deref-of-unchecked-malloc diagnostic might use:
258      - "returning possibly-NULL pointer to 'make_obj' from 'allocator'"
259      to make it clearer how the unchecked value moves from callee
260      back to caller.  */
261
262   virtual label_text describe_return_of_state (const evdesc::return_of_state &)
263   {
264     /* Default no-op implementation.  */
265     return label_text ();
266   }
267
268   /* Precision-of-wording vfunc for describing the final event within a
269      diagnostic_path.
270
271      For example a double-free diagnostic might use:
272       - "second 'free' here; first 'free' was at (3)"
273      and a use-after-free might use
274       - "use after 'free' here; memory was freed at (2)".  */
275
276   virtual label_text describe_final_event (const evdesc::final_event &)
277   {
278     /* Default no-op implementation.  */
279     return label_text ();
280   }
281
282   /* End of precision-of-wording vfuncs.  */
283
284   /* Vfunc for adding a function_entry_event to a checker_path, so that e.g.
285      the infinite recursion diagnostic can add a custom event subclass
286      that annotates recursively entering a function.  */
287
288   virtual void
289   add_function_entry_event (const exploded_edge &eedge,
290                             checker_path *emission_path);
291
292   /* Vfunc for extending/overriding creation of the events for an
293      exploded_edge that corresponds to a superedge, allowing for custom
294      events to be created that are pertinent to a particular
295      pending_diagnostic subclass.
296
297      For example, the -Wanalyzer-stale-setjmp-buffer diagnostic adds a
298      custom event showing when the pertinent stack frame is popped
299      (and thus the point at which the jmp_buf becomes invalid).  */
300
301   virtual bool maybe_add_custom_events_for_superedge (const exploded_edge &,
302                                                       checker_path *)
303   {
304     return false;
305   }
306
307   /* Vfunc for adding a call_event to a checker_path, so that e.g.
308      the varargs diagnostics can add a custom event subclass that annotates
309      the variadic arguments.  */
310   virtual void add_call_event (const exploded_edge &,
311                                checker_path *);
312
313   /* Vfunc for adding any events for the creation of regions identified
314      by the mark_interesting_stuff vfunc.
315      See the comment for class region_creation_event.  */
316   virtual void add_region_creation_events (const region *reg,
317                                            tree capacity,
318                                            location_t loc,
319                                            tree fndecl, int depth,
320                                            checker_path &emission_path);
321
322   /* Vfunc for adding the final warning_event to a checker_path, so that e.g.
323      the infinite recursion diagnostic can have its diagnostic appear at
324      the callsite, but the final event in the path be at the entrypoint
325      of the called function.  */
326   virtual void add_final_event (const state_machine *sm,
327                                 const exploded_node *enode,
328                                 const gimple *stmt,
329                                 tree var, state_machine::state_t state,
330                                 checker_path *emission_path);
331
332   /* Vfunc for determining that this pending_diagnostic supercedes OTHER,
333      and that OTHER should therefore not be emitted.
334      They have already been tested for being at the same stmt.  */
335
336   virtual bool
337   supercedes_p (const pending_diagnostic &other ATTRIBUTE_UNUSED) const
338   {
339     return false;
340   }
341
342   /* Vfunc for registering additional information of interest to this
343      diagnostic.  */
344
345   virtual void mark_interesting_stuff (interesting_t *)
346   {
347     /* Default no-op implementation.  */
348   }
349 };
350
351 /* A template to make it easier to make subclasses of pending_diagnostic.
352
353    This uses the curiously-recurring template pattern, to implement
354    pending_diagnostic::subclass_equal_p by casting and calling
355    the operator==
356
357    This assumes that BASE_OTHER has already been checked to have
358    been of the same subclass (which pending_diagnostic::equal_p does).  */
359
360 template <class Subclass>
361 class pending_diagnostic_subclass : public pending_diagnostic
362 {
363  public:
364   bool subclass_equal_p (const pending_diagnostic &base_other) const
365     final override
366   {
367     const Subclass &other = (const Subclass &)base_other;
368     return *(const Subclass*)this == other;
369   }
370 };
371
372 /* An abstract base class for capturing additional notes that are to be
373    emitted with a diagnostic.  */
374
375 class pending_note
376 {
377 public:
378   virtual ~pending_note () {}
379
380   /* Hand-coded RTTI: get an ID for the subclass.  */
381   virtual const char *get_kind () const = 0;
382
383   /* Vfunc for emitting the note.  */
384   virtual void emit () const = 0;
385
386   bool equal_p (const pending_note &other) const
387   {
388     /* Check for pointer equality on the IDs from get_kind.  */
389     if (get_kind () != other.get_kind ())
390       return false;
391     /* Call vfunc now we know they have the same ID: */
392     return subclass_equal_p (other);
393   }
394
395   /* A vfunc for testing for equality, where we've already
396      checked they have the same ID.  See pending_note_subclass
397      below for a convenience subclass for implementing this.  */
398   virtual bool subclass_equal_p (const pending_note &other) const = 0;
399 };
400
401 /* Analogous to pending_diagnostic_subclass, but for pending_note.  */
402
403 template <class Subclass>
404 class pending_note_subclass : public pending_note
405 {
406  public:
407   bool subclass_equal_p (const pending_note &base_other) const
408     final override
409   {
410     const Subclass &other = (const Subclass &)base_other;
411     return *(const Subclass*)this == other;
412   }
413 };
414
415 } // namespace ana
416
417 #endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */