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