GCC Middle and Back End API Reference
sm.h
Go to the documentation of this file.
1/* Modeling API uses and misuses via state machines.
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_SM_H
22#define GCC_ANALYZER_SM_H
23
24/* Utility functions for use by state machines. */
25
26namespace ana {
27
28class state_machine;
29class sm_context;
32
33extern bool any_pointer_p (tree expr);
34extern bool any_pointer_p (const svalue *sval);
35
36/* An abstract base class for a state machine describing an API.
37 Manages a set of state objects, and has various virtual functions
38 for pattern-matching on statements. */
39
40class state_machine : public log_user
41{
42public:
43 /* States are represented by immutable objects, owned by the state
44 machine. */
45 class state
46 {
47 public:
48 state (const char *name, unsigned id) : m_name (name), m_id (id) {}
49 virtual ~state () {}
50
51 const char *get_name () const { return m_name; }
52 virtual void dump_to_pp (pretty_printer *pp) const;
53 virtual std::unique_ptr<json::value> to_json () const;
54
55 unsigned get_id () const { return m_id; }
56
57 private:
58 const char *m_name;
59 unsigned m_id;
60 };
62
63 state_machine (const char *name, logger *logger);
64 virtual ~state_machine () {}
65
66 /* Should states be inherited from a parent region to a child region,
67 when first accessing a child region?
68 For example we should inherit the taintedness of a subregion,
69 but we should not inherit the "malloc:non-null" state of a field
70 within a heap-allocated struct. */
71 virtual bool inherited_state_p () const = 0;
72
73 /* A vfunc for more general handling of inheritance. */
74 virtual state_t
76 const svalue *,
77 const extrinsic_state &) const
78 {
79 return nullptr;
80 }
81
82 virtual bool
84 {
85 return false;
86 }
87
89 {
90 return m_start;
91 }
92
93 const char *get_name () const { return m_name; }
94
95 state_t get_state_by_name (const char *name) const;
96
97 /* Return true if STMT is a function call recognized by this sm. */
98 virtual bool on_stmt (sm_context &sm_ctxt,
99 const supernode *node,
100 const gimple *stmt) const = 0;
101
102 virtual void on_phi (sm_context &sm_ctxt ATTRIBUTE_UNUSED,
103 const supernode *node ATTRIBUTE_UNUSED,
104 const gphi *phi ATTRIBUTE_UNUSED,
105 tree rhs ATTRIBUTE_UNUSED) const
106 {
107 }
108
109 virtual void on_condition (sm_context &sm_ctxt ATTRIBUTE_UNUSED,
110 const supernode *node ATTRIBUTE_UNUSED,
111 const gimple *stmt ATTRIBUTE_UNUSED,
112 const svalue *lhs ATTRIBUTE_UNUSED,
113 enum tree_code op ATTRIBUTE_UNUSED,
114 const svalue *rhs ATTRIBUTE_UNUSED) const
115 {
116 }
117
118 virtual void
119 on_bounded_ranges (sm_context &sm_ctxt ATTRIBUTE_UNUSED,
120 const supernode *node ATTRIBUTE_UNUSED,
121 const gimple *stmt ATTRIBUTE_UNUSED,
122 const svalue &sval ATTRIBUTE_UNUSED,
123 const bounded_ranges &ranges ATTRIBUTE_UNUSED) const
124 {
125 }
126
127 virtual void
128 on_pop_frame (sm_state_map *smap ATTRIBUTE_UNUSED,
129 const frame_region *frame_reg ATTRIBUTE_UNUSED) const
130 {
131 }
132
133 /* Return true if it safe to discard the given state (to help
134 when simplifying state objects).
135 States that need leak detection should return false. */
136 virtual bool can_purge_p (state_t s) const = 0;
137
138 /* Called when VAR leaks (and !can_purge_p). */
139 virtual std::unique_ptr<pending_diagnostic>
140 on_leak (tree var ATTRIBUTE_UNUSED,
141 const program_state *old_state,
142 const program_state *new_state) const;
143
144 /* Return true if S should be reset to "start" for values passed (or reachable
145 from) calls to unknown functions. IS_MUTABLE is true for pointers as
146 non-const, false if only passed as const-pointers.
147
148 For example, in sm-malloc.cc, an on-stack ptr doesn't stop being
149 stack-allocated when passed to an unknown fn, but a malloc-ed pointer
150 could be freed when passed to an unknown fn (unless passed as "const"). */
151 virtual bool reset_when_passed_to_unknown_fn_p (state_t s ATTRIBUTE_UNUSED,
152 bool is_mutable) const
153 {
154 return is_mutable;
155 }
156
157 /* Attempt to get a state for the merger of STATE_A and STATE_B,
158 or return nullptr if merging shouldn't occur, so that differences
159 between sm-state will lead to separate exploded nodes.
160
161 Most state machines will only merge equal states, but can
162 override maybe_get_merged_states_nonequal to support mergers
163 of certain non-equal states. */
165 state_t state_b) const
166 {
167 if (state_a == state_b)
168 return state_a;
169 return maybe_get_merged_states_nonequal (state_a, state_b);
170 }
171
172 /* Base implementation of hook for maybe_get_merged_state on non-equal
173 states. */
174 virtual state_t
175 maybe_get_merged_states_nonequal (state_t state_a ATTRIBUTE_UNUSED,
176 state_t state_b ATTRIBUTE_UNUSED) const
177 {
178 /* By default, non-equal sm states should inhibit merger of enodes. */
179 return nullptr;
180 }
181
182 void validate (state_t s) const;
183
184 void dump_to_pp (pretty_printer *pp) const;
185
186 std::unique_ptr<json::object> to_json () const;
187
188 state_t get_start_state () const { return m_start; }
189
190 virtual void
192 const svalue &sval,
194
195 virtual void
198
199protected:
200 state_t add_state (const char *name);
202 {
203 m_states.safe_push (s);
204 return s;
205 }
206
207 unsigned alloc_state_id () { return m_next_state_id++; }
208
209private:
211
212 const char *m_name;
213
214 /* States are owned by the state_machine. */
216
218
219protected:
220 /* Must be inited after m_next_state_id. */
222};
223
224/* Abstract base class for state machines to pass to
225 sm_context::on_custom_transition for handling non-standard transitions
226 (e.g. adding a node and edge to simulate registering a callback and having
227 the callback be called later). */
228
230{
231public:
232 virtual ~custom_transition () {}
234 exploded_node *src_enode,
235 int sm_idx) = 0;
236};
237
238/* Abstract base class giving an interface for the state machine to call
239 the checker engine, at a particular stmt. */
240
242{
243public:
244 virtual ~sm_context () {}
245
246 /* Get the fndecl used at call, or NULL_TREE.
247 Use in preference to gimple_call_fndecl (and gimple_call_addr_fndecl),
248 since it can look through function pointer assignments and
249 other callback handling. */
250 virtual tree get_fndecl_for_call (const gcall &call) = 0;
251
252 /* Get the old state of VAR at STMT. */
254 tree var) = 0;
256 const svalue *) = 0;
257 /* Set the next state of VAR to be TO, recording the "origin" of the
258 state as ORIGIN.
259 Use STMT for location information. */
260 virtual void set_next_state (const gimple *stmt,
261 tree var,
263 tree origin = NULL_TREE) = 0;
264 virtual void set_next_state (const gimple *stmt,
265 const svalue *var,
267 tree origin = NULL_TREE) = 0;
268
269 /* Called by state_machine in response to pattern matches:
270 if VAR is in state FROM, transition it to state TO, potentially
271 recording the "origin" of the state as ORIGIN.
272 Use NODE and STMT for location information. */
273 void on_transition (const supernode *node ATTRIBUTE_UNUSED,
274 const gimple *stmt,
275 tree var,
278 tree origin = NULL_TREE)
279 {
280 state_machine::state_t current = get_state (stmt, var);
281 if (current == from)
282 set_next_state (stmt, var, to, origin);
283 }
284
285 void on_transition (const supernode *node ATTRIBUTE_UNUSED,
286 const gimple *stmt,
287 const svalue *var,
290 tree origin = NULL_TREE)
291 {
292 state_machine::state_t current = get_state (stmt, var);
293 if (current == from)
294 set_next_state (stmt, var, to, origin);
295 }
296
297 /* Called by state_machine in response to pattern matches:
298 issue a diagnostic D using NODE and STMT for location information. */
299 virtual void warn (const supernode *node, const gimple *stmt,
300 tree var,
301 std::unique_ptr<pending_diagnostic> d) = 0;
302 virtual void warn (const supernode *node, const gimple *stmt,
303 const svalue *var,
304 std::unique_ptr<pending_diagnostic> d) = 0;
305
306 /* For use when generating trees when creating pending_diagnostics, so that
307 rather than e.g.
308 "double-free of '<unknown>'"
309 we can print:
310 "double-free of 'inbuf.data'". */
312 {
313 return expr;
314 }
315 virtual tree get_diagnostic_tree (const svalue *) = 0;
316
319
320 virtual void clear_all_per_svalue_state () = 0;
321
322 /* A vfunc for handling custom transitions, such as when registering
323 a signal handler. */
325
326 /* If STMT is an assignment known to assign zero to its LHS, return
327 the LHS.
328 Otherwise return NULL_TREE. */
329 virtual tree is_zero_assignment (const gimple *stmt) = 0;
330
332 {
333 return nullptr;
334 }
335
336 /* Are we handling an external function with unknown side effects? */
337 virtual bool unknown_side_effects_p () const { return false; }
338
339 virtual const program_state *get_old_program_state () const = 0;
340 virtual const program_state *get_new_program_state () const = 0;
341
343
344protected:
345 sm_context (int sm_idx, const state_machine &sm)
346 : m_sm_idx (sm_idx), m_sm (sm) {}
347
350};
351
352
353/* The various state_machine subclasses are hidden in their respective
354 implementation files. */
355
356extern std::vector<std::unique_ptr<state_machine>>
358
359extern std::unique_ptr<state_machine> make_malloc_state_machine (logger *);
360extern std::unique_ptr<state_machine> make_fileptr_state_machine (logger *);
361extern std::unique_ptr<state_machine> make_taint_state_machine (logger *);
362extern std::unique_ptr<state_machine> make_sensitive_state_machine (logger *);
363extern std::unique_ptr<state_machine> make_signal_state_machine (logger *);
364extern std::unique_ptr<state_machine> make_pattern_test_state_machine (logger *);
365extern std::unique_ptr<state_machine> make_va_list_state_machine (logger *);
366extern std::unique_ptr<state_machine> make_fd_state_machine (logger *);
367
368} // namespace ana
369
370#endif /* GCC_ANALYZER_SM_H */
Definition ana-state-to-diagnostic-state.h:30
Definition sm.h:230
virtual void impl_transition(exploded_graph *eg, exploded_node *src_enode, int sm_idx)=0
virtual ~custom_transition()
Definition sm.h:232
Definition exploded-graph.h:806
Definition exploded-graph.h:205
Definition program-state.h:34
Definition region.h:319
log_user(logger *logger)
Definition analyzer-logging.h:34
Definition common.h:422
Definition pending-diagnostic.h:190
Definition program-state.h:224
Definition region-model.h:298
Definition sm.h:242
virtual void warn(const supernode *node, const gimple *stmt, const svalue *var, std::unique_ptr< pending_diagnostic > d)=0
const state_machine & m_sm
Definition sm.h:349
virtual state_machine::state_t get_state(const gimple *stmt, tree var)=0
virtual void set_next_state(const gimple *stmt, const svalue *var, state_machine::state_t to, tree origin=NULL_TREE)=0
virtual tree get_diagnostic_tree(tree expr)
Definition sm.h:311
virtual state_machine::state_t get_state(const gimple *stmt, const svalue *)=0
virtual void set_global_state(state_machine::state_t)=0
virtual void set_next_state(const gimple *stmt, tree var, state_machine::state_t to, tree origin=NULL_TREE)=0
virtual void warn(const supernode *node, const gimple *stmt, tree var, std::unique_ptr< pending_diagnostic > d)=0
virtual const program_state * get_old_program_state() const =0
virtual ~sm_context()
Definition sm.h:244
virtual state_machine::state_t get_global_state() const =0
virtual tree is_zero_assignment(const gimple *stmt)=0
virtual void clear_all_per_svalue_state()=0
virtual const program_state * get_new_program_state() const =0
const region_model * get_old_region_model() const
virtual path_context * get_path_context() const
Definition sm.h:331
int m_sm_idx
Definition sm.h:348
virtual bool unknown_side_effects_p() const
Definition sm.h:337
sm_context(int sm_idx, const state_machine &sm)
Definition sm.h:345
virtual tree get_diagnostic_tree(const svalue *)=0
virtual tree get_fndecl_for_call(const gcall &call)=0
void on_transition(const supernode *node, const gimple *stmt, const svalue *var, state_machine::state_t from, state_machine::state_t to, tree origin=NULL_TREE)
Definition sm.h:285
void on_transition(const supernode *node, const gimple *stmt, tree var, state_machine::state_t from, state_machine::state_t to, tree origin=NULL_TREE)
Definition sm.h:273
virtual void on_custom_transition(custom_transition *transition)=0
Definition program-state.h:92
Definition sm.h:46
virtual void dump_to_pp(pretty_printer *pp) const
unsigned m_id
Definition sm.h:59
virtual std::unique_ptr< json::value > to_json() const
unsigned get_id() const
Definition sm.h:55
state(const char *name, unsigned id)
Definition sm.h:48
virtual ~state()
Definition sm.h:49
const char * m_name
Definition sm.h:58
const char * get_name() const
Definition sm.h:51
Definition sm.h:41
const char * get_name() const
Definition sm.h:93
virtual state_t maybe_get_merged_states_nonequal(state_t state_a, state_t state_b) const
Definition sm.h:175
virtual void on_phi(sm_context &sm_ctxt, const supernode *node, const gphi *phi, tree rhs) const
Definition sm.h:102
void validate(state_t s) const
virtual ~state_machine()
Definition sm.h:64
virtual bool inherited_state_p() const =0
virtual state_machine::state_t get_default_state(const svalue *) const
Definition sm.h:88
virtual void on_bounded_ranges(sm_context &sm_ctxt, const supernode *node, const gimple *stmt, const svalue &sval, const bounded_ranges &ranges) const
Definition sm.h:119
auto_delete_vec< state > m_states
Definition sm.h:215
state_t maybe_get_merged_state(state_t state_a, state_t state_b) const
Definition sm.h:164
virtual bool reset_when_passed_to_unknown_fn_p(state_t s, bool is_mutable) const
Definition sm.h:151
virtual void on_condition(sm_context &sm_ctxt, const supernode *node, const gimple *stmt, const svalue *lhs, enum tree_code op, const svalue *rhs) const
Definition sm.h:109
state_t add_custom_state(state *s)
Definition sm.h:201
virtual void on_pop_frame(sm_state_map *smap, const frame_region *frame_reg) const
Definition sm.h:128
virtual bool on_stmt(sm_context &sm_ctxt, const supernode *node, const gimple *stmt) const =0
unsigned m_next_state_id
Definition sm.h:217
state_t get_start_state() const
Definition sm.h:188
const char * m_name
Definition sm.h:212
state_machine(const char *name, logger *logger)
std::unique_ptr< json::object > to_json() const
virtual void add_global_state_to_state_graph(analyzer_state_graph &out_state_graph, state_machine::state_t state) const
virtual bool has_alt_get_inherited_state_p() const
Definition sm.h:83
virtual state_t alt_get_inherited_state(const sm_state_map &, const svalue *, const extrinsic_state &) const
Definition sm.h:75
const state_machine::state * state_t
Definition sm.h:61
virtual std::unique_ptr< pending_diagnostic > on_leak(tree var, const program_state *old_state, const program_state *new_state) const
void dump_to_pp(pretty_printer *pp) const
unsigned alloc_state_id()
Definition sm.h:207
state_t get_state_by_name(const char *name) const
state_t m_start
Definition sm.h:221
virtual void add_state_to_state_graph(analyzer_state_graph &out_state_graph, const svalue &sval, state_machine::state_t state) const
DISABLE_COPY_AND_ASSIGN(state_machine)
state_t add_state(const char *name)
virtual bool can_purge_p(state_t s) const =0
Definition supergraph.h:239
Definition svalue.h:92
Definition vec.h:1813
Definition genmatch.cc:1506
Definition pretty-print.h:241
Definition genrecog.cc:1504
union tree_node * tree
Definition coretypes.h:97
struct state * state_t
Definition genautomata.cc:195
tree_code
Definition genmatch.cc:1002
Definition access-diagram.h:30
std::unique_ptr< state_machine > make_signal_state_machine(logger *)
@ stmt
Definition checker-event.h:38
std::unique_ptr< state_machine > make_taint_state_machine(logger *)
std::unique_ptr< state_machine > make_sensitive_state_machine(logger *)
std::unique_ptr< state_machine > make_pattern_test_state_machine(logger *)
std::unique_ptr< state_machine > make_va_list_state_machine(logger *)
std::unique_ptr< state_machine > make_fileptr_state_machine(logger *)
std::vector< std::unique_ptr< state_machine > > make_checkers(logger *logger)
std::unique_ptr< state_machine > make_malloc_state_machine(logger *)
bool any_pointer_p(tree expr)
std::unique_ptr< state_machine > make_fd_state_machine(logger *)
Definition constraint-manager.h:123
Definition gimple.h:352
Definition gimple.h:221
Definition gimple.h:461
Definition collect2.cc:168
#define NULL_TREE
Definition tree.h:318