LCOV - code coverage report
Current view: top level - gcc/analyzer - bounds-checking.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 79.9 % 680 543
Test Date: 2025-08-30 13:27:53 Functions: 90.7 % 54 49
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Bounds-checking of reads and writes to memory regions.
       2                 :             :    Copyright (C) 2019-2025 Free Software Foundation, Inc.
       3                 :             : 
       4                 :             : This file is part of GCC.
       5                 :             : 
       6                 :             : GCC is free software; you can redistribute it and/or modify it
       7                 :             : under the terms of the GNU General Public License as published by
       8                 :             : the Free Software Foundation; either version 3, or (at your option)
       9                 :             : any later version.
      10                 :             : 
      11                 :             : GCC is distributed in the hope that it will be useful, but
      12                 :             : WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14                 :             : General Public License for more details.
      15                 :             : 
      16                 :             : You should have received a copy of the GNU General Public License
      17                 :             : along with GCC; see the file COPYING3.  If not see
      18                 :             : <http://www.gnu.org/licenses/>.  */
      19                 :             : 
      20                 :             : #include "analyzer/common.h"
      21                 :             : 
      22                 :             : #include "intl.h"
      23                 :             : #include "diagnostics/diagram.h"
      24                 :             : #include "diagnostics/sarif-sink.h"
      25                 :             : 
      26                 :             : #include "analyzer/analyzer-logging.h"
      27                 :             : #include "analyzer/region-model.h"
      28                 :             : #include "analyzer/checker-event.h"
      29                 :             : #include "analyzer/checker-path.h"
      30                 :             : #include "analyzer/access-diagram.h"
      31                 :             : 
      32                 :             : #if ENABLE_ANALYZER
      33                 :             : 
      34                 :             : namespace ana {
      35                 :             : 
      36                 :             : /* Abstract base class for all out-of-bounds warnings.  */
      37                 :             : 
      38                 :             : class out_of_bounds : public pending_diagnostic
      39                 :             : {
      40                 :             : public:
      41                 :             :   class oob_region_creation_event_capacity : public region_creation_event_capacity
      42                 :             :   {
      43                 :             :   public:
      44                 :         440 :     oob_region_creation_event_capacity (tree byte_capacity,
      45                 :             :                                         const event_loc_info &loc_info,
      46                 :             :                                         out_of_bounds &oob)
      47                 :         440 :     : region_creation_event_capacity (byte_capacity,
      48                 :             :                                       loc_info),
      49                 :         440 :       m_oob (oob)
      50                 :             :     {
      51                 :             :     }
      52                 :         440 :     void prepare_for_emission (checker_path *path,
      53                 :             :                                pending_diagnostic *pd,
      54                 :             :                                diagnostics::paths::event_id_t emission_id) override
      55                 :             :     {
      56                 :         440 :       region_creation_event_capacity::prepare_for_emission (path,
      57                 :             :                                                             pd,
      58                 :             :                                                             emission_id);
      59                 :         440 :       m_oob.m_region_creation_event_id = emission_id;
      60                 :         440 :     }
      61                 :             :   private:
      62                 :             :     out_of_bounds &m_oob;
      63                 :             :   };
      64                 :             : 
      65                 :         784 :   out_of_bounds (const region_model &model,
      66                 :             :                  const region *reg,
      67                 :             :                  tree diag_arg,
      68                 :             :                  const svalue *sval_hint)
      69                 :         467 :   : m_model (model), m_reg (reg), m_diag_arg (diag_arg), m_sval_hint (sval_hint)
      70                 :             :   {}
      71                 :             : 
      72                 :         754 :   bool subclass_equal_p (const pending_diagnostic &base_other) const override
      73                 :             :   {
      74                 :         754 :     const out_of_bounds &other
      75                 :             :       (static_cast <const out_of_bounds &>(base_other));
      76                 :         754 :     return (m_reg == other.m_reg
      77                 :         754 :             && pending_diagnostic::same_tree_p (m_diag_arg, other.m_diag_arg));
      78                 :             :   }
      79                 :             : 
      80                 :        1331 :   int get_controlling_option () const final override
      81                 :             :   {
      82                 :        1331 :     return OPT_Wanalyzer_out_of_bounds;
      83                 :             :   }
      84                 :             : 
      85                 :         555 :   void mark_interesting_stuff (interesting_t *interest) final override
      86                 :             :   {
      87                 :         555 :     interest->add_region_creation (m_reg->get_base_region ());
      88                 :         555 :   }
      89                 :             : 
      90                 :         207 :   void add_region_creation_events (const region *,
      91                 :             :                                    tree byte_capacity,
      92                 :             :                                    const event_loc_info &loc_info,
      93                 :             :                                    checker_path &emission_path) override
      94                 :             :   {
      95                 :             :     /* The memory space is described in the diagnostic message itself,
      96                 :             :        so we don't need an event for that.  */
      97                 :         207 :     if (byte_capacity)
      98                 :         133 :       emission_path.add_event
      99                 :         133 :         (std::make_unique<oob_region_creation_event_capacity> (byte_capacity,
     100                 :             :                                                                loc_info,
     101                 :             :                                                                *this));
     102                 :         207 :   }
     103                 :             : 
     104                 :             :   void
     105                 :           4 :   maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
     106                 :             :     const override
     107                 :             :   {
     108                 :           4 :     auto &props = result_obj.get_or_create_properties ();
     109                 :             : #define PROPERTY_PREFIX "gcc/analyzer/out_of_bounds/"
     110                 :           8 :     props.set_string (PROPERTY_PREFIX "dir",
     111                 :           4 :                       get_dir () == access_direction::read ? "read" : "write");
     112                 :           4 :     props.set (PROPERTY_PREFIX "model", m_model.to_json ());
     113                 :           4 :     props.set (PROPERTY_PREFIX "region", m_reg->to_json ());
     114                 :           4 :     props.set (PROPERTY_PREFIX "diag_arg", tree_to_json (m_diag_arg));
     115                 :           4 :     if (m_sval_hint)
     116                 :           4 :       props.set (PROPERTY_PREFIX "sval_hint", m_sval_hint->to_json ());
     117                 :           8 :     props.set (PROPERTY_PREFIX "region_creation_event_id",
     118                 :           4 :                diagnostic_event_id_to_json (m_region_creation_event_id));
     119                 :             : #undef PROPERTY_PREFIX
     120                 :           4 :   }
     121                 :             : 
     122                 :             :   virtual enum access_direction get_dir () const = 0;
     123                 :             : 
     124                 :             : protected:
     125                 :         555 :   enum memory_space get_memory_space () const
     126                 :             :   {
     127                 :         555 :     return m_reg->get_memory_space ();
     128                 :             :   }
     129                 :             : 
     130                 :             :   void
     131                 :         555 :   maybe_show_notes (diagnostic_emission_context &ctxt) const
     132                 :             :   {
     133                 :         555 :     maybe_describe_array_bounds (ctxt.get_location ());
     134                 :         555 :     maybe_show_diagram (ctxt.get_logger ());
     135                 :         555 :   }
     136                 :             : 
     137                 :             :   /* Potentially add a note about valid ways to index this array, such
     138                 :             :      as (given "int arr[10];"):
     139                 :             :        note: valid subscripts for 'arr' are '[0]' to '[9]'
     140                 :             :      We print the '[' and ']' characters so as to express the valid
     141                 :             :      subscripts using C syntax, rather than just as byte ranges,
     142                 :             :      which hopefully is more clear to the user.  */
     143                 :             :   void
     144                 :         555 :   maybe_describe_array_bounds (location_t loc) const
     145                 :             :   {
     146                 :         555 :     if (!m_diag_arg)
     147                 :             :       return;
     148                 :         398 :     tree t = TREE_TYPE (m_diag_arg);
     149                 :         398 :     if (!t)
     150                 :             :       return;
     151                 :         398 :     if (TREE_CODE (t) != ARRAY_TYPE)
     152                 :             :       return;
     153                 :         355 :     tree domain = TYPE_DOMAIN (t);
     154                 :         355 :     if (!domain)
     155                 :             :       return;
     156                 :         354 :     tree max_idx = TYPE_MAX_VALUE (domain);
     157                 :         354 :     if (!max_idx)
     158                 :             :       return;
     159                 :         352 :     tree min_idx = TYPE_MIN_VALUE (domain);
     160                 :         352 :     inform (loc,
     161                 :             :             "valid subscripts for %qE are %<[%E]%> to %<[%E]%>",
     162                 :             :             m_diag_arg, min_idx, max_idx);
     163                 :             :   }
     164                 :             : 
     165                 :             :   void
     166                 :         555 :   maybe_show_diagram (logger *logger) const
     167                 :             :   {
     168                 :         555 :     access_operation op (m_model, get_dir (), *m_reg, m_sval_hint);
     169                 :             : 
     170                 :             :     /* Don't attempt to make a diagram if there's no valid way of
     171                 :             :        accessing the base region (e.g. a 0-element array).  */
     172                 :         555 :     if (op.get_valid_bits ().empty_p ())
     173                 :           8 :       return;
     174                 :             : 
     175                 :         551 :     if (const text_art::theme *theme = global_dc->get_diagram_theme ())
     176                 :             :       {
     177                 :          72 :         text_art::style_manager sm;
     178                 :          72 :         text_art::canvas canvas (make_access_diagram (op, sm, *theme, logger));
     179                 :          72 :         if (canvas.get_size ().w == 0 && canvas.get_size ().h == 0)
     180                 :             :           {
     181                 :             :             /* In lieu of exceptions, return a zero-sized diagram if there's
     182                 :             :                a problem.  Give up if that's happened.  */
     183                 :           4 :             return;
     184                 :             :           }
     185                 :          68 :         diagnostics::diagram diagram
     186                 :             :           (canvas,
     187                 :             :            /* Alt text.  */
     188                 :          68 :            _("Diagram visualizing the predicted out-of-bounds access"));
     189                 :          68 :         global_dc->emit_diagram (diagram);
     190                 :          72 :       }
     191                 :             :   }
     192                 :             : 
     193                 :             :   text_art::canvas
     194                 :          72 :   make_access_diagram (const access_operation &op,
     195                 :             :                        text_art::style_manager &sm,
     196                 :             :                        const text_art::theme &theme,
     197                 :             :                        logger *logger) const
     198                 :             :   {
     199                 :          72 :     access_diagram d (op, m_region_creation_event_id, sm, theme, logger);
     200                 :          72 :     return d.to_canvas (sm);
     201                 :          72 :   }
     202                 :             : 
     203                 :             :   region_model m_model;
     204                 :             :   const region *m_reg;
     205                 :             :   tree m_diag_arg;
     206                 :             :   const svalue *m_sval_hint;
     207                 :             :   diagnostics::paths::event_id_t m_region_creation_event_id;
     208                 :             : };
     209                 :             : 
     210                 :             : /* Abstract base class for all out-of-bounds warnings where the
     211                 :             :    out-of-bounds range is concrete.  */
     212                 :             : 
     213                 :             : class concrete_out_of_bounds : public out_of_bounds
     214                 :             : {
     215                 :             : public:
     216                 :         639 :   concrete_out_of_bounds (const region_model &model,
     217                 :             :                           const region *reg, tree diag_arg,
     218                 :             :                           bit_range out_of_bounds_bits,
     219                 :             :                           const svalue *sval_hint)
     220                 :         639 :   : out_of_bounds (model, reg, diag_arg, sval_hint),
     221                 :        1278 :     m_out_of_bounds_bits (out_of_bounds_bits)
     222                 :             :   {}
     223                 :             : 
     224                 :         609 :   bool subclass_equal_p (const pending_diagnostic &base_other) const override
     225                 :             :   {
     226                 :         609 :     const concrete_out_of_bounds &other
     227                 :             :       (static_cast <const concrete_out_of_bounds &>(base_other));
     228                 :         609 :     return (out_of_bounds::subclass_equal_p (other)
     229                 :         609 :             && m_out_of_bounds_bits == other.m_out_of_bounds_bits);
     230                 :             :   }
     231                 :             : 
     232                 :           4 :   void maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
     233                 :             :     const override
     234                 :             :   {
     235                 :           4 :     out_of_bounds::maybe_add_sarif_properties (result_obj);
     236                 :           4 :     auto &props = result_obj.get_or_create_properties ();
     237                 :             : #define PROPERTY_PREFIX "gcc/analyzer/concrete_out_of_bounds/"
     238                 :           8 :     props.set (PROPERTY_PREFIX "out_of_bounds_bits",
     239                 :           4 :                m_out_of_bounds_bits.to_json ());
     240                 :           4 :     byte_range out_of_bounds_bytes (0, 0);
     241                 :           4 :     if (get_out_of_bounds_bytes (&out_of_bounds_bytes))
     242                 :           8 :       props.set (PROPERTY_PREFIX "out_of_bounds_bytes",
     243                 :           4 :                  out_of_bounds_bytes.to_json ());
     244                 :             : #undef PROPERTY_PREFIX
     245                 :           4 :   }
     246                 :             : 
     247                 :         850 :   bool get_out_of_bounds_bytes (byte_range *out) const
     248                 :             :   {
     249                 :           4 :     return m_out_of_bounds_bits.as_byte_range (out);
     250                 :             :   }
     251                 :             : 
     252                 :             : protected:
     253                 :             :   bit_range m_out_of_bounds_bits;
     254                 :             : };
     255                 :             : 
     256                 :             : /* Abstract subclass to complaing about concrete out-of-bounds
     257                 :             :    past the end of the buffer.  */
     258                 :             : 
     259                 :             : class concrete_past_the_end : public concrete_out_of_bounds
     260                 :             : {
     261                 :             : public:
     262                 :         467 :   concrete_past_the_end (const region_model &model,
     263                 :             :                          const region *reg, tree diag_arg, bit_range range,
     264                 :             :                          tree bit_bound,
     265                 :             :                          const svalue *sval_hint)
     266                 :         467 :   : concrete_out_of_bounds (model, reg, diag_arg, range, sval_hint),
     267                 :         467 :     m_bit_bound (bit_bound),
     268                 :         467 :     m_byte_bound (NULL_TREE)
     269                 :             :   {
     270                 :         467 :     if (m_bit_bound && TREE_CODE (m_bit_bound) == INTEGER_CST)
     271                 :         467 :       m_byte_bound
     272                 :         934 :         = wide_int_to_tree (size_type_node,
     273                 :         467 :                             wi::to_offset (m_bit_bound) >> LOG2_BITS_PER_UNIT);
     274                 :         467 :   }
     275                 :             : 
     276                 :             :   bool
     277                 :         441 :   subclass_equal_p (const pending_diagnostic &base_other) const final override
     278                 :             :   {
     279                 :         441 :     const concrete_past_the_end &other
     280                 :             :       (static_cast <const concrete_past_the_end &>(base_other));
     281                 :         441 :     return (concrete_out_of_bounds::subclass_equal_p (other)
     282                 :         882 :             && pending_diagnostic::same_tree_p (m_bit_bound,
     283                 :         441 :                                                 other.m_bit_bound));
     284                 :             :   }
     285                 :             : 
     286                 :         307 :   void add_region_creation_events (const region *,
     287                 :             :                                    tree,
     288                 :             :                                    const event_loc_info &loc_info,
     289                 :             :                                    checker_path &emission_path) final override
     290                 :             :   {
     291                 :         307 :     if (m_byte_bound && TREE_CODE (m_byte_bound) == INTEGER_CST)
     292                 :         307 :       emission_path.add_event
     293                 :         307 :         (std::make_unique<oob_region_creation_event_capacity> (m_byte_bound,
     294                 :             :                                                                loc_info,
     295                 :             :                                                                *this));
     296                 :         307 :   }
     297                 :             : 
     298                 :           4 :   void maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
     299                 :             :     const final override
     300                 :             :   {
     301                 :           4 :     concrete_out_of_bounds::maybe_add_sarif_properties (result_obj);
     302                 :           4 :     auto &props = result_obj.get_or_create_properties ();
     303                 :             : #define PROPERTY_PREFIX "gcc/analyzer/concrete_past_the_end/"
     304                 :           8 :     props.set (PROPERTY_PREFIX "bit_bound",
     305                 :           4 :                tree_to_json (m_bit_bound));
     306                 :           8 :     props.set (PROPERTY_PREFIX "byte_bound",
     307                 :           4 :                tree_to_json (m_byte_bound));
     308                 :             : #undef PROPERTY_PREFIX
     309                 :           4 :   }
     310                 :             : 
     311                 :             : protected:
     312                 :             :   tree m_bit_bound;
     313                 :             :   tree m_byte_bound;
     314                 :             : };
     315                 :             : 
     316                 :             : /* Concrete subclass to complain about buffer overflows.  */
     317                 :             : 
     318                 :             : class concrete_buffer_overflow : public concrete_past_the_end
     319                 :             : {
     320                 :             : public:
     321                 :         178 :   concrete_buffer_overflow (const region_model &model,
     322                 :             :                             const region *reg, tree diag_arg,
     323                 :             :                             bit_range range, tree bit_bound,
     324                 :             :                             const svalue *sval_hint)
     325                 :         178 :   : concrete_past_the_end (model, reg, diag_arg, range, bit_bound, sval_hint)
     326                 :             :   {}
     327                 :             : 
     328                 :        1530 :   const char *get_kind () const final override
     329                 :             :   {
     330                 :        1530 :     return "concrete_buffer_overflow";
     331                 :             :   }
     332                 :             : 
     333                 :         156 :   bool emit (diagnostic_emission_context &ctxt) final override
     334                 :             :   {
     335                 :         156 :     bool warned;
     336                 :         156 :     switch (get_memory_space ())
     337                 :             :       {
     338                 :          54 :       default:
     339                 :          54 :         ctxt.add_cwe (787);
     340                 :          54 :         warned = ctxt.warn ("buffer overflow");
     341                 :          54 :         break;
     342                 :          73 :       case MEMSPACE_STACK:
     343                 :          73 :         ctxt.add_cwe (121);
     344                 :          73 :         warned = ctxt.warn ("stack-based buffer overflow");
     345                 :          73 :         break;
     346                 :          29 :       case MEMSPACE_HEAP:
     347                 :          29 :         ctxt.add_cwe (122);
     348                 :          29 :         warned = ctxt.warn ("heap-based buffer overflow");
     349                 :          29 :         break;
     350                 :             :       }
     351                 :             : 
     352                 :         156 :     if (warned)
     353                 :             :       {
     354                 :         156 :         if (wi::fits_uhwi_p (m_out_of_bounds_bits.m_size_in_bits))
     355                 :             :           {
     356                 :         156 :             unsigned HOST_WIDE_INT num_bad_bits
     357                 :         156 :               = m_out_of_bounds_bits.m_size_in_bits.to_uhwi ();
     358                 :         156 :             if (num_bad_bits % BITS_PER_UNIT == 0)
     359                 :             :               {
     360                 :         156 :                 unsigned HOST_WIDE_INT num_bad_bytes
     361                 :             :                   = num_bad_bits / BITS_PER_UNIT;
     362                 :         156 :                 if (m_diag_arg)
     363                 :         124 :                   inform_n (ctxt.get_location (),
     364                 :             :                             num_bad_bytes,
     365                 :             :                             "write of %wu byte to beyond the end of %qE",
     366                 :             :                             "write of %wu bytes to beyond the end of %qE",
     367                 :             :                             num_bad_bytes,
     368                 :             :                             m_diag_arg);
     369                 :             :                 else
     370                 :          32 :                   inform_n (ctxt.get_location (),
     371                 :             :                             num_bad_bytes,
     372                 :             :                             "write of %wu byte to beyond the end of the region",
     373                 :             :                             "write of %wu bytes to beyond the end of the region",
     374                 :             :                             num_bad_bytes);
     375                 :             :               }
     376                 :             :             else
     377                 :             :               {
     378                 :           0 :                 if (m_diag_arg)
     379                 :           0 :                   inform_n (ctxt.get_location (),
     380                 :             :                             num_bad_bits,
     381                 :             :                             "write of %wu bit to beyond the end of %qE",
     382                 :             :                             "write of %wu bits to beyond the end of %qE",
     383                 :             :                             num_bad_bits,
     384                 :             :                             m_diag_arg);
     385                 :             :                 else
     386                 :           0 :                   inform_n (ctxt.get_location (),
     387                 :             :                             num_bad_bits,
     388                 :             :                             "write of %wu bit to beyond the end of the region",
     389                 :             :                             "write of %wu bits to beyond the end of the region",
     390                 :             :                             num_bad_bits);
     391                 :             :               }
     392                 :             :           }
     393                 :           0 :         else if (m_diag_arg)
     394                 :           0 :           inform (ctxt.get_location (),
     395                 :             :                   "write to beyond the end of %qE",
     396                 :             :                   m_diag_arg);
     397                 :             : 
     398                 :         156 :         maybe_show_notes (ctxt);
     399                 :             :       }
     400                 :             : 
     401                 :         156 :     return warned;
     402                 :             :   }
     403                 :             : 
     404                 :             :   bool
     405                 :         312 :   describe_final_event (pretty_printer &pp,
     406                 :             :                         const evdesc::final_event &) final override
     407                 :             :   {
     408                 :         312 :     if (m_byte_bound || !m_bit_bound)
     409                 :             :       {
     410                 :         312 :         byte_range out_of_bounds_bytes (0, 0);
     411                 :         312 :         if (get_out_of_bounds_bytes (&out_of_bounds_bytes))
     412                 :             :           {
     413                 :         312 :             describe_final_event_as_bytes (pp, out_of_bounds_bytes);
     414                 :         312 :             return true;
     415                 :             :           }
     416                 :             :       }
     417                 :           0 :     describe_final_event_as_bits (pp);
     418                 :           0 :     return true;
     419                 :             :   }
     420                 :             : 
     421                 :             :   void
     422                 :         312 :   describe_final_event_as_bytes (pretty_printer &pp,
     423                 :             :                                  const byte_range &out_of_bounds_bytes)
     424                 :             :   {
     425                 :         312 :     byte_size_t start = out_of_bounds_bytes.get_start_byte_offset ();
     426                 :         312 :     byte_size_t end = out_of_bounds_bytes.get_last_byte_offset ();
     427                 :         312 :     char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     428                 :         312 :     print_dec (start, start_buf, SIGNED);
     429                 :         312 :     char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     430                 :         312 :     print_dec (end, end_buf, SIGNED);
     431                 :             : 
     432                 :         312 :     if (start == end)
     433                 :             :       {
     434                 :          84 :         if (m_diag_arg)
     435                 :          56 :           pp_printf (&pp,
     436                 :             :                      "out-of-bounds write at byte %s but %qE"
     437                 :             :                      " ends at byte %E", start_buf, m_diag_arg,
     438                 :             :                      m_byte_bound);
     439                 :             :         else
     440                 :          28 :           pp_printf (&pp,
     441                 :             :                      "out-of-bounds write at byte %s but region"
     442                 :             :                      " ends at byte %E", start_buf,
     443                 :             :                      m_byte_bound);
     444                 :             :       }
     445                 :             :     else
     446                 :             :       {
     447                 :         228 :         if (m_diag_arg)
     448                 :         192 :           pp_printf (&pp,
     449                 :             :                      "out-of-bounds write from byte %s till"
     450                 :             :                      " byte %s but %qE ends at byte %E",
     451                 :             :                      start_buf, end_buf, m_diag_arg,
     452                 :             :                      m_byte_bound);
     453                 :             :         else
     454                 :          36 :           pp_printf (&pp,
     455                 :             :                      "out-of-bounds write from byte %s till"
     456                 :             :                      " byte %s but region ends at byte %E",
     457                 :             :                      start_buf, end_buf, m_byte_bound);
     458                 :             :       }
     459                 :         312 :   }
     460                 :             : 
     461                 :             :   void
     462                 :           0 :   describe_final_event_as_bits (pretty_printer &pp)
     463                 :             :   {
     464                 :           0 :     bit_size_t start = m_out_of_bounds_bits.get_start_bit_offset ();
     465                 :           0 :     bit_size_t end = m_out_of_bounds_bits.get_last_bit_offset ();
     466                 :           0 :     char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     467                 :           0 :     print_dec (start, start_buf, SIGNED);
     468                 :           0 :     char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     469                 :           0 :     print_dec (end, end_buf, SIGNED);
     470                 :             : 
     471                 :           0 :     if (start == end)
     472                 :             :       {
     473                 :           0 :         if (m_diag_arg)
     474                 :           0 :           pp_printf (&pp,
     475                 :             :                      "out-of-bounds write at bit %s but %qE"
     476                 :             :                      " ends at bit %E", start_buf, m_diag_arg,
     477                 :             :                      m_bit_bound);
     478                 :             :         else
     479                 :           0 :           pp_printf (&pp,
     480                 :             :                      "out-of-bounds write at bit %s but region"
     481                 :             :                      " ends at bit %E", start_buf,
     482                 :             :                      m_bit_bound);
     483                 :             :       }
     484                 :             :     else
     485                 :             :       {
     486                 :           0 :         if (m_diag_arg)
     487                 :           0 :           pp_printf (&pp,
     488                 :             :                      "out-of-bounds write from bit %s till"
     489                 :             :                      " bit %s but %qE ends at bit %E",
     490                 :             :                      start_buf, end_buf, m_diag_arg,
     491                 :             :                      m_bit_bound);
     492                 :             :         else
     493                 :           0 :           pp_printf (&pp,
     494                 :             :                      "out-of-bounds write from bit %s till"
     495                 :             :                      " bit %s but region ends at bit %E",
     496                 :             :                      start_buf, end_buf, m_bit_bound);
     497                 :             :       }
     498                 :           0 :   }
     499                 :             : 
     500                 :         160 :   enum access_direction get_dir () const final override { return access_direction::write; }
     501                 :             : };
     502                 :             : 
     503                 :             : /* Concrete subclass to complain about buffer over-reads.  */
     504                 :             : 
     505                 :             : class concrete_buffer_over_read : public concrete_past_the_end
     506                 :             : {
     507                 :             : public:
     508                 :         289 :   concrete_buffer_over_read (const region_model &model,
     509                 :             :                              const region *reg, tree diag_arg,
     510                 :             :                              bit_range range, tree bit_bound)
     511                 :         289 :   : concrete_past_the_end (model, reg, diag_arg, range, bit_bound, nullptr)
     512                 :             :   {}
     513                 :             : 
     514                 :        1763 :   const char *get_kind () const final override
     515                 :             :   {
     516                 :        1763 :     return "concrete_buffer_over_read";
     517                 :             :   }
     518                 :             : 
     519                 :         154 :   bool emit (diagnostic_emission_context &ctxt) final override
     520                 :             :   {
     521                 :         154 :     bool warned;
     522                 :         154 :     ctxt.add_cwe (126);
     523                 :         154 :     switch (get_memory_space ())
     524                 :             :       {
     525                 :          44 :       default:
     526                 :          44 :         warned = ctxt.warn ("buffer over-read");
     527                 :          44 :         break;
     528                 :         102 :       case MEMSPACE_STACK:
     529                 :         102 :         warned = ctxt.warn ("stack-based buffer over-read");
     530                 :         102 :         break;
     531                 :           8 :       case MEMSPACE_HEAP:
     532                 :           8 :         warned = ctxt.warn ("heap-based buffer over-read");
     533                 :           8 :         break;
     534                 :             :       }
     535                 :             : 
     536                 :         154 :     if (warned)
     537                 :             :       {
     538                 :         154 :         if (wi::fits_uhwi_p (m_out_of_bounds_bits.m_size_in_bits))
     539                 :             :           {
     540                 :         154 :             unsigned HOST_WIDE_INT num_bad_bits
     541                 :         154 :               = m_out_of_bounds_bits.m_size_in_bits.to_uhwi ();
     542                 :         154 :             if (num_bad_bits % BITS_PER_UNIT == 0)
     543                 :             :               {
     544                 :         154 :                 unsigned HOST_WIDE_INT num_bad_bytes
     545                 :             :                   = num_bad_bits / BITS_PER_UNIT;
     546                 :         154 :                 if (m_diag_arg)
     547                 :         146 :                   inform_n (ctxt.get_location (),
     548                 :             :                             num_bad_bytes,
     549                 :             :                             "read of %wu byte from after the end of %qE",
     550                 :             :                             "read of %wu bytes from after the end of %qE",
     551                 :             :                             num_bad_bytes,
     552                 :             :                             m_diag_arg);
     553                 :             :                 else
     554                 :           8 :                   inform_n (ctxt.get_location (),
     555                 :             :                             num_bad_bytes,
     556                 :             :                             "read of %wu byte from after the end of the region",
     557                 :             :                             "read of %wu bytes from after the end of the region",
     558                 :             :                             num_bad_bytes);
     559                 :             :               }
     560                 :             :             else
     561                 :             :               {
     562                 :           0 :                 if (m_diag_arg)
     563                 :           0 :                   inform_n (ctxt.get_location (),
     564                 :             :                             num_bad_bits,
     565                 :             :                             "read of %wu bit from after the end of %qE",
     566                 :             :                             "read of %wu bits from after the end of %qE",
     567                 :             :                             num_bad_bits,
     568                 :             :                             m_diag_arg);
     569                 :             :                 else
     570                 :           0 :                   inform_n (ctxt.get_location (),
     571                 :             :                             num_bad_bits,
     572                 :             :                             "read of %wu bit from after the end of the region",
     573                 :             :                             "read of %wu bits from after the end of the region",
     574                 :             :                             num_bad_bits);
     575                 :             :               }
     576                 :             :           }
     577                 :           0 :         else if (m_diag_arg)
     578                 :           0 :           inform (ctxt.get_location (),
     579                 :             :                   "read from after the end of %qE",
     580                 :             :                   m_diag_arg);
     581                 :             : 
     582                 :         154 :         maybe_show_notes (ctxt);
     583                 :             :       }
     584                 :             : 
     585                 :         154 :     return warned;
     586                 :             :   }
     587                 :             : 
     588                 :             :   bool
     589                 :         308 :   describe_final_event (pretty_printer &pp,
     590                 :             :                         const evdesc::final_event &) final override
     591                 :             :   {
     592                 :         308 :     if (m_byte_bound || !m_bit_bound)
     593                 :             :       {
     594                 :         308 :         byte_range out_of_bounds_bytes (0, 0);
     595                 :         308 :         if (get_out_of_bounds_bytes (&out_of_bounds_bytes))
     596                 :             :           {
     597                 :         308 :             describe_final_event_as_bytes (pp, out_of_bounds_bytes);
     598                 :         308 :             return true;
     599                 :             :           }
     600                 :             :       }
     601                 :           0 :     describe_final_event_as_bits (pp);
     602                 :           0 :     return true;
     603                 :             :   }
     604                 :             : 
     605                 :             :   void
     606                 :         308 :   describe_final_event_as_bytes (pretty_printer &pp,
     607                 :             :                                  const byte_range &out_of_bounds_bytes)
     608                 :             :   {
     609                 :         308 :     byte_size_t start = out_of_bounds_bytes.get_start_byte_offset ();
     610                 :         308 :     byte_size_t end = out_of_bounds_bytes.get_last_byte_offset ();
     611                 :         308 :     char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     612                 :         308 :     print_dec (start, start_buf, SIGNED);
     613                 :         308 :     char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     614                 :         308 :     print_dec (end, end_buf, SIGNED);
     615                 :             : 
     616                 :         308 :     if (start == end)
     617                 :             :       {
     618                 :         206 :         if (m_diag_arg)
     619                 :         198 :           pp_printf (&pp,
     620                 :             :                      "out-of-bounds read at byte %s but %qE"
     621                 :             :                      " ends at byte %E", start_buf, m_diag_arg,
     622                 :             :                      m_byte_bound);
     623                 :             :         else
     624                 :           8 :           pp_printf (&pp,
     625                 :             :                      "out-of-bounds read at byte %s but region"
     626                 :             :                      " ends at byte %E", start_buf,
     627                 :             :                      m_byte_bound);
     628                 :             :       }
     629                 :             :     else
     630                 :             :       {
     631                 :         102 :         if (m_diag_arg)
     632                 :          94 :           pp_printf (&pp,
     633                 :             :                      "out-of-bounds read from byte %s till"
     634                 :             :                      " byte %s but %qE ends at byte %E",
     635                 :             :                      start_buf, end_buf, m_diag_arg,
     636                 :             :                      m_byte_bound);
     637                 :             :         else
     638                 :           8 :           pp_printf (&pp,
     639                 :             :                      "out-of-bounds read from byte %s till"
     640                 :             :                      " byte %s but region ends at byte %E",
     641                 :             :                      start_buf, end_buf, m_byte_bound);
     642                 :             :       }
     643                 :         308 :   }
     644                 :             : 
     645                 :             :   void
     646                 :           0 :   describe_final_event_as_bits (pretty_printer &pp)
     647                 :             :   {
     648                 :           0 :     bit_size_t start = m_out_of_bounds_bits.get_start_bit_offset ();
     649                 :           0 :     bit_size_t end = m_out_of_bounds_bits.get_last_bit_offset ();
     650                 :           0 :     char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     651                 :           0 :     print_dec (start, start_buf, SIGNED);
     652                 :           0 :     char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     653                 :           0 :     print_dec (end, end_buf, SIGNED);
     654                 :             : 
     655                 :           0 :     if (start == end)
     656                 :             :       {
     657                 :           0 :         if (m_diag_arg)
     658                 :           0 :           pp_printf (&pp,
     659                 :             :                      "out-of-bounds read at bit %s but %qE"
     660                 :             :                      " ends at bit %E", start_buf, m_diag_arg,
     661                 :             :                      m_bit_bound);
     662                 :             :         else
     663                 :           0 :           pp_printf (&pp,
     664                 :             :                      "out-of-bounds read at bit %s but region"
     665                 :             :                      " ends at bit %E", start_buf,
     666                 :             :                      m_bit_bound);
     667                 :             :       }
     668                 :             :     else
     669                 :             :       {
     670                 :           0 :         if (m_diag_arg)
     671                 :           0 :           pp_printf (&pp,
     672                 :             :                      "out-of-bounds read from bit %s till"
     673                 :             :                      " bit %s but %qE ends at bit %E",
     674                 :             :                      start_buf, end_buf, m_diag_arg,
     675                 :             :                      m_bit_bound);
     676                 :             :         else
     677                 :           0 :           pp_printf (&pp,
     678                 :             :                      "out-of-bounds read from bit %s till"
     679                 :             :                      " bit %s but region ends at bit %E",
     680                 :             :                      start_buf, end_buf, m_bit_bound);
     681                 :             :       }
     682                 :           0 :   }
     683                 :             : 
     684                 :         154 :   enum access_direction get_dir () const final override { return access_direction::read; }
     685                 :             : };
     686                 :             : 
     687                 :             : /* Concrete subclass to complain about buffer underwrites.  */
     688                 :             : 
     689                 :             : class concrete_buffer_underwrite : public concrete_out_of_bounds
     690                 :             : {
     691                 :             : public:
     692                 :          54 :   concrete_buffer_underwrite (const region_model &model,
     693                 :             :                               const region *reg, tree diag_arg,
     694                 :             :                               bit_range range,
     695                 :             :                               const svalue *sval_hint)
     696                 :          54 :   : concrete_out_of_bounds (model, reg, diag_arg, range, sval_hint)
     697                 :             :   {}
     698                 :             : 
     699                 :         844 :   const char *get_kind () const final override
     700                 :             :   {
     701                 :         844 :     return "concrete_buffer_underwrite";
     702                 :             :   }
     703                 :             : 
     704                 :          54 :   bool emit (diagnostic_emission_context &ctxt) final override
     705                 :             :   {
     706                 :          54 :     bool warned;
     707                 :          54 :     ctxt.add_cwe (124);
     708                 :          54 :     switch (get_memory_space ())
     709                 :             :       {
     710                 :          36 :       default:
     711                 :          36 :         warned = ctxt.warn ("buffer underwrite");
     712                 :          36 :         break;
     713                 :          14 :       case MEMSPACE_STACK:
     714                 :          14 :         warned = ctxt.warn ("stack-based buffer underwrite");
     715                 :          14 :         break;
     716                 :           4 :       case MEMSPACE_HEAP:
     717                 :           4 :         warned = ctxt.warn ("heap-based buffer underwrite");
     718                 :           4 :         break;
     719                 :             :       }
     720                 :          54 :     if (warned)
     721                 :          54 :       maybe_show_notes (ctxt);
     722                 :          54 :     return warned;
     723                 :             :   }
     724                 :             : 
     725                 :             :   bool
     726                 :         108 :   describe_final_event (pretty_printer &pp,
     727                 :             :                         const evdesc::final_event &) final override
     728                 :             :   {
     729                 :         108 :     byte_range out_of_bounds_bytes (0, 0);
     730                 :         108 :     if (get_out_of_bounds_bytes (&out_of_bounds_bytes))
     731                 :         108 :       describe_final_event_as_bytes (pp, out_of_bounds_bytes);
     732                 :             :     else
     733                 :           0 :       describe_final_event_as_bits (pp);
     734                 :         108 :     return true;
     735                 :             :   }
     736                 :             : 
     737                 :             :   void
     738                 :         108 :   describe_final_event_as_bytes (pretty_printer &pp,
     739                 :             :                                  const byte_range &out_of_bounds_bytes)
     740                 :             :   {
     741                 :         108 :     byte_size_t start = out_of_bounds_bytes.get_start_byte_offset ();
     742                 :         108 :     byte_size_t end = out_of_bounds_bytes.get_last_byte_offset ();
     743                 :         108 :     char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     744                 :         108 :     print_dec (start, start_buf, SIGNED);
     745                 :         108 :     char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     746                 :         108 :     print_dec (end, end_buf, SIGNED);
     747                 :             : 
     748                 :         108 :     if (start == end)
     749                 :             :       {
     750                 :          24 :         if (m_diag_arg)
     751                 :          24 :           pp_printf (&pp,
     752                 :             :                      "out-of-bounds write at byte %s but %qE"
     753                 :             :                      " starts at byte 0",
     754                 :             :                      start_buf, m_diag_arg);
     755                 :             :         else
     756                 :           0 :           pp_printf (&pp,
     757                 :             :                      "out-of-bounds write at byte %s but region"
     758                 :             :                      " starts at byte 0", start_buf);
     759                 :             :       }
     760                 :             :     else
     761                 :             :       {
     762                 :          84 :         if (m_diag_arg)
     763                 :          74 :           pp_printf (&pp,
     764                 :             :                      "out-of-bounds write from byte %s till"
     765                 :             :                      " byte %s but %qE starts at byte 0",
     766                 :             :                      start_buf, end_buf, m_diag_arg);
     767                 :             :         else
     768                 :          10 :           pp_printf (&pp,
     769                 :             :                      "out-of-bounds write from byte %s till"
     770                 :             :                      " byte %s but region starts at byte 0",
     771                 :         108 :                      start_buf, end_buf);;
     772                 :             :       }
     773                 :         108 :   }
     774                 :             : 
     775                 :             :   void
     776                 :           0 :   describe_final_event_as_bits (pretty_printer &pp)
     777                 :             :   {
     778                 :           0 :     bit_size_t start = m_out_of_bounds_bits.get_start_bit_offset ();
     779                 :           0 :     bit_size_t end = m_out_of_bounds_bits.get_last_bit_offset ();
     780                 :           0 :     char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     781                 :           0 :     print_dec (start, start_buf, SIGNED);
     782                 :           0 :     char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     783                 :           0 :     print_dec (end, end_buf, SIGNED);
     784                 :             : 
     785                 :           0 :     if (start == end)
     786                 :             :       {
     787                 :           0 :         if (m_diag_arg)
     788                 :           0 :           pp_printf (&pp,
     789                 :             :                      "out-of-bounds write at bit %s but %qE"
     790                 :             :                      " starts at bit 0",
     791                 :             :                      start_buf, m_diag_arg);
     792                 :             :         else
     793                 :           0 :           pp_printf (&pp,
     794                 :             :                      "out-of-bounds write at bit %s but region"
     795                 :             :                      " starts at bit 0", start_buf);
     796                 :             :       }
     797                 :             :     else
     798                 :             :       {
     799                 :           0 :         if (m_diag_arg)
     800                 :           0 :           pp_printf (&pp,
     801                 :             :                      "out-of-bounds write from bit %s till"
     802                 :             :                      " bit %s but %qE starts at bit 0",
     803                 :             :                      start_buf, end_buf, m_diag_arg);
     804                 :             :         else
     805                 :           0 :           pp_printf (&pp,
     806                 :             :                      "out-of-bounds write from bit %s till"
     807                 :             :                      " bit %s but region starts at bit 0",
     808                 :           0 :                      start_buf, end_buf);;
     809                 :             :       }
     810                 :           0 :   }
     811                 :             : 
     812                 :          54 :   enum access_direction get_dir () const final override { return access_direction::write; }
     813                 :             : };
     814                 :             : 
     815                 :             : /* Concrete subclass to complain about buffer under-reads.  */
     816                 :             : 
     817                 :             : class concrete_buffer_under_read : public concrete_out_of_bounds
     818                 :             : {
     819                 :             : public:
     820                 :         118 :   concrete_buffer_under_read (const region_model &model,
     821                 :             :                               const region *reg, tree diag_arg,
     822                 :             :                               bit_range range)
     823                 :         118 :   : concrete_out_of_bounds (model, reg, diag_arg, range, nullptr)
     824                 :             :   {}
     825                 :             : 
     826                 :        1129 :   const char *get_kind () const final override
     827                 :             :   {
     828                 :        1129 :     return "concrete_buffer_under_read";
     829                 :             :   }
     830                 :             : 
     831                 :          59 :   bool emit (diagnostic_emission_context &ctxt) final override
     832                 :             :   {
     833                 :          59 :     bool warned;
     834                 :          59 :     ctxt.add_cwe (127);
     835                 :          59 :     switch (get_memory_space ())
     836                 :             :       {
     837                 :          40 :       default:
     838                 :          40 :         warned = ctxt.warn ("buffer under-read");
     839                 :          40 :         break;
     840                 :          15 :       case MEMSPACE_STACK:
     841                 :          15 :         warned = ctxt.warn ("stack-based buffer under-read");
     842                 :          15 :         break;
     843                 :           4 :       case MEMSPACE_HEAP:
     844                 :           4 :         warned = ctxt.warn ("heap-based buffer under-read");
     845                 :           4 :         break;
     846                 :             :       }
     847                 :          59 :     if (warned)
     848                 :          59 :       maybe_show_notes (ctxt);
     849                 :          59 :     return warned;
     850                 :             :   }
     851                 :             : 
     852                 :             :   bool
     853                 :         118 :   describe_final_event (pretty_printer &pp,
     854                 :             :                         const evdesc::final_event &) final override
     855                 :             :   {
     856                 :         118 :     byte_range out_of_bounds_bytes (0, 0);
     857                 :         118 :     if (get_out_of_bounds_bytes (&out_of_bounds_bytes))
     858                 :         118 :       describe_final_event_as_bytes (pp, out_of_bounds_bytes);
     859                 :             :     else
     860                 :           0 :       describe_final_event_as_bits (pp);
     861                 :         118 :     return true;
     862                 :             :   }
     863                 :             : 
     864                 :             :   void
     865                 :         118 :   describe_final_event_as_bytes (pretty_printer &pp,
     866                 :             :                                  const byte_range &out_of_bounds_bytes)
     867                 :             :   {
     868                 :         118 :     byte_size_t start = out_of_bounds_bytes.get_start_byte_offset ();
     869                 :         118 :     byte_size_t end = out_of_bounds_bytes.get_last_byte_offset ();
     870                 :         118 :     char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     871                 :         118 :     print_dec (start, start_buf, SIGNED);
     872                 :         118 :     char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     873                 :         118 :     print_dec (end, end_buf, SIGNED);
     874                 :             : 
     875                 :         118 :     if (start == end)
     876                 :             :       {
     877                 :          34 :         if (m_diag_arg)
     878                 :          34 :           pp_printf (&pp,
     879                 :             :                      "out-of-bounds read at byte %s but %qE"
     880                 :             :                      " starts at byte 0",
     881                 :             :                      start_buf, m_diag_arg);
     882                 :             :         else
     883                 :           0 :           pp_printf (&pp,
     884                 :             :                      "out-of-bounds read at byte %s but region"
     885                 :             :                      " starts at byte 0",
     886                 :             :                      start_buf);
     887                 :             :       }
     888                 :             :     else
     889                 :             :       {
     890                 :          84 :         if (m_diag_arg)
     891                 :          76 :           pp_printf (&pp,
     892                 :             :                      "out-of-bounds read from byte %s till"
     893                 :             :                      " byte %s but %qE starts at byte 0",
     894                 :             :                      start_buf, end_buf, m_diag_arg);
     895                 :             :         else
     896                 :           8 :           pp_printf (&pp,
     897                 :             :                      "out-of-bounds read from byte %s till"
     898                 :             :                      " byte %s but region starts at byte 0",
     899                 :         118 :                      start_buf, end_buf);;
     900                 :             :       }
     901                 :         118 :   }
     902                 :             : 
     903                 :             :   void
     904                 :           0 :   describe_final_event_as_bits (pretty_printer &pp)
     905                 :             :   {
     906                 :           0 :     bit_size_t start = m_out_of_bounds_bits.get_start_bit_offset ();
     907                 :           0 :     bit_size_t end = m_out_of_bounds_bits.get_last_bit_offset ();
     908                 :           0 :     char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     909                 :           0 :     print_dec (start, start_buf, SIGNED);
     910                 :           0 :     char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
     911                 :           0 :     print_dec (end, end_buf, SIGNED);
     912                 :             : 
     913                 :           0 :     if (start == end)
     914                 :             :       {
     915                 :           0 :         if (m_diag_arg)
     916                 :           0 :           pp_printf (&pp,
     917                 :             :                      "out-of-bounds read at bit %s but %qE"
     918                 :             :                      " starts at bit 0",
     919                 :             :                      start_buf, m_diag_arg);
     920                 :             :         else
     921                 :           0 :           pp_printf (&pp,
     922                 :             :                      "out-of-bounds read at bit %s but region"
     923                 :             :                      " starts at bit 0", start_buf);
     924                 :             :       }
     925                 :             :     else
     926                 :             :       {
     927                 :           0 :         if (m_diag_arg)
     928                 :           0 :           pp_printf (&pp,
     929                 :             :                      "out-of-bounds read from bit %s till"
     930                 :             :                      " bit %s but %qE starts at bit 0",
     931                 :             :                      start_buf, end_buf, m_diag_arg);
     932                 :             :         else
     933                 :           0 :           pp_printf (&pp,
     934                 :             :                      "out-of-bounds read from bit %s till"
     935                 :             :                      " bit %s but region starts at bit 0",
     936                 :           0 :                      start_buf, end_buf);;
     937                 :             :       }
     938                 :           0 :   }
     939                 :             : 
     940                 :          59 :   enum access_direction get_dir () const final override { return access_direction::read; }
     941                 :             : };
     942                 :             : 
     943                 :             : /* Abstract class to complain about out-of-bounds read/writes where
     944                 :             :    the values are symbolic.  */
     945                 :             : 
     946                 :             : class symbolic_past_the_end : public out_of_bounds
     947                 :             : {
     948                 :             : public:
     949                 :         145 :   symbolic_past_the_end (const region_model &model,
     950                 :             :                          const region *reg, tree diag_arg, tree offset,
     951                 :             :                          tree num_bytes, tree capacity,
     952                 :             :                          const svalue *sval_hint)
     953                 :         145 :   : out_of_bounds (model, reg, diag_arg, sval_hint),
     954                 :         145 :     m_offset (offset),
     955                 :         145 :     m_num_bytes (num_bytes),
     956                 :         290 :     m_capacity (capacity)
     957                 :             :   {}
     958                 :             : 
     959                 :             :   bool
     960                 :         145 :   subclass_equal_p (const pending_diagnostic &base_other) const final override
     961                 :             :   {
     962                 :         145 :     const symbolic_past_the_end &other
     963                 :             :       (static_cast <const symbolic_past_the_end &>(base_other));
     964                 :         145 :     return (out_of_bounds::subclass_equal_p (other)
     965                 :         145 :             && pending_diagnostic::same_tree_p (m_offset, other.m_offset)
     966                 :         145 :             && pending_diagnostic::same_tree_p (m_num_bytes, other.m_num_bytes)
     967                 :         290 :             && pending_diagnostic::same_tree_p (m_capacity, other.m_capacity));
     968                 :             :   }
     969                 :             : 
     970                 :             :   void
     971                 :           0 :   maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
     972                 :             :     const final override
     973                 :             :   {
     974                 :           0 :     out_of_bounds::maybe_add_sarif_properties (result_obj);
     975                 :           0 :     auto &props = result_obj.get_or_create_properties ();
     976                 :             : #define PROPERTY_PREFIX "gcc/analyzer/symbolic_past_the_end/"
     977                 :           0 :     props.set (PROPERTY_PREFIX "offset", tree_to_json (m_offset));
     978                 :           0 :     props.set (PROPERTY_PREFIX "num_bytes", tree_to_json (m_num_bytes));
     979                 :           0 :     props.set (PROPERTY_PREFIX "capacity", tree_to_json (m_capacity));
     980                 :             : #undef PROPERTY_PREFIX
     981                 :           0 :   }
     982                 :             : 
     983                 :             : protected:
     984                 :             :   tree m_offset;
     985                 :             :   tree m_num_bytes;
     986                 :             :   tree m_capacity;
     987                 :             : };
     988                 :             : 
     989                 :             : /* Concrete subclass to complain about overflows with symbolic values.  */
     990                 :             : 
     991                 :             : class symbolic_buffer_overflow : public symbolic_past_the_end
     992                 :             : {
     993                 :             : public:
     994                 :         112 :   symbolic_buffer_overflow (const region_model &model,
     995                 :             :                             const region *reg, tree diag_arg, tree offset,
     996                 :             :                             tree num_bytes, tree capacity,
     997                 :             :                             const svalue *sval_hint)
     998                 :             :   : symbolic_past_the_end (model, reg, diag_arg, offset, num_bytes, capacity,
     999                 :         112 :                            sval_hint)
    1000                 :             :   {
    1001                 :             :   }
    1002                 :             : 
    1003                 :        1875 :   const char *get_kind () const final override
    1004                 :             :   {
    1005                 :        1875 :     return "symbolic_buffer_overflow";
    1006                 :             :   }
    1007                 :             : 
    1008                 :         111 :   bool emit (diagnostic_emission_context &ctxt) final override
    1009                 :             :   {
    1010                 :         111 :     bool warned;
    1011                 :         111 :     switch (get_memory_space ())
    1012                 :             :       {
    1013                 :          36 :       default:
    1014                 :          36 :         ctxt.add_cwe (787);
    1015                 :          36 :         warned = ctxt.warn ("buffer overflow");
    1016                 :          36 :         break;
    1017                 :          30 :       case MEMSPACE_STACK:
    1018                 :          30 :         ctxt.add_cwe (121);
    1019                 :          30 :         warned = ctxt.warn ("stack-based buffer overflow");
    1020                 :          30 :         break;
    1021                 :          45 :       case MEMSPACE_HEAP:
    1022                 :          45 :         ctxt.add_cwe (122);
    1023                 :          45 :         warned =  ctxt.warn ("heap-based buffer overflow");
    1024                 :          45 :         break;
    1025                 :             :       }
    1026                 :         111 :     if (warned)
    1027                 :         111 :       maybe_show_notes (ctxt);
    1028                 :         111 :     return warned;
    1029                 :             :   }
    1030                 :             : 
    1031                 :             :   bool
    1032                 :         222 :   describe_final_event (pretty_printer &pp,
    1033                 :             :                         const evdesc::final_event &) final override
    1034                 :             :   {
    1035                 :         222 :     if (m_offset)
    1036                 :             :       {
    1037                 :             :         /* Known offset.  */
    1038                 :         188 :         if (m_num_bytes)
    1039                 :             :           {
    1040                 :             :             /* Known offset, known size.  */
    1041                 :         182 :             if (TREE_CODE (m_num_bytes) == INTEGER_CST)
    1042                 :             :               {
    1043                 :             :                 /* Known offset, known constant size.  */
    1044                 :         164 :                 if (pending_diagnostic::same_tree_p (m_num_bytes,
    1045                 :             :                                                      integer_one_node))
    1046                 :             :                   {
    1047                 :             :                     /* Singular m_num_bytes.  */
    1048                 :         120 :                     if (m_diag_arg)
    1049                 :          32 :                       pp_printf (&pp,
    1050                 :             :                                  "write of %E byte at offset %qE exceeds %qE",
    1051                 :             :                                  m_num_bytes, m_offset, m_diag_arg);
    1052                 :             :                     else
    1053                 :          88 :                       pp_printf (&pp,
    1054                 :             :                                  "write of %E byte at offset %qE exceeds"
    1055                 :             :                                  " the buffer",
    1056                 :             :                                  m_num_bytes, m_offset);
    1057                 :             :                   }
    1058                 :             :                 else
    1059                 :             :                   {
    1060                 :             :                     /* Plural m_num_bytes.  */
    1061                 :          44 :                     if (m_diag_arg)
    1062                 :           8 :                       pp_printf (&pp,
    1063                 :             :                                  "write of %E bytes at offset %qE exceeds %qE",
    1064                 :             :                                  m_num_bytes, m_offset, m_diag_arg);
    1065                 :             :                     else
    1066                 :          36 :                       pp_printf (&pp,
    1067                 :             :                                  "write of %E bytes at offset %qE exceeds"
    1068                 :             :                                  " the buffer",
    1069                 :             :                                  m_num_bytes, m_offset);
    1070                 :             :                   }
    1071                 :             :               }
    1072                 :             :             else
    1073                 :             :               {
    1074                 :             :                 /* Known offset, known symbolic size.  */
    1075                 :          18 :                 if (m_diag_arg)
    1076                 :           0 :                   pp_printf (&pp,
    1077                 :             :                              "write of %qE bytes at offset %qE exceeds %qE",
    1078                 :             :                              m_num_bytes, m_offset, m_diag_arg);
    1079                 :             :                 else
    1080                 :          18 :                   pp_printf (&pp,
    1081                 :             :                              "write of %qE bytes at offset %qE exceeds"
    1082                 :             :                              " the buffer",
    1083                 :             :                              m_num_bytes, m_offset);
    1084                 :             :               }
    1085                 :             :           }
    1086                 :             :         else
    1087                 :             :           {
    1088                 :             :             /* Known offset, unknown size.  */
    1089                 :           6 :             if (m_diag_arg)
    1090                 :           0 :               pp_printf (&pp,
    1091                 :             :                          "write at offset %qE exceeds %qE",
    1092                 :             :                          m_offset, m_diag_arg);
    1093                 :             :             else
    1094                 :           6 :               pp_printf (&pp,
    1095                 :             :                          "write at offset %qE exceeds the buffer",
    1096                 :             :                          m_offset);
    1097                 :             :           }
    1098                 :             :       }
    1099                 :             :     else
    1100                 :             :       {
    1101                 :             :         /* Unknown offset.  */
    1102                 :          34 :         if (m_diag_arg)
    1103                 :           0 :           pp_printf (&pp,
    1104                 :             :                      "out-of-bounds write on %qE",
    1105                 :             :                      m_diag_arg);
    1106                 :             :         else
    1107                 :          34 :           pp_printf (&pp, "out-of-bounds write");
    1108                 :             :       }
    1109                 :         222 :     return true;
    1110                 :             :   }
    1111                 :             : 
    1112                 :         111 :   enum access_direction get_dir () const final override { return access_direction::write; }
    1113                 :             : };
    1114                 :             : 
    1115                 :             : /* Concrete subclass to complain about over-reads with symbolic values.  */
    1116                 :             : 
    1117                 :             : class symbolic_buffer_over_read : public symbolic_past_the_end
    1118                 :             : {
    1119                 :             : public:
    1120                 :          33 :   symbolic_buffer_over_read (const region_model &model,
    1121                 :             :                              const region *reg, tree diag_arg, tree offset,
    1122                 :             :                              tree num_bytes, tree capacity)
    1123                 :             :   : symbolic_past_the_end (model, reg, diag_arg, offset, num_bytes, capacity,
    1124                 :          33 :                            nullptr)
    1125                 :             :   {
    1126                 :             :   }
    1127                 :             : 
    1128                 :         348 :   const char *get_kind () const final override
    1129                 :             :   {
    1130                 :         348 :     return "symbolic_buffer_over_read";
    1131                 :             :   }
    1132                 :             : 
    1133                 :          21 :   bool emit (diagnostic_emission_context &ctxt) final override
    1134                 :             :   {
    1135                 :          21 :     ctxt.add_cwe (126);
    1136                 :          21 :     bool warned;
    1137                 :          21 :     switch (get_memory_space ())
    1138                 :             :       {
    1139                 :           0 :       default:
    1140                 :           0 :         ctxt.add_cwe (787);
    1141                 :           0 :         warned = ctxt.warn ("buffer over-read");
    1142                 :           0 :         break;
    1143                 :          21 :       case MEMSPACE_STACK:
    1144                 :          21 :         ctxt.add_cwe (121);
    1145                 :          21 :         warned = ctxt.warn ("stack-based buffer over-read");
    1146                 :          21 :         break;
    1147                 :           0 :       case MEMSPACE_HEAP:
    1148                 :           0 :         ctxt.add_cwe (122);
    1149                 :           0 :         warned = ctxt.warn ("heap-based buffer over-read");
    1150                 :           0 :         break;
    1151                 :             :       }
    1152                 :          21 :     if (warned)
    1153                 :          21 :       maybe_show_notes (ctxt);
    1154                 :          21 :     return warned;
    1155                 :             :   }
    1156                 :             : 
    1157                 :             :   bool
    1158                 :          42 :   describe_final_event (pretty_printer &pp,
    1159                 :             :                         const evdesc::final_event &) final override
    1160                 :             :   {
    1161                 :          42 :     if (m_offset)
    1162                 :             :       {
    1163                 :             :         /* Known offset.  */
    1164                 :          42 :         if (m_num_bytes)
    1165                 :             :           {
    1166                 :             :             /* Known offset, known size.  */
    1167                 :          42 :             if (TREE_CODE (m_num_bytes) == INTEGER_CST)
    1168                 :             :               {
    1169                 :             :                 /* Known offset, known constant size.  */
    1170                 :          24 :                 if (pending_diagnostic::same_tree_p (m_num_bytes,
    1171                 :             :                                                      integer_one_node))
    1172                 :             :                   {
    1173                 :             :                     /* Singular m_num_bytes.  */
    1174                 :           0 :                     if (m_diag_arg)
    1175                 :           0 :                       pp_printf (&pp,
    1176                 :             :                                  "read of %E byte at offset %qE exceeds %qE",
    1177                 :             :                                  m_num_bytes, m_offset, m_diag_arg);
    1178                 :             :                     else
    1179                 :           0 :                       pp_printf (&pp,
    1180                 :             :                                  "read of %E byte at offset %qE exceeds"
    1181                 :             :                                  " the buffer",
    1182                 :             :                                  m_num_bytes, m_offset);
    1183                 :             :                   }
    1184                 :             :                 else
    1185                 :             :                   {
    1186                 :             :                     /* Plural m_num_bytes.  */
    1187                 :          24 :                     if (m_diag_arg)
    1188                 :           8 :                       pp_printf (&pp,
    1189                 :             :                                  "read of %E bytes at offset %qE exceeds %qE",
    1190                 :             :                                  m_num_bytes, m_offset, m_diag_arg);
    1191                 :             :                     else
    1192                 :          16 :                       pp_printf (&pp,
    1193                 :             :                                  "read of %E bytes at offset %qE exceeds"
    1194                 :             :                                  " the buffer",
    1195                 :             :                                  m_num_bytes, m_offset);
    1196                 :             :                   }
    1197                 :             :               }
    1198                 :             :             else
    1199                 :             :               {
    1200                 :             :                 /* Known offset, known symbolic size.  */
    1201                 :          18 :                 if (m_diag_arg)
    1202                 :           0 :                   pp_printf (&pp,
    1203                 :             :                              "read of %qE bytes at offset %qE exceeds %qE",
    1204                 :             :                              m_num_bytes, m_offset, m_diag_arg);
    1205                 :             :                 else
    1206                 :          18 :                   pp_printf (&pp,
    1207                 :             :                              "read of %qE bytes at offset %qE exceeds"
    1208                 :             :                              " the buffer",
    1209                 :             :                              m_num_bytes, m_offset);
    1210                 :             :               }
    1211                 :             :           }
    1212                 :             :         else
    1213                 :             :           {
    1214                 :             :             /* Known offset, unknown size.  */
    1215                 :           0 :             if (m_diag_arg)
    1216                 :           0 :               pp_printf (&pp,
    1217                 :             :                          "read at offset %qE exceeds %qE",
    1218                 :             :                          m_offset, m_diag_arg);
    1219                 :             :             else
    1220                 :           0 :               pp_printf (&pp,
    1221                 :             :                          "read at offset %qE exceeds the buffer",
    1222                 :             :                          m_offset);
    1223                 :             :           }
    1224                 :             :       }
    1225                 :             :     else
    1226                 :             :       {
    1227                 :             :         /* Unknown offset.  */
    1228                 :           0 :         if (m_diag_arg)
    1229                 :           0 :           pp_printf (&pp,
    1230                 :             :                      "out-of-bounds read on %qE",
    1231                 :             :                      m_diag_arg);
    1232                 :             :         else
    1233                 :           0 :           pp_printf (&pp,
    1234                 :             :                      "out-of-bounds read");
    1235                 :             :       }
    1236                 :          42 :     return true;
    1237                 :             :   }
    1238                 :             : 
    1239                 :          21 :   enum access_direction get_dir () const final override { return access_direction::read; }
    1240                 :             : };
    1241                 :             : 
    1242                 :             : const svalue *
    1243                 :      152847 : strip_types (const svalue *sval,
    1244                 :             :              region_model_manager &mgr)
    1245                 :             : {
    1246                 :      165572 :   switch (sval->get_kind ())
    1247                 :             :     {
    1248                 :           0 :     default:
    1249                 :           0 :       gcc_unreachable ();
    1250                 :          18 :     case SK_REGION:
    1251                 :          18 :       {
    1252                 :          18 :         const region_svalue *region_sval = (const region_svalue *)sval;
    1253                 :          18 :         return mgr.get_ptr_svalue (NULL_TREE, region_sval->get_pointee ());
    1254                 :             :       }
    1255                 :             :     case SK_CONSTANT:
    1256                 :             :       return sval;
    1257                 :       55437 :     case SK_UNKNOWN:
    1258                 :       55437 :       return mgr.get_or_create_unknown_svalue (NULL_TREE);
    1259                 :           8 :     case SK_POISONED:
    1260                 :           8 :       {
    1261                 :           8 :         const poisoned_svalue *poisoned_sval = (const poisoned_svalue *)sval;
    1262                 :           8 :         return mgr.get_or_create_poisoned_svalue
    1263                 :           8 :           (poisoned_sval->get_poison_kind (),
    1264                 :           8 :            NULL_TREE);
    1265                 :             :       }
    1266                 :             :     case SK_SETJMP:
    1267                 :             :       return sval;
    1268                 :             :     case SK_INITIAL:
    1269                 :             :       return sval;
    1270                 :       12817 :     case SK_UNARYOP:
    1271                 :       12817 :       {
    1272                 :       12817 :         const unaryop_svalue *unaryop_sval = (const unaryop_svalue *)sval;
    1273                 :       12817 :         const enum tree_code op = unaryop_sval->get_op ();
    1274                 :       12817 :         if (op == VIEW_CONVERT_EXPR || op == NOP_EXPR)
    1275                 :       12725 :           return strip_types (unaryop_sval->get_arg (), mgr);
    1276                 :          92 :         return mgr.get_or_create_unaryop
    1277                 :          92 :           (NULL_TREE,
    1278                 :             :            op,
    1279                 :          92 :            strip_types (unaryop_sval->get_arg (), mgr));
    1280                 :             :       }
    1281                 :       21713 :     case SK_BINOP:
    1282                 :       21713 :       {
    1283                 :       21713 :         const binop_svalue *binop_sval = (const binop_svalue *)sval;
    1284                 :       21713 :         const enum tree_code op = binop_sval->get_op ();
    1285                 :       21713 :         return mgr.get_or_create_binop
    1286                 :       21713 :           (NULL_TREE,
    1287                 :             :            op,
    1288                 :             :            strip_types (binop_sval->get_arg0 (), mgr),
    1289                 :       21713 :            strip_types (binop_sval->get_arg1 (), mgr));
    1290                 :             :       }
    1291                 :         150 :     case SK_SUB:
    1292                 :         150 :       {
    1293                 :         150 :         const sub_svalue *sub_sval = (const sub_svalue *)sval;
    1294                 :         150 :         return mgr.get_or_create_sub_svalue
    1295                 :         150 :           (NULL_TREE,
    1296                 :             :            strip_types (sub_sval->get_parent (), mgr),
    1297                 :         150 :            sub_sval->get_subregion ());
    1298                 :             :       }
    1299                 :           0 :     case SK_REPEATED:
    1300                 :           0 :       {
    1301                 :           0 :         const repeated_svalue *repeated_sval = (const repeated_svalue *)sval;
    1302                 :           0 :         return mgr.get_or_create_repeated_svalue
    1303                 :           0 :           (NULL_TREE,
    1304                 :             :            strip_types (repeated_sval->get_outer_size (), mgr),
    1305                 :           0 :            strip_types (repeated_sval->get_inner_svalue (), mgr));
    1306                 :             :       }
    1307                 :           4 :     case SK_BITS_WITHIN:
    1308                 :           4 :       {
    1309                 :           4 :         const bits_within_svalue *bits_within_sval
    1310                 :             :           = (const bits_within_svalue *)sval;
    1311                 :           4 :         return mgr.get_or_create_bits_within
    1312                 :           4 :           (NULL_TREE,
    1313                 :             :            bits_within_sval->get_bits (),
    1314                 :           4 :            strip_types (bits_within_sval->get_inner_svalue (), mgr));
    1315                 :             :       }
    1316                 :           0 :     case SK_UNMERGEABLE:
    1317                 :           0 :       {
    1318                 :           0 :         const unmergeable_svalue *unmergeable_sval
    1319                 :             :           = (const unmergeable_svalue *)sval;
    1320                 :           0 :         return mgr.get_or_create_unmergeable
    1321                 :           0 :           (strip_types (unmergeable_sval->get_arg (), mgr));
    1322                 :             :       }
    1323                 :             :     case SK_PLACEHOLDER:
    1324                 :             :       return sval;
    1325                 :        1478 :     case SK_WIDENING:
    1326                 :        1478 :       {
    1327                 :        1478 :         const widening_svalue *widening_sval = (const widening_svalue *)sval;
    1328                 :        1478 :         return mgr.get_or_create_widening_svalue
    1329                 :        1478 :           (NULL_TREE,
    1330                 :             :            widening_sval->get_point (),
    1331                 :             :            strip_types (widening_sval->get_base_svalue (), mgr),
    1332                 :        1478 :            strip_types (widening_sval->get_iter_svalue (), mgr));
    1333                 :             :       }
    1334                 :           0 :     case SK_COMPOUND:
    1335                 :           0 :       {
    1336                 :           0 :         const compound_svalue *compound_sval = (const compound_svalue *)sval;
    1337                 :           0 :         binding_map typeless_map;
    1338                 :           0 :         for (auto iter : compound_sval->get_map ())
    1339                 :             :           {
    1340                 :           0 :             const binding_key *key = iter.first;
    1341                 :           0 :             const svalue *bound_sval = iter.second;
    1342                 :           0 :             typeless_map.put (key, strip_types (bound_sval, mgr));
    1343                 :             :           }
    1344                 :           0 :         return mgr.get_or_create_compound_svalue (NULL_TREE, typeless_map);
    1345                 :           0 :       }
    1346                 :             :     case SK_CONJURED:
    1347                 :             :       return sval;
    1348                 :          94 :     case SK_ASM_OUTPUT:
    1349                 :          94 :       {
    1350                 :          94 :         const asm_output_svalue *asm_output_sval
    1351                 :             :           = (const asm_output_svalue *)sval;
    1352                 :          94 :         auto_vec<const svalue *> typeless_inputs
    1353                 :          94 :           (asm_output_sval->get_num_inputs ());
    1354                 :         282 :         for (unsigned idx = 0; idx < asm_output_sval->get_num_inputs (); idx++)
    1355                 :         188 :           typeless_inputs.quick_push
    1356                 :         188 :             (strip_types (asm_output_sval->get_input (idx),
    1357                 :             :                           mgr));
    1358                 :          94 :         return mgr.get_or_create_asm_output_svalue
    1359                 :          94 :           (NULL_TREE,
    1360                 :             :            asm_output_sval->get_asm_string (),
    1361                 :             :            asm_output_sval->get_output_idx (),
    1362                 :             :            asm_output_sval->get_num_outputs (),
    1363                 :             :            typeless_inputs);
    1364                 :          94 :       }
    1365                 :          16 :     case SK_CONST_FN_RESULT:
    1366                 :          16 :       {
    1367                 :          16 :         const const_fn_result_svalue *const_fn_result_sval
    1368                 :             :           = (const const_fn_result_svalue *)sval;
    1369                 :          16 :         auto_vec<const svalue *> typeless_inputs
    1370                 :          16 :           (const_fn_result_sval->get_num_inputs ());
    1371                 :          16 :         for (unsigned idx = 0;
    1372                 :          32 :              idx < const_fn_result_sval->get_num_inputs ();
    1373                 :             :              idx++)
    1374                 :          16 :           typeless_inputs.quick_push
    1375                 :          16 :             (strip_types (const_fn_result_sval->get_input (idx),
    1376                 :             :                           mgr));
    1377                 :          16 :         return mgr.get_or_create_const_fn_result_svalue
    1378                 :          16 :           (NULL_TREE,
    1379                 :             :            const_fn_result_sval->get_fndecl (),
    1380                 :             :            typeless_inputs);
    1381                 :          16 :       }
    1382                 :             :     }
    1383                 :             : }
    1384                 :             : 
    1385                 :             : /* Check whether an access is past the end of the BASE_REG.
    1386                 :             :   Return TRUE if the access was valid, FALSE otherwise.  */
    1387                 :             : 
    1388                 :             : bool
    1389                 :       52569 : region_model::check_symbolic_bounds (const region *base_reg,
    1390                 :             :                                      const svalue *sym_byte_offset,
    1391                 :             :                                      const svalue *num_bytes_sval,
    1392                 :             :                                      const svalue *capacity,
    1393                 :             :                                      enum access_direction dir,
    1394                 :             :                                      const svalue *sval_hint,
    1395                 :             :                                      region_model_context *ctxt) const
    1396                 :             : {
    1397                 :       52569 :   gcc_assert (ctxt);
    1398                 :             : 
    1399                 :       52569 :   const svalue *next_byte
    1400                 :       52569 :     = m_mgr->get_or_create_binop (NULL_TREE, PLUS_EXPR,
    1401                 :             :                                   sym_byte_offset, num_bytes_sval);
    1402                 :             : 
    1403                 :       52569 :   next_byte = strip_types (next_byte, *m_mgr);
    1404                 :       52569 :   capacity = strip_types (capacity, *m_mgr);
    1405                 :             : 
    1406                 :       52569 :   if (eval_condition (next_byte, GT_EXPR, capacity).is_true ())
    1407                 :             :     {
    1408                 :         145 :       tree diag_arg = get_representative_tree (base_reg);
    1409                 :         145 :       tree offset_tree = get_representative_tree (sym_byte_offset);
    1410                 :         145 :       tree num_bytes_tree = get_representative_tree (num_bytes_sval);
    1411                 :         145 :       tree capacity_tree = get_representative_tree (capacity);
    1412                 :         145 :       const region *offset_reg = m_mgr->get_offset_region (base_reg,
    1413                 :             :                                                            NULL_TREE,
    1414                 :             :                                                            sym_byte_offset);
    1415                 :         145 :       const region *sized_offset_reg = m_mgr->get_sized_region (offset_reg,
    1416                 :             :                                                                 NULL_TREE,
    1417                 :         145 :                                                                 num_bytes_sval);
    1418                 :         145 :       switch (dir)
    1419                 :             :         {
    1420                 :           0 :         default:
    1421                 :           0 :           gcc_unreachable ();
    1422                 :          33 :           break;
    1423                 :          33 :         case access_direction::read:
    1424                 :          33 :           gcc_assert (sval_hint == nullptr);
    1425                 :          33 :           ctxt->warn
    1426                 :          33 :             (std::make_unique<symbolic_buffer_over_read> (*this,
    1427                 :             :                                                           sized_offset_reg,
    1428                 :             :                                                           diag_arg,
    1429                 :             :                                                           offset_tree,
    1430                 :             :                                                           num_bytes_tree,
    1431                 :             :                                                           capacity_tree));
    1432                 :          33 :           return false;
    1433                 :         112 :           break;
    1434                 :         112 :         case access_direction::write:
    1435                 :         112 :           ctxt->warn
    1436                 :         112 :             (std::make_unique<symbolic_buffer_overflow> (*this,
    1437                 :             :                                                          sized_offset_reg,
    1438                 :             :                                                          diag_arg,
    1439                 :             :                                                          offset_tree,
    1440                 :             :                                                          num_bytes_tree,
    1441                 :             :                                                          capacity_tree,
    1442                 :             :                                                          sval_hint));
    1443                 :         112 :           return false;
    1444                 :         145 :           break;
    1445                 :             :         }
    1446                 :             :     }
    1447                 :             :   return true;
    1448                 :             : }
    1449                 :             : 
    1450                 :             : static tree
    1451                 :     1394860 : maybe_get_integer_cst_tree (const svalue *sval)
    1452                 :             : {
    1453                 :     1394860 :   tree cst_tree = sval->maybe_get_constant ();
    1454                 :     1394860 :   if (cst_tree && TREE_CODE (cst_tree) == INTEGER_CST)
    1455                 :     1333539 :     return cst_tree;
    1456                 :             : 
    1457                 :             :   return NULL_TREE;
    1458                 :             : }
    1459                 :             : 
    1460                 :             : /* May complain when the access on REG is out-of-bounds.
    1461                 :             :    Return TRUE if the access was valid, FALSE otherwise.  */
    1462                 :             : 
    1463                 :             : bool
    1464                 :      697440 : region_model::check_region_bounds (const region *reg,
    1465                 :             :                                    enum access_direction dir,
    1466                 :             :                                    const svalue *sval_hint,
    1467                 :             :                                    region_model_context *ctxt) const
    1468                 :             : {
    1469                 :      697440 :   gcc_assert (ctxt);
    1470                 :             : 
    1471                 :             :   /* Get the offset.  */
    1472                 :      697440 :   region_offset reg_offset = reg->get_offset (m_mgr);
    1473                 :      697440 :   const region *base_reg = reg_offset.get_base_region ();
    1474                 :             : 
    1475                 :             :   /* Find out how many bits were accessed.  */
    1476                 :      697440 :   const svalue *num_bits_sval = reg->get_bit_size_sval (m_mgr);
    1477                 :      697440 :   tree num_bits_tree = maybe_get_integer_cst_tree (num_bits_sval);
    1478                 :             :   /* Bail out if 0 bits are accessed.  */
    1479                 :      697440 :   if (num_bits_tree && zerop (num_bits_tree))
    1480                 :             :           return true;
    1481                 :             : 
    1482                 :             :   /* Get the capacity of the buffer (in bytes).  */
    1483                 :      697420 :   const svalue *byte_capacity = get_capacity (base_reg);
    1484                 :      697420 :   tree cst_byte_capacity_tree = maybe_get_integer_cst_tree (byte_capacity);
    1485                 :             : 
    1486                 :             :   /* The constant offset from a pointer is represented internally as a sizetype
    1487                 :             :      but should be interpreted as a signed value here.  The statement below
    1488                 :             :      converts the offset from bits to bytes and then to a signed integer with
    1489                 :             :      the same precision the sizetype has on the target system.
    1490                 :             : 
    1491                 :             :      For example, this is needed for out-of-bounds-3.c test1 to pass when
    1492                 :             :      compiled with a 64-bit gcc build targeting 32-bit systems.  */
    1493                 :      697420 :   bit_offset_t bit_offset;
    1494                 :      697420 :   if (!reg_offset.symbolic_p ())
    1495                 :      687503 :     bit_offset = wi::sext (reg_offset.get_bit_offset (),
    1496                 :      687503 :                            TYPE_PRECISION (size_type_node));
    1497                 :             : 
    1498                 :             :   /* If any of the base region, the offset, or the number of bytes accessed
    1499                 :             :      are symbolic, we have to reason about symbolic values.  */
    1500                 :      697420 :   if (base_reg->symbolic_p () || reg_offset.symbolic_p () || !num_bits_tree)
    1501                 :             :     {
    1502                 :       52569 :       const svalue* byte_offset_sval;
    1503                 :       52569 :       if (!reg_offset.symbolic_p ())
    1504                 :             :         {
    1505                 :       42652 :           tree byte_offset_tree
    1506                 :       85304 :             = wide_int_to_tree (integer_type_node,
    1507                 :       42652 :                                 bit_offset >> LOG2_BITS_PER_UNIT);
    1508                 :       42652 :           byte_offset_sval
    1509                 :       42652 :             = m_mgr->get_or_create_constant_svalue (byte_offset_tree);
    1510                 :             :         }
    1511                 :             :       else
    1512                 :        9917 :         byte_offset_sval = reg_offset.get_symbolic_byte_offset ();
    1513                 :       52569 :       const svalue *num_bytes_sval = reg->get_byte_size_sval (m_mgr);
    1514                 :       52569 :       return check_symbolic_bounds (base_reg, byte_offset_sval, num_bytes_sval,
    1515                 :       52569 :                                     byte_capacity, dir, sval_hint, ctxt);
    1516                 :             :     }
    1517                 :             : 
    1518                 :             :   /* Otherwise continue to check with concrete values.  */
    1519                 :      644851 :   bit_range bits_outside (0, 0);
    1520                 :      644851 :   bool oob_safe = true;
    1521                 :             :   /* NUM_BITS_TREE should always be interpreted as unsigned.  */
    1522                 :      644851 :   bit_offset_t num_bits_unsigned = wi::to_offset (num_bits_tree);
    1523                 :      644851 :   bit_range read_bits (bit_offset, num_bits_unsigned);
    1524                 :             :   /* If read_bits has a subset < 0, we do have an underwrite.  */
    1525                 :      644851 :   if (read_bits.falls_short_of_p (0, &bits_outside))
    1526                 :             :     {
    1527                 :         172 :       tree diag_arg = get_representative_tree (base_reg);
    1528                 :         172 :       switch (dir)
    1529                 :             :         {
    1530                 :           0 :         default:
    1531                 :           0 :           gcc_unreachable ();
    1532                 :         118 :           break;
    1533                 :         118 :         case access_direction::read:
    1534                 :         118 :           gcc_assert (sval_hint == nullptr);
    1535                 :         118 :           ctxt->warn
    1536                 :         118 :             (std::make_unique<concrete_buffer_under_read> (*this, reg,
    1537                 :             :                                                            diag_arg,
    1538                 :             :                                                            bits_outside));
    1539                 :         118 :           oob_safe = false;
    1540                 :         118 :           break;
    1541                 :          54 :         case access_direction::write:
    1542                 :          54 :           ctxt->warn
    1543                 :          54 :             (std::make_unique<concrete_buffer_underwrite> (*this,
    1544                 :             :                                                            reg, diag_arg,
    1545                 :             :                                                            bits_outside,
    1546                 :             :                                                            sval_hint));
    1547                 :          54 :           oob_safe = false;
    1548                 :          54 :           break;
    1549                 :             :         }
    1550                 :             :     }
    1551                 :             : 
    1552                 :             :   /* For accesses past the end, we do need a concrete capacity.  No need to
    1553                 :             :      do a symbolic check here because the inequality check does not reason
    1554                 :             :      whether constants are greater than symbolic values.  */
    1555                 :      644851 :   if (!cst_byte_capacity_tree)
    1556                 :             :     return oob_safe;
    1557                 :             : 
    1558                 :      641509 :   bit_range buffer (0, wi::to_offset (cst_byte_capacity_tree) * BITS_PER_UNIT);
    1559                 :             :   /* If READ_BITS exceeds BUFFER, we do have an overflow.  */
    1560                 :      641509 :   if (read_bits.exceeds_p (buffer, &bits_outside))
    1561                 :             :     {
    1562                 :         467 :       tree bit_bound = wide_int_to_tree (size_type_node,
    1563                 :         467 :                                          buffer.get_next_bit_offset ());
    1564                 :         467 :       tree diag_arg = get_representative_tree (base_reg);
    1565                 :             : 
    1566                 :         467 :       switch (dir)
    1567                 :             :         {
    1568                 :           0 :         default:
    1569                 :           0 :           gcc_unreachable ();
    1570                 :         289 :           break;
    1571                 :         289 :         case access_direction::read:
    1572                 :         289 :           gcc_assert (sval_hint == nullptr);
    1573                 :         289 :           ctxt->warn
    1574                 :         289 :             (std::make_unique<concrete_buffer_over_read> (*this,
    1575                 :             :                                                           reg, diag_arg,
    1576                 :             :                                                           bits_outside,
    1577                 :             :                                                           bit_bound));
    1578                 :         289 :           oob_safe = false;
    1579                 :         289 :           break;
    1580                 :         178 :         case access_direction::write:
    1581                 :         178 :           ctxt->warn
    1582                 :         178 :             (std::make_unique<concrete_buffer_overflow> (*this,
    1583                 :             :                                                          reg, diag_arg,
    1584                 :             :                                                          bits_outside,
    1585                 :             :                                                          bit_bound,
    1586                 :             :                                                          sval_hint));
    1587                 :         178 :           oob_safe = false;
    1588                 :         178 :           break;
    1589                 :             :         }
    1590                 :             :     }
    1591                 :             :   return oob_safe;
    1592                 :             : }
    1593                 :             : 
    1594                 :             : } // namespace ana
    1595                 :             : 
    1596                 :             : #endif /* #if ENABLE_ANALYZER */
        

Generated by: LCOV version 2.1-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.