LCOV - code coverage report
Current view: top level - gcc/analyzer - call-details.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 66.1 % 236 156
Test Date: 2026-02-28 14:20:25 Functions: 81.8 % 33 27
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Helper class for handling a call with specific arguments.
       2              :    Copyright (C) 2020-2026 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 "diagnostics/sarif-sink.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       362297 : call_details::call_details (const gcall &call, region_model *model,
      44       362297 :                             region_model_context *ctxt)
      45       362297 : : m_call (call), m_model (model), m_ctxt (ctxt),
      46       362297 :   m_lhs_type (NULL_TREE), m_lhs_region (nullptr)
      47              : {
      48       362297 :   m_lhs_type = NULL_TREE;
      49       362297 :   if (tree lhs = gimple_call_lhs (&call))
      50              :     {
      51       142273 :       m_lhs_region = model->get_lvalue (lhs, ctxt);
      52       142273 :       m_lhs_type = TREE_TYPE (lhs);
      53              :     }
      54       362297 : }
      55              : 
      56              : /* call_details's ctor: copy CD, but override the context,
      57              :    using CTXT instead.  */
      58              : 
      59         1054 : call_details::call_details (const call_details &cd,
      60         1054 :                             region_model_context *ctxt)
      61         1054 : : m_call (cd.m_call), m_model (cd.m_model),
      62         1054 :   m_ctxt (ctxt),
      63         1054 :   m_lhs_type (cd.m_lhs_type),
      64         1054 :   m_lhs_region (cd.m_lhs_region)
      65              : {
      66         1054 : }
      67              : 
      68              : /* Get the manager from m_model.  */
      69              : 
      70              : region_model_manager *
      71       122109 : call_details::get_manager () const
      72              : {
      73       122109 :   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 nullptr;
      85              : }
      86              : 
      87              : /* Get any uncertainty_t associated with the region_model_context.  */
      88              : 
      89              : uncertainty_t *
      90          227 : call_details::get_uncertainty () const
      91              : {
      92          227 :   if (m_ctxt)
      93          193 :     return m_ctxt->get_uncertainty ();
      94              :   else
      95              :     return nullptr;
      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        32431 : call_details::maybe_set_lhs (const svalue *result) const
     104              : {
     105        32431 :   gcc_assert (result);
     106        32431 :   if (m_lhs_region)
     107              :     {
     108        30110 :       m_model->set_value (m_lhs_region, result, m_ctxt);
     109        30110 :       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        13430 : const_fn_p (const call_details &cd)
     120              : {
     121        13430 :   tree fndecl = cd.get_fndecl_for_call ();
     122        13430 :   if (!fndecl)
     123              :     return false;
     124        12041 :   gcc_assert (DECL_P (fndecl));
     125        12041 :   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 nullptr otherwise.  */
     131              : 
     132              : static const svalue *
     133        13430 : maybe_get_const_fn_result (const call_details &cd)
     134              : {
     135        13430 :   if (!const_fn_p (cd))
     136              :     return nullptr;
     137              : 
     138          928 :   unsigned num_args = cd.num_args ();
     139          928 :   if (num_args > const_fn_result_svalue::MAX_INPUTS)
     140              :     /* Too many arguments.  */
     141              :     return nullptr;
     142              : 
     143          896 :   auto_vec<const svalue *> inputs (num_args);
     144         1297 :   for (unsigned arg_idx = 0; arg_idx < num_args; arg_idx++)
     145              :     {
     146          472 :       const svalue *arg_sval = cd.get_arg_svalue (arg_idx);
     147          472 :       if (!arg_sval->can_have_associated_state_p ())
     148           71 :         return nullptr;
     149          401 :       inputs.quick_push (arg_sval);
     150              :     }
     151              : 
     152          825 :   region_model_manager *mgr = cd.get_manager ();
     153          825 :   const svalue *sval
     154          825 :     = mgr->get_or_create_const_fn_result_svalue (cd.get_lhs_type (),
     155              :                                                  cd.get_fndecl_for_call (),
     156              :                                                  inputs);
     157          825 :   return sval;
     158          896 : }
     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        12605 : get_result_size_in_bytes (const call_details &cd)
     167              : {
     168        12605 :   const tree attr = cd.lookup_function_attribute ("alloc_size");
     169        12605 :   if (!attr)
     170              :     return nullptr;
     171              : 
     172          125 :   const tree atval_1 = TREE_VALUE (attr);
     173          125 :   if (!atval_1)
     174              :     return nullptr;
     175              : 
     176          125 :   unsigned argidx1 = TREE_INT_CST_LOW (TREE_VALUE (atval_1)) - 1;
     177          125 :   if (cd.num_args () <= argidx1)
     178              :     return nullptr;
     179              : 
     180          125 :   const svalue *sval_arg1 = cd.get_arg_svalue (argidx1);
     181              : 
     182          125 :   if (const tree atval_2 = TREE_CHAIN (atval_1))
     183              :     {
     184              :       /* Two arguments.  */
     185           45 :       unsigned argidx2 = TREE_INT_CST_LOW (TREE_VALUE (atval_2)) - 1;
     186           45 :       if (cd.num_args () <= argidx2)
     187              :         return nullptr;
     188           45 :       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           45 :       return cd.get_manager ()->get_or_create_cast
     192           45 :         (size_type_node,
     193              :          cd.get_manager ()->get_or_create_binop (size_type_node,
     194              :                                                  MULT_EXPR,
     195           45 :                                                  sval_arg1, sval_arg2));
     196              :     }
     197              :   else
     198              :     /* Single argument.  */
     199           80 :     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        27498 : call_details::set_any_lhs_with_defaults () const
     214              : {
     215        27498 :   if (!m_lhs_region)
     216              :     return;
     217              : 
     218        13430 :   const svalue *sval = maybe_get_const_fn_result (*this);
     219        13430 :   if (!sval)
     220              :     {
     221        12605 :       region_model_manager *mgr = get_manager ();
     222        12605 :       if (lookup_function_attribute ("malloc"))
     223              :         {
     224            0 :           const region *new_reg
     225            0 :             = m_model->get_or_create_region_for_heap_alloc (nullptr, m_ctxt);
     226            0 :           m_model->mark_region_as_unknown (new_reg, nullptr);
     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        12605 :         sval = get_or_create_conjured_svalue (m_lhs_region);
     234        12605 :       if (const svalue *size_in_bytes = get_result_size_in_bytes (*this))
     235              :         {
     236          125 :           const region *reg
     237          125 :             = m_model->deref_rvalue (sval, NULL_TREE, m_ctxt, false);
     238          125 :           m_model->set_dynamic_extents (reg, size_in_bytes, m_ctxt);
     239              :         }
     240              :     }
     241        13430 :   maybe_set_lhs (sval);
     242              : }
     243              : 
     244              : /* Return the number of arguments used by the call statement.  */
     245              : 
     246              : unsigned
     247       388540 : call_details::num_args () const
     248              : {
     249       388540 :   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        63411 : call_details::arg_is_size_p (unsigned idx) const
     256              : {
     257        63411 :   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         5026 : call_details::get_location () const
     264              : {
     265         5026 :   return m_call.location;
     266              : }
     267              : 
     268              : /* Get argument IDX at the callsite as a tree.  */
     269              : 
     270              : tree
     271       166031 : call_details::get_arg_tree (unsigned idx) const
     272              : {
     273       166031 :   return gimple_call_arg (&m_call, idx);
     274              : }
     275              : 
     276              : /* Get the type of argument IDX.  */
     277              : 
     278              : tree
     279       198031 : call_details::get_arg_type (unsigned idx) const
     280              : {
     281       198031 :   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       116495 : call_details::get_arg_svalue (unsigned idx) const
     288              : {
     289       116495 :   tree arg = get_arg_tree (idx);
     290       116495 :   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 nullptr.  */
     296              : 
     297              : const region *
     298           81 : call_details::deref_ptr_arg (unsigned idx) const
     299              : {
     300           81 :   const svalue *ptr_sval = get_arg_svalue (idx);
     301           81 :   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 nullptr
     305              :    otherwise.
     306              :    For use when implementing "__analyzer_*" functions that take
     307              :    string literals.  */
     308              : 
     309              : const char *
     310          451 : call_details::get_arg_string_literal (unsigned idx) const
     311              : {
     312          451 :   const svalue *str_arg = get_arg_svalue (idx);
     313          451 :   if (const region *pointee = str_arg->maybe_get_region ())
     314          447 :     if (const string_region *string_reg = pointee->dyn_cast_string_region ())
     315              :       {
     316          447 :         tree string_cst = string_reg->get_string_cst ();
     317          447 :         return TREE_STRING_POINTER (string_cst);
     318              :       }
     319              :   return nullptr;
     320              : }
     321              : 
     322              : /* Attempt to get the fndecl used at this call, if known, or NULL_TREE
     323              :    otherwise.  */
     324              : 
     325              : tree
     326       261767 : call_details::get_fndecl_for_call () const
     327              : {
     328       261767 :   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        14854 : call_details::get_or_create_conjured_svalue (const region *reg) const
     427              : {
     428        14854 :   region_model_manager *mgr = m_model->get_manager ();
     429        14854 :   return mgr->get_or_create_conjured_svalue (reg->get_type (), &m_call, reg,
     430        14854 :                                              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        74314 : call_details::lookup_function_attribute (const char *attr_name) const
     439              : {
     440        74314 :   tree allocfntype;
     441        74314 :   if (tree fndecl = get_fndecl_for_call ())
     442        69908 :     allocfntype = TREE_TYPE (fndecl);
     443              :   else
     444         4406 :     allocfntype = gimple_call_fntype (&m_call);
     445              : 
     446        70742 :   if (!allocfntype)
     447              :     return NULL_TREE;
     448              : 
     449        70742 :   return lookup_attribute (attr_name, TYPE_ATTRIBUTES (allocfntype));
     450              : }
     451              : 
     452              : void
     453         2926 : call_details::check_for_null_terminated_string_arg (unsigned arg_idx) const
     454              : {
     455         2926 :   check_for_null_terminated_string_arg (arg_idx, false, nullptr);
     456         2926 : }
     457              : 
     458              : const svalue *
     459         6970 : call_details::
     460              : check_for_null_terminated_string_arg (unsigned arg_idx,
     461              :                                       bool include_terminator,
     462              :                                       const svalue **out_sval) const
     463              : {
     464         6970 :   region_model *model = get_model ();
     465         6970 :   return model->check_for_null_terminated_string_arg (*this,
     466              :                                                       arg_idx,
     467              :                                                       include_terminator,
     468         6970 :                                                       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          428 :   const char *get_kind () const final override
     490              :   {
     491          428 :     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 (diagnostics::sarif_object &result_obj)
     532              :     const final override
     533              :   {
     534            0 :     auto &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         1785 : call_details::complain_about_overlap (unsigned arg_idx_a,
     561              :                                       unsigned arg_idx_b,
     562              :                                       const svalue *num_bytes_read_sval) const
     563              : {
     564         1785 :   region_model_context *ctxt = get_ctxt ();
     565         1785 :   if (!ctxt)
     566         1749 :     return;
     567              : 
     568          850 :   region_model *model = get_model ();
     569          850 :   region_model_manager *mgr = model->get_manager ();
     570              : 
     571          850 :   const svalue *arg_a_ptr_sval = get_arg_svalue (arg_idx_a);
     572          850 :   if (arg_a_ptr_sval->get_kind () == SK_UNKNOWN)
     573              :     return;
     574          819 :   const region *arg_a_reg = model->deref_rvalue (arg_a_ptr_sval,
     575              :                                                  get_arg_tree (arg_idx_a),
     576              :                                                  ctxt);
     577          819 :   const svalue *arg_b_ptr_sval = get_arg_svalue (arg_idx_b);
     578          819 :   if (arg_b_ptr_sval->get_kind () == SK_UNKNOWN)
     579              :     return;
     580          806 :   const region *arg_b_reg = model->deref_rvalue (arg_b_ptr_sval,
     581              :                                                  get_arg_tree (arg_idx_b),
     582              :                                                  ctxt);
     583          806 :   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 */
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.