Branch data Line data Source code
1 : : /* Classes for saving, deduplicating, and emitting analyzer diagnostics.
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
8 : : under the terms of the GNU General Public License as published by
9 : : the Free Software Foundation; either version 3, or (at your option)
10 : : any later version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License 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_ANALYZER_DIAGNOSTIC_MANAGER_H
22 : : #define GCC_ANALYZER_DIAGNOSTIC_MANAGER_H
23 : :
24 : : namespace ana {
25 : :
26 : : class epath_finder;
27 : :
28 : : /* A to-be-emitted diagnostic stored within diagnostic_manager. */
29 : :
30 : : class saved_diagnostic
31 : : {
32 : : public:
33 : : saved_diagnostic (const state_machine *sm,
34 : : const pending_location &ploc,
35 : : tree var, const svalue *sval,
36 : : state_machine::state_t state,
37 : : std::unique_ptr<pending_diagnostic> d,
38 : : unsigned idx);
39 : :
40 : : bool operator== (const saved_diagnostic &other) const;
41 : :
42 : : void add_note (std::unique_ptr<pending_note> pn);
43 : : void add_event (std::unique_ptr<checker_event> event);
44 : :
45 : : std::unique_ptr<json::object> to_json () const;
46 : :
47 : : void dump_dot_id (pretty_printer *pp) const;
48 : : void dump_as_dot_node (pretty_printer *pp) const;
49 : :
50 : 3988 : const feasibility_problem *get_feasibility_problem () const
51 : : {
52 : 3988 : return m_problem.get ();
53 : : }
54 : :
55 : : bool calc_best_epath (epath_finder *pf);
56 : 3988 : const exploded_path *get_best_epath () const { return m_best_epath.get (); }
57 : : unsigned get_epath_length () const;
58 : :
59 : : void add_duplicate (saved_diagnostic *other);
60 : 11305 : unsigned get_num_dupes () const { return m_duplicates.length (); }
61 : :
62 : 4012 : unsigned get_index () const { return m_idx; }
63 : :
64 : : bool supercedes_p (const saved_diagnostic &other) const;
65 : :
66 : : void add_any_saved_events (checker_path &dst_path);
67 : :
68 : : void emit_any_notes () const;
69 : :
70 : : void
71 : : maybe_add_sarif_properties (diagnostics::sarif_object &result_obj) const;
72 : :
73 : : //private:
74 : : const state_machine *m_sm;
75 : : const exploded_node *m_enode;
76 : : const supernode *m_snode;
77 : : const gimple *m_stmt;
78 : : std::unique_ptr<stmt_finder> m_stmt_finder;
79 : : location_t m_loc;
80 : : tree m_var;
81 : : const svalue *m_sval;
82 : : state_machine::state_t m_state;
83 : : std::unique_ptr<pending_diagnostic> m_d;
84 : : const exploded_edge *m_trailing_eedge;
85 : :
86 : : private:
87 : : DISABLE_COPY_AND_ASSIGN (saved_diagnostic);
88 : :
89 : : unsigned m_idx;
90 : : std::unique_ptr<exploded_path> m_best_epath;
91 : : std::unique_ptr<feasibility_problem> m_problem;
92 : :
93 : : auto_vec<const saved_diagnostic *> m_duplicates;
94 : : auto_delete_vec <pending_note> m_notes;
95 : :
96 : : /* Optionally: additional context-dependent events to be emitted
97 : : immediately before the warning_event, giving more details of what
98 : : operation was being simulated when a diagnostic was saved
99 : : e.g. "looking for null terminator in param 2 of 'foo'". */
100 : : auto_delete_vec <checker_event> m_saved_events;
101 : : };
102 : :
103 : : class path_builder;
104 : :
105 : : /* A bundle of information capturing where a pending_diagnostic should
106 : : be emitted. */
107 : :
108 : : struct pending_location
109 : : {
110 : : public:
111 : 10731 : pending_location (exploded_node *enode,
112 : : const supernode *snode,
113 : : const gimple *stmt,
114 : : const stmt_finder *finder)
115 : 10731 : : m_enode (enode),
116 : 10731 : m_snode (snode),
117 : 10731 : m_stmt (stmt),
118 : 10731 : m_finder (finder),
119 : 10731 : m_loc (UNKNOWN_LOCATION)
120 : : {
121 : 10731 : gcc_assert (m_stmt || m_finder);
122 : 8896 : }
123 : :
124 : : /* ctor for cases where we have a location_t but there isn't any
125 : : gimple stmt associated with the diagnostic. */
126 : :
127 : 88 : pending_location (exploded_node *enode,
128 : : const supernode *snode,
129 : : location_t loc)
130 : 88 : : m_enode (enode),
131 : 88 : m_snode (snode),
132 : 88 : m_stmt (nullptr),
133 : 88 : m_finder (nullptr),
134 : 88 : m_loc (loc)
135 : : {
136 : : }
137 : :
138 : : exploded_node *m_enode;
139 : : const supernode *m_snode;
140 : : const gimple *m_stmt;
141 : : const stmt_finder *m_finder;
142 : : location_t m_loc;
143 : : };
144 : :
145 : : /* A class with responsibility for saving pending diagnostics, so that
146 : : they can be emitted after the exploded_graph is complete.
147 : : This lets us de-duplicate diagnostics, and find the shortest path
148 : : for each similar diagnostic, potentially using edges that might
149 : : not have been found when each diagnostic was first saved.
150 : :
151 : : This also lets us compute shortest_paths once, rather than
152 : : per-diagnostic. */
153 : :
154 : 3310 : class diagnostic_manager : public log_user
155 : : {
156 : : public:
157 : : diagnostic_manager (logger *logger, engine *eng, int verbosity);
158 : :
159 : : engine *get_engine () const { return m_eng; }
160 : :
161 : : std::unique_ptr<json::object> to_json () const;
162 : :
163 : : bool add_diagnostic (const state_machine *sm,
164 : : const pending_location &ploc,
165 : : tree var,
166 : : const svalue *sval,
167 : : state_machine::state_t state,
168 : : std::unique_ptr<pending_diagnostic> d);
169 : :
170 : : bool add_diagnostic (const pending_location &ploc,
171 : : std::unique_ptr<pending_diagnostic> d);
172 : :
173 : : void add_note (std::unique_ptr<pending_note> pn);
174 : : void add_event (std::unique_ptr<checker_event> event);
175 : :
176 : : void emit_saved_diagnostics (const exploded_graph &eg);
177 : :
178 : : void emit_saved_diagnostic (const exploded_graph &eg,
179 : : saved_diagnostic &sd);
180 : :
181 : 40 : unsigned get_num_diagnostics () const
182 : : {
183 : 44 : return m_saved_diagnostics.length ();
184 : : }
185 : 8 : saved_diagnostic *get_saved_diagnostic (unsigned idx)
186 : : {
187 : 8 : return m_saved_diagnostics[idx];
188 : : }
189 : : const saved_diagnostic *get_saved_diagnostic (unsigned idx) const
190 : : {
191 : : return m_saved_diagnostics[idx];
192 : : }
193 : :
194 : : private:
195 : : const diagnostics::logical_locations::manager &
196 : : get_logical_location_manager () const;
197 : :
198 : : void build_emission_path (const path_builder &pb,
199 : : const exploded_path &epath,
200 : : checker_path *emission_path) const;
201 : :
202 : : void add_event_on_final_node (const path_builder &pb,
203 : : const exploded_node *final_enode,
204 : : checker_path *emission_path,
205 : : interesting_t *interest) const;
206 : :
207 : : void add_events_for_eedge (const path_builder &pb,
208 : : const exploded_edge &eedge,
209 : : checker_path *emission_path,
210 : : interesting_t *interest) const;
211 : :
212 : : bool significant_edge_p (const path_builder &pb,
213 : : const exploded_edge &eedge) const;
214 : :
215 : : void add_events_for_superedge (const path_builder &pb,
216 : : const exploded_edge &eedge,
217 : : checker_path *emission_path) const;
218 : :
219 : : void prune_path (checker_path *path,
220 : : const state_machine *sm,
221 : : const svalue *sval,
222 : : state_machine::state_t state) const;
223 : :
224 : : void prune_for_sm_diagnostic (checker_path *path,
225 : : const state_machine *sm,
226 : : tree var,
227 : : state_machine::state_t state) const;
228 : : void prune_for_sm_diagnostic (checker_path *path,
229 : : const state_machine *sm,
230 : : const svalue *sval,
231 : : state_machine::state_t state) const;
232 : : void update_for_unsuitable_sm_exprs (tree *expr) const;
233 : : void prune_interproc_events (checker_path *path) const;
234 : : void prune_system_headers (checker_path *path) const;
235 : : void consolidate_conditions (checker_path *path) const;
236 : : void consolidate_unwind_events (checker_path *path) const;
237 : : void finish_pruning (checker_path *path) const;
238 : :
239 : : engine *m_eng;
240 : : auto_delete_vec<saved_diagnostic> m_saved_diagnostics;
241 : : const int m_verbosity;
242 : : int m_num_disabled_diagnostics;
243 : : };
244 : :
245 : : } // namespace ana
246 : :
247 : : #endif /* GCC_ANALYZER_DIAGNOSTIC_MANAGER_H */
|