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