Branch data Line data Source code
1 : : /* Helper class for handling a call with specific arguments.
2 : : Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 : :
5 : : This file is part of GCC.
6 : :
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.
11 : :
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.
16 : :
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/>. */
20 : :
21 : : #include "analyzer/common.h"
22 : :
23 : : #include "diagnostic.h"
24 : : #include "tree-diagnostic.h" /* for default_tree_printer. */
25 : : #include "gimple-pretty-print.h"
26 : : #include "stringpool.h"
27 : : #include "attribs.h"
28 : : #include "diagnostic-format-sarif.h"
29 : :
30 : : #include "analyzer/analyzer-logging.h"
31 : : #include "analyzer/region-model.h"
32 : : #include "analyzer/call-details.h"
33 : : #include "analyzer/ranges.h"
34 : :
35 : : #if ENABLE_ANALYZER
36 : :
37 : : namespace ana {
38 : :
39 : : /* class call_details. */
40 : :
41 : : /* call_details's ctor. */
42 : :
43 : 378977 : call_details::call_details (const gcall &call, region_model *model,
44 : 378977 : region_model_context *ctxt)
45 : 378977 : : m_call (call), m_model (model), m_ctxt (ctxt),
46 : 378977 : m_lhs_type (NULL_TREE), m_lhs_region (NULL)
47 : : {
48 : 378977 : m_lhs_type = NULL_TREE;
49 : 378977 : if (tree lhs = gimple_call_lhs (&call))
50 : : {
51 : 152578 : m_lhs_region = model->get_lvalue (lhs, ctxt);
52 : 152578 : m_lhs_type = TREE_TYPE (lhs);
53 : : }
54 : 378977 : }
55 : :
56 : : /* call_details's ctor: copy CD, but override the context,
57 : : using CTXT instead. */
58 : :
59 : 1536 : call_details::call_details (const call_details &cd,
60 : 1536 : region_model_context *ctxt)
61 : 1536 : : m_call (cd.m_call), m_model (cd.m_model),
62 : 1536 : m_ctxt (ctxt),
63 : 1536 : m_lhs_type (cd.m_lhs_type),
64 : 1536 : m_lhs_region (cd.m_lhs_region)
65 : : {
66 : 1536 : }
67 : :
68 : : /* Get the manager from m_model. */
69 : :
70 : : region_model_manager *
71 : 75026 : call_details::get_manager () const
72 : : {
73 : 75026 : return m_model->get_manager ();
74 : : }
75 : :
76 : : /* Get any logger associated with this object. */
77 : :
78 : : logger *
79 : 0 : call_details::get_logger () const
80 : : {
81 : 0 : if (m_ctxt)
82 : 0 : return m_ctxt->get_logger ();
83 : : else
84 : : return NULL;
85 : : }
86 : :
87 : : /* Get any uncertainty_t associated with the region_model_context. */
88 : :
89 : : uncertainty_t *
90 : 263 : call_details::get_uncertainty () const
91 : : {
92 : 263 : if (m_ctxt)
93 : 203 : return m_ctxt->get_uncertainty ();
94 : : else
95 : : return NULL;
96 : : }
97 : :
98 : : /* If the callsite has a left-hand-side region, set it to RESULT
99 : : and return true.
100 : : Otherwise do nothing and return false. */
101 : :
102 : : bool
103 : 38919 : call_details::maybe_set_lhs (const svalue *result) const
104 : : {
105 : 38919 : gcc_assert (result);
106 : 38919 : if (m_lhs_region)
107 : : {
108 : 36967 : m_model->set_value (m_lhs_region, result, m_ctxt);
109 : 36967 : return true;
110 : : }
111 : : else
112 : : return false;
113 : : }
114 : :
115 : : /* Return true if CD is known to be a call to a function with
116 : : __attribute__((const)). */
117 : :
118 : : static bool
119 : 19374 : const_fn_p (const call_details &cd)
120 : : {
121 : 19374 : tree fndecl = cd.get_fndecl_for_call ();
122 : 19374 : if (!fndecl)
123 : : return false;
124 : 17987 : gcc_assert (DECL_P (fndecl));
125 : 17987 : return TREE_READONLY (fndecl);
126 : : }
127 : :
128 : : /* If this CD is known to be a call to a function with
129 : : __attribute__((const)), attempt to get a const_fn_result_svalue
130 : : based on the arguments, or return NULL otherwise. */
131 : :
132 : : static const svalue *
133 : 19374 : maybe_get_const_fn_result (const call_details &cd)
134 : : {
135 : 19374 : if (!const_fn_p (cd))
136 : : return NULL;
137 : :
138 : 1215 : unsigned num_args = cd.num_args ();
139 : 1215 : if (num_args > const_fn_result_svalue::MAX_INPUTS)
140 : : /* Too many arguments. */
141 : : return NULL;
142 : :
143 : 1183 : auto_vec<const svalue *> inputs (num_args);
144 : 1839 : for (unsigned arg_idx = 0; arg_idx < num_args; arg_idx++)
145 : : {
146 : 759 : const svalue *arg_sval = cd.get_arg_svalue (arg_idx);
147 : 759 : if (!arg_sval->can_have_associated_state_p ())
148 : 103 : return NULL;
149 : 656 : inputs.quick_push (arg_sval);
150 : : }
151 : :
152 : 1080 : region_model_manager *mgr = cd.get_manager ();
153 : 1080 : const svalue *sval
154 : 1080 : = mgr->get_or_create_const_fn_result_svalue (cd.get_lhs_type (),
155 : : cd.get_fndecl_for_call (),
156 : : inputs);
157 : 1080 : return sval;
158 : 1183 : }
159 : :
160 : : /* Look for attribute "alloc_size" on the called function and, if found,
161 : : return a symbolic value of type size_type_node for the allocation size
162 : : based on the call's parameters.
163 : : Otherwise, return null. */
164 : :
165 : : static const svalue *
166 : 18294 : get_result_size_in_bytes (const call_details &cd)
167 : : {
168 : 18294 : const tree attr = cd.lookup_function_attribute ("alloc_size");
169 : 18294 : if (!attr)
170 : : return nullptr;
171 : :
172 : 195 : const tree atval_1 = TREE_VALUE (attr);
173 : 195 : if (!atval_1)
174 : : return nullptr;
175 : :
176 : 195 : unsigned argidx1 = TREE_INT_CST_LOW (TREE_VALUE (atval_1)) - 1;
177 : 195 : if (cd.num_args () <= argidx1)
178 : : return nullptr;
179 : :
180 : 195 : const svalue *sval_arg1 = cd.get_arg_svalue (argidx1);
181 : :
182 : 195 : if (const tree atval_2 = TREE_CHAIN (atval_1))
183 : : {
184 : : /* Two arguments. */
185 : 68 : unsigned argidx2 = TREE_INT_CST_LOW (TREE_VALUE (atval_2)) - 1;
186 : 68 : if (cd.num_args () <= argidx2)
187 : : return nullptr;
188 : 68 : const svalue *sval_arg2 = cd.get_arg_svalue (argidx2);
189 : : /* TODO: ideally we shouldn't need this cast here;
190 : : see PR analyzer/110902. */
191 : 68 : return cd.get_manager ()->get_or_create_cast
192 : 68 : (size_type_node,
193 : : cd.get_manager ()->get_or_create_binop (size_type_node,
194 : : MULT_EXPR,
195 : 68 : sval_arg1, sval_arg2));
196 : : }
197 : : else
198 : : /* Single argument. */
199 : 127 : return cd.get_manager ()->get_or_create_cast (size_type_node, sval_arg1);
200 : : }
201 : :
202 : : /* If this call has an LHS, assign a value to it based on attributes
203 : : of the function:
204 : : - if __attribute__((const)), use a const_fn_result_svalue,
205 : : - if __attribute__((malloc)), use a heap-allocated region with
206 : : unknown content
207 : : - otherwise, use a conjured_svalue.
208 : :
209 : : If __attribute__((alloc_size), set the dynamic extents on the region
210 : : pointed to. */
211 : :
212 : : void
213 : 41744 : call_details::set_any_lhs_with_defaults () const
214 : : {
215 : 41744 : if (!m_lhs_region)
216 : : return;
217 : :
218 : 19374 : const svalue *sval = maybe_get_const_fn_result (*this);
219 : 19374 : if (!sval)
220 : : {
221 : 18294 : region_model_manager *mgr = get_manager ();
222 : 18294 : if (lookup_function_attribute ("malloc"))
223 : : {
224 : 0 : const region *new_reg
225 : 0 : = m_model->get_or_create_region_for_heap_alloc (NULL, m_ctxt);
226 : 0 : m_model->mark_region_as_unknown (new_reg, NULL);
227 : 0 : sval = mgr->get_ptr_svalue (get_lhs_type (), new_reg);
228 : : }
229 : : else
230 : : /* For the common case of functions without __attribute__((const)),
231 : : use a conjured value, and purge any prior state involving that
232 : : value (in case this is in a loop). */
233 : 18294 : sval = get_or_create_conjured_svalue (m_lhs_region);
234 : 18294 : if (const svalue *size_in_bytes = get_result_size_in_bytes (*this))
235 : : {
236 : 195 : const region *reg
237 : 195 : = m_model->deref_rvalue (sval, NULL_TREE, m_ctxt, false);
238 : 195 : m_model->set_dynamic_extents (reg, size_in_bytes, m_ctxt);
239 : : }
240 : : }
241 : 19374 : maybe_set_lhs (sval);
242 : : }
243 : :
244 : : /* Return the number of arguments used by the call statement. */
245 : :
246 : : unsigned
247 : 338796 : call_details::num_args () const
248 : : {
249 : 338796 : return gimple_call_num_args (&m_call);
250 : : }
251 : :
252 : : /* Return true if argument IDX is a size_t (or compatible with it). */
253 : :
254 : : bool
255 : 56413 : call_details::arg_is_size_p (unsigned idx) const
256 : : {
257 : 56413 : return types_compatible_p (get_arg_type (idx), size_type_node);
258 : : }
259 : :
260 : : /* Get the location of the call statement. */
261 : :
262 : : location_t
263 : 4776 : call_details::get_location () const
264 : : {
265 : 4776 : return m_call.location;
266 : : }
267 : :
268 : : /* Get argument IDX at the callsite as a tree. */
269 : :
270 : : tree
271 : 160010 : call_details::get_arg_tree (unsigned idx) const
272 : : {
273 : 160010 : return gimple_call_arg (&m_call, idx);
274 : : }
275 : :
276 : : /* Get the type of argument IDX. */
277 : :
278 : : tree
279 : 180399 : call_details::get_arg_type (unsigned idx) const
280 : : {
281 : 180399 : return TREE_TYPE (gimple_call_arg (&m_call, idx));
282 : : }
283 : :
284 : : /* Get argument IDX at the callsite as an svalue. */
285 : :
286 : : const svalue *
287 : 128446 : call_details::get_arg_svalue (unsigned idx) const
288 : : {
289 : 128446 : tree arg = get_arg_tree (idx);
290 : 128446 : return m_model->get_rvalue (arg, m_ctxt);
291 : : }
292 : :
293 : : /* If argument IDX's svalue at the callsite is of pointer type,
294 : : return the region it points to.
295 : : Otherwise return NULL. */
296 : :
297 : : const region *
298 : 117 : call_details::deref_ptr_arg (unsigned idx) const
299 : : {
300 : 117 : const svalue *ptr_sval = get_arg_svalue (idx);
301 : 117 : return m_model->deref_rvalue (ptr_sval, get_arg_tree (idx), m_ctxt);
302 : : }
303 : :
304 : : /* Attempt to get the string literal for argument IDX, or return NULL
305 : : otherwise.
306 : : For use when implementing "__analyzer_*" functions that take
307 : : string literals. */
308 : :
309 : : const char *
310 : 455 : call_details::get_arg_string_literal (unsigned idx) const
311 : : {
312 : 455 : const svalue *str_arg = get_arg_svalue (idx);
313 : 455 : if (const region *pointee = str_arg->maybe_get_region ())
314 : 451 : if (const string_region *string_reg = pointee->dyn_cast_string_region ())
315 : : {
316 : 451 : tree string_cst = string_reg->get_string_cst ();
317 : 451 : return TREE_STRING_POINTER (string_cst);
318 : : }
319 : : return NULL;
320 : : }
321 : :
322 : : /* Attempt to get the fndecl used at this call, if known, or NULL_TREE
323 : : otherwise. */
324 : :
325 : : tree
326 : 120513 : call_details::get_fndecl_for_call () const
327 : : {
328 : 120513 : return m_model->get_fndecl_for_call (m_call, m_ctxt);
329 : : }
330 : :
331 : : /* Dump a multiline representation of this call to PP. */
332 : :
333 : : void
334 : 0 : call_details::dump_to_pp (pretty_printer *pp, bool simple) const
335 : : {
336 : 0 : pp_string (pp, "gcall: ");
337 : 0 : pp_gimple_stmt_1 (pp, &m_call, 0 /* spc */, TDF_NONE /* flags */);
338 : 0 : pp_newline (pp);
339 : 0 : pp_string (pp, "return region: ");
340 : 0 : if (m_lhs_region)
341 : 0 : m_lhs_region->dump_to_pp (pp, simple);
342 : : else
343 : 0 : pp_string (pp, "NULL");
344 : 0 : pp_newline (pp);
345 : 0 : for (unsigned i = 0; i < gimple_call_num_args (&m_call); i++)
346 : : {
347 : 0 : const svalue *arg_sval = get_arg_svalue (i);
348 : 0 : pp_printf (pp, "arg %i: ", i);
349 : 0 : arg_sval->dump_to_pp (pp, simple);
350 : 0 : pp_newline (pp);
351 : : }
352 : 0 : }
353 : :
354 : : /* Dump a multiline representation of this call to stderr. */
355 : :
356 : : DEBUG_FUNCTION void
357 : 0 : call_details::dump (bool simple) const
358 : : {
359 : 0 : tree_dump_pretty_printer pp (stderr);
360 : 0 : dump_to_pp (&pp, simple);
361 : 0 : }
362 : :
363 : : /* Dump a tree-like representation of this call to stderr. */
364 : :
365 : : DEBUG_FUNCTION void
366 : 0 : call_details::dump () const
367 : : {
368 : 0 : text_art::dump (*this);
369 : 0 : }
370 : :
371 : : std::unique_ptr<text_art::tree_widget>
372 : 0 : call_details::make_dump_widget (const text_art::dump_widget_info &dwi) const
373 : : {
374 : 0 : using text_art::tree_widget;
375 : 0 : std::unique_ptr<tree_widget> cd_widget
376 : 0 : (tree_widget::from_fmt (dwi, nullptr, "Call Details"));
377 : :
378 : 0 : {
379 : 0 : pretty_printer the_pp;
380 : 0 : pretty_printer * const pp = &the_pp;
381 : 0 : pp_format_decoder (pp) = default_tree_printer;
382 : 0 : pp_string (pp, "gcall: ");
383 : 0 : pp_gimple_stmt_1 (pp, &m_call, 0 /* spc */, TDF_NONE /* flags */);
384 : 0 : cd_widget->add_child (tree_widget::make (dwi, pp));
385 : 0 : }
386 : 0 : {
387 : 0 : pretty_printer the_pp;
388 : 0 : pretty_printer * const pp = &the_pp;
389 : 0 : pp_format_decoder (pp) = default_tree_printer;
390 : 0 : pp_string (pp, "return region: ");
391 : 0 : if (m_lhs_region)
392 : 0 : m_lhs_region->dump_to_pp (pp, true);
393 : : else
394 : 0 : pp_string (pp, "NULL");
395 : 0 : auto w = tree_widget::make (dwi, pp);
396 : 0 : if (m_lhs_region)
397 : 0 : w->add_child (m_lhs_region->make_dump_widget (dwi));
398 : 0 : cd_widget->add_child (std::move (w));
399 : 0 : }
400 : 0 : if (gimple_call_num_args (&m_call) > 0)
401 : : {
402 : 0 : std::unique_ptr<tree_widget> args_widget
403 : 0 : (tree_widget::from_fmt (dwi, nullptr, "Arguments"));
404 : 0 : for (unsigned i = 0; i < gimple_call_num_args (&m_call); i++)
405 : : {
406 : 0 : pretty_printer the_pp;
407 : 0 : pretty_printer * const pp = &the_pp;
408 : 0 : pp_format_decoder (pp) = default_tree_printer;
409 : 0 : const svalue *arg_sval = get_arg_svalue (i);
410 : 0 : pp_printf (pp, "%i: ", i);
411 : 0 : arg_sval->dump_to_pp (pp, true);
412 : 0 : auto w = tree_widget::make (dwi, pp);
413 : 0 : w->add_child (arg_sval->make_dump_widget (dwi));
414 : 0 : args_widget->add_child (std::move (w));
415 : 0 : }
416 : 0 : cd_widget->add_child (std::move (args_widget));
417 : 0 : }
418 : :
419 : 0 : return cd_widget;
420 : : }
421 : :
422 : : /* Get a conjured_svalue for this call for REG,
423 : : and purge any state already relating to that conjured_svalue. */
424 : :
425 : : const svalue *
426 : 20554 : call_details::get_or_create_conjured_svalue (const region *reg) const
427 : : {
428 : 20554 : region_model_manager *mgr = m_model->get_manager ();
429 : 20554 : return mgr->get_or_create_conjured_svalue (reg->get_type (), &m_call, reg,
430 : 20554 : conjured_purge (m_model, m_ctxt));
431 : : }
432 : :
433 : : /* Look for a function attribute with name ATTR_NAME on the called
434 : : function (or on its type).
435 : : Return the attribute if one is found, otherwise return NULL_TREE. */
436 : :
437 : : tree
438 : 93868 : call_details::lookup_function_attribute (const char *attr_name) const
439 : : {
440 : 93868 : tree allocfntype;
441 : 93868 : if (tree fndecl = get_fndecl_for_call ())
442 : 89671 : allocfntype = TREE_TYPE (fndecl);
443 : : else
444 : 4197 : allocfntype = gimple_call_fntype (&m_call);
445 : :
446 : 90752 : if (!allocfntype)
447 : : return NULL_TREE;
448 : :
449 : 90752 : return lookup_attribute (attr_name, TYPE_ATTRIBUTES (allocfntype));
450 : : }
451 : :
452 : : void
453 : 3536 : call_details::check_for_null_terminated_string_arg (unsigned arg_idx) const
454 : : {
455 : 3536 : check_for_null_terminated_string_arg (arg_idx, false, nullptr);
456 : 3536 : }
457 : :
458 : : const svalue *
459 : 7206 : call_details::
460 : : check_for_null_terminated_string_arg (unsigned arg_idx,
461 : : bool include_terminator,
462 : : const svalue **out_sval) const
463 : : {
464 : 7206 : region_model *model = get_model ();
465 : 7206 : return model->check_for_null_terminated_string_arg (*this,
466 : : arg_idx,
467 : : include_terminator,
468 : 7206 : out_sval);
469 : : }
470 : :
471 : : /* A subclass of pending_diagnostic for complaining about overlapping
472 : : buffers. */
473 : :
474 : : class overlapping_buffers
475 : : : public pending_diagnostic_subclass<overlapping_buffers>
476 : : {
477 : : public:
478 : 36 : overlapping_buffers (tree fndecl,
479 : : const symbolic_byte_range &byte_range_a,
480 : : const symbolic_byte_range &byte_range_b,
481 : : const svalue *num_bytes_read_sval)
482 : 36 : : m_fndecl (fndecl),
483 : 36 : m_byte_range_a (byte_range_a),
484 : 36 : m_byte_range_b (byte_range_b),
485 : 36 : m_num_bytes_read_sval (num_bytes_read_sval)
486 : : {
487 : : }
488 : :
489 : 140 : const char *get_kind () const final override
490 : : {
491 : 140 : return "overlapping_buffers";
492 : : }
493 : :
494 : 36 : bool operator== (const overlapping_buffers &other) const
495 : : {
496 : 36 : return m_fndecl == other.m_fndecl;
497 : : }
498 : :
499 : 68 : int get_controlling_option () const final override
500 : : {
501 : 68 : return OPT_Wanalyzer_overlapping_buffers;
502 : : }
503 : :
504 : 32 : bool emit (diagnostic_emission_context &ctxt) final override
505 : : {
506 : 32 : auto_diagnostic_group d;
507 : :
508 : 32 : bool warned = ctxt.warn ("overlapping buffers passed as arguments to %qD",
509 : : m_fndecl);
510 : :
511 : : // TODO: draw a picture?
512 : :
513 : 32 : if (warned)
514 : 32 : inform (DECL_SOURCE_LOCATION (m_fndecl),
515 : : "the behavior of %qD is undefined for overlapping buffers",
516 : : m_fndecl);
517 : :
518 : 64 : return warned;
519 : 32 : }
520 : :
521 : : bool
522 : 64 : describe_final_event (pretty_printer &pp,
523 : : const evdesc::final_event &) final override
524 : : {
525 : 64 : pp_printf (&pp,
526 : : "overlapping buffers passed as arguments to %qD",
527 : : m_fndecl);
528 : 64 : return true;
529 : : }
530 : :
531 : 0 : void maybe_add_sarif_properties (sarif_object &result_obj)
532 : : const final override
533 : : {
534 : 0 : sarif_property_bag &props = result_obj.get_or_create_properties ();
535 : : #define PROPERTY_PREFIX "gcc/analyzer/overlapping_buffers/"
536 : 0 : props.set (PROPERTY_PREFIX "bytes_range_a",
537 : 0 : m_byte_range_a.to_json ());
538 : 0 : props.set (PROPERTY_PREFIX "bytes_range_b",
539 : 0 : m_byte_range_b.to_json ());
540 : 0 : props.set (PROPERTY_PREFIX "num_bytes_read_sval",
541 : 0 : m_num_bytes_read_sval->to_json ());
542 : : #undef PROPERTY_PREFIX
543 : 0 : }
544 : :
545 : : private:
546 : : tree m_fndecl;
547 : : symbolic_byte_range m_byte_range_a;
548 : : symbolic_byte_range m_byte_range_b;
549 : : const svalue *m_num_bytes_read_sval;
550 : : };
551 : :
552 : :
553 : : /* Check if the buffers pointed to by arguments ARG_IDX_A and ARG_IDX_B
554 : : (zero-based) overlap, when considering them both to be of size
555 : : NUM_BYTES_READ_SVAL.
556 : :
557 : : If they do overlap, complain to the context. */
558 : :
559 : : void
560 : 1415 : call_details::complain_about_overlap (unsigned arg_idx_a,
561 : : unsigned arg_idx_b,
562 : : const svalue *num_bytes_read_sval) const
563 : : {
564 : 1415 : region_model_context *ctxt = get_ctxt ();
565 : 1415 : if (!ctxt)
566 : 1379 : return;
567 : :
568 : 787 : region_model *model = get_model ();
569 : 787 : region_model_manager *mgr = model->get_manager ();
570 : :
571 : 787 : const svalue *arg_a_ptr_sval = get_arg_svalue (arg_idx_a);
572 : 787 : if (arg_a_ptr_sval->get_kind () == SK_UNKNOWN)
573 : : return;
574 : 755 : const region *arg_a_reg = model->deref_rvalue (arg_a_ptr_sval,
575 : : get_arg_tree (arg_idx_a),
576 : : ctxt);
577 : 755 : const svalue *arg_b_ptr_sval = get_arg_svalue (arg_idx_b);
578 : 755 : if (arg_b_ptr_sval->get_kind () == SK_UNKNOWN)
579 : : return;
580 : 737 : const region *arg_b_reg = model->deref_rvalue (arg_b_ptr_sval,
581 : : get_arg_tree (arg_idx_b),
582 : : ctxt);
583 : 737 : if (arg_a_reg->get_base_region () != arg_b_reg->get_base_region ())
584 : : return;
585 : :
586 : : /* Are they within NUM_BYTES_READ_SVAL of each other? */
587 : 72 : symbolic_byte_range byte_range_a (arg_a_reg->get_offset (mgr),
588 : : num_bytes_read_sval,
589 : 72 : *mgr);
590 : 72 : symbolic_byte_range byte_range_b (arg_b_reg->get_offset (mgr),
591 : : num_bytes_read_sval,
592 : 72 : *mgr);
593 : 72 : if (!byte_range_a.intersection (byte_range_b, *model).is_true ())
594 : : return;
595 : :
596 : 36 : ctxt->warn (std::make_unique<overlapping_buffers> (get_fndecl_for_call (),
597 : : byte_range_a,
598 : : byte_range_b,
599 : : num_bytes_read_sval));
600 : : }
601 : :
602 : : } // namespace ana
603 : :
604 : : #endif /* #if ENABLE_ANALYZER */
|