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