xref: /netbsd-src/external/gpl3/gcc/dist/gcc/analyzer/analyzer.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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
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 /* 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
get_diagnostic_tree_for_gassign_1(const gassign * assign_stmt,hash_set<tree> * visited)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 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
maybe_reconstruct_from_def_stmt(tree ssa_name,hash_set<tree> * visited)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
fixup_tree_for_diagnostic_1(tree expr,hash_set<tree> * visited)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
fixup_tree_for_diagnostic(tree expr)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
get_diagnostic_tree_for_gassign(const gassign * assign_stmt)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
is_special_named_call_p(const gcall * call,const char * funcname,unsigned int num_args)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.cc.  */
245 
246 bool
is_named_call_p(const_tree fndecl,const char * funcname)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.cc: 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
is_std_function_p(const_tree fndecl)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
is_std_named_call_p(const_tree fndecl,const char * funcname)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
is_named_call_p(const_tree fndecl,const char * funcname,const gcall * call,unsigned int num_args)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
is_std_named_call_p(const_tree fndecl,const char * funcname,const gcall * call,unsigned int num_args)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
is_setjmp_call_p(const gcall * call)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
is_longjmp_call_p(const gcall * call)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 *
get_user_facing_name(const gcall * call)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
make_label_text(bool can_colorize,const char * fmt,...)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 */
450