GCC Middle and Back End API Reference
impl-sm-context.h
Go to the documentation of this file.
1/* Concrete implementation of sm_context.
2 Copyright (C) 2019-2025 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_IMPL_SM_CONTEXT
22#define GCC_ANALYZER_IMPL_SM_CONTEXT
23
24namespace ana {
25
26/* Concrete implementation of sm_context, wiring it up to the rest of this
27 file. */
28
30{
31public:
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 : sm_context (sm_idx, sm),
43 m_logger (eg.get_logger ()),
44 m_eg (eg), m_enode_for_diag (enode_for_diag),
45 m_old_state (old_state), m_new_state (new_state),
46 m_old_smap (old_smap), m_new_smap (new_smap),
47 m_path_ctxt (path_ctxt),
48 m_unknown_side_effects (unknown_side_effects)
49 {
50 }
51
52 logger *get_logger () const { return m_logger.get_logger (); }
53
54 tree get_fndecl_for_call (const gcall &call) final override
55 {
57 (m_eg, m_enode_for_diag, nullptr, nullptr, nullptr/*m_enode->get_state ()*/,
58 nullptr, &call);
59 region_model *model = m_new_state->m_region_model;
60 return model->get_fndecl_for_call (call, &old_ctxt);
61 }
62
64 {
65 logger * const logger = get_logger ();
67 /* Use nullptr ctxt on this get_rvalue call to avoid triggering
68 uninitialized value warnings. */
69 const svalue *var_old_sval
70 = m_old_state->m_region_model->get_rvalue (var, nullptr);
71
73 = m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ());
74 return current;
75 }
76 state_machine::state_t get_state (const svalue *sval) final override
77 {
78 logger * const logger = get_logger ();
81 = m_old_smap->get_state (sval, m_eg.get_ext_state ());
82 return current;
83 }
84
85
88 tree origin) final override
89 {
90 logger * const logger = get_logger ();
92 const svalue *var_new_sval
93 = m_new_state->m_region_model->get_rvalue (var, nullptr);
94 const svalue *origin_new_sval
95 = m_new_state->m_region_model->get_rvalue (origin, nullptr);
96
97 /* We use the new sval here to avoid issues with uninitialized values. */
99 = m_old_smap->get_state (var_new_sval, m_eg.get_ext_state ());
100 if (logger)
101 logger->log ("%s: state transition of %qE: %s -> %s",
102 m_sm.get_name (),
103 var,
104 current->get_name (),
105 to->get_name ());
106 m_new_smap->set_state (m_new_state->m_region_model, var_new_sval,
107 to, origin_new_sval, m_eg.get_ext_state ());
108 }
109
110 void set_next_state (const svalue *sval,
112 tree origin) final override
113 {
114 logger * const logger = get_logger ();
117 (m_eg, m_enode_for_diag, nullptr, nullptr, nullptr/*m_enode->get_state ()*/,
118 nullptr, nullptr);
119
120 const svalue *origin_new_sval
121 = m_new_state->m_region_model->get_rvalue (origin, nullptr);
122
124 = m_old_smap->get_state (sval, m_eg.get_ext_state ());
125 if (logger)
126 {
128 logger->log_partial ("%s: state transition of ",
129 m_sm.get_name ());
130 sval->dump_to_pp (logger->get_printer (), true);
131 logger->log_partial (": %s -> %s",
132 current->get_name (),
133 to->get_name ());
135 }
136 m_new_smap->set_state (m_new_state->m_region_model, sval,
137 to, origin_new_sval, m_eg.get_ext_state ());
138 }
139
140 void warn (tree var,
141 std::unique_ptr<pending_diagnostic> d) final override
142 {
143 LOG_FUNC (get_logger ());
144 gcc_assert (d);
145 const svalue *var_old_sval
146 = m_old_state->m_region_model->get_rvalue (var, nullptr);
148 = (var
149 ? m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ())
150 : m_old_smap->get_global_state ());
151 bool terminate_path = d->terminate_path_p ();
153 m_eg.get_diagnostic_manager ().add_diagnostic
154 (&m_sm, std::move (ploc),
155 var, var_old_sval, current, std::move (d));
156 if (m_path_ctxt
157 && terminate_path
158 && flag_analyzer_suppress_followups)
159 m_path_ctxt->terminate_path ();
160 }
161
162 void warn (const svalue *sval,
163 std::unique_ptr<pending_diagnostic> d) final override
164 {
165 LOG_FUNC (get_logger ());
166 gcc_assert (d);
168 = (sval
169 ? m_old_smap->get_state (sval, m_eg.get_ext_state ())
170 : m_old_smap->get_global_state ());
171 bool terminate_path = d->terminate_path_p ();
173 m_eg.get_diagnostic_manager ().add_diagnostic
174 (&m_sm, std::move (ploc),
175 NULL_TREE, sval, current, std::move (d));
176 if (m_path_ctxt
177 && terminate_path
178 && flag_analyzer_suppress_followups)
179 m_path_ctxt->terminate_path ();
180 }
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
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 if (TREE_CODE (expr) != SSA_NAME)
193 return expr;
194 if (SSA_NAME_VAR (expr) != NULL)
195 return expr;
196
198 const svalue *sval = m_new_state->m_region_model->get_rvalue (expr, nullptr);
199 /* Find trees for all regions storing the value. */
200 if (tree t = m_new_state->m_region_model->get_representative_tree (sval))
201 return t;
202 else
203 return expr;
204 }
205
206 tree get_diagnostic_tree (const svalue *sval) final override
207 {
208 return m_new_state->m_region_model->get_representative_tree (sval);
209 }
210
212 {
213 return m_old_state->m_checker_states[m_sm_idx]->get_global_state ();
214 }
215
217 {
218 m_new_state->m_checker_states[m_sm_idx]->set_global_state (state);
219 }
220
222 {
223 m_new_state->m_checker_states[m_sm_idx]->clear_all_per_svalue_state ();
224 }
225
227 {
228 transition->impl_transition (&m_eg,
229 const_cast<exploded_node *> (m_enode_for_diag),
230 m_sm_idx);
231 }
232
233 tree is_zero_assignment (const gimple *stmt) final override
234 {
235 const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
236 if (!assign_stmt)
237 return NULL_TREE;
239 (m_eg, m_enode_for_diag, m_old_state, m_new_state, nullptr, nullptr, stmt);
240 if (const svalue *sval
241 = m_new_state->m_region_model->get_gassign_result (assign_stmt,
242 &old_ctxt))
243 if (tree cst = sval->maybe_get_constant ())
244 if (::zerop(cst))
245 return gimple_assign_lhs (assign_stmt);
246 return NULL_TREE;
247 }
248
250 {
251 return m_path_ctxt;
252 }
253
254 bool unknown_side_effects_p () const final override
255 {
257 }
258
260 {
261 return m_old_state;
262 }
263
265 {
266 return m_new_state;
267 }
268
269 location_t get_emission_location () const final override
270 {
272 }
273
282
283 /* Are we handling an external function with unknown side effects? */
285};
286
287} // namespace ana
288
289#endif /* GCC_ANALYZER_IMPL_SM_CONTEXT */
#define LOG_FUNC(LOGGER)
Definition analyzer-logging.h:293
Definition sm.h:232
Definition exploded-graph.h:783
Definition exploded-graph.h:206
Definition exploded-graph.h:40
impl_sm_context(exploded_graph &eg, int sm_idx, const state_machine &sm, exploded_node *enode_for_diag, const program_state *old_state, program_state *new_state, const sm_state_map *old_smap, sm_state_map *new_smap, path_context *path_ctxt, bool unknown_side_effects=false)
Definition impl-sm-context.h:32
void set_next_state(const svalue *sval, state_machine::state_t to, tree origin) final override
Definition impl-sm-context.h:110
sm_state_map * m_new_smap
Definition impl-sm-context.h:280
void set_global_state(state_machine::state_t state) final override
Definition impl-sm-context.h:216
path_context * m_path_ctxt
Definition impl-sm-context.h:281
void warn(tree var, std::unique_ptr< pending_diagnostic > d) final override
Definition impl-sm-context.h:140
const program_state * get_new_program_state() const final override
Definition impl-sm-context.h:264
bool unknown_side_effects_p() const final override
Definition impl-sm-context.h:254
tree is_zero_assignment(const gimple *stmt) final override
Definition impl-sm-context.h:233
log_user m_logger
Definition impl-sm-context.h:274
const program_state * m_old_state
Definition impl-sm-context.h:277
program_state * m_new_state
Definition impl-sm-context.h:278
const sm_state_map * m_old_smap
Definition impl-sm-context.h:279
void on_custom_transition(custom_transition *transition) final override
Definition impl-sm-context.h:226
void set_next_state(tree var, state_machine::state_t to, tree origin) final override
Definition impl-sm-context.h:86
void clear_all_per_svalue_state() final override
Definition impl-sm-context.h:221
const program_state * get_old_program_state() const final override
Definition impl-sm-context.h:259
tree get_fndecl_for_call(const gcall &call) final override
Definition impl-sm-context.h:54
state_machine::state_t get_state(tree var) final override
Definition impl-sm-context.h:63
state_machine::state_t get_global_state() const final override
Definition impl-sm-context.h:211
exploded_node * m_enode_for_diag
Definition impl-sm-context.h:276
state_machine::state_t get_state(const svalue *sval) final override
Definition impl-sm-context.h:76
bool m_unknown_side_effects
Definition impl-sm-context.h:284
path_context * get_path_context() const final override
Definition impl-sm-context.h:249
tree get_diagnostic_tree(tree expr) final override
Definition impl-sm-context.h:188
location_t get_emission_location() const final override
Definition impl-sm-context.h:269
exploded_graph & m_eg
Definition impl-sm-context.h:275
void warn(const svalue *sval, std::unique_ptr< pending_diagnostic > d) final override
Definition impl-sm-context.h:162
tree get_diagnostic_tree(const svalue *sval) final override
Definition impl-sm-context.h:206
logger * get_logger() const
Definition impl-sm-context.h:52
Definition analyzer-logging.h:189
Definition analyzer-logging.h:34
pretty_printer * get_printer() const
Definition analyzer-logging.h:60
void log_partial(const char *fmt,...) ATTRIBUTE_GCC_DIAG(2
void log(const char *fmt,...) ATTRIBUTE_GCC_DIAG(2
void void void start_log_line()
void void void end_log_line()
Definition common.h:435
Definition program-state.h:224
Definition region-model.h:299
tree get_fndecl_for_call(const gcall &call, region_model_context *ctxt)
const state_machine & m_sm
Definition sm.h:343
int m_sm_idx
Definition sm.h:342
sm_context(int sm_idx, const state_machine &sm)
Definition sm.h:339
Definition program-state.h:92
const char * get_name() const
Definition sm.h:53
Definition sm.h:43
const state_machine::state * state_t
Definition sm.h:63
Definition svalue.h:92
Definition genmatch.cc:1506
Definition genrecog.cc:1504
union tree_node * tree
Definition coretypes.h:97
void final(rtx_insn *first, FILE *file, int optimize_p)
Definition final.cc:2009
tree gimple_assign_lhs(const gassign *gs)
Definition gimple.h:2616
T dyn_cast(U *p)
Definition is-a.h:280
Definition access-diagram.h:30
@ stmt
Definition checker-event.h:38
Definition diagnostic-manager.h:35
location_t get_location() const
Definition diagnostic-manager.h:52
Definition gimple.h:907
Definition gimple.h:352
Definition gimple.h:221
Definition genautomata.cc:669
#define NULL
Definition system.h:50
#define gcc_assert(EXPR)
Definition system.h:817
bool zerop(const_tree expr)
Definition tree.cc:2986
#define SSA_NAME_VAR(NODE)
Definition tree.h:2202
#define TREE_CODE(NODE)
Definition tree.h:325
#define NULL_TREE
Definition tree.h:318