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 : : #include "logical-location.h"
27 : :
28 : : class sarif_builder;
29 : : class sarif_object;
30 : :
31 : : /* A diagnostic_path is an optional additional piece of metadata associated
32 : : with a diagnostic (via its rich_location).
33 : :
34 : : It describes a sequence of events predicted by the compiler that
35 : : lead to the problem occurring, with their locations in the user's source,
36 : : and text descriptions.
37 : :
38 : : For example, the following error has a 3-event path:
39 : :
40 : : test.c: In function 'demo':
41 : : test.c:29:5: error: passing NULL as argument 1 to 'PyList_Append' which
42 : : requires a non-NULL parameter
43 : : 29 | PyList_Append(list, item);
44 : : | ^~~~~~~~~~~~~~~~~~~~~~~~~
45 : : 'demo': events 1-3
46 : : 25 | list = PyList_New(0);
47 : : | ^~~~~~~~~~~~~
48 : : | |
49 : : | (1) when 'PyList_New' fails, returning NULL
50 : : 26 |
51 : : 27 | for (i = 0; i < count; i++) {
52 : : | ~~~
53 : : | |
54 : : | (2) when 'i < count'
55 : : 28 | item = PyLong_FromLong(random());
56 : : 29 | PyList_Append(list, item);
57 : : | ~~~~~~~~~~~~~~~~~~~~~~~~~
58 : : | |
59 : : | (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
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 : 63402 : 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 : 3579 : meaning ()
118 : : : m_verb (VERB_unknown),
119 : : m_noun (NOUN_unknown),
120 : : m_property (PROPERTY_unknown)
121 : : {
122 : : }
123 : 936 : meaning (enum verb verb, enum noun noun)
124 : : : m_verb (verb), m_noun (noun), m_property (PROPERTY_unknown)
125 : : {
126 : : }
127 : 230 : 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 : 4993 : virtual ~diagnostic_event () {}
144 : :
145 : : virtual location_t get_location () const = 0;
146 : :
147 : : /* Stack depth, so that consumers can visualize the interprocedural
148 : : calls, returns, and frame nesting. */
149 : : virtual int get_stack_depth () const = 0;
150 : :
151 : : /* Print a localized (and possibly colorized) description of this event. */
152 : : virtual void print_desc (pretty_printer &pp) const = 0;
153 : :
154 : : /* Get a logical location for this event, or null if there is none. */
155 : : virtual logical_location get_logical_location () const = 0;
156 : :
157 : : virtual meaning get_meaning () const = 0;
158 : :
159 : : /* True iff we should draw a line connecting this event to the
160 : : next event (e.g. to highlight control flow). */
161 : : virtual bool connect_to_next_event_p () const = 0;
162 : :
163 : : virtual diagnostic_thread_id_t get_thread_id () const = 0;
164 : :
165 : : /* Hook for SARIF output to allow for adding diagnostic-specific
166 : : properties to the threadFlowLocation object's property bag. */
167 : : virtual void
168 : 9 : maybe_add_sarif_properties (sarif_builder &,
169 : : sarif_object &/*thread_flow_loc_obj*/) const
170 : : {
171 : 9 : }
172 : :
173 : : label_text get_desc (pretty_printer &ref_pp) const;
174 : : };
175 : :
176 : : /* Abstract base class representing a thread of execution within
177 : : a diagnostic_path.
178 : : Each diagnostic_event is associated with one thread.
179 : : Typically there is just one thread per diagnostic_path. */
180 : :
181 : 5629 : class diagnostic_thread
182 : : {
183 : : public:
184 : : virtual ~diagnostic_thread () {}
185 : : virtual label_text get_name (bool can_colorize) const = 0;
186 : : };
187 : :
188 : : /* Abstract base class for getting at a sequence of events. */
189 : :
190 : : class diagnostic_path
191 : : {
192 : : public:
193 : 4 : virtual ~diagnostic_path () {}
194 : : virtual unsigned num_events () const = 0;
195 : : virtual const diagnostic_event & get_event (int idx) const = 0;
196 : : virtual unsigned num_threads () const = 0;
197 : : virtual const diagnostic_thread &
198 : : get_thread (diagnostic_thread_id_t) const = 0;
199 : :
200 : : /* Return true iff the two events are both within the same function,
201 : : or both outside of any function. */
202 : : virtual bool
203 : : same_function_p (int event_idx_a,
204 : : int event_idx_b) const = 0;
205 : :
206 : : bool interprocedural_p () const;
207 : : bool multithreaded_p () const;
208 : :
209 : 5152 : const logical_location_manager &get_logical_location_manager () const
210 : : {
211 : 5152 : return m_logical_loc_mgr;
212 : : }
213 : :
214 : : protected:
215 : 5635 : diagnostic_path (const logical_location_manager &logical_loc_mgr)
216 : 5635 : : m_logical_loc_mgr (logical_loc_mgr)
217 : : {
218 : : }
219 : :
220 : : private:
221 : : bool get_first_event_in_a_function (unsigned *out_idx) const;
222 : :
223 : : const logical_location_manager &m_logical_loc_mgr;
224 : : };
225 : :
226 : : /* Concrete subclasses of the above can be found in
227 : : simple-diagnostic-path.h. */
228 : :
229 : : extern void debug (diagnostic_path *path);
230 : :
231 : : #endif /* ! GCC_DIAGNOSTIC_PATH_H */
|