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