analyzer: eliminate non-determinism in logs
[gcc.git] / gcc / analyzer / analyzer.cc
1 /* Utility functions for the analyzer.
2 Copyright (C) 2019-2020 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 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "function.h"
26 #include "basic-block.h"
27 #include "gimple.h"
28 #include "diagnostic.h"
29 #include "intl.h"
30 #include "function.h"
31 #include "analyzer/analyzer.h"
32
33 #if ENABLE_ANALYZER
34
35 namespace ana {
36
37 /* Workaround for missing location information for some stmts,
38 which ultimately should be solved by fixing the frontends
39 to provide the locations (TODO). */
40
41 location_t
42 get_stmt_location (const gimple *stmt, function *fun)
43 {
44 if (get_pure_location (stmt->location) == UNKNOWN_LOCATION)
45 {
46 /* Workaround for missing location information for clobber
47 stmts, which seem to lack location information in the C frontend
48 at least. Created by gimplify_bind_expr, which uses the
49 BLOCK_SOURCE_END_LOCATION (BIND_EXPR_BLOCK (bind_expr))
50 but this is never set up when the block is created in
51 c_end_compound_stmt's pop_scope.
52 TODO: fix this missing location information.
53
54 For now, as a hackish workaround, use the location of the end of
55 the function. */
56 if (gimple_clobber_p (stmt) && fun)
57 return fun->function_end_locus;
58 }
59
60 return stmt->location;
61 }
62
63 } // namespace ana
64
65 /* Helper function for checkers. Is the CALL to the given function name,
66 and with the given number of arguments?
67
68 This doesn't resolve function pointers via the region model;
69 is_named_call_p should be used instead, using a fndecl from
70 get_fndecl_for_call; this function should only be used for special cases
71 where it's not practical to get at the region model, or for special
72 analyzer functions such as __analyzer_dump. */
73
74 bool
75 is_special_named_call_p (const gcall *call, const char *funcname,
76 unsigned int num_args)
77 {
78 gcc_assert (funcname);
79
80 tree fndecl = gimple_call_fndecl (call);
81 if (!fndecl)
82 return false;
83
84 return is_named_call_p (fndecl, funcname, call, num_args);
85 }
86
87 /* Helper function for checkers. Is FNDECL an extern fndecl at file scope
88 that has the given FUNCNAME?
89
90 Compare with special_function_p in calls.c. */
91
92 bool
93 is_named_call_p (tree fndecl, const char *funcname)
94 {
95 gcc_assert (fndecl);
96 gcc_assert (funcname);
97
98 if (!maybe_special_function_p (fndecl))
99 return false;
100
101 tree identifier = DECL_NAME (fndecl);
102 const char *name = IDENTIFIER_POINTER (identifier);
103 const char *tname = name;
104
105 /* Potentially disregard prefix _ or __ in FNDECL's name, but not if
106 FUNCNAME itself has leading underscores (e.g. when looking for
107 "__analyzer_eval"). */
108 if (funcname[0] != '_' && name[0] == '_')
109 {
110 if (name[1] == '_')
111 tname += 2;
112 else
113 tname += 1;
114 }
115
116 return 0 == strcmp (tname, funcname);
117 }
118
119 /* Return true if FNDECL is within the namespace "std".
120 Compare with cp/typeck.c: decl_in_std_namespace_p, but this doesn't
121 rely on being the C++ FE (or handle inline namespaces inside of std). */
122
123 static inline bool
124 is_std_function_p (const_tree fndecl)
125 {
126 tree name_decl = DECL_NAME (fndecl);
127 if (!name_decl)
128 return false;
129 if (!DECL_CONTEXT (fndecl))
130 return false;
131 if (TREE_CODE (DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
132 return false;
133 tree ns = DECL_CONTEXT (fndecl);
134 if (!(DECL_CONTEXT (ns) == NULL_TREE
135 || TREE_CODE (DECL_CONTEXT (ns)) == TRANSLATION_UNIT_DECL))
136 return false;
137 if (!DECL_NAME (ns))
138 return false;
139 return id_equal ("std", DECL_NAME (ns));
140 }
141
142 /* Like is_named_call_p, but look for std::FUNCNAME. */
143
144 bool
145 is_std_named_call_p (tree fndecl, const char *funcname)
146 {
147 gcc_assert (fndecl);
148 gcc_assert (funcname);
149
150 if (!is_std_function_p (fndecl))
151 return false;
152
153 tree identifier = DECL_NAME (fndecl);
154 const char *name = IDENTIFIER_POINTER (identifier);
155 const char *tname = name;
156
157 /* Don't disregard prefix _ or __ in FNDECL's name. */
158
159 return 0 == strcmp (tname, funcname);
160 }
161
162 /* Helper function for checkers. Is FNDECL an extern fndecl at file scope
163 that has the given FUNCNAME, and does CALL have the given number of
164 arguments? */
165
166 bool
167 is_named_call_p (tree fndecl, const char *funcname,
168 const gcall *call, unsigned int num_args)
169 {
170 gcc_assert (fndecl);
171 gcc_assert (funcname);
172
173 if (!is_named_call_p (fndecl, funcname))
174 return false;
175
176 if (gimple_call_num_args (call) != num_args)
177 return false;
178
179 return true;
180 }
181
182 /* Like is_named_call_p, but check for std::FUNCNAME. */
183
184 bool
185 is_std_named_call_p (tree fndecl, const char *funcname,
186 const gcall *call, unsigned int num_args)
187 {
188 gcc_assert (fndecl);
189 gcc_assert (funcname);
190
191 if (!is_std_named_call_p (fndecl, funcname))
192 return false;
193
194 if (gimple_call_num_args (call) != num_args)
195 return false;
196
197 return true;
198 }
199
200 /* Return true if stmt is a setjmp or sigsetjmp call. */
201
202 bool
203 is_setjmp_call_p (const gcall *call)
204 {
205 if (is_special_named_call_p (call, "setjmp", 1)
206 || is_special_named_call_p (call, "sigsetjmp", 2))
207 /* region_model::on_setjmp requires a pointer. */
208 if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
209 return true;
210
211 return false;
212 }
213
214 /* Return true if stmt is a longjmp or siglongjmp call. */
215
216 bool
217 is_longjmp_call_p (const gcall *call)
218 {
219 if (is_special_named_call_p (call, "longjmp", 2)
220 || is_special_named_call_p (call, "siglongjmp", 2))
221 /* exploded_node::on_longjmp requires a pointer for the initial
222 argument. */
223 if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
224 return true;
225
226 return false;
227 }
228
229 /* For a CALL that matched is_special_named_call_p or is_named_call_p for
230 some name, return a name for the called function suitable for use in
231 diagnostics (stripping the leading underscores). */
232
233 const char *
234 get_user_facing_name (const gcall *call)
235 {
236 tree fndecl = gimple_call_fndecl (call);
237 gcc_assert (fndecl);
238
239 tree identifier = DECL_NAME (fndecl);
240 gcc_assert (identifier);
241
242 const char *name = IDENTIFIER_POINTER (identifier);
243
244 /* Strip prefix _ or __ in FNDECL's name. */
245 if (name[0] == '_')
246 {
247 if (name[1] == '_')
248 return name + 2;
249 else
250 return name + 1;
251 }
252
253 return name;
254 }
255
256 /* Generate a label_text instance by formatting FMT, using a
257 temporary clone of the global_dc's printer (thus using its
258 formatting callbacks).
259
260 Colorize if the global_dc supports colorization and CAN_COLORIZE is
261 true. */
262
263 label_text
264 make_label_text (bool can_colorize, const char *fmt, ...)
265 {
266 pretty_printer *pp = global_dc->printer->clone ();
267 pp_clear_output_area (pp);
268
269 if (!can_colorize)
270 pp_show_color (pp) = false;
271
272 text_info ti;
273 rich_location rich_loc (line_table, UNKNOWN_LOCATION);
274
275 va_list ap;
276
277 va_start (ap, fmt);
278
279 ti.format_spec = _(fmt);
280 ti.args_ptr = &ap;
281 ti.err_no = 0;
282 ti.x_data = NULL;
283 ti.m_richloc = &rich_loc;
284
285 pp_format (pp, &ti);
286 pp_output_formatted_text (pp);
287
288 va_end (ap);
289
290 label_text result = label_text::take (xstrdup (pp_formatted_text (pp)));
291 delete pp;
292 return result;
293 }
294
295 #endif /* #if ENABLE_ANALYZER */