1 /* Classes for analyzer diagnostics.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
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)
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.
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/>. */
21 #ifndef GCC_ANALYZER_PENDING_DIAGNOSTIC_H
22 #define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
26 /* A bundle of information about things that are of interest to a
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
35 void add_region_creation (const region
*reg
);
37 void dump_to_pp (pretty_printer
*pp
, bool simple
) const;
39 auto_vec
<const region
*> m_region_creation
;
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. */
51 event_desc (bool colorize
) : m_colorize (colorize
) {}
53 label_text
formatted_print (const char *fmt
, ...) const
54 ATTRIBUTE_GCC_DIAG(2,3);
59 /* For use by pending_diagnostic::describe_state_change. */
61 struct state_change
: public event_desc
63 state_change (bool colorize
,
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
)
76 bool is_global_p () const { return m_expr
== NULL_TREE
; }
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
;
86 /* For use by pending_diagnostic::describe_call_with_state. */
88 struct call_with_state
: public event_desc
90 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
),
101 tree m_caller_fndecl
;
102 tree m_callee_fndecl
;
104 state_machine::state_t m_state
;
107 /* For use by pending_diagnostic::describe_return_of_state. */
109 struct return_of_state
: public event_desc
111 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
),
121 tree m_caller_fndecl
;
122 tree m_callee_fndecl
;
123 state_machine::state_t m_state
;
126 /* For use by pending_diagnostic::describe_final_event. */
128 struct final_event
: public event_desc
130 final_event (bool colorize
,
131 tree expr
, state_machine::state_t state
)
132 : event_desc (colorize
),
133 m_expr (expr
), m_state (state
)
137 state_machine::state_t m_state
;
140 } /* end of namespace evdesc */
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
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
151 This class also supports comparison, so that multiple pending_diagnostic
152 instances can be de-duplicated.
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
160 class pending_diagnostic
163 virtual ~pending_diagnostic () {}
165 /* Vfunc for emitting the diagnostic. The rich_location will have been
166 populated with a diagnostic_path.
167 Return true if a diagnostic is actually emitted. */
168 virtual bool emit (rich_location
*) = 0;
170 /* Hand-coded RTTI: get an ID for the subclass. */
171 virtual const char *get_kind () const = 0;
173 /* A vfunc for identifying "use of uninitialized value". */
174 virtual bool use_of_uninit_p () const { return false; }
176 /* Compare for equality with OTHER, which might be of a different
179 bool equal_p (const pending_diagnostic
&other
) const
181 /* Check for pointer equality on the IDs from get_kind. */
182 if (get_kind () != other
.get_kind ())
184 /* Call vfunc now we know they have the same ID: */
185 return subclass_equal_p (other
);
188 /* A vfunc for testing for equality, where we've already
189 checked they have the same ID. See pending_diagnostic_subclass
190 below for a convenience subclass for implementing this. */
191 virtual bool subclass_equal_p (const pending_diagnostic
&other
) const = 0;
193 /* Return true if T1 and T2 are "the same" for the purposes of
194 diagnostic deduplication. */
195 static bool same_tree_p (tree t1
, tree t2
);
197 /* A vfunc for fixing up locations (both the primary location for the
198 diagnostic, and for events in their paths), e.g. to avoid unwinding
199 inside specific macros. */
200 virtual location_t
fixup_location (location_t loc
) const
205 /* For greatest precision-of-wording, the various following "describe_*"
206 virtual functions give the pending diagnostic a way to describe events
207 in a diagnostic_path in terms that make sense for that diagnostic.
209 In each case, return a non-NULL label_text to give the event a custom
210 description; NULL otherwise (falling back on a more generic
213 /* Precision-of-wording vfunc for describing a critical state change
214 within the diagnostic_path.
216 For example, a double-free diagnostic might use the descriptions:
217 - "first 'free' happens here"
218 - "second 'free' happens here"
219 for the pertinent events, whereas a use-after-free might use the
222 - "use after free here"
223 Note how in both cases the first event is a "free": the best
224 description to use depends on the diagnostic. */
226 virtual label_text
describe_state_change (const evdesc::state_change
&)
228 /* Default no-op implementation. */
229 return label_text ();
232 /* Precision-of-wording vfunc for describing an interprocedural call
233 carrying critial state for the diagnostic, from caller to callee.
235 For example a double-free diagnostic might use:
236 - "passing freed pointer 'ptr' in call to 'deallocator' from 'test'"
237 to make it clearer how the freed value moves from caller to
240 virtual label_text
describe_call_with_state (const evdesc::call_with_state
&)
242 /* Default no-op implementation. */
243 return label_text ();
246 /* Precision-of-wording vfunc for describing an interprocedural return
247 within the diagnostic_path that carries critial state for the
248 diagnostic, from callee back to caller.
250 For example, a deref-of-unchecked-malloc diagnostic might use:
251 - "returning possibly-NULL pointer to 'make_obj' from 'allocator'"
252 to make it clearer how the unchecked value moves from callee
255 virtual label_text
describe_return_of_state (const evdesc::return_of_state
&)
257 /* Default no-op implementation. */
258 return label_text ();
261 /* Precision-of-wording vfunc for describing the final event within a
264 For example a double-free diagnostic might use:
265 - "second 'free' here; first 'free' was at (3)"
266 and a use-after-free might use
267 - "use after 'free' here; memory was freed at (2)". */
269 virtual label_text
describe_final_event (const evdesc::final_event
&)
271 /* Default no-op implementation. */
272 return label_text ();
275 /* End of precision-of-wording vfuncs. */
277 /* Vfunc for extending/overriding creation of the events for an
278 exploded_edge that corresponds to a superedge, allowing for custom
279 events to be created that are pertinent to a particular
280 pending_diagnostic subclass.
282 For example, the -Wanalyzer-stale-setjmp-buffer diagnostic adds a
283 custom event showing when the pertinent stack frame is popped
284 (and thus the point at which the jmp_buf becomes invalid). */
286 virtual bool maybe_add_custom_events_for_superedge (const exploded_edge
&,
292 /* Vfunc for determining that this pending_diagnostic supercedes OTHER,
293 and that OTHER should therefore not be emitted.
294 They have already been tested for being at the same stmt. */
297 supercedes_p (const pending_diagnostic
&other ATTRIBUTE_UNUSED
) const
302 /* Vfunc for registering additional information of interest to this
305 virtual void mark_interesting_stuff (interesting_t
*)
307 /* Default no-op implementation. */
311 /* A template to make it easier to make subclasses of pending_diagnostic.
313 This uses the curiously-recurring template pattern, to implement
314 pending_diagnostic::subclass_equal_p by casting and calling
317 This assumes that BASE_OTHER has already been checked to have
318 been of the same subclass (which pending_diagnostic::equal_p does). */
320 template <class Subclass
>
321 class pending_diagnostic_subclass
: public pending_diagnostic
324 bool subclass_equal_p (const pending_diagnostic
&base_other
) const
327 const Subclass
&other
= (const Subclass
&)base_other
;
328 return *(const Subclass
*)this == other
;
334 #endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */