1 /* Utility functions for the analyzer.
2 Copyright (C) 2019-2021 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
get_stmt_location(const gimple * stmt,function * fun)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 static tree
64 fixup_tree_for_diagnostic_1 (tree expr, hash_set<tree> *visited);
65
66 /* Subroutine of fixup_tree_for_diagnostic_1, called on SSA names.
67 Attempt to reconstruct a a tree expression for SSA_NAME
68 based on its def-stmt.
69 SSA_NAME must be non-NULL.
70 VISITED must be non-NULL; it is used to ensure termination.
71
72 Return NULL_TREE if there is a problem. */
73
74 static tree
maybe_reconstruct_from_def_stmt(tree ssa_name,hash_set<tree> * visited)75 maybe_reconstruct_from_def_stmt (tree ssa_name,
76 hash_set<tree> *visited)
77 {
78 /* Ensure termination. */
79 if (visited->contains (ssa_name))
80 return NULL_TREE;
81 visited->add (ssa_name);
82
83 gimple *def_stmt = SSA_NAME_DEF_STMT (ssa_name);
84
85 switch (gimple_code (def_stmt))
86 {
87 default:
88 gcc_unreachable ();
89 case GIMPLE_NOP:
90 case GIMPLE_PHI:
91 /* Can't handle these. */
92 return NULL_TREE;
93 case GIMPLE_ASSIGN:
94 {
95 enum tree_code code = gimple_assign_rhs_code (def_stmt);
96
97 /* Reverse the effect of extract_ops_from_tree during
98 gimplification. */
99 switch (get_gimple_rhs_class (code))
100 {
101 default:
102 case GIMPLE_INVALID_RHS:
103 gcc_unreachable ();
104 case GIMPLE_TERNARY_RHS:
105 case GIMPLE_BINARY_RHS:
106 case GIMPLE_UNARY_RHS:
107 {
108 tree t = make_node (code);
109 TREE_TYPE (t) = TREE_TYPE (ssa_name);
110 unsigned num_rhs_args = gimple_num_ops (def_stmt) - 1;
111 for (unsigned i = 0; i < num_rhs_args; i++)
112 {
113 tree op = gimple_op (def_stmt, i + 1);
114 if (op)
115 {
116 op = fixup_tree_for_diagnostic_1 (op, visited);
117 if (op == NULL_TREE)
118 return NULL_TREE;
119 }
120 TREE_OPERAND (t, i) = op;
121 }
122 return t;
123 }
124 case GIMPLE_SINGLE_RHS:
125 {
126 tree op = gimple_op (def_stmt, 1);
127 op = fixup_tree_for_diagnostic_1 (op, visited);
128 return op;
129 }
130 }
131 }
132 break;
133 case GIMPLE_CALL:
134 {
135 gcall *call_stmt = as_a <gcall *> (def_stmt);
136 tree return_type = gimple_call_return_type (call_stmt);
137 tree fn = fixup_tree_for_diagnostic_1 (gimple_call_fn (call_stmt),
138 visited);
139 unsigned num_args = gimple_call_num_args (call_stmt);
140 auto_vec<tree> args (num_args);
141 for (unsigned i = 0; i < num_args; i++)
142 {
143 tree arg = gimple_call_arg (call_stmt, i);
144 arg = fixup_tree_for_diagnostic_1 (arg, visited);
145 if (arg == NULL_TREE)
146 return NULL_TREE;
147 args.quick_push (arg);
148 }
149 return build_call_array_loc (gimple_location (call_stmt),
150 return_type, fn,
151 num_args, args.address ());
152 }
153 break;
154 }
155 }
156
157 /* Subroutine of fixup_tree_for_diagnostic: attempt to fixup EXPR,
158 which can be NULL.
159 VISITED must be non-NULL; it is used to ensure termination. */
160
161 static tree
fixup_tree_for_diagnostic_1(tree expr,hash_set<tree> * visited)162 fixup_tree_for_diagnostic_1 (tree expr, hash_set<tree> *visited)
163 {
164 if (expr
165 && TREE_CODE (expr) == SSA_NAME
166 && (SSA_NAME_VAR (expr) == NULL_TREE
167 || DECL_ARTIFICIAL (SSA_NAME_VAR (expr))))
168 if (tree expr2 = maybe_reconstruct_from_def_stmt (expr, visited))
169 return expr2;
170 return expr;
171 }
172
173 /* We don't want to print '<unknown>' in our diagnostics (PR analyzer/99771),
174 but sometimes we generate diagnostics involving an ssa name for a
175 temporary.
176
177 Work around this by attempting to reconstruct a tree expression for
178 such temporaries based on their def-stmts.
179
180 Otherwise return EXPR.
181
182 EXPR can be NULL. */
183
184 tree
fixup_tree_for_diagnostic(tree expr)185 fixup_tree_for_diagnostic (tree expr)
186 {
187 hash_set<tree> visited;
188 return fixup_tree_for_diagnostic_1 (expr, &visited);
189 }
190
191 } // namespace ana
192
193 /* Helper function for checkers. Is the CALL to the given function name,
194 and with the given number of arguments?
195
196 This doesn't resolve function pointers via the region model;
197 is_named_call_p should be used instead, using a fndecl from
198 get_fndecl_for_call; this function should only be used for special cases
199 where it's not practical to get at the region model, or for special
200 analyzer functions such as __analyzer_dump. */
201
202 bool
is_special_named_call_p(const gcall * call,const char * funcname,unsigned int num_args)203 is_special_named_call_p (const gcall *call, const char *funcname,
204 unsigned int num_args)
205 {
206 gcc_assert (funcname);
207
208 tree fndecl = gimple_call_fndecl (call);
209 if (!fndecl)
210 return false;
211
212 return is_named_call_p (fndecl, funcname, call, num_args);
213 }
214
215 /* Helper function for checkers. Is FNDECL an extern fndecl at file scope
216 that has the given FUNCNAME?
217
218 Compare with special_function_p in calls.c. */
219
220 bool
is_named_call_p(tree fndecl,const char * funcname)221 is_named_call_p (tree fndecl, const char *funcname)
222 {
223 gcc_assert (fndecl);
224 gcc_assert (funcname);
225
226 if (!maybe_special_function_p (fndecl))
227 return false;
228
229 tree identifier = DECL_NAME (fndecl);
230 const char *name = IDENTIFIER_POINTER (identifier);
231 const char *tname = name;
232
233 /* Potentially disregard prefix _ or __ in FNDECL's name, but not if
234 FUNCNAME itself has leading underscores (e.g. when looking for
235 "__analyzer_eval"). */
236 if (funcname[0] != '_' && name[0] == '_')
237 {
238 if (name[1] == '_')
239 tname += 2;
240 else
241 tname += 1;
242 }
243
244 return 0 == strcmp (tname, funcname);
245 }
246
247 /* Return true if FNDECL is within the namespace "std".
248 Compare with cp/typeck.c: decl_in_std_namespace_p, but this doesn't
249 rely on being the C++ FE (or handle inline namespaces inside of std). */
250
251 static inline bool
is_std_function_p(const_tree fndecl)252 is_std_function_p (const_tree fndecl)
253 {
254 tree name_decl = DECL_NAME (fndecl);
255 if (!name_decl)
256 return false;
257 if (!DECL_CONTEXT (fndecl))
258 return false;
259 if (TREE_CODE (DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
260 return false;
261 tree ns = DECL_CONTEXT (fndecl);
262 if (!(DECL_CONTEXT (ns) == NULL_TREE
263 || TREE_CODE (DECL_CONTEXT (ns)) == TRANSLATION_UNIT_DECL))
264 return false;
265 if (!DECL_NAME (ns))
266 return false;
267 return id_equal ("std", DECL_NAME (ns));
268 }
269
270 /* Like is_named_call_p, but look for std::FUNCNAME. */
271
272 bool
is_std_named_call_p(tree fndecl,const char * funcname)273 is_std_named_call_p (tree fndecl, const char *funcname)
274 {
275 gcc_assert (fndecl);
276 gcc_assert (funcname);
277
278 if (!is_std_function_p (fndecl))
279 return false;
280
281 tree identifier = DECL_NAME (fndecl);
282 const char *name = IDENTIFIER_POINTER (identifier);
283 const char *tname = name;
284
285 /* Don't disregard prefix _ or __ in FNDECL's name. */
286
287 return 0 == strcmp (tname, funcname);
288 }
289
290 /* Helper function for checkers. Is FNDECL an extern fndecl at file scope
291 that has the given FUNCNAME, and does CALL have the given number of
292 arguments? */
293
294 bool
is_named_call_p(tree fndecl,const char * funcname,const gcall * call,unsigned int num_args)295 is_named_call_p (tree fndecl, const char *funcname,
296 const gcall *call, unsigned int num_args)
297 {
298 gcc_assert (fndecl);
299 gcc_assert (funcname);
300
301 if (!is_named_call_p (fndecl, funcname))
302 return false;
303
304 if (gimple_call_num_args (call) != num_args)
305 return false;
306
307 return true;
308 }
309
310 /* Like is_named_call_p, but check for std::FUNCNAME. */
311
312 bool
is_std_named_call_p(tree fndecl,const char * funcname,const gcall * call,unsigned int num_args)313 is_std_named_call_p (tree fndecl, const char *funcname,
314 const gcall *call, unsigned int num_args)
315 {
316 gcc_assert (fndecl);
317 gcc_assert (funcname);
318
319 if (!is_std_named_call_p (fndecl, funcname))
320 return false;
321
322 if (gimple_call_num_args (call) != num_args)
323 return false;
324
325 return true;
326 }
327
328 /* Return true if stmt is a setjmp or sigsetjmp call. */
329
330 bool
is_setjmp_call_p(const gcall * call)331 is_setjmp_call_p (const gcall *call)
332 {
333 if (is_special_named_call_p (call, "setjmp", 1)
334 || is_special_named_call_p (call, "sigsetjmp", 2))
335 /* region_model::on_setjmp requires a pointer. */
336 if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
337 return true;
338
339 return false;
340 }
341
342 /* Return true if stmt is a longjmp or siglongjmp call. */
343
344 bool
is_longjmp_call_p(const gcall * call)345 is_longjmp_call_p (const gcall *call)
346 {
347 if (is_special_named_call_p (call, "longjmp", 2)
348 || is_special_named_call_p (call, "siglongjmp", 2))
349 /* exploded_node::on_longjmp requires a pointer for the initial
350 argument. */
351 if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
352 return true;
353
354 return false;
355 }
356
357 /* For a CALL that matched is_special_named_call_p or is_named_call_p for
358 some name, return a name for the called function suitable for use in
359 diagnostics (stripping the leading underscores). */
360
361 const char *
get_user_facing_name(const gcall * call)362 get_user_facing_name (const gcall *call)
363 {
364 tree fndecl = gimple_call_fndecl (call);
365 gcc_assert (fndecl);
366
367 tree identifier = DECL_NAME (fndecl);
368 gcc_assert (identifier);
369
370 const char *name = IDENTIFIER_POINTER (identifier);
371
372 /* Strip prefix _ or __ in FNDECL's name. */
373 if (name[0] == '_')
374 {
375 if (name[1] == '_')
376 return name + 2;
377 else
378 return name + 1;
379 }
380
381 return name;
382 }
383
384 /* Generate a label_text instance by formatting FMT, using a
385 temporary clone of the global_dc's printer (thus using its
386 formatting callbacks).
387
388 Colorize if the global_dc supports colorization and CAN_COLORIZE is
389 true. */
390
391 label_text
make_label_text(bool can_colorize,const char * fmt,...)392 make_label_text (bool can_colorize, const char *fmt, ...)
393 {
394 pretty_printer *pp = global_dc->printer->clone ();
395 pp_clear_output_area (pp);
396
397 if (!can_colorize)
398 pp_show_color (pp) = false;
399
400 text_info ti;
401 rich_location rich_loc (line_table, UNKNOWN_LOCATION);
402
403 va_list ap;
404
405 va_start (ap, fmt);
406
407 ti.format_spec = _(fmt);
408 ti.args_ptr = ≈
409 ti.err_no = 0;
410 ti.x_data = NULL;
411 ti.m_richloc = &rich_loc;
412
413 pp_format (pp, &ti);
414 pp_output_formatted_text (pp);
415
416 va_end (ap);
417
418 label_text result = label_text::take (xstrdup (pp_formatted_text (pp)));
419 delete pp;
420 return result;
421 }
422
423 #endif /* #if ENABLE_ANALYZER */
424