d: Add test for PR d/108167 to the testsuite [PR108167]
[official-gcc.git] / gcc / analyzer / kf-analyzer.cc
blob32aa87bfbdcf6a61077f7f80b24cee56dbb69377
1 /* Handling for the various __analyzer_* known functions.
2 Copyright (C) 2020-2023 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
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.
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.
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/>. */
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-core.h"
30 #include "analyzer/analyzer.h"
31 #include "analyzer/analyzer-logging.h"
32 #include "diagnostic.h"
33 #include "tree-diagnostic.h" /* for default_tree_printer. */
34 #include "analyzer/region-model.h"
35 #include "analyzer/pending-diagnostic.h"
36 #include "analyzer/call-details.h"
37 #include "make-unique.h"
39 #if ENABLE_ANALYZER
41 namespace ana {
43 /* Handle calls to "__analyzer_break" by triggering a breakpoint within
44 the analyzer. */
46 class kf_analyzer_break : public known_function
48 public:
49 bool matches_call_types_p (const call_details &cd) const final override
51 return cd.num_args () == 0;
53 void impl_call_pre (const call_details &) const final override
55 /* TODO: is there a good cross-platform way to do this? */
56 raise (SIGINT);
60 /* Handler for calls to "__analyzer_describe".
62 Emit a warning describing the 2nd argument (which can be of any
63 type), at the given verbosity level. This is for use when
64 debugging, and may be of use in DejaGnu tests. */
66 class kf_analyzer_describe : public known_function
68 public:
69 bool matches_call_types_p (const call_details &cd) const final override
71 return cd.num_args () == 2;
73 void impl_call_pre (const call_details &cd) const final override
75 if (!cd.get_ctxt ())
76 return;
77 tree t_verbosity = cd.get_arg_tree (0);
78 const svalue *sval = cd.get_arg_svalue (1);
79 bool simple = zerop (t_verbosity);
80 label_text desc = sval->get_desc (simple);
81 warning_at (cd.get_location (), 0, "svalue: %qs", desc.get ());
85 /* Handler for calls to "__analyzer_dump_capacity".
87 Emit a warning describing the capacity of the base region of
88 the region pointed to by the 1st argument.
89 This is for use when debugging, and may be of use in DejaGnu tests. */
91 class kf_analyzer_dump_capacity : public known_function
93 public:
94 bool matches_call_types_p (const call_details &cd) const final override
96 return (cd.num_args () == 1
97 && cd.arg_is_pointer_p (0));
100 void impl_call_pre (const call_details &cd) const final override
102 region_model_context *ctxt = cd.get_ctxt ();
103 if (!ctxt)
104 return;
105 region_model *model = cd.get_model ();
106 tree t_ptr = cd.get_arg_tree (0);
107 const svalue *sval_ptr = model->get_rvalue (t_ptr, ctxt);
108 const region *reg = model->deref_rvalue (sval_ptr, t_ptr, ctxt);
109 const region *base_reg = reg->get_base_region ();
110 const svalue *capacity = model->get_capacity (base_reg);
111 label_text desc = capacity->get_desc (true);
112 warning_at (cd.get_call_stmt ()->location, 0,
113 "capacity: %qs", desc.get ());
117 /* Compare D1 and D2 using their names, and then IDs to order them. */
119 static int
120 cmp_decls (tree d1, tree d2)
122 gcc_assert (DECL_P (d1));
123 gcc_assert (DECL_P (d2));
124 if (DECL_NAME (d1) && DECL_NAME (d2))
125 if (int cmp = strcmp (IDENTIFIER_POINTER (DECL_NAME (d1)),
126 IDENTIFIER_POINTER (DECL_NAME (d2))))
127 return cmp;
128 return (int)DECL_UID (d1) - (int)DECL_UID (d2);
131 /* Comparator for use by vec<tree>::qsort,
132 using their names, and then IDs to order them. */
134 static int
135 cmp_decls_ptr_ptr (const void *p1, const void *p2)
137 tree const *d1 = (tree const *)p1;
138 tree const *d2 = (tree const *)p2;
140 return cmp_decls (*d1, *d2);
143 /* Handler for calls to "__analyzer_dump_escaped".
145 Emit a warning giving the number of decls that have escaped, followed
146 by a comma-separated list of their names, in alphabetical order.
148 This is for use when debugging, and may be of use in DejaGnu tests. */
150 class kf_analyzer_dump_escaped : public known_function
152 public:
153 bool matches_call_types_p (const call_details &cd) const final override
155 return cd.num_args () == 0;
157 void impl_call_pre (const call_details &cd) const final override
159 region_model_context *ctxt = cd.get_ctxt ();
160 if (!ctxt)
161 return;
162 region_model *model = cd.get_model ();
164 auto_vec<tree> escaped_decls;
165 for (auto iter : *model->get_store ())
167 const binding_cluster *c = iter.second;
168 if (!c->escaped_p ())
169 continue;
170 if (tree decl = c->get_base_region ()->maybe_get_decl ())
171 escaped_decls.safe_push (decl);
174 /* Sort them into deterministic order; alphabetical is
175 probably most user-friendly. */
176 escaped_decls.qsort (cmp_decls_ptr_ptr);
178 pretty_printer pp;
179 pp_format_decoder (&pp) = default_tree_printer;
180 pp_show_color (&pp) = pp_show_color (global_dc->printer);
181 bool first = true;
182 for (auto iter : escaped_decls)
184 if (first)
185 first = false;
186 else
187 pp_string (&pp, ", ");
188 pp_printf (&pp, "%qD", iter);
190 /* Print the number to make it easier to write DejaGnu tests for
191 the "nothing has escaped" case. */
192 warning_at (cd.get_location (), 0, "escaped: %i: %s",
193 escaped_decls.length (),
194 pp_formatted_text (&pp));
198 /* Placeholder handler for calls to "__analyzer_dump_exploded_nodes".
199 This is a no-op; the real implementation happens when the
200 exploded_graph is postprocessed. */
202 class kf_analyzer_dump_exploded_nodes : public known_function
204 public:
205 bool matches_call_types_p (const call_details &cd) const final override
207 return cd.num_args () == 1;
211 /* Handler for calls to "__analyzer_dump_named_constant".
213 Look up the given name, and emit a warning describing the
214 state of the corresponding stashed value.
216 This is for use when debugging, and for DejaGnu tests. */
218 class kf_analyzer_dump_named_constant : public known_function
220 public:
221 bool matches_call_types_p (const call_details &cd) const final override
223 return cd.num_args () == 1;
225 void impl_call_pre (const call_details &cd) const final override
227 region_model_context *ctxt = cd.get_ctxt ();
228 if (!ctxt)
229 return;
231 const char *name = cd.get_arg_string_literal (0);
232 if (!name)
234 error_at (cd.get_location (), "cannot determine name");
235 return;
237 tree value = get_stashed_constant_by_name (name);
238 if (value)
239 warning_at (cd.get_location (), 0, "named constant %qs has value %qE",
240 name, value);
241 else
242 warning_at (cd.get_location (), 0, "named constant %qs has unknown value",
243 name);
247 /* A pending_diagnostic subclass for implementing "__analyzer_dump_path". */
249 class dump_path_diagnostic
250 : public pending_diagnostic_subclass<dump_path_diagnostic>
252 public:
253 int get_controlling_option () const final override
255 return 0;
258 bool emit (rich_location *richloc) final override
260 inform (richloc, "path");
261 return true;
264 const char *get_kind () const final override
266 return "dump_path_diagnostic";
269 bool operator== (const dump_path_diagnostic &) const
271 return true;
275 /* Handle calls to "__analyzer_dump_path" by queuing a diagnostic at this
276 exploded_node. */
278 class kf_analyzer_dump_path : public known_function
280 public:
281 bool matches_call_types_p (const call_details &cd) const final override
283 return cd.num_args () == 0;
285 void impl_call_pre (const call_details &cd) const final override
287 region_model_context *ctxt = cd.get_ctxt ();
288 if (!ctxt)
289 return;
290 ctxt->warn (make_unique<dump_path_diagnostic> ());
294 /* Handle calls to "__analyzer_dump_region_model" by dumping
295 the region model's state to stderr. */
297 class kf_analyzer_dump_region_model : public known_function
299 public:
300 bool matches_call_types_p (const call_details &cd) const final override
302 return cd.num_args () == 0;
304 void impl_call_pre (const call_details &cd) const final override
306 region_model_context *ctxt = cd.get_ctxt ();
307 if (!ctxt)
308 return;
309 region_model *model = cd.get_model ();
310 model->dump (false);
314 /* Handle a call to "__analyzer_eval" by evaluating the input
315 and dumping as a dummy warning, so that test cases can use
316 dg-warning to validate the result (and so unexpected warnings will
317 lead to DejaGnu failures).
318 Broken out as a subroutine to make it easier to put a breakpoint on it
319 - though typically this doesn't help, as we have an SSA name as the arg,
320 and what's more interesting is usually the def stmt for that name. */
322 class kf_analyzer_eval : public known_function
324 public:
325 bool matches_call_types_p (const call_details &cd) const final override
327 return cd.num_args () == 1;
329 void impl_call_pre (const call_details &cd) const final override
331 region_model_context *ctxt = cd.get_ctxt ();
332 if (!ctxt)
333 return;
334 region_model *model = cd.get_model ();
336 tree t_arg = cd.get_arg_tree (0);
337 tristate t = model->eval_condition (t_arg, NE_EXPR, integer_zero_node,
338 ctxt);
339 warning_at (cd.get_location (), 0, "%s", t.as_string ());
343 /* Handler for "__analyzer_get_unknown_ptr". */
345 class kf_analyzer_get_unknown_ptr : public known_function
347 public:
348 bool matches_call_types_p (const call_details &cd) const final override
350 return cd.num_args () == 0;
352 void impl_call_pre (const call_details &cd) const final override
354 region_model_manager *mgr = cd.get_manager ();
355 const svalue *ptr_sval
356 = mgr->get_or_create_unknown_svalue (cd.get_lhs_type ());
357 cd.maybe_set_lhs (ptr_sval);
361 /* Populate KFM with instances of known functions used for debugging the
362 analyzer and for writing DejaGnu tests, all with a "__analyzer_" prefix. */
364 void
365 register_known_analyzer_functions (known_function_manager &kfm)
367 kfm.add ("__analyzer_break", make_unique<kf_analyzer_break> ());
368 kfm.add ("__analyzer_describe", make_unique<kf_analyzer_describe> ());
369 kfm.add ("__analyzer_dump_capacity",
370 make_unique<kf_analyzer_dump_capacity> ());
371 kfm.add ("__analyzer_dump_escaped", make_unique<kf_analyzer_dump_escaped> ());
372 kfm.add ("__analyzer_dump_exploded_nodes",
373 make_unique<kf_analyzer_dump_exploded_nodes> ());
374 kfm.add ("__analyzer_dump_named_constant",
375 make_unique<kf_analyzer_dump_named_constant> ());
376 kfm.add ("__analyzer_dump_path", make_unique<kf_analyzer_dump_path> ());
377 kfm.add ("__analyzer_dump_region_model",
378 make_unique<kf_analyzer_dump_region_model> ());
379 kfm.add ("__analyzer_eval", make_unique<kf_analyzer_eval> ());
380 kfm.add ("__analyzer_get_unknown_ptr",
381 make_unique<kf_analyzer_get_unknown_ptr> ());
384 } // namespace ana
386 #endif /* #if ENABLE_ANALYZER */