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)
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
24 #include "coretypes.h"
27 #include "basic-block.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"
43 /* Handle calls to "__analyzer_break" by triggering a breakpoint within
46 class kf_analyzer_break
: public known_function
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? */
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
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
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
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 ();
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. */
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
))))
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. */
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
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 ();
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 ())
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
);
179 pp_format_decoder (&pp
) = default_tree_printer
;
180 pp_show_color (&pp
) = pp_show_color (global_dc
->printer
);
182 for (auto iter
: escaped_decls
)
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
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
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 ();
231 const char *name
= cd
.get_arg_string_literal (0);
234 error_at (cd
.get_location (), "cannot determine name");
237 tree value
= get_stashed_constant_by_name (name
);
239 warning_at (cd
.get_location (), 0, "named constant %qs has value %qE",
242 warning_at (cd
.get_location (), 0, "named constant %qs has unknown value",
247 /* A pending_diagnostic subclass for implementing "__analyzer_dump_path". */
249 class dump_path_diagnostic
250 : public pending_diagnostic_subclass
<dump_path_diagnostic
>
253 int get_controlling_option () const final override
258 bool emit (rich_location
*richloc
) final override
260 inform (richloc
, "path");
264 const char *get_kind () const final override
266 return "dump_path_diagnostic";
269 bool operator== (const dump_path_diagnostic
&) const
275 /* Handle calls to "__analyzer_dump_path" by queuing a diagnostic at this
278 class kf_analyzer_dump_path
: public known_function
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 ();
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
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 region_model
*model
= cd
.get_model ();
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
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 ();
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
,
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
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. */
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
> ());
386 #endif /* #if ENABLE_ANALYZER */