Line data Source code
1 : /* Paths through the code associated with a diagnostic.
2 : Copyright (C) 2019-2026 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_DIAGNOSTICS_PATHS_H
22 : #define GCC_DIAGNOSTICS_PATHS_H
23 :
24 : #include "diagnostic.h" /* for ATTRIBUTE_GCC_DIAG. */
25 : #include "diagnostics/event-id.h"
26 : #include "diagnostics/logical-locations.h"
27 :
28 : namespace diagnostics {
29 : namespace digraphs {
30 : class digraph;
31 : } // namespace digraphs
32 : namespace logical_locations {
33 : class manager;
34 : } // logical_locations
35 : class sarif_builder;
36 : class sarif_object;
37 : } //namespace diagnostics
38 :
39 : namespace diagnostics {
40 : namespace paths {
41 :
42 : /* A diagnostics::paths::path is an optional additional piece of metadata associated
43 : with a diagnostic (via its rich_location).
44 :
45 : It describes a sequence of events predicted by the compiler that
46 : lead to the problem occurring, with their locations in the user's source,
47 : and text descriptions.
48 :
49 : For example, the following error has a 3-event path:
50 :
51 : test.c: In function 'demo':
52 : test.c:29:5: error: passing NULL as argument 1 to 'PyList_Append' which
53 : requires a non-NULL parameter
54 : 29 | PyList_Append(list, item);
55 : | ^~~~~~~~~~~~~~~~~~~~~~~~~
56 : 'demo': events 1-3
57 : 25 | list = PyList_New(0);
58 : | ^~~~~~~~~~~~~
59 : | |
60 : | (1) when 'PyList_New' fails, returning NULL
61 : 26 |
62 : 27 | for (i = 0; i < count; i++) {
63 : | ~~~
64 : | |
65 : | (2) when 'i < count'
66 : 28 | item = PyLong_FromLong(random());
67 : 29 | PyList_Append(list, item);
68 : | ~~~~~~~~~~~~~~~~~~~~~~~~~
69 : | |
70 : | (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
71 :
72 : The diagnostic-printing code has consolidated the path into a single
73 : run of events, since all the events are near each other and within the same
74 : function; more complicated examples (such as interprocedural paths)
75 : might be printed as multiple runs of events. */
76 :
77 : /* Abstract base classes, describing events within a path, and the paths
78 : themselves. */
79 :
80 : /* One event within a path. */
81 :
82 41408 : class event
83 : {
84 : public:
85 : /* Enums for giving a sense of what this event means.
86 : Roughly corresponds to SARIF v2.1.0 section 3.38.8. */
87 : enum class verb
88 : {
89 : unknown,
90 :
91 : acquire,
92 : release,
93 : enter,
94 : exit,
95 : call,
96 : return_,
97 : branch,
98 :
99 : danger,
100 :
101 : // Special control flow operations:
102 : throw_,
103 : catch_,
104 : unwind_, // unwinding stack frame(s) during exception-handling
105 : setjmp_,
106 : longjmp_
107 : };
108 : enum class noun
109 : {
110 : unknown,
111 :
112 : taint,
113 : sensitive, // this one isn't in SARIF v2.1.0; filed as https://github.com/oasis-tcs/sarif-spec/issues/530
114 : function,
115 : lock,
116 : memory,
117 : resource
118 : };
119 : enum class property
120 : {
121 : unknown,
122 :
123 : true_,
124 : false_
125 : };
126 : /* A bundle of such enums, allowing for descriptions of the meaning of
127 : an event, such as
128 : - "acquire memory": meaning (verb::acquire, noun::memory)
129 : - "take true branch"": meaning (verb::branch, property::true)
130 : - "return from function": meaning (verb::return, noun::function)
131 : etc, as per SARIF's threadFlowLocation "kinds" property
132 : (SARIF v2.1.0 section 3.38.8). */
133 : struct meaning
134 : {
135 3612 : meaning ()
136 : : m_verb (verb::unknown),
137 : m_noun (noun::unknown),
138 : m_property (property::unknown)
139 : {
140 : }
141 58 : meaning (enum verb verb)
142 : : m_verb (verb), m_noun (noun::unknown), m_property (property::unknown)
143 : {
144 : }
145 997 : meaning (enum verb verb, enum noun noun)
146 : : m_verb (verb), m_noun (noun), m_property (property::unknown)
147 : {
148 : }
149 252 : meaning (enum verb verb, enum property property)
150 : : m_verb (verb), m_noun (noun::unknown), m_property (property)
151 : {
152 : }
153 :
154 : void dump_to_pp (pretty_printer *pp) const;
155 :
156 : static const char *maybe_get_verb_str (enum verb);
157 : static const char *maybe_get_noun_str (enum noun);
158 : static const char *maybe_get_property_str (enum property);
159 :
160 : enum verb m_verb;
161 : enum noun m_noun;
162 : enum property m_property;
163 : };
164 :
165 4862 : virtual ~event () {}
166 :
167 : virtual location_t get_location () const = 0;
168 :
169 : /* Stack depth, so that consumers can visualize the interprocedural
170 : calls, returns, and frame nesting. */
171 : virtual int get_stack_depth () const = 0;
172 :
173 : /* Print a localized (and possibly colorized) description of this event. */
174 : virtual void print_desc (pretty_printer &pp) const = 0;
175 :
176 : /* Get a logical location for this event, or null if there is none. */
177 : virtual logical_locations::key get_logical_location () const = 0;
178 :
179 : virtual meaning get_meaning () const = 0;
180 :
181 : /* True iff we should draw a line connecting this event to the
182 : next event (e.g. to highlight control flow). */
183 : virtual bool connect_to_next_event_p () const = 0;
184 :
185 : virtual thread_id_t get_thread_id () const = 0;
186 :
187 : /* Hook for SARIF output to allow for adding diagnostic-specific
188 : properties to the threadFlowLocation object's property bag. */
189 : virtual void
190 9 : maybe_add_sarif_properties (sarif_builder &,
191 : sarif_object &/*thread_flow_loc_obj*/) const
192 : {
193 9 : }
194 :
195 : /* Hook for capturing state at this event, potentially for visualizing
196 : in HTML output, or for adding to SARIF. */
197 : virtual std::unique_ptr<digraphs::digraph>
198 : maybe_make_diagnostic_state_graph (bool debug) const;
199 :
200 : label_text get_desc (pretty_printer &ref_pp) const;
201 : };
202 :
203 : /* Abstract base class representing a thread of execution within
204 : a diagnostics::paths::path.
205 : Each event is associated with one thread.
206 : Typically there is just one thread per diagnostics::paths::path. */
207 :
208 11424 : class thread
209 : {
210 : public:
211 : virtual ~thread () {}
212 : virtual label_text get_name (bool can_colorize) const = 0;
213 : };
214 :
215 : /* Abstract base class for getting at a sequence of events. */
216 :
217 : class path
218 : {
219 : public:
220 : virtual ~path () {}
221 : virtual unsigned num_events () const = 0;
222 : virtual const event & get_event (int idx) const = 0;
223 : virtual unsigned num_threads () const = 0;
224 : virtual const thread &
225 : get_thread (thread_id_t) const = 0;
226 :
227 : /* Return true iff the two events are both within the same function,
228 : or both outside of any function. */
229 : virtual bool
230 : same_function_p (int event_idx_a,
231 : int event_idx_b) const = 0;
232 :
233 : bool interprocedural_p () const;
234 : bool multithreaded_p () const;
235 :
236 10953 : const logical_locations::manager &get_logical_location_manager () const
237 : {
238 10953 : return m_logical_loc_mgr;
239 : }
240 :
241 : protected:
242 901708 : path (const logical_locations::manager &logical_loc_mgr)
243 901708 : : m_logical_loc_mgr (logical_loc_mgr)
244 : {
245 : }
246 :
247 : private:
248 : bool get_first_event_in_a_function (unsigned *out_idx) const;
249 :
250 : const logical_locations::manager &m_logical_loc_mgr;
251 : };
252 :
253 : } // namespace paths
254 : } // namespace diagnostics
255 :
256 : /* Concrete subclasses of the above can be found in
257 : simple-diagnostic-path.h. */
258 :
259 : extern void debug (diagnostics::paths::path *path);
260 :
261 : #endif /* ! GCC_DIAGNOSTICS_PATHS_H */
|