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