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)
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/>. */
22 #define INCLUDE_MEMORY
23 #define INCLUDE_VECTOR
25 #include "coretypes.h"
28 #include "basic-block.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"
45 /* Handle calls to "__analyzer_break" by triggering a breakpoint within
48 class kf_analyzer_break
: public known_function
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? */
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
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
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
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 ();
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. */
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
))))
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. */
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
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 ();
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 ())
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
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 ());
194 for (auto iter
: m_escaped_decls
)
199 pp_string (pp
.get (), ", ");
200 pp_printf (pp
.get (), "%qD", iter
);
202 pp_string (&ctxt
.m_pp
, pp_formatted_text (pp
.get ()));
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 (),
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
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
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 ();
250 const char *name
= cd
.get_arg_string_literal (0);
253 error_at (cd
.get_location (), "cannot determine name");
256 tree value
= get_stashed_constant_by_name (name
);
258 warning_at (cd
.get_location (), 0, "named constant %qs has value %qE",
261 warning_at (cd
.get_location (), 0, "named constant %qs has unknown value",
266 /* A pending_diagnostic subclass for implementing "__analyzer_dump_path". */
268 class dump_path_diagnostic
269 : public pending_diagnostic_subclass
<dump_path_diagnostic
>
272 int get_controlling_option () const final override
277 bool emit (diagnostic_emission_context
&ctxt
) final override
279 ctxt
.inform ("path");
283 const char *get_kind () const final override
285 return "dump_path_diagnostic";
288 bool operator== (const dump_path_diagnostic
&) const
294 /* Handle calls to "__analyzer_dump_path" by queuing a diagnostic at this
297 class kf_analyzer_dump_path
: public known_function
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 ();
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
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 ();
328 region_model
*model
= cd
.get_model ();
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
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 ();
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
,
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
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. */
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 ());
406 #endif /* #if ENABLE_ANALYZER */