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-2026 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"
27
28namespace ana {
29
30/* A bundle of information about things that are of interest to a
31 pending_diagnostic:
32
33 * a set of regions that are pertinent to the
34 diagnostic, so that we can notify the user about when they
35 were created.
36
37 * a set of regions that a pertinent value for the diagnostic was
38 read from, so that we can notify the user about where those values
39 came from. */
40
42{
43 void add_region_creation (const region *reg);
44
45 void add_read_region (const region *reg, std::string debug_desc);
46
47 void dump_to_pp (pretty_printer *pp, bool simple) const;
48
50 std::vector<diagnostic_state> m_read_regions;
51};
52
53/* Various bundles of information used for generating more precise
54 messages for events within a diagnostic path, for passing to the
55 various "describe_*" vfuncs of pending_diagnostic. See those
56 for more information. */
57
58namespace evdesc {
59
60/* For use by pending_diagnostic::describe_state_change. */
61
84
85/* For use by pending_diagnostic::describe_origin_of_state. */
86
88{
89 origin_of_state (tree dst_reg_expr)
90 : m_dst_reg_expr (dst_reg_expr)
91 {
93 }
94
96};
97
98/* For use by pending_diagnostic::describe_call_with_state. */
99
101{
102 call_with_state (tree caller_fndecl, tree callee_fndecl,
104 const state_transition_at_call *state_trans)
105 : m_caller_fndecl (caller_fndecl),
106 m_callee_fndecl (callee_fndecl),
107 m_expr (expr),
108 m_state (state),
109 m_state_trans (state_trans)
110 {
111 if (state_trans)
112 m_src_event_id = state_trans->get_src_event_id ();
113 }
114
121};
122
123/* For use by pending_diagnostic::describe_return_of_state. */
124
126{
127 return_of_state (tree caller_fndecl, tree callee_fndecl,
129 const state_transition_at_return *state_trans)
130 : m_caller_fndecl (caller_fndecl),
131 m_callee_fndecl (callee_fndecl),
132 m_state (state),
133 m_state_trans (state_trans)
134 {
135 if (state_trans)
136 m_src_event_id = state_trans->get_src_event_id ();
137 }
138
144};
145
146/* For use by pending_diagnostic::describe_copy_of_state. */
147
149{
150 copy_of_state (tree src_reg_expr,
152 tree dst_reg_expr)
153 : m_src_reg_expr (src_reg_expr),
154 m_src_event_id (src_event_id),
155 m_dst_reg_expr (dst_reg_expr)
156 {
159 }
160
164};
165
166/* For use by pending_diagnostic::describe_use_of_state. */
167
169{
170 use_of_state (tree src_reg_expr,
172 : m_src_reg_expr (src_reg_expr),
173 m_src_event_id (src_event_id)
174 {
176 }
177
180};
181
182/* For use by pending_diagnostic::describe_final_event. */
183
195
196} /* end of namespace evdesc */
197
198/* A bundle of information for use by implementations of the
199 pending_diagnostic::emit vfunc.
200
201 The rich_location will have already been populated with a
202 diagnostics::paths::path. */
203
205{
206public:
208 rich_location &rich_loc,
209 diagnostics::metadata &metadata,
210 logger *logger)
211 : m_sd (sd),
212 m_rich_loc (rich_loc),
213 m_metadata (metadata),
215 {
216 }
217
219
220 bool warn (const char *, ...) ATTRIBUTE_GCC_DIAG (2,3);
221 void inform (const char *, ...) ATTRIBUTE_GCC_DIAG (2,3);
222
223 location_t get_location () const { return m_rich_loc.get_loc (); }
224 logger *get_logger () const { return m_logger; }
225
226 void add_cwe (int cwe) { m_metadata.add_cwe (cwe); }
228 {
229 m_metadata.add_rule (r);
230 }
231
232private:
234 rich_location &m_rich_loc;
237};
238
239/* An abstract base class for capturing information about a diagnostic in
240 a form that is ready to emit at a later point (or be rejected).
241 Each kind of diagnostic will have a concrete subclass of
242 pending_diagnostic.
243
244 Normally, gcc diagnostics are emitted using va_list, which can't be
245 portably stored for later use, so we have to use an "emit" virtual
246 function.
247
248 This class also supports comparison, so that multiple pending_diagnostic
249 instances can be de-duplicated.
250
251 As well as emitting a diagnostic, the class has various "precision of
252 wording" virtual functions, for generating descriptions for events
253 within a diagnostic path. These are optional, but implementing these
254 allows for more precise wordings than the more generic
255 implementation. */
256
258{
259 public:
261
262 /* Vfunc to get the command-line option used when emitting the diagnostic,
263 or zero if there is none.
264 Used by diagnostic_manager for early rejection of diagnostics (to avoid
265 having to generate feasible execution paths for them). */
266 virtual int get_controlling_option () const = 0;
267
268 /* Vfunc to give the diagnostic the chance to terminate the execution
269 path being explored. By default, don't terminate the path. */
270 virtual bool terminate_path_p () const { return false; }
271
272 /* Vfunc for emitting the diagnostic.
273 Return true if a diagnostic is actually emitted. */
274 virtual bool emit (diagnostic_emission_context &) = 0;
275
276 /* Hand-coded RTTI: get an ID for the subclass. */
277 virtual const char *get_kind () const = 0;
278
279 /* A vfunc for identifying "use of uninitialized value". */
280 virtual bool use_of_uninit_p () const { return false; }
281
282 /* Compare for equality with OTHER, which might be of a different
283 subclass. */
284
285 bool equal_p (const pending_diagnostic &other) const
286 {
287 /* Check for pointer equality on the IDs from get_kind. */
288 if (get_kind () != other.get_kind ())
289 return false;
290 /* Call vfunc now we know they have the same ID: */
291 return subclass_equal_p (other);
292 }
293
294 /* A vfunc for testing for equality, where we've already
295 checked they have the same ID. See pending_diagnostic_subclass
296 below for a convenience subclass for implementing this. */
297 virtual bool subclass_equal_p (const pending_diagnostic &other) const = 0;
298
299 /* Return true if T1 and T2 are "the same" for the purposes of
300 diagnostic deduplication. */
301 static bool same_tree_p (tree t1, tree t2);
302
303 /* Vfunc for fixing up locations, e.g. to avoid unwinding
304 inside specific macros. PRIMARY is true for the primary location
305 for the diagnostic, and FALSE for events in their paths. */
306 virtual location_t fixup_location (location_t loc, bool primary) const;
307
308 /* Precision-of-wording vfunc for describing a critical state change
309 within the diagnostic path.
310
311 For example, a double-free diagnostic might use the descriptions:
312 - "first 'free' happens here"
313 - "second 'free' happens here"
314 for the pertinent events, whereas a use-after-free might use the
315 descriptions:
316 - "freed here"
317 - "use after free here"
318 Note how in both cases the first event is a "free": the best
319 description to use depends on the diagnostic.
320
321 Print the description to PP and return true,
322 or do nothing and return false. */
323
325 const evdesc::state_change &)
326 {
327 /* Default no-op implementation. */
328 return false;
329 }
330
331 /* Vfunc for implementing event::get_meaning for
332 state_change_event. */
335 {
336 /* Default no-op implementation. */
338 }
339
340 /* Precision-of-wording vfunc for use in describing state_transition_event
341 instances of state_transition::kind::origin.
342 Return true if a description of the event was printed to the
343 pretty-printer, or false otherwise.
344 For example, a divide-by-zero diagnostic might use:
345 "zero value originates here"
346 at the point where the zero comes from. */
349 {
350 /* Default no-op implementation. */
351 return false;
352 }
353
354 /* Precision-of-wording vfunc for describing an interprocedural call
355 carrying critial state for the diagnostic, from caller to callee.
356
357 For example a double-free diagnostic might use:
358 - "passing freed pointer 'ptr' in call to 'deallocator' from 'test'"
359 to make it clearer how the freed value moves from caller to
360 callee. */
361
364 {
365 /* Default no-op implementation. */
366 return false;
367 }
368
369 /* Precision-of-wording vfunc for describing an interprocedural return
370 within the diagnostic path that carries critial state for the
371 diagnostic, from callee back to caller.
372
373 For example, a deref-of-unchecked-malloc diagnostic might use:
374 - "returning possibly-NULL pointer to 'make_obj' from 'allocator'"
375 to make it clearer how the unchecked value moves from callee
376 back to caller. */
377
380 {
381 /* Default no-op implementation. */
382 return false;
383 }
384
385 /* Precision-of-wording vfunc for use in describing state_transition_event
386 instances of state_transition::kind::copy.
387 Return true if a description of the event was printed to the
388 pretty-printer, or false otherwise.
389 For example, a divide-by-zero diagnostic might use:
390 "copying zero value from (3) from 'x' to 'y'". */
392 const evdesc::copy_of_state &)
393 {
394 /* Default no-op implementation. */
395 return false;
396 }
397
398 /* Precision-of-wording vfunc for use in describing state_transition_event
399 instances of state_transition::kind::use.
400 Return true if a description of the event was printed to the
401 pretty-printer, or false otherwise.
402 For example, a divide-by-zero diagnostic might use:
403 "using zero value from (7) from 'y'". */
405 const evdesc::use_of_state &)
406 {
407 /* Default no-op implementation. */
408 return false;
409 }
410
411 /* Precision-of-wording vfunc for describing the final event within a
412 diagnostic path.
413
414 For example a double-free diagnostic might use:
415 - "second 'free' here; first 'free' was at (3)"
416 and a use-after-free might use
417 - "use after 'free' here; memory was freed at (2)". */
418
420 const evdesc::final_event &)
421 {
422 /* Default no-op implementation. */
423 return false;
424 }
425
426 /* End of precision-of-wording vfuncs. */
427
428 /* Vfunc for adding a function_entry_event to a checker_path, so that e.g.
429 the infinite recursion diagnostic can add a custom event subclass
430 that annotates recursively entering a function. */
431
432 virtual void
434 checker_path *emission_path,
435 const state_transition_at_call *state_trans);
436
437 /* Vfunc for extending/overriding creation of the events for an
438 exploded_edge, allowing for custom events to be created that are
439 pertinent to a particular pending_diagnostic subclass.
440
441 For example, the -Wanalyzer-stale-setjmp-buffer diagnostic adds a
442 custom event showing when the pertinent stack frame is popped
443 (and thus the point at which the jmp_buf becomes invalid). */
444
446 checker_path *)
447 {
448 return false;
449 }
450
451 /* Vfunc for adding a call_event to a checker_path, so that e.g.
452 the varargs diagnostics can add a custom event subclass that annotates
453 the variadic arguments. */
454 virtual void add_call_event (const exploded_edge &,
455 const gcall &call_stmt,
456 checker_path &emission_path,
457 const state_transition_at_call *state_trans);
458
459 /* Vfunc for adding any events for the creation of regions identified
460 by the mark_interesting_stuff vfunc.
461 See the comment for class region_creation_event. */
462 virtual void add_region_creation_events (const region *reg,
463 tree capacity,
464 const event_loc_info &loc_info,
465 checker_path &emission_path);
466
467 /* Vfunc for adding the final warning_event to a checker_path, so that e.g.
468 the infinite recursion diagnostic can have its diagnostic appear at
469 the callsite, but the final event in the path be at the entrypoint
470 of the called function. */
471 virtual void add_final_event (const state_machine *sm,
472 const exploded_node *enode,
473 const event_loc_info &loc_info,
475 checker_path *emission_path);
476
477 virtual const program_state *
479 {
480 return nullptr;
481 }
482
483 /* Vfunc for determining that this pending_diagnostic supercedes OTHER,
484 and that OTHER should therefore not be emitted.
485 They have already been tested for being at the same stmt. */
486
487 virtual bool
488 supercedes_p (const pending_diagnostic &other ATTRIBUTE_UNUSED) const
489 {
490 return false;
491 }
492
493 /* Vfunc for registering additional information of interest to this
494 diagnostic. */
495
497 {
498 /* Default no-op implementation. */
499 }
500
501 /* Vfunc to give diagnostic subclasses the opportunity to reject diagnostics
502 by imposing their own additional feasibility checks on the path to a
503 given feasible_node. */
504 virtual bool check_valid_fpath_p (const feasible_node &) const
505 {
506 /* Default implementation: accept this path. */
507 return true;
508 }
509
510 /* Vfunc for use in SARIF output to give pending_diagnostic subclasses
511 the opportunity to add diagnostic-specific properties to the SARIF
512 "result" object for the diagnostic.
513 This is intended for use when debugging a diagnostic. */
514 virtual void
516 {
517 /* Default no-op implementation. */
518 }
519};
520
521/* A template to make it easier to make subclasses of pending_diagnostic.
522
523 This uses the curiously-recurring template pattern, to implement
524 pending_diagnostic::subclass_equal_p by casting and calling
525 the operator==
526
527 This assumes that BASE_OTHER has already been checked to have
528 been of the same subclass (which pending_diagnostic::equal_p does). */
529
530template <class Subclass>
532{
533 public:
534 bool subclass_equal_p (const pending_diagnostic &base_other) const
535 final override
536 {
537 const Subclass &other = (const Subclass &)base_other;
538 return *(const Subclass*)this == other;
539 }
540};
541
542/* An abstract base class for capturing additional notes that are to be
543 emitted with a diagnostic. */
544
546{
547public:
548 virtual ~pending_note () {}
549
550 /* Hand-coded RTTI: get an ID for the subclass. */
551 virtual const char *get_kind () const = 0;
552
553 /* Vfunc for emitting the note. */
554 virtual void emit () const = 0;
555
556 bool equal_p (const pending_note &other) const
557 {
558 /* Check for pointer equality on the IDs from get_kind. */
559 if (get_kind () != other.get_kind ())
560 return false;
561 /* Call vfunc now we know they have the same ID: */
562 return subclass_equal_p (other);
563 }
564
565 /* A vfunc for testing for equality, where we've already
566 checked they have the same ID. See pending_note_subclass
567 below for a convenience subclass for implementing this. */
568 virtual bool subclass_equal_p (const pending_note &other) const = 0;
569};
570
571/* Analogous to pending_diagnostic_subclass, but for pending_note. */
572
573template <class Subclass>
575{
576 public:
577 bool subclass_equal_p (const pending_note &base_other) const
578 final override
579 {
580 const Subclass &other = (const Subclass &)base_other;
581 return *(const Subclass*)this == other;
582 }
583};
584
585} // namespace ana
586
587#endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */
Definition checker-path.h:32
Definition pending-diagnostic.h:205
const saved_diagnostic & m_sd
Definition pending-diagnostic.h:233
void add_rule(const diagnostics::metadata::rule &r)
Definition pending-diagnostic.h:227
diagnostics::metadata & m_metadata
Definition pending-diagnostic.h:235
bool warn(const char *,...) ATTRIBUTE_GCC_DIAG(2
rich_location & m_rich_loc
Definition pending-diagnostic.h:234
bool void inform(const char *,...) ATTRIBUTE_GCC_DIAG(2
void add_cwe(int cwe)
Definition pending-diagnostic.h:226
logger * m_logger
Definition pending-diagnostic.h:236
logger * get_logger() const
Definition pending-diagnostic.h:224
diagnostic_emission_context(const saved_diagnostic &sd, rich_location &rich_loc, diagnostics::metadata &metadata, logger *logger)
Definition pending-diagnostic.h:207
bool void location_t get_location() const
Definition pending-diagnostic.h:223
const pending_diagnostic & get_pending_diagnostic() const
Definition exploded-graph.h:335
Definition exploded-graph.h:206
Definition feasible-graph.h:84
Definition analyzer-logging.h:36
Definition pending-diagnostic.h:532
bool subclass_equal_p(const pending_diagnostic &base_other) const final override
Definition pending-diagnostic.h:534
Definition pending-diagnostic.h:258
virtual bool describe_origin_of_state(pretty_printer &, const evdesc::origin_of_state &)
Definition pending-diagnostic.h:347
virtual bool describe_final_event(pretty_printer &, const evdesc::final_event &)
Definition pending-diagnostic.h:419
virtual bool describe_return_of_state(pretty_printer &, const evdesc::return_of_state &)
Definition pending-diagnostic.h:378
virtual diagnostics::paths::event::meaning get_meaning_for_state_change(const evdesc::state_change &) const
Definition pending-diagnostic.h:334
virtual bool describe_use_of_state(pretty_printer &, const evdesc::use_of_state &)
Definition pending-diagnostic.h:404
virtual ~pending_diagnostic()
Definition pending-diagnostic.h:260
virtual void maybe_add_sarif_properties(diagnostics::sarif_object &) const
Definition pending-diagnostic.h:515
virtual bool use_of_uninit_p() const
Definition pending-diagnostic.h:280
virtual const program_state * get_final_state() const
Definition pending-diagnostic.h:478
virtual bool describe_call_with_state(pretty_printer &, const evdesc::call_with_state &)
Definition pending-diagnostic.h:362
virtual bool subclass_equal_p(const pending_diagnostic &other) const =0
virtual bool maybe_add_custom_events_for_eedge(const exploded_edge &, checker_path *)
Definition pending-diagnostic.h:445
virtual void mark_interesting_stuff(interesting_t *)
Definition pending-diagnostic.h:496
virtual bool describe_state_change(pretty_printer &, const evdesc::state_change &)
Definition pending-diagnostic.h:324
virtual void add_call_event(const exploded_edge &, const gcall &call_stmt, checker_path &emission_path, const state_transition_at_call *state_trans)
virtual void add_region_creation_events(const region *reg, tree capacity, const event_loc_info &loc_info, checker_path &emission_path)
virtual bool describe_copy_of_state(pretty_printer &, const evdesc::copy_of_state &)
Definition pending-diagnostic.h:391
virtual const char * get_kind() const =0
virtual bool check_valid_fpath_p(const feasible_node &) const
Definition pending-diagnostic.h:504
virtual bool terminate_path_p() const
Definition pending-diagnostic.h:270
virtual bool supercedes_p(const pending_diagnostic &other) const
Definition pending-diagnostic.h:488
bool equal_p(const pending_diagnostic &other) const
Definition pending-diagnostic.h:285
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 int get_controlling_option() const =0
static bool same_tree_p(tree t1, tree t2)
virtual bool emit(diagnostic_emission_context &)=0
virtual void add_function_entry_event(const exploded_edge &eedge, checker_path *emission_path, const state_transition_at_call *state_trans)
virtual location_t fixup_location(location_t loc, bool primary) const
Definition pending-diagnostic.h:575
bool subclass_equal_p(const pending_note &base_other) const final override
Definition pending-diagnostic.h:577
Definition pending-diagnostic.h:546
virtual ~pending_note()
Definition pending-diagnostic.h:548
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:556
Definition program-state.h:224
Definition region.h:127
Definition diagnostic-manager.h:79
Definition checker-event.h:417
Definition sm.h:43
const state_machine::state * state_t
Definition sm.h:63
Definition state-transition.h:99
Definition state-transition.h:126
diagnostics::paths::event_id_t get_src_event_id() const
Definition checker-event.h:931
Definition vec.h:1667
Definition metadata.h:48
Definition metadata.h:41
Definition sarif-sink.h:151
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:58
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:101
diagnostics::paths::event_id_t m_src_event_id
Definition pending-diagnostic.h:120
tree m_caller_fndecl
Definition pending-diagnostic.h:115
const state_transition_at_call * m_state_trans
Definition pending-diagnostic.h:119
tree m_callee_fndecl
Definition pending-diagnostic.h:116
call_with_state(tree caller_fndecl, tree callee_fndecl, tree expr, state_machine::state_t state, const state_transition_at_call *state_trans)
Definition pending-diagnostic.h:102
state_machine::state_t m_state
Definition pending-diagnostic.h:118
tree m_expr
Definition pending-diagnostic.h:117
Definition pending-diagnostic.h:149
copy_of_state(tree src_reg_expr, diagnostics::paths::event_id_t src_event_id, tree dst_reg_expr)
Definition pending-diagnostic.h:150
diagnostics::paths::event_id_t m_src_event_id
Definition pending-diagnostic.h:162
tree m_src_reg_expr
Definition pending-diagnostic.h:161
tree m_dst_reg_expr
Definition pending-diagnostic.h:163
Definition pending-diagnostic.h:185
state_machine::state_t m_state
Definition pending-diagnostic.h:192
final_event(tree expr, state_machine::state_t state, const warning_event &event)
Definition pending-diagnostic.h:186
const warning_event & m_event
Definition pending-diagnostic.h:193
tree m_expr
Definition pending-diagnostic.h:191
Definition pending-diagnostic.h:88
origin_of_state(tree dst_reg_expr)
Definition pending-diagnostic.h:89
tree m_dst_reg_expr
Definition pending-diagnostic.h:95
Definition pending-diagnostic.h:126
const state_transition_at_return * m_state_trans
Definition pending-diagnostic.h:142
diagnostics::paths::event_id_t m_src_event_id
Definition pending-diagnostic.h:143
tree m_callee_fndecl
Definition pending-diagnostic.h:140
state_machine::state_t m_state
Definition pending-diagnostic.h:141
tree m_caller_fndecl
Definition pending-diagnostic.h:139
return_of_state(tree caller_fndecl, tree callee_fndecl, state_machine::state_t state, const state_transition_at_return *state_trans)
Definition pending-diagnostic.h:127
Definition pending-diagnostic.h:63
diagnostics::paths::event_id_t m_event_id
Definition pending-diagnostic.h:81
tree m_expr
Definition pending-diagnostic.h:77
state_machine::state_t m_old_state
Definition pending-diagnostic.h:79
const state_change_event & m_event
Definition pending-diagnostic.h:82
bool is_global_p() const
Definition pending-diagnostic.h:75
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:64
state_machine::state_t m_new_state
Definition pending-diagnostic.h:80
tree m_origin
Definition pending-diagnostic.h:78
Definition pending-diagnostic.h:169
diagnostics::paths::event_id_t m_src_event_id
Definition pending-diagnostic.h:179
tree m_src_reg_expr
Definition pending-diagnostic.h:178
use_of_state(tree src_reg_expr, diagnostics::paths::event_id_t src_event_id)
Definition pending-diagnostic.h:170
Definition event-loc-info.h:29
Definition pending-diagnostic.h:42
std::vector< diagnostic_state > m_read_regions
Definition pending-diagnostic.h:50
void dump_to_pp(pretty_printer *pp, bool simple) const
void add_region_creation(const region *reg)
void add_read_region(const region *reg, std::string debug_desc)
auto_vec< const region * > m_region_creation
Definition pending-diagnostic.h:49
Definition gimple.h:355
Definition genautomata.cc:669
#define gcc_assert(EXPR)
Definition system.h:817
#define NULL_TREE
Definition tree.h:318