Branch data Line data Source code
1 : : /* Paths through the code associated with a diagnostic.
2 : : Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it under
8 : : the terms of the GNU General Public License as published by the Free
9 : : Software Foundation; either version 3, or (at your option) any later
10 : : version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : : for more details.
16 : :
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/>. */
20 : :
21 : : #ifndef GCC_DIAGNOSTIC_PATH_H
22 : : #define GCC_DIAGNOSTIC_PATH_H
23 : :
24 : : #include "diagnostic.h" /* for ATTRIBUTE_GCC_DIAG. */
25 : : #include "diagnostic-event-id.h"
26 : :
27 : : class sarif_object;
28 : :
29 : : /* A diagnostic_path is an optional additional piece of metadata associated
30 : : with a diagnostic (via its rich_location).
31 : :
32 : : It describes a sequence of events predicted by the compiler that
33 : : lead to the problem occurring, with their locations in the user's source,
34 : : and text descriptions.
35 : :
36 : : For example, the following error has a 3-event path:
37 : :
38 : : test.c: In function 'demo':
39 : : test.c:29:5: error: passing NULL as argument 1 to 'PyList_Append' which
40 : : requires a non-NULL parameter
41 : : 29 | PyList_Append(list, item);
42 : : | ^~~~~~~~~~~~~~~~~~~~~~~~~
43 : : 'demo': events 1-3
44 : : 25 | list = PyList_New(0);
45 : : | ^~~~~~~~~~~~~
46 : : | |
47 : : | (1) when 'PyList_New' fails, returning NULL
48 : : 26 |
49 : : 27 | for (i = 0; i < count; i++) {
50 : : | ~~~
51 : : | |
52 : : | (2) when 'i < count'
53 : : 28 | item = PyLong_FromLong(random());
54 : : 29 | PyList_Append(list, item);
55 : : | ~~~~~~~~~~~~~~~~~~~~~~~~~
56 : : | |
57 : : | (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
58 : :
59 : : The diagnostic-printing code has consolidated the path into a single
60 : : run of events, since all the events are near each other and within the same
61 : : function; more complicated examples (such as interprocedural paths)
62 : : might be printed as multiple runs of events. */
63 : :
64 : : /* Abstract base classes, describing events within a path, and the paths
65 : : themselves. */
66 : :
67 : : /* One event within a diagnostic_path. */
68 : :
69 : 62019 : class diagnostic_event
70 : : {
71 : : public:
72 : : /* Enums for giving a sense of what this event means.
73 : : Roughly corresponds to SARIF v2.1.0 section 3.38.8. */
74 : : enum verb
75 : : {
76 : : VERB_unknown,
77 : :
78 : : VERB_acquire,
79 : : VERB_release,
80 : : VERB_enter,
81 : : VERB_exit,
82 : : VERB_call,
83 : : VERB_return,
84 : : VERB_branch,
85 : :
86 : : VERB_danger
87 : : };
88 : : enum noun
89 : : {
90 : : NOUN_unknown,
91 : :
92 : : NOUN_taint,
93 : : NOUN_sensitive, // this one isn't in SARIF v2.1.0; filed as https://github.com/oasis-tcs/sarif-spec/issues/530
94 : : NOUN_function,
95 : : NOUN_lock,
96 : : NOUN_memory,
97 : : NOUN_resource
98 : : };
99 : : enum property
100 : : {
101 : : PROPERTY_unknown,
102 : :
103 : : PROPERTY_true,
104 : : PROPERTY_false
105 : : };
106 : : /* A bundle of such enums, allowing for descriptions of the meaning of
107 : : an event, such as
108 : : - "acquire memory": meaning (VERB_acquire, NOUN_memory)
109 : : - "take true branch"": meaning (VERB_branch, PROPERTY_true)
110 : : - "return from function": meaning (VERB_return, NOUN_function)
111 : : etc, as per SARIF's threadFlowLocation "kinds" property
112 : : (SARIF v2.1.0 section 3.38.8). */
113 : : struct meaning
114 : : {
115 : 3568 : meaning ()
116 : : : m_verb (VERB_unknown),
117 : : m_noun (NOUN_unknown),
118 : : m_property (PROPERTY_unknown)
119 : : {
120 : : }
121 : 936 : meaning (enum verb verb, enum noun noun)
122 : : : m_verb (verb), m_noun (noun), m_property (PROPERTY_unknown)
123 : : {
124 : : }
125 : 230 : meaning (enum verb verb, enum property property)
126 : : : m_verb (verb), m_noun (NOUN_unknown), m_property (property)
127 : : {
128 : : }
129 : :
130 : : void dump_to_pp (pretty_printer *pp) const;
131 : :
132 : : static const char *maybe_get_verb_str (enum verb);
133 : : static const char *maybe_get_noun_str (enum noun);
134 : : static const char *maybe_get_property_str (enum property);
135 : :
136 : : enum verb m_verb;
137 : : enum noun m_noun;
138 : : enum property m_property;
139 : : };
140 : :
141 : 4993 : virtual ~diagnostic_event () {}
142 : :
143 : : virtual location_t get_location () const = 0;
144 : :
145 : : /* Stack depth, so that consumers can visualize the interprocedural
146 : : calls, returns, and frame nesting. */
147 : : virtual int get_stack_depth () const = 0;
148 : :
149 : : /* Print a localized (and possibly colorized) description of this event. */
150 : : virtual void print_desc (pretty_printer &pp) const = 0;
151 : :
152 : : /* Get a logical_location for this event, or nullptr if there is none. */
153 : : virtual const logical_location *get_logical_location () const = 0;
154 : :
155 : : virtual meaning get_meaning () const = 0;
156 : :
157 : : /* True iff we should draw a line connecting this event to the
158 : : next event (e.g. to highlight control flow). */
159 : : virtual bool connect_to_next_event_p () const = 0;
160 : :
161 : : virtual diagnostic_thread_id_t get_thread_id () const = 0;
162 : :
163 : : /* Hook for SARIF output to allow for adding diagnostic-specific
164 : : properties to the threadFlowLocation object's property bag. */
165 : : virtual void
166 : 9 : maybe_add_sarif_properties (sarif_object &/*thread_flow_loc_obj*/) const
167 : : {
168 : 9 : }
169 : :
170 : : label_text get_desc (pretty_printer &ref_pp) const;
171 : : };
172 : :
173 : : /* Abstract base class representing a thread of execution within
174 : : a diagnostic_path.
175 : : Each diagnostic_event is associated with one thread.
176 : : Typically there is just one thread per diagnostic_path. */
177 : :
178 : 5543 : class diagnostic_thread
179 : : {
180 : : public:
181 : : virtual ~diagnostic_thread () {}
182 : : virtual label_text get_name (bool can_colorize) const = 0;
183 : : };
184 : :
185 : : /* Abstract base class for getting at a sequence of events. */
186 : :
187 : 5549 : class diagnostic_path
188 : : {
189 : : public:
190 : 4 : virtual ~diagnostic_path () {}
191 : : virtual unsigned num_events () const = 0;
192 : : virtual const diagnostic_event & get_event (int idx) const = 0;
193 : : virtual unsigned num_threads () const = 0;
194 : : virtual const diagnostic_thread &
195 : : get_thread (diagnostic_thread_id_t) const = 0;
196 : :
197 : : /* Return true iff the two events are both within the same function,
198 : : or both outside of any function. */
199 : : virtual bool
200 : : same_function_p (int event_idx_a,
201 : : int event_idx_b) const = 0;
202 : :
203 : : bool interprocedural_p () const;
204 : : bool multithreaded_p () const;
205 : :
206 : : private:
207 : : bool get_first_event_in_a_function (unsigned *out_idx) const;
208 : : };
209 : :
210 : : /* Concrete subclasses of the above can be found in
211 : : simple-diagnostic-path.h. */
212 : :
213 : : extern void debug (diagnostic_path *path);
214 : :
215 : : #endif /* ! GCC_DIAGNOSTIC_PATH_H */
|