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