]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/analyzer/analyzer.cc
analyzer: fix ICE on negative values for size_t [PR114472]
[thirdparty/gcc.git] / gcc / analyzer / analyzer.cc
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 get_stmt_location (const gimple *stmt, function *fun)
46 {
47 if (!stmt)
48 return UNKNOWN_LOCATION;
49 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 if (gimple_clobber_p (stmt) && fun)
62 return fun->function_end_locus;
63 }
64
65 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 get_diagnostic_tree_for_gassign_1 (const gassign *assign_stmt,
76 hash_set<tree> *visited)
77 {
78 enum tree_code code = gimple_assign_rhs_code (assign_stmt);
79
80 /* Reverse the effect of extract_ops_from_tree during
81 gimplification. */
82 switch (get_gimple_rhs_class (code))
83 {
84 default:
85 case GIMPLE_INVALID_RHS:
86 gcc_unreachable ();
87 case GIMPLE_TERNARY_RHS:
88 case GIMPLE_BINARY_RHS:
89 case GIMPLE_UNARY_RHS:
90 {
91 tree t = make_node (code);
92 TREE_TYPE (t) = TREE_TYPE (gimple_assign_lhs (assign_stmt));
93 unsigned num_rhs_args = gimple_num_ops (assign_stmt) - 1;
94 for (unsigned i = 0; i < num_rhs_args; i++)
95 {
96 tree op = gimple_op (assign_stmt, i + 1);
97 if (op)
98 {
99 op = fixup_tree_for_diagnostic_1 (op, visited);
100 if (op == NULL_TREE)
101 return NULL_TREE;
102 }
103 TREE_OPERAND (t, i) = op;
104 }
105 return t;
106 }
107 case GIMPLE_SINGLE_RHS:
108 {
109 tree op = gimple_op (assign_stmt, 1);
110 op = fixup_tree_for_diagnostic_1 (op, visited);
111 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 maybe_reconstruct_from_def_stmt (tree ssa_name,
126 hash_set<tree> *visited)
127 {
128 /* Ensure termination. */
129 if (visited->contains (ssa_name))
130 return NULL_TREE;
131 visited->add (ssa_name);
132
133 gimple *def_stmt = SSA_NAME_DEF_STMT (ssa_name);
134
135 switch (gimple_code (def_stmt))
136 {
137 default:
138 gcc_unreachable ();
139 case GIMPLE_ASM:
140 case GIMPLE_NOP:
141 case GIMPLE_PHI:
142 /* Can't handle these. */
143 return NULL_TREE;
144 case GIMPLE_ASSIGN:
145 return get_diagnostic_tree_for_gassign_1
146 (as_a <const gassign *> (def_stmt), visited);
147 case GIMPLE_CALL:
148 {
149 gcall *call_stmt = as_a <gcall *> (def_stmt);
150 tree return_type = gimple_call_return_type (call_stmt);
151 tree fn = fixup_tree_for_diagnostic_1 (gimple_call_fn (call_stmt),
152 visited);
153 if (fn == NULL_TREE)
154 return NULL_TREE;
155 unsigned num_args = gimple_call_num_args (call_stmt);
156 auto_vec<tree> args (num_args);
157 for (unsigned i = 0; i < num_args; i++)
158 {
159 tree arg = gimple_call_arg (call_stmt, i);
160 arg = fixup_tree_for_diagnostic_1 (arg, visited);
161 if (arg == NULL_TREE)
162 return NULL_TREE;
163 args.quick_push (arg);
164 }
165 gcc_assert (fn);
166 return build_call_array_loc (gimple_location (call_stmt),
167 return_type, fn,
168 num_args, args.address ());
169 }
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 fixup_tree_for_diagnostic_1 (tree expr, hash_set<tree> *visited)
180 {
181 if (expr
182 && TREE_CODE (expr) == SSA_NAME
183 && (SSA_NAME_VAR (expr) == NULL_TREE
184 || DECL_ARTIFICIAL (SSA_NAME_VAR (expr))))
185 {
186 if (tree var = SSA_NAME_VAR (expr))
187 if (VAR_P (var) && DECL_HAS_DEBUG_EXPR_P (var))
188 return DECL_DEBUG_EXPR (var);
189 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 fixup_tree_for_diagnostic (tree expr)
208 {
209 hash_set<tree> visited;
210 return fixup_tree_for_diagnostic_1 (expr, &visited);
211 }
212
213 /* Attempt to generate a tree for the LHS of ASSIGN_STMT. */
214
215 tree
216 get_diagnostic_tree_for_gassign (const gassign *assign_stmt)
217 {
218 hash_set<tree> visited;
219 return get_diagnostic_tree_for_gassign_1 (assign_stmt, &visited);
220 }
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 tree_to_json (tree node)
228 {
229 if (!node)
230 return new json::literal (json::JSON_NULL);
231
232 pretty_printer pp;
233 dump_generic_node (&pp, node, 0, TDF_VOPS|TDF_MEMSYMS, false);
234 return new json::string (pp_formatted_text (&pp));
235 }
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 diagnostic_event_id_to_json (const diagnostic_event_id_t &event_id)
244 {
245 if (event_id.known_p ())
246 {
247 pretty_printer pp;
248 pp_printf (&pp, "%@", &event_id);
249 return new json::string (pp_formatted_text (&pp));
250 }
251 else
252 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 bit_offset_to_json (const bit_offset_t &offset)
261 {
262 pretty_printer pp;
263 pp_wide_int_large (&pp, offset, SIGNED);
264 return new json::string (pp_formatted_text (&pp));
265 }
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 byte_offset_to_json (const byte_offset_t &offset)
273 {
274 pretty_printer pp;
275 pp_wide_int_large (&pp, offset, SIGNED);
276 return new json::string (pp_formatted_text (&pp));
277 }
278
279 /* Workaround for lack of const-correctness of ssa_default_def. */
280
281 tree
282 get_ssa_default_def (const function &fun, tree var)
283 {
284 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 is_special_named_call_p (const gcall *call, const char *funcname,
300 unsigned int num_args)
301 {
302 gcc_assert (funcname);
303
304 tree fndecl = gimple_call_fndecl (call);
305 if (!fndecl)
306 return false;
307
308 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 is_named_call_p (const_tree fndecl, const char *funcname)
318 {
319 gcc_assert (fndecl);
320 gcc_assert (funcname);
321
322 if (!maybe_special_function_p (fndecl))
323 return false;
324
325 tree identifier = DECL_NAME (fndecl);
326 const char *name = IDENTIFIER_POINTER (identifier);
327 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 if (funcname[0] != '_' && name[0] == '_')
333 {
334 if (name[1] == '_')
335 tname += 2;
336 else
337 tname += 1;
338 }
339
340 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 is_std_function_p (const_tree fndecl)
349 {
350 tree name_decl = DECL_NAME (fndecl);
351 if (!name_decl)
352 return false;
353 if (!DECL_CONTEXT (fndecl))
354 return false;
355 if (TREE_CODE (DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
356 return false;
357 tree ns = DECL_CONTEXT (fndecl);
358 if (!(DECL_CONTEXT (ns) == NULL_TREE
359 || TREE_CODE (DECL_CONTEXT (ns)) == TRANSLATION_UNIT_DECL))
360 return false;
361 if (!DECL_NAME (ns))
362 return false;
363 return id_equal ("std", DECL_NAME (ns));
364 }
365
366 /* Like is_named_call_p, but look for std::FUNCNAME. */
367
368 bool
369 is_std_named_call_p (const_tree fndecl, const char *funcname)
370 {
371 gcc_assert (fndecl);
372 gcc_assert (funcname);
373
374 if (!is_std_function_p (fndecl))
375 return false;
376
377 tree identifier = DECL_NAME (fndecl);
378 const char *name = IDENTIFIER_POINTER (identifier);
379 const char *tname = name;
380
381 /* Don't disregard prefix _ or __ in FNDECL's name. */
382
383 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 is_named_call_p (const_tree fndecl, const char *funcname,
392 const gcall *call, unsigned int num_args)
393 {
394 gcc_assert (fndecl);
395 gcc_assert (funcname);
396
397 if (!is_named_call_p (fndecl, funcname))
398 return false;
399
400 if (gimple_call_num_args (call) != num_args)
401 return false;
402
403 return true;
404 }
405
406 /* Like is_named_call_p, but check for std::FUNCNAME. */
407
408 bool
409 is_std_named_call_p (const_tree fndecl, const char *funcname,
410 const gcall *call, unsigned int num_args)
411 {
412 gcc_assert (fndecl);
413 gcc_assert (funcname);
414
415 if (!is_std_named_call_p (fndecl, funcname))
416 return false;
417
418 if (gimple_call_num_args (call) != num_args)
419 return false;
420
421 return true;
422 }
423
424 /* Return true if stmt is a setjmp or sigsetjmp call. */
425
426 bool
427 is_setjmp_call_p (const gcall *call)
428 {
429 if (is_special_named_call_p (call, "setjmp", 1)
430 || is_special_named_call_p (call, "sigsetjmp", 2))
431 /* region_model::on_setjmp requires a pointer. */
432 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 is_longjmp_call_p (const gcall *call)
442 {
443 if (is_special_named_call_p (call, "longjmp", 2)
444 || is_special_named_call_p (call, "siglongjmp", 2))
445 /* exploded_node::on_longjmp requires a pointer for the initial
446 argument. */
447 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 get_user_facing_name (const gcall *call)
459 {
460 tree fndecl = gimple_call_fndecl (call);
461 gcc_assert (fndecl);
462
463 tree identifier = DECL_NAME (fndecl);
464 gcc_assert (identifier);
465
466 const char *name = IDENTIFIER_POINTER (identifier);
467
468 /* Strip prefix _ or __ in FNDECL's name. */
469 if (name[0] == '_')
470 {
471 if (name[1] == '_')
472 return name + 2;
473 else
474 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 make_label_text (bool can_colorize, const char *fmt, ...)
489 {
490 pretty_printer *pp = global_dc->printer->clone ();
491 pp_clear_output_area (pp);
492
493 if (!can_colorize)
494 pp_show_color (pp) = false;
495
496 rich_location rich_loc (line_table, UNKNOWN_LOCATION);
497
498 va_list ap;
499
500 va_start (ap, fmt);
501
502 text_info ti (_(fmt), &ap, 0, NULL, &rich_loc);
503 pp_format (pp, &ti);
504 pp_output_formatted_text (pp);
505
506 va_end (ap);
507
508 label_text result = label_text::take (xstrdup (pp_formatted_text (pp)));
509 delete pp;
510 return result;
511 }
512
513 /* As above, but with singular vs plural. */
514
515 label_text
516 make_label_text_n (bool can_colorize, unsigned HOST_WIDE_INT n,
517 const char *singular_fmt,
518 const char *plural_fmt, ...)
519 {
520 pretty_printer *pp = global_dc->printer->clone ();
521 pp_clear_output_area (pp);
522
523 if (!can_colorize)
524 pp_show_color (pp) = false;
525
526 rich_location rich_loc (line_table, UNKNOWN_LOCATION);
527
528 va_list ap;
529
530 va_start (ap, plural_fmt);
531
532 const char *fmt = ngettext (singular_fmt, plural_fmt, n);
533
534 text_info ti (fmt, &ap, 0, NULL, &rich_loc);
535
536 pp_format (pp, &ti);
537 pp_output_formatted_text (pp);
538
539 va_end (ap);
540
541 label_text result = label_text::take (xstrdup (pp_formatted_text (pp)));
542 delete pp;
543 return result;
544 }
545
546 #endif /* #if ENABLE_ANALYZER */