Branch data Line data Source code
1 : : /* Paths through the code associated with a diagnostic.
2 : : Copyright (C) 2019-2024 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 : : |
45 : : | 25 | list = PyList_New(0);
46 : : | | ^~~~~~~~~~~~~
47 : : | | |
48 : : | | (1) when 'PyList_New' fails, returning NULL
49 : : | 26 |
50 : : | 27 | for (i = 0; i < count; i++) {
51 : : | | ~~~
52 : : | | |
53 : : | | (2) when 'i < count'
54 : : | 28 | item = PyLong_FromLong(random());
55 : : | 29 | PyList_Append(list, item);
56 : : | | ~~~~~~~~~~~~~~~~~~~~~~~~~
57 : : | | |
58 : : | | (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
59 : : |
60 : :
61 : : The diagnostic-printing code has consolidated the path into a single
62 : : run of events, since all the events are near each other and within the same
63 : : function; more complicated examples (such as interprocedural paths)
64 : : might be printed as multiple runs of events. */
65 : :
66 : : /* Abstract base classes, describing events within a path, and the paths
67 : : themselves. */
68 : :
69 : : /* One event within a diagnostic_path. */
70 : :
71 : 66274 : class diagnostic_event
72 : : {
73 : : public:
74 : : /* Enums for giving a sense of what this event means.
75 : : Roughly corresponds to SARIF v2.1.0 section 3.38.8. */
76 : : enum verb
77 : : {
78 : : VERB_unknown,
79 : :
80 : : VERB_acquire,
81 : : VERB_release,
82 : : VERB_enter,
83 : : VERB_exit,
84 : : VERB_call,
85 : : VERB_return,
86 : : VERB_branch,
87 : :
88 : : VERB_danger
89 : : };
90 : : enum noun
91 : : {
92 : : NOUN_unknown,
93 : :
94 : : NOUN_taint,
95 : : NOUN_sensitive, // this one isn't in SARIF v2.1.0; filed as https://github.com/oasis-tcs/sarif-spec/issues/530
96 : : NOUN_function,
97 : : NOUN_lock,
98 : : NOUN_memory,
99 : : NOUN_resource
100 : : };
101 : : enum property
102 : : {
103 : : PROPERTY_unknown,
104 : :
105 : : PROPERTY_true,
106 : : PROPERTY_false
107 : : };
108 : : /* A bundle of such enums, allowing for descriptions of the meaning of
109 : : an event, such as
110 : : - "acquire memory": meaning (VERB_acquire, NOUN_memory)
111 : : - "take true branch"": meaning (VERB_branch, PROPERTY_true)
112 : : - "return from function": meaning (VERB_return, NOUN_function)
113 : : etc, as per SARIF's threadFlowLocation "kinds" property
114 : : (SARIF v2.1.0 section 3.38.8). */
115 : : struct meaning
116 : : {
117 : 49 : meaning ()
118 : : : m_verb (VERB_unknown),
119 : : m_noun (NOUN_unknown),
120 : : m_property (PROPERTY_unknown)
121 : : {
122 : : }
123 : 165 : meaning (enum verb verb, enum noun noun)
124 : : : m_verb (verb), m_noun (noun), m_property (PROPERTY_unknown)
125 : : {
126 : : }
127 : 10 : meaning (enum verb verb, enum property property)
128 : : : m_verb (verb), m_noun (NOUN_unknown), m_property (property)
129 : : {
130 : : }
131 : :
132 : : void dump_to_pp (pretty_printer *pp) const;
133 : :
134 : : static const char *maybe_get_verb_str (enum verb);
135 : : static const char *maybe_get_noun_str (enum noun);
136 : : static const char *maybe_get_property_str (enum property);
137 : :
138 : : enum verb m_verb;
139 : : enum noun m_noun;
140 : : enum property m_property;
141 : : };
142 : :
143 : 542 : virtual ~diagnostic_event () {}
144 : :
145 : : virtual location_t get_location () const = 0;
146 : :
147 : : virtual tree get_fndecl () const = 0;
148 : :
149 : : /* Stack depth, so that consumers can visualizes the interprocedural
150 : : calls, returns, and frame nesting. */
151 : : virtual int get_stack_depth () const = 0;
152 : :
153 : : /* Get a localized (and possibly colorized) description of this event. */
154 : : virtual label_text get_desc (bool can_colorize) const = 0;
155 : :
156 : : /* Get a logical_location for this event, or NULL. */
157 : : virtual const logical_location *get_logical_location () const = 0;
158 : :
159 : : virtual meaning get_meaning () 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 : :
171 : : /* Abstract base class representing a thread of execution within
172 : : a diagnostic_path.
173 : : Each diagnostic_event is associated with one thread.
174 : : Typically there is just one thread per diagnostic_path. */
175 : :
176 : 4551 : class diagnostic_thread
177 : : {
178 : : public:
179 : : virtual ~diagnostic_thread () {}
180 : : virtual label_text get_name (bool can_colorize) const = 0;
181 : : };
182 : :
183 : : /* Abstract base class for getting at a sequence of events. */
184 : :
185 : 4545 : class diagnostic_path
186 : : {
187 : : public:
188 : : virtual ~diagnostic_path () {}
189 : : virtual unsigned num_events () const = 0;
190 : : virtual const diagnostic_event & get_event (int idx) const = 0;
191 : : virtual unsigned num_threads () const = 0;
192 : : virtual const diagnostic_thread &
193 : : get_thread (diagnostic_thread_id_t) const = 0;
194 : :
195 : : bool interprocedural_p () const;
196 : : bool multithreaded_p () const;
197 : :
198 : : private:
199 : : bool get_first_event_in_a_function (unsigned *out_idx) const;
200 : : };
201 : :
202 : : /* Concrete subclasses. */
203 : :
204 : : /* A simple implementation of diagnostic_event. */
205 : :
206 : : class simple_diagnostic_event : public diagnostic_event
207 : : {
208 : : public:
209 : : simple_diagnostic_event (location_t loc, tree fndecl, int depth,
210 : : const char *desc,
211 : : diagnostic_thread_id_t thread_id = 0);
212 : : ~simple_diagnostic_event ();
213 : :
214 : 375 : location_t get_location () const final override { return m_loc; }
215 : 546 : tree get_fndecl () const final override { return m_fndecl; }
216 : 587 : int get_stack_depth () const final override { return m_depth; }
217 : 261 : label_text get_desc (bool) const final override
218 : : {
219 : 261 : return label_text::borrow (m_desc);
220 : : }
221 : 9 : const logical_location *get_logical_location () const final override
222 : : {
223 : 9 : return NULL;
224 : : }
225 : 9 : meaning get_meaning () const final override
226 : : {
227 : 9 : return meaning ();
228 : : }
229 : 706 : diagnostic_thread_id_t get_thread_id () const final override
230 : : {
231 : 706 : return m_thread_id;
232 : : }
233 : :
234 : : private:
235 : : location_t m_loc;
236 : : tree m_fndecl;
237 : : int m_depth;
238 : : char *m_desc; // has been i18n-ed and formatted
239 : : diagnostic_thread_id_t m_thread_id;
240 : : };
241 : :
242 : : /* A simple implementation of diagnostic_thread. */
243 : :
244 : : class simple_diagnostic_thread : public diagnostic_thread
245 : : {
246 : : public:
247 : 4551 : simple_diagnostic_thread (const char *name) : m_name (name) {}
248 : 289 : label_text get_name (bool) const final override
249 : : {
250 : 289 : return label_text::borrow (m_name);
251 : : }
252 : :
253 : : private:
254 : : const char *m_name; // has been i18n-ed and formatted
255 : : };
256 : :
257 : : /* A simple implementation of diagnostic_path, as a vector of
258 : : simple_diagnostic_event instances. */
259 : :
260 : : class simple_diagnostic_path : public diagnostic_path
261 : : {
262 : : public:
263 : : simple_diagnostic_path (pretty_printer *event_pp);
264 : :
265 : : unsigned num_events () const final override;
266 : : const diagnostic_event & get_event (int idx) const final override;
267 : : unsigned num_threads () const final override;
268 : : const diagnostic_thread &
269 : : get_thread (diagnostic_thread_id_t) const final override;
270 : :
271 : : diagnostic_thread_id_t add_thread (const char *name);
272 : :
273 : : diagnostic_event_id_t add_event (location_t loc, tree fndecl, int depth,
274 : : const char *fmt, ...)
275 : : ATTRIBUTE_GCC_DIAG(5,6);
276 : : diagnostic_event_id_t
277 : : add_thread_event (diagnostic_thread_id_t thread_id,
278 : : location_t loc, tree fndecl, int depth,
279 : : const char *fmt, ...)
280 : : ATTRIBUTE_GCC_DIAG(6,7);
281 : :
282 : : private:
283 : : auto_delete_vec<simple_diagnostic_thread> m_threads;
284 : : auto_delete_vec<simple_diagnostic_event> m_events;
285 : :
286 : : /* (for use by add_event). */
287 : : pretty_printer *m_event_pp;
288 : : };
289 : :
290 : : extern void debug (diagnostic_path *path);
291 : :
292 : : #endif /* ! GCC_DIAGNOSTIC_PATH_H */
|