libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / analyzer / call-details.cc
bloba9c613bc1822bf20d1f6f66987191315bb146527
1 /* Helper class for handling a call with specific arguments.
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 "gimple-pretty-print.h"
36 #include "analyzer/region-model.h"
37 #include "analyzer/call-details.h"
38 #include "analyzer/ranges.h"
39 #include "stringpool.h"
40 #include "attribs.h"
41 #include "make-unique.h"
42 #include "diagnostic-format-sarif.h"
44 #if ENABLE_ANALYZER
46 namespace ana {
48 /* class call_details. */
50 /* call_details's ctor. */
52 call_details::call_details (const gcall *call, region_model *model,
53 region_model_context *ctxt)
54 : m_call (call), m_model (model), m_ctxt (ctxt),
55 m_lhs_type (NULL_TREE), m_lhs_region (NULL)
57 m_lhs_type = NULL_TREE;
58 if (tree lhs = gimple_call_lhs (call))
60 m_lhs_region = model->get_lvalue (lhs, ctxt);
61 m_lhs_type = TREE_TYPE (lhs);
65 /* call_details's ctor: copy CD, but override the context,
66 using CTXT instead. */
68 call_details::call_details (const call_details &cd,
69 region_model_context *ctxt)
71 *this = cd;
72 m_ctxt = ctxt;
75 /* Get the manager from m_model. */
77 region_model_manager *
78 call_details::get_manager () const
80 return m_model->get_manager ();
83 /* Get any logger associated with this object. */
85 logger *
86 call_details::get_logger () const
88 if (m_ctxt)
89 return m_ctxt->get_logger ();
90 else
91 return NULL;
94 /* Get any uncertainty_t associated with the region_model_context. */
96 uncertainty_t *
97 call_details::get_uncertainty () const
99 if (m_ctxt)
100 return m_ctxt->get_uncertainty ();
101 else
102 return NULL;
105 /* If the callsite has a left-hand-side region, set it to RESULT
106 and return true.
107 Otherwise do nothing and return false. */
109 bool
110 call_details::maybe_set_lhs (const svalue *result) const
112 gcc_assert (result);
113 if (m_lhs_region)
115 m_model->set_value (m_lhs_region, result, m_ctxt);
116 return true;
118 else
119 return false;
122 /* Return true if CD is known to be a call to a function with
123 __attribute__((const)). */
125 static bool
126 const_fn_p (const call_details &cd)
128 tree fndecl = cd.get_fndecl_for_call ();
129 if (!fndecl)
130 return false;
131 gcc_assert (DECL_P (fndecl));
132 return TREE_READONLY (fndecl);
135 /* If this CD is known to be a call to a function with
136 __attribute__((const)), attempt to get a const_fn_result_svalue
137 based on the arguments, or return NULL otherwise. */
139 static const svalue *
140 maybe_get_const_fn_result (const call_details &cd)
142 if (!const_fn_p (cd))
143 return NULL;
145 unsigned num_args = cd.num_args ();
146 if (num_args > const_fn_result_svalue::MAX_INPUTS)
147 /* Too many arguments. */
148 return NULL;
150 auto_vec<const svalue *> inputs (num_args);
151 for (unsigned arg_idx = 0; arg_idx < num_args; arg_idx++)
153 const svalue *arg_sval = cd.get_arg_svalue (arg_idx);
154 if (!arg_sval->can_have_associated_state_p ())
155 return NULL;
156 inputs.quick_push (arg_sval);
159 region_model_manager *mgr = cd.get_manager ();
160 const svalue *sval
161 = mgr->get_or_create_const_fn_result_svalue (cd.get_lhs_type (),
162 cd.get_fndecl_for_call (),
163 inputs);
164 return sval;
167 /* Look for attribute "alloc_size" on the called function and, if found,
168 return a symbolic value of type size_type_node for the allocation size
169 based on the call's parameters.
170 Otherwise, return null. */
172 static const svalue *
173 get_result_size_in_bytes (const call_details &cd)
175 const tree attr = cd.lookup_function_attribute ("alloc_size");
176 if (!attr)
177 return nullptr;
179 const tree atval_1 = TREE_VALUE (attr);
180 if (!atval_1)
181 return nullptr;
183 unsigned argidx1 = TREE_INT_CST_LOW (TREE_VALUE (atval_1)) - 1;
184 if (cd.num_args () <= argidx1)
185 return nullptr;
187 const svalue *sval_arg1 = cd.get_arg_svalue (argidx1);
189 if (const tree atval_2 = TREE_CHAIN (atval_1))
191 /* Two arguments. */
192 unsigned argidx2 = TREE_INT_CST_LOW (TREE_VALUE (atval_2)) - 1;
193 if (cd.num_args () <= argidx2)
194 return nullptr;
195 const svalue *sval_arg2 = cd.get_arg_svalue (argidx2);
196 /* TODO: ideally we shouldn't need this cast here;
197 see PR analyzer/110902. */
198 return cd.get_manager ()->get_or_create_cast
199 (size_type_node,
200 cd.get_manager ()->get_or_create_binop (size_type_node,
201 MULT_EXPR,
202 sval_arg1, sval_arg2));
204 else
205 /* Single argument. */
206 return cd.get_manager ()->get_or_create_cast (size_type_node, sval_arg1);
209 /* If this call has an LHS, assign a value to it based on attributes
210 of the function:
211 - if __attribute__((const)), use a const_fn_result_svalue,
212 - if __attribute__((malloc)), use a heap-allocated region with
213 unknown content
214 - otherwise, use a conjured_svalue.
216 If __attribute__((alloc_size), set the dynamic extents on the region
217 pointed to. */
219 void
220 call_details::set_any_lhs_with_defaults () const
222 if (!m_lhs_region)
223 return;
225 const svalue *sval = maybe_get_const_fn_result (*this);
226 if (!sval)
228 region_model_manager *mgr = get_manager ();
229 if (lookup_function_attribute ("malloc"))
231 const region *new_reg
232 = m_model->get_or_create_region_for_heap_alloc (NULL, m_ctxt);
233 m_model->mark_region_as_unknown (new_reg, NULL);
234 sval = mgr->get_ptr_svalue (get_lhs_type (), new_reg);
236 else
237 /* For the common case of functions without __attribute__((const)),
238 use a conjured value, and purge any prior state involving that
239 value (in case this is in a loop). */
240 sval = get_or_create_conjured_svalue (m_lhs_region);
241 if (const svalue *size_in_bytes = get_result_size_in_bytes (*this))
243 const region *reg
244 = m_model->deref_rvalue (sval, NULL_TREE, m_ctxt, false);
245 m_model->set_dynamic_extents (reg, size_in_bytes, m_ctxt);
248 maybe_set_lhs (sval);
251 /* Return the number of arguments used by the call statement. */
253 unsigned
254 call_details::num_args () const
256 return gimple_call_num_args (m_call);
259 /* Return true if argument IDX is a size_t (or compatible with it). */
261 bool
262 call_details::arg_is_size_p (unsigned idx) const
264 return types_compatible_p (get_arg_type (idx), size_type_node);
267 /* Get the location of the call statement. */
269 location_t
270 call_details::get_location () const
272 return m_call->location;
275 /* Get argument IDX at the callsite as a tree. */
277 tree
278 call_details::get_arg_tree (unsigned idx) const
280 return gimple_call_arg (m_call, idx);
283 /* Get the type of argument IDX. */
285 tree
286 call_details::get_arg_type (unsigned idx) const
288 return TREE_TYPE (gimple_call_arg (m_call, idx));
291 /* Get argument IDX at the callsite as an svalue. */
293 const svalue *
294 call_details::get_arg_svalue (unsigned idx) const
296 tree arg = get_arg_tree (idx);
297 return m_model->get_rvalue (arg, m_ctxt);
300 /* If argument IDX's svalue at the callsite is of pointer type,
301 return the region it points to.
302 Otherwise return NULL. */
304 const region *
305 call_details::deref_ptr_arg (unsigned idx) const
307 const svalue *ptr_sval = get_arg_svalue (idx);
308 return m_model->deref_rvalue (ptr_sval, get_arg_tree (idx), m_ctxt);
311 /* Attempt to get the string literal for argument IDX, or return NULL
312 otherwise.
313 For use when implementing "__analyzer_*" functions that take
314 string literals. */
316 const char *
317 call_details::get_arg_string_literal (unsigned idx) const
319 const svalue *str_arg = get_arg_svalue (idx);
320 if (const region *pointee = str_arg->maybe_get_region ())
321 if (const string_region *string_reg = pointee->dyn_cast_string_region ())
323 tree string_cst = string_reg->get_string_cst ();
324 return TREE_STRING_POINTER (string_cst);
326 return NULL;
329 /* Attempt to get the fndecl used at this call, if known, or NULL_TREE
330 otherwise. */
332 tree
333 call_details::get_fndecl_for_call () const
335 return m_model->get_fndecl_for_call (m_call, m_ctxt);
338 /* Dump a multiline representation of this call to PP. */
340 void
341 call_details::dump_to_pp (pretty_printer *pp, bool simple) const
343 pp_string (pp, "gcall: ");
344 pp_gimple_stmt_1 (pp, m_call, 0 /* spc */, TDF_NONE /* flags */);
345 pp_newline (pp);
346 pp_string (pp, "return region: ");
347 if (m_lhs_region)
348 m_lhs_region->dump_to_pp (pp, simple);
349 else
350 pp_string (pp, "NULL");
351 pp_newline (pp);
352 for (unsigned i = 0; i < gimple_call_num_args (m_call); i++)
354 const svalue *arg_sval = get_arg_svalue (i);
355 pp_printf (pp, "arg %i: ", i);
356 arg_sval->dump_to_pp (pp, simple);
357 pp_newline (pp);
361 /* Dump a multiline representation of this call to stderr. */
363 DEBUG_FUNCTION void
364 call_details::dump (bool simple) const
366 tree_dump_pretty_printer pp (stderr);
367 dump_to_pp (&pp, simple);
370 /* Get a conjured_svalue for this call for REG,
371 and purge any state already relating to that conjured_svalue. */
373 const svalue *
374 call_details::get_or_create_conjured_svalue (const region *reg) const
376 region_model_manager *mgr = m_model->get_manager ();
377 return mgr->get_or_create_conjured_svalue (reg->get_type (), m_call, reg,
378 conjured_purge (m_model, m_ctxt));
381 /* Look for a function attribute with name ATTR_NAME on the called
382 function (or on its type).
383 Return the attribute if one is found, otherwise return NULL_TREE. */
385 tree
386 call_details::lookup_function_attribute (const char *attr_name) const
388 tree allocfntype;
389 if (tree fndecl = get_fndecl_for_call ())
390 allocfntype = TREE_TYPE (fndecl);
391 else
392 allocfntype = gimple_call_fntype (m_call);
394 if (!allocfntype)
395 return NULL_TREE;
397 return lookup_attribute (attr_name, TYPE_ATTRIBUTES (allocfntype));
400 void
401 call_details::check_for_null_terminated_string_arg (unsigned arg_idx) const
403 check_for_null_terminated_string_arg (arg_idx, false, nullptr);
406 const svalue *
407 call_details::
408 check_for_null_terminated_string_arg (unsigned arg_idx,
409 bool include_terminator,
410 const svalue **out_sval) const
412 region_model *model = get_model ();
413 return model->check_for_null_terminated_string_arg (*this,
414 arg_idx,
415 include_terminator,
416 out_sval);
419 /* A subclass of pending_diagnostic for complaining about overlapping
420 buffers. */
422 class overlapping_buffers
423 : public pending_diagnostic_subclass<overlapping_buffers>
425 public:
426 overlapping_buffers (tree fndecl,
427 const symbolic_byte_range &byte_range_a,
428 const symbolic_byte_range &byte_range_b,
429 const svalue *num_bytes_read_sval)
430 : m_fndecl (fndecl),
431 m_byte_range_a (byte_range_a),
432 m_byte_range_b (byte_range_b),
433 m_num_bytes_read_sval (num_bytes_read_sval)
437 const char *get_kind () const final override
439 return "overlapping_buffers";
442 bool operator== (const overlapping_buffers &other) const
444 return m_fndecl == other.m_fndecl;
447 int get_controlling_option () const final override
449 return OPT_Wanalyzer_overlapping_buffers;
452 bool emit (diagnostic_emission_context &ctxt) final override
454 auto_diagnostic_group d;
456 bool warned = ctxt.warn ("overlapping buffers passed as arguments to %qD",
457 m_fndecl);
459 // TODO: draw a picture?
461 if (warned)
462 inform (DECL_SOURCE_LOCATION (m_fndecl),
463 "the behavior of %qD is undefined for overlapping buffers",
464 m_fndecl);
466 return warned;
469 label_text describe_final_event (const evdesc::final_event &ev) final override
471 return ev.formatted_print
472 ("overlapping buffers passed as arguments to %qD",
473 m_fndecl);
476 void maybe_add_sarif_properties (sarif_object &result_obj)
477 const final override
479 sarif_property_bag &props = result_obj.get_or_create_properties ();
480 #define PROPERTY_PREFIX "gcc/analyzer/overlapping_buffers/"
481 props.set (PROPERTY_PREFIX "bytes_range_a",
482 m_byte_range_a.to_json ());
483 props.set (PROPERTY_PREFIX "bytes_range_b",
484 m_byte_range_b.to_json ());
485 props.set (PROPERTY_PREFIX "num_bytes_read_sval",
486 m_num_bytes_read_sval->to_json ());
487 #undef PROPERTY_PREFIX
490 private:
491 tree m_fndecl;
492 symbolic_byte_range m_byte_range_a;
493 symbolic_byte_range m_byte_range_b;
494 const svalue *m_num_bytes_read_sval;
498 /* Check if the buffers pointed to by arguments ARG_IDX_A and ARG_IDX_B
499 (zero-based) overlap, when considering them both to be of size
500 NUM_BYTES_READ_SVAL.
502 If they do overlap, complain to the context. */
504 void
505 call_details::complain_about_overlap (unsigned arg_idx_a,
506 unsigned arg_idx_b,
507 const svalue *num_bytes_read_sval) const
509 region_model_context *ctxt = get_ctxt ();
510 if (!ctxt)
511 return;
513 region_model *model = get_model ();
514 region_model_manager *mgr = model->get_manager ();
516 const svalue *arg_a_ptr_sval = get_arg_svalue (arg_idx_a);
517 if (arg_a_ptr_sval->get_kind () == SK_UNKNOWN)
518 return;
519 const region *arg_a_reg = model->deref_rvalue (arg_a_ptr_sval,
520 get_arg_tree (arg_idx_a),
521 ctxt);
522 const svalue *arg_b_ptr_sval = get_arg_svalue (arg_idx_b);
523 if (arg_b_ptr_sval->get_kind () == SK_UNKNOWN)
524 return;
525 const region *arg_b_reg = model->deref_rvalue (arg_b_ptr_sval,
526 get_arg_tree (arg_idx_b),
527 ctxt);
528 if (arg_a_reg->get_base_region () != arg_b_reg->get_base_region ())
529 return;
531 /* Are they within NUM_BYTES_READ_SVAL of each other? */
532 symbolic_byte_range byte_range_a (arg_a_reg->get_offset (mgr),
533 num_bytes_read_sval,
534 *mgr);
535 symbolic_byte_range byte_range_b (arg_b_reg->get_offset (mgr),
536 num_bytes_read_sval,
537 *mgr);
538 if (!byte_range_a.intersection (byte_range_b, *model).is_true ())
539 return;
541 ctxt->warn (make_unique<overlapping_buffers> (get_fndecl_for_call (),
542 byte_range_a,
543 byte_range_b,
544 num_bytes_read_sval));
547 } // namespace ana
549 #endif /* #if ENABLE_ANALYZER */