GCC Middle and Back End API Reference
pending-diagnostic.h
Go to the documentation of this file.
1/* Classes for analyzer diagnostics.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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-metadata.h"
25#include "diagnostic-path.h"
26#include "analyzer/sm.h"
27
28namespace ana {
29
30/* A bundle of information about things that are of interest to a
31 pending_diagnostic.
32
33 For now, merely the set of regions that are pertinent to the
34 diagnostic, so that we can notify the user about when they
35 were created. */
36
38{
39 void add_region_creation (const region *reg);
40
41 void dump_to_pp (pretty_printer *pp, bool simple) const;
42
44};
45
46/* Various bundles of information used for generating more precise
47 messages for events within a diagnostic_path, for passing to the
48 various "describe_*" vfuncs of pending_diagnostic. See those
49 for more information. */
50
51namespace evdesc {
52
54{
55 event_desc (bool colorize) : m_colorize (colorize) {}
56
57 label_text formatted_print (const char *fmt, ...) const
59
61};
62
63/* For use by pending_diagnostic::describe_state_change. */
64
65struct state_change : public event_desc
66{
67 state_change (bool colorize,
68 tree expr,
69 tree origin,
70 state_machine::state_t old_state,
71 state_machine::state_t new_state,
72 diagnostic_event_id_t event_id,
73 const state_change_event &event)
74 : event_desc (colorize),
75 m_expr (expr), m_origin (origin),
76 m_old_state (old_state), m_new_state (new_state),
77 m_event_id (event_id), m_event (event)
78 {}
79
80 bool is_global_p () const { return m_expr == NULL_TREE; }
81
88};
89
90/* For use by pending_diagnostic::describe_call_with_state. */
91
93{
94 call_with_state (bool colorize,
95 tree caller_fndecl, tree callee_fndecl,
97 : event_desc (colorize),
98 m_caller_fndecl (caller_fndecl),
99 m_callee_fndecl (callee_fndecl),
100 m_expr (expr),
101 m_state (state)
102 {
103 }
104
109};
110
111/* For use by pending_diagnostic::describe_return_of_state. */
112
114{
115 return_of_state (bool colorize,
116 tree caller_fndecl, tree callee_fndecl,
118 : event_desc (colorize),
119 m_caller_fndecl (caller_fndecl),
120 m_callee_fndecl (callee_fndecl),
121 m_state (state)
122 {
123 }
124
128};
129
130/* For use by pending_diagnostic::describe_final_event. */
131
132struct final_event : public event_desc
133{
134 final_event (bool colorize,
136 const warning_event &event)
137 : event_desc (colorize),
138 m_expr (expr), m_state (state), m_event (event)
139 {}
140
144};
145
146} /* end of namespace evdesc */
147
148/* A bundle of information for use by implementations of the
149 pending_diagnostic::emit vfunc.
150
151 The rich_location will have already been populated with a
152 diagnostic_path. */
153
155{
156public:
158 rich_location &rich_loc,
159 diagnostic_metadata &metadata,
160 logger *logger)
161 : m_sd (sd),
162 m_rich_loc (rich_loc),
163 m_metadata (metadata),
164 m_logger (logger)
165 {
166 }
167
169
170 bool warn (const char *, ...) ATTRIBUTE_GCC_DIAG (2,3);
171 void inform (const char *, ...) ATTRIBUTE_GCC_DIAG (2,3);
172
173 location_t get_location () const { return m_rich_loc.get_loc (); }
174 logger *get_logger () const { return m_logger; }
175
176 void add_cwe (int cwe) { m_metadata.add_cwe (cwe); }
178 {
179 m_metadata.add_rule (r);
180 }
181
182private:
184 rich_location &m_rich_loc;
187};
188
189/* An abstract base class for capturing information about a diagnostic in
190 a form that is ready to emit at a later point (or be rejected).
191 Each kind of diagnostic will have a concrete subclass of
192 pending_diagnostic.
193
194 Normally, gcc diagnostics are emitted using va_list, which can't be
195 portably stored for later use, so we have to use an "emit" virtual
196 function.
197
198 This class also supports comparison, so that multiple pending_diagnostic
199 instances can be de-duplicated.
200
201 As well as emitting a diagnostic, the class has various "precision of
202 wording" virtual functions, for generating descriptions for events
203 within a diagnostic_path. These are optional, but implementing these
204 allows for more precise wordings than the more generic
205 implementation. */
206
208{
209 public:
211
212 /* Vfunc to get the command-line option used when emitting the diagnostic,
213 or zero if there is none.
214 Used by diagnostic_manager for early rejection of diagnostics (to avoid
215 having to generate feasible execution paths for them). */
216 virtual int get_controlling_option () const = 0;
217
218 /* Vfunc to give the diagnostic the chance to terminate the execution
219 path being explored. By default, don't terminate the path. */
220 virtual bool terminate_path_p () const { return false; }
221
222 /* Vfunc for emitting the diagnostic.
223 Return true if a diagnostic is actually emitted. */
224 virtual bool emit (diagnostic_emission_context &) = 0;
225
226 /* Hand-coded RTTI: get an ID for the subclass. */
227 virtual const char *get_kind () const = 0;
228
229 /* A vfunc for identifying "use of uninitialized value". */
230 virtual bool use_of_uninit_p () const { return false; }
231
232 /* Compare for equality with OTHER, which might be of a different
233 subclass. */
234
235 bool equal_p (const pending_diagnostic &other) const
236 {
237 /* Check for pointer equality on the IDs from get_kind. */
238 if (get_kind () != other.get_kind ())
239 return false;
240 /* Call vfunc now we know they have the same ID: */
241 return subclass_equal_p (other);
242 }
243
244 /* A vfunc for testing for equality, where we've already
245 checked they have the same ID. See pending_diagnostic_subclass
246 below for a convenience subclass for implementing this. */
247 virtual bool subclass_equal_p (const pending_diagnostic &other) const = 0;
248
249 /* Return true if T1 and T2 are "the same" for the purposes of
250 diagnostic deduplication. */
251 static bool same_tree_p (tree t1, tree t2);
252
253 /* Vfunc for fixing up locations, e.g. to avoid unwinding
254 inside specific macros. PRIMARY is true for the primary location
255 for the diagnostic, and FALSE for events in their paths. */
256 virtual location_t fixup_location (location_t loc, bool primary) const;
257
258 /* Precision-of-wording vfunc for describing a critical state change
259 within the diagnostic_path.
260
261 For example, a double-free diagnostic might use the descriptions:
262 - "first 'free' happens here"
263 - "second 'free' happens here"
264 for the pertinent events, whereas a use-after-free might use the
265 descriptions:
266 - "freed here"
267 - "use after free here"
268 Note how in both cases the first event is a "free": the best
269 description to use depends on the diagnostic. */
270
271 virtual label_text describe_state_change (const evdesc::state_change &)
272 {
273 /* Default no-op implementation. */
274 return label_text ();
275 }
276
277 /* Vfunc for implementing diagnostic_event::get_meaning for
278 state_change_event. */
281 {
282 /* Default no-op implementation. */
284 }
285
286 /* Precision-of-wording vfunc for describing an interprocedural call
287 carrying critial state for the diagnostic, from caller to callee.
288
289 For example a double-free diagnostic might use:
290 - "passing freed pointer 'ptr' in call to 'deallocator' from 'test'"
291 to make it clearer how the freed value moves from caller to
292 callee. */
293
295 {
296 /* Default no-op implementation. */
297 return label_text ();
298 }
299
300 /* Precision-of-wording vfunc for describing an interprocedural return
301 within the diagnostic_path that carries critial state for the
302 diagnostic, from callee back to caller.
303
304 For example, a deref-of-unchecked-malloc diagnostic might use:
305 - "returning possibly-NULL pointer to 'make_obj' from 'allocator'"
306 to make it clearer how the unchecked value moves from callee
307 back to caller. */
308
310 {
311 /* Default no-op implementation. */
312 return label_text ();
313 }
314
315 /* Precision-of-wording vfunc for describing the final event within a
316 diagnostic_path.
317
318 For example a double-free diagnostic might use:
319 - "second 'free' here; first 'free' was at (3)"
320 and a use-after-free might use
321 - "use after 'free' here; memory was freed at (2)". */
322
323 virtual label_text describe_final_event (const evdesc::final_event &)
324 {
325 /* Default no-op implementation. */
326 return label_text ();
327 }
328
329 /* End of precision-of-wording vfuncs. */
330
331 /* Vfunc for adding a function_entry_event to a checker_path, so that e.g.
332 the infinite recursion diagnostic can add a custom event subclass
333 that annotates recursively entering a function. */
334
335 virtual void
337 checker_path *emission_path);
338
339 /* Vfunc for extending/overriding creation of the events for an
340 exploded_edge that corresponds to a superedge, allowing for custom
341 events to be created that are pertinent to a particular
342 pending_diagnostic subclass.
343
344 For example, the -Wanalyzer-stale-setjmp-buffer diagnostic adds a
345 custom event showing when the pertinent stack frame is popped
346 (and thus the point at which the jmp_buf becomes invalid). */
347
349 checker_path *)
350 {
351 return false;
352 }
353
354 /* Vfunc for adding a call_event to a checker_path, so that e.g.
355 the varargs diagnostics can add a custom event subclass that annotates
356 the variadic arguments. */
357 virtual void add_call_event (const exploded_edge &,
358 checker_path *);
359
360 /* Vfunc for adding any events for the creation of regions identified
361 by the mark_interesting_stuff vfunc.
362 See the comment for class region_creation_event. */
363 virtual void add_region_creation_events (const region *reg,
364 tree capacity,
365 const event_loc_info &loc_info,
366 checker_path &emission_path);
367
368 /* Vfunc for adding the final warning_event to a checker_path, so that e.g.
369 the infinite recursion diagnostic can have its diagnostic appear at
370 the callsite, but the final event in the path be at the entrypoint
371 of the called function. */
372 virtual void add_final_event (const state_machine *sm,
373 const exploded_node *enode,
374 const event_loc_info &loc_info,
376 checker_path *emission_path);
377
378 /* Vfunc for determining that this pending_diagnostic supercedes OTHER,
379 and that OTHER should therefore not be emitted.
380 They have already been tested for being at the same stmt. */
381
382 virtual bool
383 supercedes_p (const pending_diagnostic &other ATTRIBUTE_UNUSED) const
384 {
385 return false;
386 }
387
388 /* Vfunc for registering additional information of interest to this
389 diagnostic. */
390
392 {
393 /* Default no-op implementation. */
394 }
395
396 /* Vfunc to give diagnostic subclasses the opportunity to reject diagnostics
397 by imposing their own additional feasibility checks on the path to a
398 given feasible_node. */
399 virtual bool check_valid_fpath_p (const feasible_node &,
400 const gimple *) const
401 {
402 /* Default implementation: accept this path. */
403 return true;
404 }
405
406 /* Vfunc for use in SARIF output to give pending_diagnostic subclasses
407 the opportunity to add diagnostic-specific properties to the SARIF
408 "result" object for the diagnostic.
409 This is intended for use when debugging a diagnostic. */
410 virtual void maybe_add_sarif_properties (sarif_object &/*result_obj*/) const
411 {
412 /* Default no-op implementation. */
413 }
414};
415
416/* A template to make it easier to make subclasses of pending_diagnostic.
417
418 This uses the curiously-recurring template pattern, to implement
419 pending_diagnostic::subclass_equal_p by casting and calling
420 the operator==
421
422 This assumes that BASE_OTHER has already been checked to have
423 been of the same subclass (which pending_diagnostic::equal_p does). */
424
425template <class Subclass>
427{
428 public:
429 bool subclass_equal_p (const pending_diagnostic &base_other) const
430 final override
431 {
432 const Subclass &other = (const Subclass &)base_other;
433 return *(const Subclass*)this == other;
434 }
435};
436
437/* An abstract base class for capturing additional notes that are to be
438 emitted with a diagnostic. */
439
441{
442public:
443 virtual ~pending_note () {}
444
445 /* Hand-coded RTTI: get an ID for the subclass. */
446 virtual const char *get_kind () const = 0;
447
448 /* Vfunc for emitting the note. */
449 virtual void emit () const = 0;
450
451 bool equal_p (const pending_note &other) const
452 {
453 /* Check for pointer equality on the IDs from get_kind. */
454 if (get_kind () != other.get_kind ())
455 return false;
456 /* Call vfunc now we know they have the same ID: */
457 return subclass_equal_p (other);
458 }
459
460 /* A vfunc for testing for equality, where we've already
461 checked they have the same ID. See pending_note_subclass
462 below for a convenience subclass for implementing this. */
463 virtual bool subclass_equal_p (const pending_note &other) const = 0;
464};
465
466/* Analogous to pending_diagnostic_subclass, but for pending_note. */
467
468template <class Subclass>
470{
471 public:
472 bool subclass_equal_p (const pending_note &base_other) const
473 final override
474 {
475 const Subclass &other = (const Subclass &)base_other;
476 return *(const Subclass*)this == other;
477 }
478};
479
480} // namespace ana
481
482#endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */
Definition checker-path.h:32
Definition pending-diagnostic.h:155
const saved_diagnostic & m_sd
Definition pending-diagnostic.h:183
bool warn(const char *,...) ATTRIBUTE_GCC_DIAG(2
rich_location & m_rich_loc
Definition pending-diagnostic.h:184
diagnostic_metadata & m_metadata
Definition pending-diagnostic.h:185
void add_cwe(int cwe)
Definition pending-diagnostic.h:176
logger * m_logger
Definition pending-diagnostic.h:186
logger * get_logger() const
Definition pending-diagnostic.h:174
diagnostic_emission_context(const saved_diagnostic &sd, rich_location &rich_loc, diagnostic_metadata &metadata, logger *logger)
Definition pending-diagnostic.h:157
const pending_diagnostic & get_pending_diagnostic() const
void add_rule(const diagnostic_metadata::rule &r)
Definition pending-diagnostic.h:177
Definition exploded-graph.h:381
Definition exploded-graph.h:203
Definition feasible-graph.h:84
Definition analyzer-logging.h:34
Definition pending-diagnostic.h:427
bool subclass_equal_p(const pending_diagnostic &base_other) const final override
Definition pending-diagnostic.h:429
Definition pending-diagnostic.h:208
virtual ~pending_diagnostic()
Definition pending-diagnostic.h:210
virtual bool use_of_uninit_p() const
Definition pending-diagnostic.h:230
virtual bool subclass_equal_p(const pending_diagnostic &other) const =0
virtual void mark_interesting_stuff(interesting_t *)
Definition pending-diagnostic.h:391
virtual void maybe_add_sarif_properties(sarif_object &) const
Definition pending-diagnostic.h:410
virtual bool maybe_add_custom_events_for_superedge(const exploded_edge &, checker_path *)
Definition pending-diagnostic.h:348
virtual void add_region_creation_events(const region *reg, tree capacity, const event_loc_info &loc_info, checker_path &emission_path)
virtual const char * get_kind() const =0
virtual label_text describe_call_with_state(const evdesc::call_with_state &)
Definition pending-diagnostic.h:294
virtual bool terminate_path_p() const
Definition pending-diagnostic.h:220
virtual bool supercedes_p(const pending_diagnostic &other) const
Definition pending-diagnostic.h:383
bool equal_p(const pending_diagnostic &other) const
Definition pending-diagnostic.h:235
virtual label_text describe_return_of_state(const evdesc::return_of_state &)
Definition pending-diagnostic.h:309
virtual void add_final_event(const state_machine *sm, const exploded_node *enode, const event_loc_info &loc_info, tree var, state_machine::state_t state, checker_path *emission_path)
virtual void add_function_entry_event(const exploded_edge &eedge, checker_path *emission_path)
virtual void add_call_event(const exploded_edge &, checker_path *)
virtual int get_controlling_option() const =0
virtual diagnostic_event::meaning get_meaning_for_state_change(const evdesc::state_change &) const
Definition pending-diagnostic.h:280
virtual bool check_valid_fpath_p(const feasible_node &, const gimple *) const
Definition pending-diagnostic.h:399
static bool same_tree_p(tree t1, tree t2)
virtual label_text describe_final_event(const evdesc::final_event &)
Definition pending-diagnostic.h:323
virtual bool emit(diagnostic_emission_context &)=0
virtual label_text describe_state_change(const evdesc::state_change &)
Definition pending-diagnostic.h:271
virtual location_t fixup_location(location_t loc, bool primary) const
Definition pending-diagnostic.h:470
bool subclass_equal_p(const pending_note &base_other) const final override
Definition pending-diagnostic.h:472
Definition pending-diagnostic.h:441
virtual ~pending_note()
Definition pending-diagnostic.h:443
virtual bool subclass_equal_p(const pending_note &other) const =0
virtual void emit() const =0
virtual const char * get_kind() const =0
bool equal_p(const pending_note &other) const
Definition pending-diagnostic.h:451
Definition region.h:126
Definition diagnostic-manager.h:31
Definition checker-event.h:347
Definition sm.h:45
Definition sm.h:40
Definition checker-event.h:674
Definition vec.h:1656
Definition diagnostic-event-id.h:37
Definition diagnostic-metadata.h:38
Definition diagnostic-metadata.h:33
Definition genmatch.cc:845
Definition pretty-print.h:255
Definition diagnostic-format-sarif.h:42
union tree_node * tree
Definition coretypes.h:97
#define ATTRIBUTE_GCC_DIAG(m, n)
Definition diagnostic-core.h:67
bool bool bool bool bool bool void void void inform(location_t, const char *,...) ATTRIBUTE_GCC_DIAG(2
static location_t get_location(const gimple *stmt)
Definition gimple-ssa-warn-access.cc:76
Definition access-diagram.h:30
poly_int< N, C > r
Definition poly-int.h:770
Definition pending-diagnostic.h:93
tree m_caller_fndecl
Definition pending-diagnostic.h:105
tree m_callee_fndecl
Definition pending-diagnostic.h:106
state_machine::state_t m_state
Definition pending-diagnostic.h:108
call_with_state(bool colorize, tree caller_fndecl, tree callee_fndecl, tree expr, state_machine::state_t state)
Definition pending-diagnostic.h:94
tree m_expr
Definition pending-diagnostic.h:107
Definition pending-diagnostic.h:54
event_desc(bool colorize)
Definition pending-diagnostic.h:55
label_text formatted_print(const char *fmt,...) const ATTRIBUTE_GCC_DIAG(2
label_text bool m_colorize
Definition pending-diagnostic.h:60
Definition pending-diagnostic.h:133
state_machine::state_t m_state
Definition pending-diagnostic.h:142
final_event(bool colorize, tree expr, state_machine::state_t state, const warning_event &event)
Definition pending-diagnostic.h:134
const warning_event & m_event
Definition pending-diagnostic.h:143
tree m_expr
Definition pending-diagnostic.h:141
Definition pending-diagnostic.h:114
tree m_callee_fndecl
Definition pending-diagnostic.h:126
state_machine::state_t m_state
Definition pending-diagnostic.h:127
return_of_state(bool colorize, tree caller_fndecl, tree callee_fndecl, state_machine::state_t state)
Definition pending-diagnostic.h:115
tree m_caller_fndecl
Definition pending-diagnostic.h:125
Definition pending-diagnostic.h:66
tree m_expr
Definition pending-diagnostic.h:82
state_machine::state_t m_old_state
Definition pending-diagnostic.h:84
state_change(bool colorize, tree expr, tree origin, state_machine::state_t old_state, state_machine::state_t new_state, diagnostic_event_id_t event_id, const state_change_event &event)
Definition pending-diagnostic.h:67
const state_change_event & m_event
Definition pending-diagnostic.h:87
diagnostic_event_id_t m_event_id
Definition pending-diagnostic.h:86
bool is_global_p() const
Definition pending-diagnostic.h:80
state_machine::state_t m_new_state
Definition pending-diagnostic.h:85
tree m_origin
Definition pending-diagnostic.h:83
Definition event-loc-info.h:29
Definition pending-diagnostic.h:38
void dump_to_pp(pretty_printer *pp, bool simple) const
void add_region_creation(const region *reg)
auto_vec< const region * > m_region_creation
Definition pending-diagnostic.h:43
Definition diagnostic-path.h:114
Definition gimple.h:225
Definition genautomata.cc:669
#define NULL_TREE
Definition tree.h:317