Line data Source code
1 : /* Concrete implementation of sm_context.
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
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_IMPL_SM_CONTEXT
22 : #define GCC_ANALYZER_IMPL_SM_CONTEXT
23 :
24 : namespace ana {
25 :
26 : /* Concrete implementation of sm_context, wiring it up to the rest of this
27 : file. */
28 :
29 2438563 : class impl_sm_context : public sm_context
30 : {
31 : public:
32 2439311 : impl_sm_context (exploded_graph &eg,
33 : int sm_idx,
34 : const state_machine &sm,
35 : exploded_node *enode_for_diag,
36 : const program_state *old_state,
37 : program_state *new_state,
38 : const sm_state_map *old_smap,
39 : sm_state_map *new_smap,
40 : path_context *path_ctxt,
41 : bool unknown_side_effects = false)
42 2439311 : : sm_context (sm_idx, sm),
43 2439311 : m_logger (eg.get_logger ()),
44 2439311 : m_eg (eg), m_enode_for_diag (enode_for_diag),
45 2439311 : m_old_state (old_state), m_new_state (new_state),
46 2439311 : m_old_smap (old_smap), m_new_smap (new_smap),
47 2439311 : m_path_ctxt (path_ctxt),
48 2439311 : m_unknown_side_effects (unknown_side_effects)
49 : {
50 : }
51 :
52 262955 : logger *get_logger () const { return m_logger.get_logger (); }
53 :
54 346774 : tree get_fndecl_for_call (const gcall &call) final override
55 : {
56 346774 : impl_region_model_context old_ctxt
57 : (m_eg, m_enode_for_diag, nullptr, nullptr, nullptr/*m_enode->get_state ()*/,
58 346774 : nullptr, &call);
59 346774 : region_model *model = m_new_state->m_region_model;
60 346774 : return model->get_fndecl_for_call (call, &old_ctxt);
61 346774 : }
62 :
63 80340 : state_machine::state_t get_state (tree var) final override
64 : {
65 80340 : logger * const logger = get_logger ();
66 80340 : LOG_FUNC (logger);
67 : /* Use nullptr ctxt on this get_rvalue call to avoid triggering
68 : uninitialized value warnings. */
69 80340 : const svalue *var_old_sval
70 80340 : = m_old_state->m_region_model->get_rvalue (var, nullptr);
71 :
72 80340 : state_machine::state_t current
73 80340 : = m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ());
74 160680 : return current;
75 80340 : }
76 140742 : state_machine::state_t get_state (const svalue *sval) final override
77 : {
78 140742 : logger * const logger = get_logger ();
79 140742 : LOG_FUNC (logger);
80 140742 : state_machine::state_t current
81 140742 : = m_old_smap->get_state (sval, m_eg.get_ext_state ());
82 281484 : return current;
83 140742 : }
84 :
85 :
86 31940 : void set_next_state (tree var,
87 : state_machine::state_t to,
88 : tree origin) final override
89 : {
90 31940 : logger * const logger = get_logger ();
91 31940 : LOG_FUNC (logger);
92 31940 : const svalue *var_new_sval
93 31940 : = m_new_state->m_region_model->get_rvalue (var, nullptr);
94 31940 : const svalue *origin_new_sval
95 31940 : = m_new_state->m_region_model->get_rvalue (origin, nullptr);
96 :
97 : /* We use the new sval here to avoid issues with uninitialized values. */
98 31940 : state_machine::state_t current
99 31940 : = m_old_smap->get_state (var_new_sval, m_eg.get_ext_state ());
100 31940 : if (logger)
101 25 : logger->log ("%s: state transition of %qE: %s -> %s",
102 25 : m_sm.get_name (),
103 : var,
104 : current->get_name (),
105 : to->get_name ());
106 31940 : m_new_smap->set_state (m_new_state->m_region_model, var_new_sval,
107 31940 : to, origin_new_sval, m_eg.get_ext_state ());
108 31940 : }
109 :
110 4308 : void set_next_state (const svalue *sval,
111 : state_machine::state_t to,
112 : tree origin) final override
113 : {
114 4308 : logger * const logger = get_logger ();
115 4308 : LOG_FUNC (logger);
116 4308 : impl_region_model_context old_ctxt
117 : (m_eg, m_enode_for_diag, nullptr, nullptr, nullptr/*m_enode->get_state ()*/,
118 4308 : nullptr, nullptr);
119 :
120 4308 : const svalue *origin_new_sval
121 4308 : = m_new_state->m_region_model->get_rvalue (origin, nullptr);
122 :
123 4308 : state_machine::state_t current
124 4308 : = m_old_smap->get_state (sval, m_eg.get_ext_state ());
125 4308 : if (logger)
126 : {
127 0 : logger->start_log_line ();
128 0 : logger->log_partial ("%s: state transition of ",
129 0 : m_sm.get_name ());
130 0 : sval->dump_to_pp (logger->get_printer (), true);
131 0 : logger->log_partial (": %s -> %s",
132 : current->get_name (),
133 : to->get_name ());
134 0 : logger->end_log_line ();
135 : }
136 4308 : m_new_smap->set_state (m_new_state->m_region_model, sval,
137 4308 : to, origin_new_sval, m_eg.get_ext_state ());
138 4308 : }
139 :
140 5513 : void warn (tree var,
141 : std::unique_ptr<pending_diagnostic> d) final override
142 : {
143 5513 : LOG_FUNC (get_logger ());
144 5513 : gcc_assert (d);
145 5513 : const svalue *var_old_sval
146 5513 : = m_old_state->m_region_model->get_rvalue (var, nullptr);
147 5513 : state_machine::state_t current
148 : = (var
149 5513 : ? m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ())
150 67 : : m_old_smap->get_global_state ());
151 5513 : bool terminate_path = d->terminate_path_p ();
152 5513 : pending_location ploc (m_enode_for_diag);
153 5513 : m_eg.get_diagnostic_manager ().add_diagnostic
154 5513 : (&m_sm, std::move (ploc),
155 : var, var_old_sval, current, std::move (d));
156 5513 : if (m_path_ctxt
157 5222 : && terminate_path
158 180 : && flag_analyzer_suppress_followups)
159 138 : m_path_ctxt->terminate_path ();
160 5513 : }
161 :
162 112 : void warn (const svalue *sval,
163 : std::unique_ptr<pending_diagnostic> d) final override
164 : {
165 112 : LOG_FUNC (get_logger ());
166 112 : gcc_assert (d);
167 112 : state_machine::state_t current
168 : = (sval
169 112 : ? m_old_smap->get_state (sval, m_eg.get_ext_state ())
170 0 : : m_old_smap->get_global_state ());
171 112 : bool terminate_path = d->terminate_path_p ();
172 112 : pending_location ploc (m_enode_for_diag);
173 112 : m_eg.get_diagnostic_manager ().add_diagnostic
174 112 : (&m_sm, std::move (ploc),
175 : NULL_TREE, sval, current, std::move (d));
176 112 : if (m_path_ctxt
177 12 : && terminate_path
178 0 : && flag_analyzer_suppress_followups)
179 0 : m_path_ctxt->terminate_path ();
180 112 : }
181 :
182 : /* Hook for picking more readable trees for SSA names of temporaries,
183 : so that rather than e.g.
184 : "double-free of '<unknown>'"
185 : we can print:
186 : "double-free of 'inbuf.data'". */
187 :
188 5891 : tree get_diagnostic_tree (tree expr) final override
189 : {
190 : /* Only for SSA_NAMEs of temporaries; otherwise, return EXPR, as it's
191 : likely to be the least surprising tree to report. */
192 5891 : if (TREE_CODE (expr) != SSA_NAME)
193 : return expr;
194 5793 : if (SSA_NAME_VAR (expr) != NULL)
195 : return expr;
196 :
197 290 : gcc_assert (m_new_state);
198 290 : const svalue *sval = m_new_state->m_region_model->get_rvalue (expr, nullptr);
199 : /* Find trees for all regions storing the value. */
200 290 : if (tree t = m_new_state->m_region_model->get_representative_tree (sval))
201 : return t;
202 : else
203 : return expr;
204 : }
205 :
206 132 : tree get_diagnostic_tree (const svalue *sval) final override
207 : {
208 132 : return m_new_state->m_region_model->get_representative_tree (sval);
209 : }
210 :
211 251407 : state_machine::state_t get_global_state () const final override
212 : {
213 251407 : return m_old_state->m_checker_states[m_sm_idx]->get_global_state ();
214 : }
215 :
216 45356 : void set_global_state (state_machine::state_t state) final override
217 : {
218 45356 : m_new_state->m_checker_states[m_sm_idx]->set_global_state (state);
219 45356 : }
220 :
221 9681 : void clear_all_per_svalue_state () final override
222 : {
223 9681 : m_new_state->m_checker_states[m_sm_idx]->clear_all_per_svalue_state ();
224 9681 : }
225 :
226 10 : void on_custom_transition (custom_transition *transition) final override
227 : {
228 10 : transition->impl_transition (&m_eg,
229 : const_cast<exploded_node *> (m_enode_for_diag),
230 : m_sm_idx);
231 10 : }
232 :
233 232447 : tree is_zero_assignment (const gimple *stmt) final override
234 : {
235 232447 : const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
236 152822 : if (!assign_stmt)
237 : return NULL_TREE;
238 152822 : impl_region_model_context old_ctxt
239 152822 : (m_eg, m_enode_for_diag, m_old_state, m_new_state, nullptr, nullptr, stmt);
240 305644 : if (const svalue *sval
241 152822 : = m_new_state->m_region_model->get_gassign_result (assign_stmt,
242 : &old_ctxt))
243 147810 : if (tree cst = sval->maybe_get_constant ())
244 36353 : if (::zerop(cst))
245 14567 : return gimple_assign_lhs (assign_stmt);
246 : return NULL_TREE;
247 152822 : }
248 :
249 24 : path_context *get_path_context () const final override
250 : {
251 24 : return m_path_ctxt;
252 : }
253 :
254 45369 : bool unknown_side_effects_p () const final override
255 : {
256 45369 : return m_unknown_side_effects;
257 : }
258 :
259 271724 : const program_state *get_old_program_state () const final override
260 : {
261 271724 : return m_old_state;
262 : }
263 :
264 1634 : const program_state *get_new_program_state () const final override
265 : {
266 1634 : return m_new_state;
267 : }
268 :
269 147 : location_t get_emission_location () const final override
270 : {
271 147 : return pending_location (m_enode_for_diag).get_location ();
272 : }
273 :
274 : log_user m_logger;
275 : exploded_graph &m_eg;
276 : exploded_node *m_enode_for_diag;
277 : const program_state *m_old_state;
278 : program_state *m_new_state;
279 : const sm_state_map *m_old_smap;
280 : sm_state_map *m_new_smap;
281 : path_context *m_path_ctxt;
282 :
283 : /* Are we handling an external function with unknown side effects? */
284 : bool m_unknown_side_effects;
285 : };
286 :
287 : } // namespace ana
288 :
289 : #endif /* GCC_ANALYZER_IMPL_SM_CONTEXT */
|