Branch data Line data Source code
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 : :
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 : : #define INCLUDE_LIST
22 : : #include "analyzer/common.h"
23 : :
24 : : #include "tree-diagnostic.h"
25 : :
26 : : #include "analyzer/analyzer-logging.h"
27 : : #include "analyzer/sm.h"
28 : : #include "analyzer/call-string.h"
29 : : #include "analyzer/program-point.h"
30 : : #include "analyzer/store.h"
31 : : #include "analyzer/svalue.h"
32 : : #include "analyzer/program-state.h"
33 : : #include "analyzer/pending-diagnostic.h"
34 : :
35 : : #if ENABLE_ANALYZER
36 : :
37 : : namespace ana {
38 : :
39 : : /* Return true if VAR has pointer or reference type. */
40 : :
41 : : bool
42 : 35955 : any_pointer_p (tree var)
43 : : {
44 : 35955 : return POINTER_TYPE_P (TREE_TYPE (var));
45 : : }
46 : :
47 : : /* Return true if SVAL has pointer or reference type. */
48 : :
49 : : bool
50 : 55230 : any_pointer_p (const svalue *sval)
51 : : {
52 : 55230 : if (!sval->get_type ())
53 : : return false;
54 : 55230 : return POINTER_TYPE_P (sval->get_type ());
55 : : }
56 : :
57 : : /* class state_machine::state. */
58 : :
59 : : /* Base implementation of dump_to_pp vfunc. */
60 : :
61 : : void
62 : 806 : state_machine::state::dump_to_pp (pretty_printer *pp) const
63 : : {
64 : 806 : pp_string (pp, m_name);
65 : 806 : }
66 : :
67 : : /* Return a new json::string describing the state. */
68 : :
69 : : std::unique_ptr<json::value>
70 : 9 : state_machine::state::to_json () const
71 : : {
72 : 9 : pretty_printer pp;
73 : 9 : pp_format_decoder (&pp) = default_tree_printer;
74 : 9 : dump_to_pp (&pp);
75 : 9 : return std::make_unique<json::string> (pp_formatted_text (&pp));
76 : 9 : }
77 : :
78 : : /* class state_machine. */
79 : :
80 : : /* state_machine's ctor. */
81 : :
82 : 23218 : state_machine::state_machine (const char *name, logger *logger)
83 : 23218 : : log_user (logger), m_name (name), m_next_state_id (0),
84 : 23218 : m_start (add_state ("start"))
85 : : {
86 : 23218 : }
87 : :
88 : : /* Add a state with name NAME to this state_machine.
89 : : The string is required to outlive the state_machine.
90 : :
91 : : Return the state_t for the new state. */
92 : :
93 : : state_machine::state_t
94 : 135870 : state_machine::add_state (const char *name)
95 : : {
96 : 135870 : state *s = new state (name, alloc_state_id ());
97 : 135870 : m_states.safe_push (s);
98 : 135870 : return s;
99 : : }
100 : :
101 : : /* Get the state with name NAME, which must exist.
102 : : This is purely intended for use in selftests. */
103 : :
104 : : state_machine::state_t
105 : 188 : state_machine::get_state_by_name (const char *name) const
106 : : {
107 : 188 : unsigned i;
108 : 188 : state *s;
109 : 376 : FOR_EACH_VEC_ELT (m_states, i, s)
110 : 376 : if (!strcmp (name, s->get_name ()))
111 : 188 : return s;
112 : : /* Name not found. */
113 : 0 : gcc_unreachable ();
114 : : }
115 : :
116 : : /* Base implementation of state_machine::on_leak. */
117 : :
118 : : std::unique_ptr<pending_diagnostic>
119 : 437 : state_machine::on_leak (tree var ATTRIBUTE_UNUSED) const
120 : : {
121 : 437 : return NULL;
122 : : }
123 : :
124 : : /* Dump a multiline representation of this state machine to PP. */
125 : :
126 : : void
127 : 0 : state_machine::dump_to_pp (pretty_printer *pp) const
128 : : {
129 : 0 : unsigned i;
130 : 0 : state *s;
131 : 0 : FOR_EACH_VEC_ELT (m_states, i, s)
132 : : {
133 : 0 : pp_printf (pp, " state %i: ", i);
134 : 0 : s->dump_to_pp (pp);
135 : 0 : pp_newline (pp);
136 : : }
137 : 0 : }
138 : :
139 : : /* Return a new json::object of the form
140 : : {"name" : str,
141 : : "states" : [str]}. */
142 : :
143 : : std::unique_ptr<json::object>
144 : 0 : state_machine::to_json () const
145 : : {
146 : 0 : auto sm_obj = std::make_unique<json::object> ();
147 : :
148 : 0 : sm_obj->set_string ("name", m_name);
149 : 0 : {
150 : 0 : auto states_arr = std::make_unique<json::array> ();
151 : 0 : unsigned i;
152 : 0 : state *s;
153 : 0 : FOR_EACH_VEC_ELT (m_states, i, s)
154 : 0 : states_arr->append (s->to_json ());
155 : 0 : sm_obj->set ("states", std::move (states_arr));
156 : 0 : }
157 : :
158 : 0 : return sm_obj;
159 : : }
160 : :
161 : : /* class sm_context. */
162 : :
163 : : const region_model *
164 : 268465 : sm_context::get_old_region_model () const
165 : : {
166 : 268465 : if (const program_state *old_state = get_old_program_state ())
167 : 268465 : return old_state->m_region_model;
168 : : else
169 : : return NULL;
170 : : }
171 : :
172 : : /* Create instances of the various state machines, each using LOGGER,
173 : : returning a vector of them. */
174 : :
175 : : std::vector<std::unique_ptr<state_machine>>
176 : 3313 : make_checkers (logger *logger)
177 : : {
178 : : /* Start with a list so that we can filter it. */
179 : 3313 : std::list<std::unique_ptr<state_machine>> out;
180 : 3313 : out.push_back (make_malloc_state_machine (logger));
181 : 3313 : out.push_back (make_fileptr_state_machine (logger));
182 : 3313 : out.push_back (make_fd_state_machine (logger));
183 : 3313 : out.push_back (make_taint_state_machine (logger));
184 : 3313 : out.push_back (make_sensitive_state_machine (logger));
185 : 3313 : out.push_back (make_signal_state_machine (logger));
186 : 3313 : out.push_back (make_va_list_state_machine (logger));
187 : :
188 : : /* We only attempt to run the pattern tests if it might have been manually
189 : : enabled (for DejaGnu purposes). */
190 : 3313 : if (flag_analyzer_checker)
191 : 10 : out.push_back (make_pattern_test_state_machine (logger));
192 : :
193 : 3313 : if (flag_analyzer_checker)
194 : : {
195 : 10 : out.remove_if ([] (auto &sm)
196 : : {
197 : 80 : return 0 != strcmp (flag_analyzer_checker,
198 : 80 : sm->get_name ());
199 : : });
200 : : }
201 : :
202 : 3313 : std::vector<std::unique_ptr<state_machine>> out_vec;
203 : 26444 : for (auto &iter: out)
204 : 23131 : out_vec.push_back (std::move (iter));
205 : :
206 : 3313 : return out_vec;
207 : 3313 : }
208 : :
209 : : } // namespace ana
210 : :
211 : : #endif /* #if ENABLE_ANALYZER */
|