Branch data Line data Source code
1 : : /* Utility functions for the analyzer.
2 : : Copyright (C) 2019-2024 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 : : #define INCLUDE_MEMORY
23 : : #include "system.h"
24 : : #include "coretypes.h"
25 : : #include "tree.h"
26 : : #include "function.h"
27 : : #include "basic-block.h"
28 : : #include "gimple.h"
29 : : #include "diagnostic.h"
30 : : #include "intl.h"
31 : : #include "analyzer/analyzer.h"
32 : : #include "tree-pretty-print.h"
33 : : #include "diagnostic-event-id.h"
34 : : #include "tree-dfa.h"
35 : :
36 : : #if ENABLE_ANALYZER
37 : :
38 : : namespace ana {
39 : :
40 : : /* Workaround for missing location information for some stmts,
41 : : which ultimately should be solved by fixing the frontends
42 : : to provide the locations (TODO). */
43 : :
44 : : location_t
45 : 20515 : get_stmt_location (const gimple *stmt, function *fun)
46 : : {
47 : 20515 : if (!stmt)
48 : : return UNKNOWN_LOCATION;
49 : 20515 : if (get_pure_location (stmt->location) == UNKNOWN_LOCATION)
50 : : {
51 : : /* Workaround for missing location information for clobber
52 : : stmts, which seem to lack location information in the C frontend
53 : : at least. Created by gimplify_bind_expr, which uses the
54 : : BLOCK_SOURCE_END_LOCATION (BIND_EXPR_BLOCK (bind_expr))
55 : : but this is never set up when the block is created in
56 : : c_end_compound_stmt's pop_scope.
57 : : TODO: fix this missing location information.
58 : :
59 : : For now, as a hackish workaround, use the location of the end of
60 : : the function. */
61 : 384 : if (gimple_clobber_p (stmt) && fun)
62 : 384 : return fun->function_end_locus;
63 : : }
64 : :
65 : 20131 : return stmt->location;
66 : : }
67 : :
68 : : static tree
69 : : fixup_tree_for_diagnostic_1 (tree expr, hash_set<tree> *visited);
70 : :
71 : : /* Attemp to generate a tree for the LHS of ASSIGN_STMT.
72 : : VISITED must be non-NULL; it is used to ensure termination. */
73 : :
74 : : static tree
75 : 379718 : get_diagnostic_tree_for_gassign_1 (const gassign *assign_stmt,
76 : : hash_set<tree> *visited)
77 : : {
78 : 379718 : enum tree_code code = gimple_assign_rhs_code (assign_stmt);
79 : :
80 : : /* Reverse the effect of extract_ops_from_tree during
81 : : gimplification. */
82 : 379718 : switch (get_gimple_rhs_class (code))
83 : : {
84 : 0 : default:
85 : 0 : case GIMPLE_INVALID_RHS:
86 : 0 : gcc_unreachable ();
87 : 158220 : case GIMPLE_TERNARY_RHS:
88 : 158220 : case GIMPLE_BINARY_RHS:
89 : 158220 : case GIMPLE_UNARY_RHS:
90 : 158220 : {
91 : 158220 : tree t = make_node (code);
92 : 158220 : TREE_TYPE (t) = TREE_TYPE (gimple_assign_lhs (assign_stmt));
93 : 158220 : unsigned num_rhs_args = gimple_num_ops (assign_stmt) - 1;
94 : 422319 : for (unsigned i = 0; i < num_rhs_args; i++)
95 : : {
96 : 264099 : tree op = gimple_op (assign_stmt, i + 1);
97 : 264099 : if (op)
98 : : {
99 : 264099 : op = fixup_tree_for_diagnostic_1 (op, visited);
100 : 264099 : if (op == NULL_TREE)
101 : : return NULL_TREE;
102 : : }
103 : 264099 : TREE_OPERAND (t, i) = op;
104 : : }
105 : : return t;
106 : : }
107 : 221498 : case GIMPLE_SINGLE_RHS:
108 : 221498 : {
109 : 221498 : tree op = gimple_op (assign_stmt, 1);
110 : 221498 : op = fixup_tree_for_diagnostic_1 (op, visited);
111 : 221498 : return op;
112 : : }
113 : : }
114 : : }
115 : :
116 : : /* Subroutine of fixup_tree_for_diagnostic_1, called on SSA names.
117 : : Attempt to reconstruct a tree expression for SSA_NAME
118 : : based on its def-stmt.
119 : : SSA_NAME must be non-NULL.
120 : : VISITED must be non-NULL; it is used to ensure termination.
121 : :
122 : : Return NULL_TREE if there is a problem. */
123 : :
124 : : static tree
125 : 165279 : maybe_reconstruct_from_def_stmt (tree ssa_name,
126 : : hash_set<tree> *visited)
127 : : {
128 : : /* Ensure termination. */
129 : 165279 : if (visited->contains (ssa_name))
130 : : return NULL_TREE;
131 : 165176 : visited->add (ssa_name);
132 : :
133 : 165176 : gimple *def_stmt = SSA_NAME_DEF_STMT (ssa_name);
134 : :
135 : 165176 : switch (gimple_code (def_stmt))
136 : : {
137 : 0 : default:
138 : 0 : gcc_unreachable ();
139 : : case GIMPLE_ASM:
140 : : case GIMPLE_NOP:
141 : : case GIMPLE_PHI:
142 : : /* Can't handle these. */
143 : : return NULL_TREE;
144 : 131951 : case GIMPLE_ASSIGN:
145 : 131951 : return get_diagnostic_tree_for_gassign_1
146 : 131951 : (as_a <const gassign *> (def_stmt), visited);
147 : 29474 : case GIMPLE_CALL:
148 : 29474 : {
149 : 29474 : gcall *call_stmt = as_a <gcall *> (def_stmt);
150 : 29474 : tree return_type = gimple_call_return_type (call_stmt);
151 : 29474 : tree fn = fixup_tree_for_diagnostic_1 (gimple_call_fn (call_stmt),
152 : : visited);
153 : 29474 : if (fn == NULL_TREE)
154 : : return NULL_TREE;
155 : 29234 : unsigned num_args = gimple_call_num_args (call_stmt);
156 : 29234 : auto_vec<tree> args (num_args);
157 : 65201 : for (unsigned i = 0; i < num_args; i++)
158 : : {
159 : 35967 : tree arg = gimple_call_arg (call_stmt, i);
160 : 35967 : arg = fixup_tree_for_diagnostic_1 (arg, visited);
161 : 35967 : if (arg == NULL_TREE)
162 : 0 : return NULL_TREE;
163 : 35967 : args.quick_push (arg);
164 : : }
165 : 29234 : gcc_assert (fn);
166 : 29234 : return build_call_array_loc (gimple_location (call_stmt),
167 : : return_type, fn,
168 : 29234 : num_args, args.address ());
169 : 29234 : }
170 : : break;
171 : : }
172 : : }
173 : :
174 : : /* Subroutine of fixup_tree_for_diagnostic: attempt to fixup EXPR,
175 : : which can be NULL.
176 : : VISITED must be non-NULL; it is used to ensure termination. */
177 : :
178 : : static tree
179 : 582958 : fixup_tree_for_diagnostic_1 (tree expr, hash_set<tree> *visited)
180 : : {
181 : 582958 : if (expr
182 : 568746 : && TREE_CODE (expr) == SSA_NAME
183 : 856937 : && (SSA_NAME_VAR (expr) == NULL_TREE
184 : 109454 : || DECL_ARTIFICIAL (SSA_NAME_VAR (expr))))
185 : : {
186 : 165476 : if (tree var = SSA_NAME_VAR (expr))
187 : 951 : if (VAR_P (var) && DECL_HAS_DEBUG_EXPR_P (var))
188 : 197 : return DECL_DEBUG_EXPR (var);
189 : 165279 : if (tree expr2 = maybe_reconstruct_from_def_stmt (expr, visited))
190 : : return expr2;
191 : : }
192 : : return expr;
193 : : }
194 : :
195 : : /* We don't want to print '<unknown>' in our diagnostics (PR analyzer/99771),
196 : : but sometimes we generate diagnostics involving an ssa name for a
197 : : temporary.
198 : :
199 : : Work around this by attempting to reconstruct a tree expression for
200 : : such temporaries based on their def-stmts.
201 : :
202 : : Otherwise return EXPR.
203 : :
204 : : EXPR can be NULL. */
205 : :
206 : : tree
207 : 31920 : fixup_tree_for_diagnostic (tree expr)
208 : : {
209 : 31920 : hash_set<tree> visited;
210 : 31920 : return fixup_tree_for_diagnostic_1 (expr, &visited);
211 : 31920 : }
212 : :
213 : : /* Attempt to generate a tree for the LHS of ASSIGN_STMT. */
214 : :
215 : : tree
216 : 247767 : get_diagnostic_tree_for_gassign (const gassign *assign_stmt)
217 : : {
218 : 247767 : hash_set<tree> visited;
219 : 247767 : return get_diagnostic_tree_for_gassign_1 (assign_stmt, &visited);
220 : 247767 : }
221 : :
222 : : /* Generate a JSON value for NODE, which can be NULL_TREE.
223 : : This is intended for debugging the analyzer rather than serialization and
224 : : thus is a string (or null, for NULL_TREE). */
225 : :
226 : : json::value *
227 : 15 : tree_to_json (tree node)
228 : : {
229 : 15 : if (!node)
230 : 0 : return new json::literal (json::JSON_NULL);
231 : :
232 : 15 : pretty_printer pp;
233 : 15 : dump_generic_node (&pp, node, 0, TDF_VOPS|TDF_MEMSYMS, false);
234 : 15 : return new json::string (pp_formatted_text (&pp));
235 : 15 : }
236 : :
237 : : /* Generate a JSON value for EVENT_ID.
238 : : This is intended for debugging the analyzer rather than serialization and
239 : : thus is a string matching those seen in event messags (or null,
240 : : for unknown). */
241 : :
242 : : json::value *
243 : 55 : diagnostic_event_id_to_json (const diagnostic_event_id_t &event_id)
244 : : {
245 : 55 : if (event_id.known_p ())
246 : : {
247 : 55 : pretty_printer pp;
248 : 55 : pp_printf (&pp, "%@", &event_id);
249 : 55 : return new json::string (pp_formatted_text (&pp));
250 : 55 : }
251 : : else
252 : 0 : return new json::literal (json::JSON_NULL);
253 : : }
254 : :
255 : : /* Generate a JSON value for OFFSET.
256 : : This is intended for debugging the analyzer rather than serialization and
257 : : thus is a string. */
258 : :
259 : : json::value *
260 : 10 : bit_offset_to_json (const bit_offset_t &offset)
261 : : {
262 : 10 : pretty_printer pp;
263 : 10 : pp_wide_int_large (&pp, offset, SIGNED);
264 : 10 : return new json::string (pp_formatted_text (&pp));
265 : 10 : }
266 : :
267 : : /* Generate a JSON value for OFFSET.
268 : : This is intended for debugging the analyzer rather than serialization and
269 : : thus is a string. */
270 : :
271 : : json::value *
272 : 10 : byte_offset_to_json (const byte_offset_t &offset)
273 : : {
274 : 10 : pretty_printer pp;
275 : 10 : pp_wide_int_large (&pp, offset, SIGNED);
276 : 10 : return new json::string (pp_formatted_text (&pp));
277 : 10 : }
278 : :
279 : : /* Workaround for lack of const-correctness of ssa_default_def. */
280 : :
281 : : tree
282 : 37307 : get_ssa_default_def (const function &fun, tree var)
283 : : {
284 : 37307 : return ssa_default_def (const_cast <function *> (&fun), var);
285 : : }
286 : :
287 : : } // namespace ana
288 : :
289 : : /* Helper function for checkers. Is the CALL to the given function name,
290 : : and with the given number of arguments?
291 : :
292 : : This doesn't resolve function pointers via the region model;
293 : : is_named_call_p should be used instead, using a fndecl from
294 : : get_fndecl_for_call; this function should only be used for special cases
295 : : where it's not practical to get at the region model, or for special
296 : : analyzer functions such as __analyzer_dump. */
297 : :
298 : : bool
299 : 514631 : is_special_named_call_p (const gcall *call, const char *funcname,
300 : : unsigned int num_args)
301 : : {
302 : 514631 : gcc_assert (funcname);
303 : :
304 : 514631 : tree fndecl = gimple_call_fndecl (call);
305 : 514631 : if (!fndecl)
306 : : return false;
307 : :
308 : 501609 : return is_named_call_p (fndecl, funcname, call, num_args);
309 : : }
310 : :
311 : : /* Helper function for checkers. Is FNDECL an extern fndecl at file scope
312 : : that has the given FUNCNAME?
313 : :
314 : : Compare with special_function_p in calls.cc. */
315 : :
316 : : bool
317 : 2498773 : is_named_call_p (const_tree fndecl, const char *funcname)
318 : : {
319 : 2498773 : gcc_assert (fndecl);
320 : 2498773 : gcc_assert (funcname);
321 : :
322 : 2498773 : if (!maybe_special_function_p (fndecl))
323 : : return false;
324 : :
325 : 2344180 : tree identifier = DECL_NAME (fndecl);
326 : 2344180 : const char *name = IDENTIFIER_POINTER (identifier);
327 : 2344180 : const char *tname = name;
328 : :
329 : : /* Potentially disregard prefix _ or __ in FNDECL's name, but not if
330 : : FUNCNAME itself has leading underscores (e.g. when looking for
331 : : "__analyzer_eval"). */
332 : 2344180 : if (funcname[0] != '_' && name[0] == '_')
333 : : {
334 : 922479 : if (name[1] == '_')
335 : 917637 : tname += 2;
336 : : else
337 : 4842 : tname += 1;
338 : : }
339 : :
340 : 2344180 : return 0 == strcmp (tname, funcname);
341 : : }
342 : :
343 : : /* Return true if FNDECL is within the namespace "std".
344 : : Compare with cp/typeck.cc: decl_in_std_namespace_p, but this doesn't
345 : : rely on being the C++ FE (or handle inline namespaces inside of std). */
346 : :
347 : : static inline bool
348 : 178069 : is_std_function_p (const_tree fndecl)
349 : : {
350 : 178069 : tree name_decl = DECL_NAME (fndecl);
351 : 178069 : if (!name_decl)
352 : : return false;
353 : 178069 : if (!DECL_CONTEXT (fndecl))
354 : : return false;
355 : 176606 : if (TREE_CODE (DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
356 : : return false;
357 : 87 : tree ns = DECL_CONTEXT (fndecl);
358 : 87 : if (!(DECL_CONTEXT (ns) == NULL_TREE
359 : 72 : || TREE_CODE (DECL_CONTEXT (ns)) == TRANSLATION_UNIT_DECL))
360 : : return false;
361 : 87 : if (!DECL_NAME (ns))
362 : : return false;
363 : 87 : return id_equal ("std", DECL_NAME (ns));
364 : : }
365 : :
366 : : /* Like is_named_call_p, but look for std::FUNCNAME. */
367 : :
368 : : bool
369 : 178069 : is_std_named_call_p (const_tree fndecl, const char *funcname)
370 : : {
371 : 178069 : gcc_assert (fndecl);
372 : 178069 : gcc_assert (funcname);
373 : :
374 : 178069 : if (!is_std_function_p (fndecl))
375 : : return false;
376 : :
377 : 48 : tree identifier = DECL_NAME (fndecl);
378 : 48 : const char *name = IDENTIFIER_POINTER (identifier);
379 : 48 : const char *tname = name;
380 : :
381 : : /* Don't disregard prefix _ or __ in FNDECL's name. */
382 : :
383 : 48 : return 0 == strcmp (tname, funcname);
384 : : }
385 : :
386 : : /* Helper function for checkers. Is FNDECL an extern fndecl at file scope
387 : : that has the given FUNCNAME, and does CALL have the given number of
388 : : arguments? */
389 : :
390 : : bool
391 : 2256378 : is_named_call_p (const_tree fndecl, const char *funcname,
392 : : const gcall *call, unsigned int num_args)
393 : : {
394 : 2256378 : gcc_assert (fndecl);
395 : 2256378 : gcc_assert (funcname);
396 : :
397 : 2256378 : if (!is_named_call_p (fndecl, funcname))
398 : : return false;
399 : :
400 : 24461 : if (gimple_call_num_args (call) != num_args)
401 : 868 : return false;
402 : :
403 : : return true;
404 : : }
405 : :
406 : : /* Like is_named_call_p, but check for std::FUNCNAME. */
407 : :
408 : : bool
409 : 177985 : is_std_named_call_p (const_tree fndecl, const char *funcname,
410 : : const gcall *call, unsigned int num_args)
411 : : {
412 : 177985 : gcc_assert (fndecl);
413 : 177985 : gcc_assert (funcname);
414 : :
415 : 177985 : if (!is_std_named_call_p (fndecl, funcname))
416 : : return false;
417 : :
418 : 16 : if (gimple_call_num_args (call) != num_args)
419 : 0 : return false;
420 : :
421 : : return true;
422 : : }
423 : :
424 : : /* Return true if stmt is a setjmp or sigsetjmp call. */
425 : :
426 : : bool
427 : 75561 : is_setjmp_call_p (const gcall *call)
428 : : {
429 : 75561 : if (is_special_named_call_p (call, "setjmp", 1)
430 : 75561 : || is_special_named_call_p (call, "sigsetjmp", 2))
431 : : /* region_model::on_setjmp requires a pointer. */
432 : 83 : if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
433 : : return true;
434 : :
435 : : return false;
436 : : }
437 : :
438 : : /* Return true if stmt is a longjmp or siglongjmp call. */
439 : :
440 : : bool
441 : 66485 : is_longjmp_call_p (const gcall *call)
442 : : {
443 : 66485 : if (is_special_named_call_p (call, "longjmp", 2)
444 : 66485 : || is_special_named_call_p (call, "siglongjmp", 2))
445 : : /* exploded_node::on_longjmp requires a pointer for the initial
446 : : argument. */
447 : 79 : if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
448 : : return true;
449 : :
450 : : return false;
451 : : }
452 : :
453 : : /* For a CALL that matched is_special_named_call_p or is_named_call_p for
454 : : some name, return a name for the called function suitable for use in
455 : : diagnostics (stripping the leading underscores). */
456 : :
457 : : const char *
458 : 150 : get_user_facing_name (const gcall *call)
459 : : {
460 : 150 : tree fndecl = gimple_call_fndecl (call);
461 : 150 : gcc_assert (fndecl);
462 : :
463 : 150 : tree identifier = DECL_NAME (fndecl);
464 : 150 : gcc_assert (identifier);
465 : :
466 : 150 : const char *name = IDENTIFIER_POINTER (identifier);
467 : :
468 : : /* Strip prefix _ or __ in FNDECL's name. */
469 : 150 : if (name[0] == '_')
470 : : {
471 : 0 : if (name[1] == '_')
472 : 0 : return name + 2;
473 : : else
474 : 0 : return name + 1;
475 : : }
476 : :
477 : : return name;
478 : : }
479 : :
480 : : /* Generate a label_text instance by formatting FMT, using a
481 : : temporary clone of the global_dc's printer (thus using its
482 : : formatting callbacks).
483 : :
484 : : Colorize if the global_dc supports colorization and CAN_COLORIZE is
485 : : true. */
486 : :
487 : : label_text
488 : 21791 : make_label_text (bool can_colorize, const char *fmt, ...)
489 : : {
490 : 21791 : pretty_printer *pp = global_dc->printer->clone ();
491 : 21791 : pp_clear_output_area (pp);
492 : :
493 : 21791 : if (!can_colorize)
494 : 21791 : pp_show_color (pp) = false;
495 : :
496 : 21791 : rich_location rich_loc (line_table, UNKNOWN_LOCATION);
497 : :
498 : 21791 : va_list ap;
499 : :
500 : 21791 : va_start (ap, fmt);
501 : :
502 : 21791 : text_info ti (_(fmt), &ap, 0, NULL, &rich_loc);
503 : 21791 : pp_format (pp, &ti);
504 : 21791 : pp_output_formatted_text (pp);
505 : :
506 : 21791 : va_end (ap);
507 : :
508 : 21791 : label_text result = label_text::take (xstrdup (pp_formatted_text (pp)));
509 : 21791 : delete pp;
510 : 43582 : return result;
511 : 21791 : }
512 : :
513 : : /* As above, but with singular vs plural. */
514 : :
515 : : label_text
516 : 1828 : make_label_text_n (bool can_colorize, unsigned HOST_WIDE_INT n,
517 : : const char *singular_fmt,
518 : : const char *plural_fmt, ...)
519 : : {
520 : 1828 : pretty_printer *pp = global_dc->printer->clone ();
521 : 1828 : pp_clear_output_area (pp);
522 : :
523 : 1828 : if (!can_colorize)
524 : 1828 : pp_show_color (pp) = false;
525 : :
526 : 1828 : rich_location rich_loc (line_table, UNKNOWN_LOCATION);
527 : :
528 : 1828 : va_list ap;
529 : :
530 : 1828 : va_start (ap, plural_fmt);
531 : :
532 : 1828 : const char *fmt = ngettext (singular_fmt, plural_fmt, n);
533 : :
534 : 1828 : text_info ti (fmt, &ap, 0, NULL, &rich_loc);
535 : :
536 : 1828 : pp_format (pp, &ti);
537 : 1828 : pp_output_formatted_text (pp);
538 : :
539 : 1828 : va_end (ap);
540 : :
541 : 1828 : label_text result = label_text::take (xstrdup (pp_formatted_text (pp)));
542 : 1828 : delete pp;
543 : 3656 : return result;
544 : 1828 : }
545 : :
546 : : #endif /* #if ENABLE_ANALYZER */
|