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 : : #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 "analyzer/analyzer.h"
31 : : #include "tree-pretty-print.h"
32 : : #include "diagnostic-event-id.h"
33 : : #include "tree-dfa.h"
34 : : #include "make-unique.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 : 17444 : get_stmt_location (const gimple *stmt, function *fun)
46 : : {
47 : 17444 : if (!stmt)
48 : : return UNKNOWN_LOCATION;
49 : 17365 : 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 : 347 : if (gimple_clobber_p (stmt) && fun)
62 : 347 : return fun->function_end_locus;
63 : : }
64 : :
65 : 17018 : 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 : 314118 : get_diagnostic_tree_for_gassign_1 (const gassign *assign_stmt,
76 : : hash_set<tree> *visited)
77 : : {
78 : 314118 : enum tree_code code = gimple_assign_rhs_code (assign_stmt);
79 : :
80 : : /* Reverse the effect of extract_ops_from_tree during
81 : : gimplification. */
82 : 314118 : switch (get_gimple_rhs_class (code))
83 : : {
84 : 0 : default:
85 : 0 : case GIMPLE_INVALID_RHS:
86 : 0 : gcc_unreachable ();
87 : 134030 : case GIMPLE_TERNARY_RHS:
88 : 134030 : case GIMPLE_BINARY_RHS:
89 : 134030 : case GIMPLE_UNARY_RHS:
90 : 134030 : {
91 : 134030 : tree t = make_node (code);
92 : 134030 : TREE_TYPE (t) = TREE_TYPE (gimple_assign_lhs (assign_stmt));
93 : 134030 : unsigned num_rhs_args = gimple_num_ops (assign_stmt) - 1;
94 : 357667 : for (unsigned i = 0; i < num_rhs_args; i++)
95 : : {
96 : 223637 : tree op = gimple_op (assign_stmt, i + 1);
97 : 223637 : if (op)
98 : : {
99 : 223637 : op = fixup_tree_for_diagnostic_1 (op, visited);
100 : 223637 : if (op == NULL_TREE)
101 : : return NULL_TREE;
102 : : }
103 : 223637 : TREE_OPERAND (t, i) = op;
104 : : }
105 : : return t;
106 : : }
107 : 180088 : case GIMPLE_SINGLE_RHS:
108 : 180088 : {
109 : 180088 : tree op = gimple_op (assign_stmt, 1);
110 : 180088 : op = fixup_tree_for_diagnostic_1 (op, visited);
111 : 180088 : 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 : 134639 : maybe_reconstruct_from_def_stmt (tree ssa_name,
126 : : hash_set<tree> *visited)
127 : : {
128 : : /* Ensure termination. */
129 : 134639 : if (visited->contains (ssa_name))
130 : : return NULL_TREE;
131 : 134549 : visited->add (ssa_name);
132 : :
133 : 134549 : gimple *def_stmt = SSA_NAME_DEF_STMT (ssa_name);
134 : :
135 : 134549 : 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 : 108157 : case GIMPLE_ASSIGN:
145 : 108157 : return get_diagnostic_tree_for_gassign_1
146 : 108157 : (as_a <const gassign *> (def_stmt), visited);
147 : 23991 : case GIMPLE_CALL:
148 : 23991 : {
149 : 23991 : gcall *call_stmt = as_a <gcall *> (def_stmt);
150 : 23991 : tree return_type = gimple_call_return_type (call_stmt);
151 : 23991 : tree fn = fixup_tree_for_diagnostic_1 (gimple_call_fn (call_stmt),
152 : : visited);
153 : 23991 : if (fn == NULL_TREE)
154 : : return NULL_TREE;
155 : 23751 : unsigned num_args = gimple_call_num_args (call_stmt);
156 : 23751 : auto_vec<tree> args (num_args);
157 : 51687 : for (unsigned i = 0; i < num_args; i++)
158 : : {
159 : 27936 : tree arg = gimple_call_arg (call_stmt, i);
160 : 27936 : arg = fixup_tree_for_diagnostic_1 (arg, visited);
161 : 27936 : if (arg == NULL_TREE)
162 : 0 : return NULL_TREE;
163 : 27936 : args.quick_push (arg);
164 : : }
165 : 23751 : gcc_assert (fn);
166 : 23751 : return build_call_array_loc (gimple_location (call_stmt),
167 : : return_type, fn,
168 : 23751 : num_args, args.address ());
169 : 23751 : }
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 : 483080 : fixup_tree_for_diagnostic_1 (tree expr, hash_set<tree> *visited)
180 : : {
181 : 483080 : if (expr
182 : 470776 : && TREE_CODE (expr) == SSA_NAME
183 : 710538 : && (SSA_NAME_VAR (expr) == NULL_TREE
184 : 93392 : || DECL_ARTIFICIAL (SSA_NAME_VAR (expr))))
185 : : {
186 : 134835 : if (tree var = SSA_NAME_VAR (expr))
187 : 769 : if (VAR_P (var) && DECL_HAS_DEBUG_EXPR_P (var))
188 : 196 : return DECL_DEBUG_EXPR (var);
189 : 134639 : 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 : 27428 : fixup_tree_for_diagnostic (tree expr)
208 : : {
209 : 27428 : hash_set<tree> visited;
210 : 27428 : return fixup_tree_for_diagnostic_1 (expr, &visited);
211 : 27428 : }
212 : :
213 : : /* Attempt to generate a tree for the LHS of ASSIGN_STMT. */
214 : :
215 : : tree
216 : 205961 : get_diagnostic_tree_for_gassign (const gassign *assign_stmt)
217 : : {
218 : 205961 : hash_set<tree> visited;
219 : 205961 : return get_diagnostic_tree_for_gassign_1 (assign_stmt, &visited);
220 : 205961 : }
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 : : std::unique_ptr<json::value>
227 : 12 : tree_to_json (tree node)
228 : : {
229 : 12 : if (!node)
230 : 0 : return ::make_unique<json::literal> (json::JSON_NULL);
231 : :
232 : 12 : pretty_printer pp;
233 : 12 : dump_generic_node (&pp, node, 0, TDF_VOPS|TDF_MEMSYMS, false);
234 : 12 : return ::make_unique<json::string> (pp_formatted_text (&pp));
235 : 12 : }
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 : : std::unique_ptr<json::value>
243 : 58 : diagnostic_event_id_to_json (const diagnostic_event_id_t &event_id)
244 : : {
245 : 58 : if (event_id.known_p ())
246 : : {
247 : 58 : pretty_printer pp;
248 : 58 : pp_printf (&pp, "%@", &event_id);
249 : 58 : return ::make_unique<json::string> (pp_formatted_text (&pp));
250 : 58 : }
251 : : else
252 : 0 : return ::make_unique<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 : : std::unique_ptr<json::value>
260 : 8 : bit_offset_to_json (const bit_offset_t &offset)
261 : : {
262 : 8 : pretty_printer pp;
263 : 8 : pp_wide_int_large (&pp, offset, SIGNED);
264 : 8 : return ::make_unique<json::string> (pp_formatted_text (&pp));
265 : 8 : }
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 : : std::unique_ptr<json::value>
272 : 8 : byte_offset_to_json (const byte_offset_t &offset)
273 : : {
274 : 8 : pretty_printer pp;
275 : 8 : pp_wide_int_large (&pp, offset, SIGNED);
276 : 8 : return ::make_unique<json::string> (pp_formatted_text (&pp));
277 : 8 : }
278 : :
279 : : /* Workaround for lack of const-correctness of ssa_default_def. */
280 : :
281 : : tree
282 : 32041 : get_ssa_default_def (const function &fun, tree var)
283 : : {
284 : 32041 : 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 : : If LOOK_IN_STD is true, then also look for within std:: for the name. */
299 : :
300 : : bool
301 : 429087 : is_special_named_call_p (const gcall *call, const char *funcname,
302 : : unsigned int num_args, bool look_in_std)
303 : : {
304 : 429087 : gcc_assert (funcname);
305 : :
306 : 429087 : tree fndecl = gimple_call_fndecl (call);
307 : 429087 : if (!fndecl)
308 : : return false;
309 : :
310 : 417502 : if (is_named_call_p (fndecl, funcname, call, num_args))
311 : : return true;
312 : 415564 : if (look_in_std)
313 : 21128 : if (is_std_named_call_p (fndecl, funcname, call, num_args))
314 : : return true;
315 : : return false;
316 : : }
317 : :
318 : : /* Helper function for checkers. Is FNDECL an extern fndecl at file scope
319 : : that has the given FUNCNAME?
320 : :
321 : : Compare with special_function_p in calls.cc. */
322 : :
323 : : bool
324 : 2076473 : is_named_call_p (const_tree fndecl, const char *funcname)
325 : : {
326 : 2076473 : gcc_assert (fndecl);
327 : 2076473 : gcc_assert (funcname);
328 : :
329 : 2076473 : if (!maybe_special_function_p (fndecl))
330 : : return false;
331 : :
332 : 1948677 : tree identifier = DECL_NAME (fndecl);
333 : 1948677 : const char *name = IDENTIFIER_POINTER (identifier);
334 : 1948677 : const char *tname = name;
335 : :
336 : : /* Potentially disregard prefix _ or __ in FNDECL's name, but not if
337 : : FUNCNAME itself has leading underscores (e.g. when looking for
338 : : "__analyzer_eval"). */
339 : 1948677 : if (funcname[0] != '_' && name[0] == '_')
340 : : {
341 : 764067 : if (name[1] == '_')
342 : 759541 : tname += 2;
343 : : else
344 : 4526 : tname += 1;
345 : : }
346 : :
347 : 1948677 : return 0 == strcmp (tname, funcname);
348 : : }
349 : :
350 : : /* Return true if FNDECL is within the namespace "std".
351 : : Compare with cp/typeck.cc: decl_in_std_namespace_p, but this doesn't
352 : : rely on being the C++ FE (or handle inline namespaces inside of std). */
353 : :
354 : : bool
355 : 593390 : is_std_function_p (const_tree fndecl)
356 : : {
357 : 593390 : tree name_decl = DECL_NAME (fndecl);
358 : 593390 : if (!name_decl)
359 : : return false;
360 : 593390 : if (!DECL_CONTEXT (fndecl))
361 : : return false;
362 : 587436 : if (TREE_CODE (DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
363 : : return false;
364 : 305 : tree ns = DECL_CONTEXT (fndecl);
365 : 305 : if (!(DECL_CONTEXT (ns) == NULL_TREE
366 : 237 : || TREE_CODE (DECL_CONTEXT (ns)) == TRANSLATION_UNIT_DECL))
367 : : return false;
368 : 305 : if (!DECL_NAME (ns))
369 : : return false;
370 : 305 : return id_equal ("std", DECL_NAME (ns));
371 : : }
372 : :
373 : : /* Like is_named_call_p, but look for std::FUNCNAME. */
374 : :
375 : : bool
376 : 257813 : is_std_named_call_p (const_tree fndecl, const char *funcname)
377 : : {
378 : 257813 : gcc_assert (fndecl);
379 : 257813 : gcc_assert (funcname);
380 : :
381 : 257813 : if (!is_std_function_p (fndecl))
382 : : return false;
383 : :
384 : 57 : tree identifier = DECL_NAME (fndecl);
385 : 57 : const char *name = IDENTIFIER_POINTER (identifier);
386 : 57 : const char *tname = name;
387 : :
388 : : /* Don't disregard prefix _ or __ in FNDECL's name. */
389 : :
390 : 57 : return 0 == strcmp (tname, funcname);
391 : : }
392 : :
393 : : /* Helper function for checkers. Is FNDECL an extern fndecl at file scope
394 : : that has the given FUNCNAME, and does CALL have the given number of
395 : : arguments? */
396 : :
397 : : bool
398 : 1874913 : is_named_call_p (const_tree fndecl, const char *funcname,
399 : : const gcall *call, unsigned int num_args)
400 : : {
401 : 1874913 : gcc_assert (fndecl);
402 : 1874913 : gcc_assert (funcname);
403 : :
404 : 1874913 : if (!is_named_call_p (fndecl, funcname))
405 : : return false;
406 : :
407 : 20004 : if (gimple_call_num_args (call) != num_args)
408 : 678 : return false;
409 : :
410 : : return true;
411 : : }
412 : :
413 : : /* Like is_named_call_p, but check for std::FUNCNAME. */
414 : :
415 : : bool
416 : 257742 : is_std_named_call_p (const_tree fndecl, const char *funcname,
417 : : const gcall *call, unsigned int num_args)
418 : : {
419 : 257742 : gcc_assert (fndecl);
420 : 257742 : gcc_assert (funcname);
421 : :
422 : 257742 : if (!is_std_named_call_p (fndecl, funcname))
423 : : return false;
424 : :
425 : 12 : if (gimple_call_num_args (call) != num_args)
426 : 0 : return false;
427 : :
428 : : return true;
429 : : }
430 : :
431 : : /* Return true if stmt is a setjmp or sigsetjmp call. */
432 : :
433 : : bool
434 : 63230 : is_setjmp_call_p (const gcall *call)
435 : : {
436 : 63230 : if (is_special_named_call_p (call, "setjmp", 1)
437 : 63230 : || is_special_named_call_p (call, "sigsetjmp", 2))
438 : : /* region_model::on_setjmp requires a pointer. */
439 : 70 : if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
440 : : return true;
441 : :
442 : : return false;
443 : : }
444 : :
445 : : /* Return true if stmt is a longjmp or siglongjmp call. */
446 : :
447 : : bool
448 : 55269 : is_longjmp_call_p (const gcall *call)
449 : : {
450 : 55269 : if (is_special_named_call_p (call, "longjmp", 2)
451 : 55269 : || is_special_named_call_p (call, "siglongjmp", 2))
452 : : /* exploded_node::on_longjmp requires a pointer for the initial
453 : : argument. */
454 : 67 : if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
455 : : return true;
456 : :
457 : : return false;
458 : : }
459 : :
460 : : /* For a CALL that matched is_special_named_call_p or is_named_call_p for
461 : : some name, return a name for the called function suitable for use in
462 : : diagnostics (stripping the leading underscores). */
463 : :
464 : : const char *
465 : 130 : get_user_facing_name (const gcall *call)
466 : : {
467 : 130 : tree fndecl = gimple_call_fndecl (call);
468 : 130 : gcc_assert (fndecl);
469 : :
470 : 130 : tree identifier = DECL_NAME (fndecl);
471 : 130 : gcc_assert (identifier);
472 : :
473 : 130 : const char *name = IDENTIFIER_POINTER (identifier);
474 : :
475 : : /* Strip prefix _ or __ in FNDECL's name. */
476 : 130 : if (name[0] == '_')
477 : : {
478 : 0 : if (name[1] == '_')
479 : 0 : return name + 2;
480 : : else
481 : 0 : return name + 1;
482 : : }
483 : :
484 : : return name;
485 : : }
486 : :
487 : : /* Generate a label_text instance by formatting FMT, using a
488 : : temporary clone of the global_dc's printer (thus using its
489 : : formatting callbacks).
490 : :
491 : : Colorize if the global_dc supports colorization and CAN_COLORIZE is
492 : : true. */
493 : :
494 : : label_text
495 : 3971 : make_label_text (bool can_colorize, const char *fmt, ...)
496 : : {
497 : 3971 : std::unique_ptr<pretty_printer> pp (global_dc->clone_printer ());
498 : 3971 : pp_clear_output_area (pp.get ());
499 : :
500 : 3971 : if (!can_colorize)
501 : 3968 : pp_show_color (pp.get ()) = false;
502 : :
503 : 3971 : rich_location rich_loc (line_table, UNKNOWN_LOCATION);
504 : :
505 : 3971 : va_list ap;
506 : :
507 : 3971 : va_start (ap, fmt);
508 : :
509 : 3971 : text_info ti (_(fmt), &ap, 0, NULL, &rich_loc);
510 : 3971 : pp_format (pp.get (), &ti);
511 : 3971 : pp_output_formatted_text (pp.get ());
512 : :
513 : 3971 : va_end (ap);
514 : :
515 : 3971 : label_text result = label_text::take (xstrdup (pp_formatted_text (pp.get ())));
516 : 7942 : return result;
517 : 3971 : }
518 : :
519 : : /* As above, but with singular vs plural. */
520 : :
521 : : label_text
522 : 0 : make_label_text_n (bool can_colorize, unsigned HOST_WIDE_INT n,
523 : : const char *singular_fmt,
524 : : const char *plural_fmt, ...)
525 : : {
526 : 0 : std::unique_ptr<pretty_printer> pp (global_dc->clone_printer ());
527 : 0 : pp_clear_output_area (pp.get ());
528 : :
529 : 0 : if (!can_colorize)
530 : 0 : pp_show_color (pp.get ()) = false;
531 : :
532 : 0 : rich_location rich_loc (line_table, UNKNOWN_LOCATION);
533 : :
534 : 0 : va_list ap;
535 : :
536 : 0 : va_start (ap, plural_fmt);
537 : :
538 : 0 : const char *fmt = ngettext (singular_fmt, plural_fmt, n);
539 : :
540 : 0 : text_info ti (fmt, &ap, 0, NULL, &rich_loc);
541 : :
542 : 0 : pp_format (pp.get (), &ti);
543 : 0 : pp_output_formatted_text (pp.get ());
544 : :
545 : 0 : va_end (ap);
546 : :
547 : 0 : label_text result
548 : 0 : = label_text::take (xstrdup (pp_formatted_text (pp.get ())));
549 : 0 : return result;
550 : 0 : }
551 : :
552 : : #endif /* #if ENABLE_ANALYZER */
|