phiopt: do factor_out_conditional_operation for all phis [PR112418]
[official-gcc.git] / gcc / analyzer / kf-analyzer.cc
blobda49baa5bff1aeecdbf3dc58f7503acd352d6234
1 /* Handling for the various __analyzer_* known functions.
2 Copyright (C) 2020-2024 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 #define INCLUDE_VECTOR
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tree.h"
27 #include "function.h"
28 #include "basic-block.h"
29 #include "gimple.h"
30 #include "diagnostic-core.h"
31 #include "analyzer/analyzer.h"
32 #include "analyzer/analyzer-logging.h"
33 #include "diagnostic.h"
34 #include "tree-diagnostic.h" /* for default_tree_printer. */
35 #include "analyzer/region-model.h"
36 #include "analyzer/pending-diagnostic.h"
37 #include "analyzer/call-details.h"
38 #include "make-unique.h"
39 #include "pretty-print-markup.h"
41 #if ENABLE_ANALYZER
43 namespace ana {
45 /* Handle calls to "__analyzer_break" by triggering a breakpoint within
46 the analyzer. */
48 class kf_analyzer_break : public known_function
50 public:
51 bool matches_call_types_p (const call_details &cd) const final override
53 return cd.num_args () == 0;
55 void impl_call_pre (const call_details &) const final override
57 /* TODO: is there a good cross-platform way to do this? */
58 raise (SIGINT);
62 /* Handler for calls to "__analyzer_describe".
64 Emit a warning describing the 2nd argument (which can be of any
65 type), at the given verbosity level. This is for use when
66 debugging, and may be of use in DejaGnu tests. */
68 class kf_analyzer_describe : public known_function
70 public:
71 bool matches_call_types_p (const call_details &cd) const final override
73 return cd.num_args () == 2;
75 void impl_call_pre (const call_details &cd) const final override
77 if (!cd.get_ctxt ())
78 return;
79 tree t_verbosity = cd.get_arg_tree (0);
80 const svalue *sval = cd.get_arg_svalue (1);
81 bool simple = zerop (t_verbosity);
82 label_text desc = sval->get_desc (simple);
83 warning_at (cd.get_location (), 0, "svalue: %qs", desc.get ());
87 /* Handler for calls to "__analyzer_dump_capacity".
89 Emit a warning describing the capacity of the base region of
90 the region pointed to by the 1st argument.
91 This is for use when debugging, and may be of use in DejaGnu tests. */
93 class kf_analyzer_dump_capacity : public known_function
95 public:
96 bool matches_call_types_p (const call_details &cd) const final override
98 return (cd.num_args () == 1
99 && cd.arg_is_pointer_p (0));
102 void impl_call_pre (const call_details &cd) const final override
104 region_model_context *ctxt = cd.get_ctxt ();
105 if (!ctxt)
106 return;
107 region_model *model = cd.get_model ();
108 tree t_ptr = cd.get_arg_tree (0);
109 const svalue *sval_ptr = model->get_rvalue (t_ptr, ctxt);
110 const region *reg = model->deref_rvalue (sval_ptr, t_ptr, ctxt);
111 const region *base_reg = reg->get_base_region ();
112 const svalue *capacity = model->get_capacity (base_reg);
113 label_text desc = capacity->get_desc (true);
114 warning_at (cd.get_call_stmt ()->location, 0,
115 "capacity: %qs", desc.get ());
119 /* Compare D1 and D2 using their names, and then IDs to order them. */
121 static int
122 cmp_decls (tree d1, tree d2)
124 gcc_assert (DECL_P (d1));
125 gcc_assert (DECL_P (d2));
126 if (DECL_NAME (d1) && DECL_NAME (d2))
127 if (int cmp = strcmp (IDENTIFIER_POINTER (DECL_NAME (d1)),
128 IDENTIFIER_POINTER (DECL_NAME (d2))))
129 return cmp;
130 return (int)DECL_UID (d1) - (int)DECL_UID (d2);
133 /* Comparator for use by vec<tree>::qsort,
134 using their names, and then IDs to order them. */
136 static int
137 cmp_decls_ptr_ptr (const void *p1, const void *p2)
139 tree const *d1 = (tree const *)p1;
140 tree const *d2 = (tree const *)p2;
142 return cmp_decls (*d1, *d2);
145 /* Handler for calls to "__analyzer_dump_escaped".
147 Emit a warning giving the number of decls that have escaped, followed
148 by a comma-separated list of their names, in alphabetical order.
150 This is for use when debugging, and may be of use in DejaGnu tests. */
152 class kf_analyzer_dump_escaped : public known_function
154 public:
155 bool matches_call_types_p (const call_details &cd) const final override
157 return cd.num_args () == 0;
159 void impl_call_pre (const call_details &cd) const final override
161 region_model_context *ctxt = cd.get_ctxt ();
162 if (!ctxt)
163 return;
164 region_model *model = cd.get_model ();
166 auto_vec<tree> escaped_decls;
167 for (auto iter : *model->get_store ())
169 const binding_cluster *c = iter.second;
170 if (!c->escaped_p ())
171 continue;
172 if (tree decl = c->get_base_region ()->maybe_get_decl ())
173 escaped_decls.safe_push (decl);
176 /* Sort them into deterministic order; alphabetical is
177 probably most user-friendly. */
178 escaped_decls.qsort (cmp_decls_ptr_ptr);
180 class escaped_list_element : public pp_element
182 public:
183 escaped_list_element (auto_vec<tree> &escaped_decls)
184 : m_escaped_decls (escaped_decls)
188 void add_to_phase_2 (pp_markup::context &ctxt) final override
190 /* We can't call pp_printf directly on ctxt.m_pp from within
191 formatting. As a workaround, work with a clone of the pp. */
192 std::unique_ptr<pretty_printer> pp (ctxt.m_pp.clone ());
193 bool first = true;
194 for (auto iter : m_escaped_decls)
196 if (first)
197 first = false;
198 else
199 pp_string (pp.get (), ", ");
200 pp_printf (pp.get (), "%qD", iter);
202 pp_string (&ctxt.m_pp, pp_formatted_text (pp.get ()));
205 private:
206 auto_vec<tree> &m_escaped_decls;
207 } e_escaped (escaped_decls);
209 /* Print the number to make it easier to write DejaGnu tests for
210 the "nothing has escaped" case. */
211 warning_at (cd.get_location (), 0, "escaped: %i: %e",
212 escaped_decls.length (),
213 &e_escaped);
217 /* Placeholder handler for calls to "__analyzer_dump_exploded_nodes".
218 This is a no-op; the real implementation happens when the
219 exploded_graph is postprocessed. */
221 class kf_analyzer_dump_exploded_nodes : public known_function
223 public:
224 bool matches_call_types_p (const call_details &cd) const final override
226 return cd.num_args () == 1;
230 /* Handler for calls to "__analyzer_dump_named_constant".
232 Look up the given name, and emit a warning describing the
233 state of the corresponding stashed value.
235 This is for use when debugging, and for DejaGnu tests. */
237 class kf_analyzer_dump_named_constant : public known_function
239 public:
240 bool matches_call_types_p (const call_details &cd) const final override
242 return cd.num_args () == 1;
244 void impl_call_pre (const call_details &cd) const final override
246 region_model_context *ctxt = cd.get_ctxt ();
247 if (!ctxt)
248 return;
250 const char *name = cd.get_arg_string_literal (0);
251 if (!name)
253 error_at (cd.get_location (), "cannot determine name");
254 return;
256 tree value = get_stashed_constant_by_name (name);
257 if (value)
258 warning_at (cd.get_location (), 0, "named constant %qs has value %qE",
259 name, value);
260 else
261 warning_at (cd.get_location (), 0, "named constant %qs has unknown value",
262 name);
266 /* A pending_diagnostic subclass for implementing "__analyzer_dump_path". */
268 class dump_path_diagnostic
269 : public pending_diagnostic_subclass<dump_path_diagnostic>
271 public:
272 int get_controlling_option () const final override
274 return 0;
277 bool emit (diagnostic_emission_context &ctxt) final override
279 ctxt.inform ("path");
280 return true;
283 const char *get_kind () const final override
285 return "dump_path_diagnostic";
288 bool operator== (const dump_path_diagnostic &) const
290 return true;
294 /* Handle calls to "__analyzer_dump_path" by queuing a diagnostic at this
295 exploded_node. */
297 class kf_analyzer_dump_path : 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 ctxt->warn (make_unique<dump_path_diagnostic> ());
313 /* Handle calls to "__analyzer_dump_region_model" by dumping
314 the region model's state to stderr. */
316 class kf_analyzer_dump_region_model : public known_function
318 public:
319 bool matches_call_types_p (const call_details &cd) const final override
321 return cd.num_args () == 0;
323 void impl_call_pre (const call_details &cd) const final override
325 region_model_context *ctxt = cd.get_ctxt ();
326 if (!ctxt)
327 return;
328 region_model *model = cd.get_model ();
329 model->dump (false);
333 /* Handle a call to "__analyzer_eval" by evaluating the input
334 and dumping as a dummy warning, so that test cases can use
335 dg-warning to validate the result (and so unexpected warnings will
336 lead to DejaGnu failures).
337 Broken out as a subroutine to make it easier to put a breakpoint on it
338 - though typically this doesn't help, as we have an SSA name as the arg,
339 and what's more interesting is usually the def stmt for that name. */
341 class kf_analyzer_eval : public known_function
343 public:
344 bool matches_call_types_p (const call_details &cd) const final override
346 return cd.num_args () == 1;
348 void impl_call_pre (const call_details &cd) const final override
350 region_model_context *ctxt = cd.get_ctxt ();
351 if (!ctxt)
352 return;
353 region_model *model = cd.get_model ();
355 tree t_arg = cd.get_arg_tree (0);
356 tristate t = model->eval_condition (t_arg, NE_EXPR, integer_zero_node,
357 ctxt);
358 warning_at (cd.get_location (), 0, "%s", t.as_string ());
362 /* Handler for "__analyzer_get_unknown_ptr". */
364 class kf_analyzer_get_unknown_ptr : public known_function
366 public:
367 bool matches_call_types_p (const call_details &cd) const final override
369 return cd.num_args () == 0;
371 void impl_call_pre (const call_details &cd) const final override
373 region_model_manager *mgr = cd.get_manager ();
374 const svalue *ptr_sval
375 = mgr->get_or_create_unknown_svalue (cd.get_lhs_type ());
376 cd.maybe_set_lhs (ptr_sval);
380 /* Populate KFM with instances of known functions used for debugging the
381 analyzer and for writing DejaGnu tests, all with a "__analyzer_" prefix. */
383 void
384 register_known_analyzer_functions (known_function_manager &kfm)
386 kfm.add ("__analyzer_break", make_unique<kf_analyzer_break> ());
387 kfm.add ("__analyzer_describe", make_unique<kf_analyzer_describe> ());
388 kfm.add ("__analyzer_dump_capacity",
389 make_unique<kf_analyzer_dump_capacity> ());
390 kfm.add ("__analyzer_dump_escaped", make_unique<kf_analyzer_dump_escaped> ());
391 kfm.add ("__analyzer_dump_exploded_nodes",
392 make_unique<kf_analyzer_dump_exploded_nodes> ());
393 kfm.add ("__analyzer_dump_named_constant",
394 make_unique<kf_analyzer_dump_named_constant> ());
395 kfm.add ("__analyzer_dump_path", make_unique<kf_analyzer_dump_path> ());
396 kfm.add ("__analyzer_dump_region_model",
397 make_unique<kf_analyzer_dump_region_model> ());
398 kfm.add ("__analyzer_eval", make_unique<kf_analyzer_eval> ());
399 kfm.add ("__analyzer_get_unknown_ptr",
400 make_unique<kf_analyzer_get_unknown_ptr> ());
401 kfm.add ("__analyzer_get_strlen", make_kf_strlen ());
404 } // namespace ana
406 #endif /* #if ENABLE_ANALYZER */