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

source code of gcc/analyzer/diagnostic-manager.h