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