1 /* Bounds-checking of reads and writes to memory regions.
2 Copyright (C) 2019-2023 Free Software Foundation, Inc.
4 This file is part of GCC.
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)
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.
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/>. */
21 #define INCLUDE_MEMORY
23 #include "coretypes.h"
24 #include "make-unique.h"
27 #include "basic-block.h"
29 #include "gimple-iterator.h"
30 #include "diagnostic-core.h"
31 #include "diagnostic-metadata.h"
32 #include "analyzer/analyzer.h"
33 #include "analyzer/analyzer-logging.h"
34 #include "analyzer/region-model.h"
35 #include "analyzer/checker-event.h"
36 #include "analyzer/checker-path.h"
42 /* Abstract base class for all out-of-bounds warnings. */
44 class out_of_bounds
: public pending_diagnostic
47 out_of_bounds (const region
*reg
, tree diag_arg
)
48 : m_reg (reg
), m_diag_arg (diag_arg
)
51 bool subclass_equal_p (const pending_diagnostic
&base_other
) const override
53 const out_of_bounds
&other
54 (static_cast <const out_of_bounds
&>(base_other
));
55 return (m_reg
== other
.m_reg
56 && pending_diagnostic::same_tree_p (m_diag_arg
, other
.m_diag_arg
));
59 int get_controlling_option () const final override
61 return OPT_Wanalyzer_out_of_bounds
;
64 void mark_interesting_stuff (interesting_t
*interest
) final override
66 interest
->add_region_creation (m_reg
);
69 void add_region_creation_events (const region
*,
71 const event_loc_info
&loc_info
,
72 checker_path
&emission_path
) override
74 /* The memory space is described in the diagnostic message itself,
75 so we don't need an event for that. */
77 emission_path
.add_event
78 (make_unique
<region_creation_event_capacity
> (capacity
, loc_info
));
82 enum memory_space
get_memory_space () const
84 return m_reg
->get_memory_space ();
87 /* Potentially add a note about valid ways to index this array, such
88 as (given "int arr[10];"):
89 note: valid subscripts for 'arr' are '[0]' to '[9]'
90 We print the '[' and ']' characters so as to express the valid
91 subscripts using C syntax, rather than just as byte ranges,
92 which hopefully is more clear to the user. */
94 maybe_describe_array_bounds (location_t loc
) const
98 tree t
= TREE_TYPE (m_diag_arg
);
101 if (TREE_CODE (t
) != ARRAY_TYPE
)
103 tree domain
= TYPE_DOMAIN (t
);
106 tree max_idx
= TYPE_MAX_VALUE (domain
);
109 tree min_idx
= TYPE_MIN_VALUE (domain
);
111 "valid subscripts for %qE are %<[%E]%> to %<[%E]%>",
112 m_diag_arg
, min_idx
, max_idx
);
119 /* Abstract base class for all out-of-bounds warnings where the
120 out-of-bounds range is concrete. */
122 class concrete_out_of_bounds
: public out_of_bounds
125 concrete_out_of_bounds (const region
*reg
, tree diag_arg
,
126 byte_range out_of_bounds_range
)
127 : out_of_bounds (reg
, diag_arg
),
128 m_out_of_bounds_range (out_of_bounds_range
)
131 bool subclass_equal_p (const pending_diagnostic
&base_other
) const override
133 const concrete_out_of_bounds
&other
134 (static_cast <const concrete_out_of_bounds
&>(base_other
));
135 return (out_of_bounds::subclass_equal_p (other
)
136 && m_out_of_bounds_range
== other
.m_out_of_bounds_range
);
140 byte_range m_out_of_bounds_range
;
143 /* Abstract subclass to complaing about concrete out-of-bounds
144 past the end of the buffer. */
146 class concrete_past_the_end
: public concrete_out_of_bounds
149 concrete_past_the_end (const region
*reg
, tree diag_arg
, byte_range range
,
151 : concrete_out_of_bounds (reg
, diag_arg
, range
), m_byte_bound (byte_bound
)
155 subclass_equal_p (const pending_diagnostic
&base_other
) const final override
157 const concrete_past_the_end
&other
158 (static_cast <const concrete_past_the_end
&>(base_other
));
159 return (concrete_out_of_bounds::subclass_equal_p (other
)
160 && pending_diagnostic::same_tree_p (m_byte_bound
,
161 other
.m_byte_bound
));
164 void add_region_creation_events (const region
*,
166 const event_loc_info
&loc_info
,
167 checker_path
&emission_path
) final override
169 if (m_byte_bound
&& TREE_CODE (m_byte_bound
) == INTEGER_CST
)
170 emission_path
.add_event
171 (make_unique
<region_creation_event_capacity
> (m_byte_bound
, loc_info
));
178 /* Concrete subclass to complain about buffer overflows. */
180 class concrete_buffer_overflow
: public concrete_past_the_end
183 concrete_buffer_overflow (const region
*reg
, tree diag_arg
,
184 byte_range range
, tree byte_bound
)
185 : concrete_past_the_end (reg
, diag_arg
, range
, byte_bound
)
188 const char *get_kind () const final override
190 return "concrete_buffer_overflow";
193 bool emit (rich_location
*rich_loc
) final override
195 diagnostic_metadata m
;
197 switch (get_memory_space ())
201 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
206 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
207 "stack-based buffer overflow");
211 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
212 "heap-based buffer overflow");
218 if (wi::fits_uhwi_p (m_out_of_bounds_range
.m_size_in_bytes
))
220 unsigned HOST_WIDE_INT num_bad_bytes
221 = m_out_of_bounds_range
.m_size_in_bytes
.to_uhwi ();
223 inform_n (rich_loc
->get_loc (),
225 "write of %wu byte to beyond the end of %qE",
226 "write of %wu bytes to beyond the end of %qE",
230 inform_n (rich_loc
->get_loc (),
232 "write of %wu byte to beyond the end of the region",
233 "write of %wu bytes to beyond the end of the region",
237 inform (rich_loc
->get_loc (),
238 "write to beyond the end of %qE",
241 maybe_describe_array_bounds (rich_loc
->get_loc ());
247 label_text
describe_final_event (const evdesc::final_event
&ev
)
250 byte_size_t start
= m_out_of_bounds_range
.get_start_byte_offset ();
251 byte_size_t end
= m_out_of_bounds_range
.get_last_byte_offset ();
252 char start_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
253 print_dec (start
, start_buf
, SIGNED
);
254 char end_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
255 print_dec (end
, end_buf
, SIGNED
);
260 return ev
.formatted_print ("out-of-bounds write at byte %s but %qE"
261 " ends at byte %E", start_buf
, m_diag_arg
,
263 return ev
.formatted_print ("out-of-bounds write at byte %s but region"
264 " ends at byte %E", start_buf
,
270 return ev
.formatted_print ("out-of-bounds write from byte %s till"
271 " byte %s but %qE ends at byte %E",
272 start_buf
, end_buf
, m_diag_arg
,
274 return ev
.formatted_print ("out-of-bounds write from byte %s till"
275 " byte %s but region ends at byte %E",
276 start_buf
, end_buf
, m_byte_bound
);
281 /* Concrete subclass to complain about buffer over-reads. */
283 class concrete_buffer_over_read
: public concrete_past_the_end
286 concrete_buffer_over_read (const region
*reg
, tree diag_arg
,
287 byte_range range
, tree byte_bound
)
288 : concrete_past_the_end (reg
, diag_arg
, range
, byte_bound
)
291 const char *get_kind () const final override
293 return "concrete_buffer_over_read";
296 bool emit (rich_location
*rich_loc
) final override
298 diagnostic_metadata m
;
301 switch (get_memory_space ())
304 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
308 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
309 "stack-based buffer over-read");
312 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
313 "heap-based buffer over-read");
319 if (wi::fits_uhwi_p (m_out_of_bounds_range
.m_size_in_bytes
))
321 unsigned HOST_WIDE_INT num_bad_bytes
322 = m_out_of_bounds_range
.m_size_in_bytes
.to_uhwi ();
324 inform_n (rich_loc
->get_loc (),
326 "read of %wu byte from after the end of %qE",
327 "read of %wu bytes from after the end of %qE",
331 inform_n (rich_loc
->get_loc (),
333 "read of %wu byte from after the end of the region",
334 "read of %wu bytes from after the end of the region",
338 inform (rich_loc
->get_loc (),
339 "read from after the end of %qE",
342 maybe_describe_array_bounds (rich_loc
->get_loc ());
348 label_text
describe_final_event (const evdesc::final_event
&ev
)
351 byte_size_t start
= m_out_of_bounds_range
.get_start_byte_offset ();
352 byte_size_t end
= m_out_of_bounds_range
.get_last_byte_offset ();
353 char start_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
354 print_dec (start
, start_buf
, SIGNED
);
355 char end_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
356 print_dec (end
, end_buf
, SIGNED
);
361 return ev
.formatted_print ("out-of-bounds read at byte %s but %qE"
362 " ends at byte %E", start_buf
, m_diag_arg
,
364 return ev
.formatted_print ("out-of-bounds read at byte %s but region"
365 " ends at byte %E", start_buf
,
371 return ev
.formatted_print ("out-of-bounds read from byte %s till"
372 " byte %s but %qE ends at byte %E",
373 start_buf
, end_buf
, m_diag_arg
,
375 return ev
.formatted_print ("out-of-bounds read from byte %s till"
376 " byte %s but region ends at byte %E",
377 start_buf
, end_buf
, m_byte_bound
);
382 /* Concrete subclass to complain about buffer underwrites. */
384 class concrete_buffer_underwrite
: public concrete_out_of_bounds
387 concrete_buffer_underwrite (const region
*reg
, tree diag_arg
,
389 : concrete_out_of_bounds (reg
, diag_arg
, range
)
392 const char *get_kind () const final override
394 return "concrete_buffer_underwrite";
397 bool emit (rich_location
*rich_loc
) final override
399 diagnostic_metadata m
;
402 switch (get_memory_space ())
405 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
406 "buffer underwrite");
409 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
410 "stack-based buffer underwrite");
413 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
414 "heap-based buffer underwrite");
418 maybe_describe_array_bounds (rich_loc
->get_loc ());
422 label_text
describe_final_event (const evdesc::final_event
&ev
)
425 byte_size_t start
= m_out_of_bounds_range
.get_start_byte_offset ();
426 byte_size_t end
= m_out_of_bounds_range
.get_last_byte_offset ();
427 char start_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
428 print_dec (start
, start_buf
, SIGNED
);
429 char end_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
430 print_dec (end
, end_buf
, SIGNED
);
435 return ev
.formatted_print ("out-of-bounds write at byte %s but %qE"
436 " starts at byte 0", start_buf
,
438 return ev
.formatted_print ("out-of-bounds write at byte %s but region"
439 " starts at byte 0", start_buf
);
444 return ev
.formatted_print ("out-of-bounds write from byte %s till"
445 " byte %s but %qE starts at byte 0",
446 start_buf
, end_buf
, m_diag_arg
);
447 return ev
.formatted_print ("out-of-bounds write from byte %s till"
448 " byte %s but region starts at byte 0",
449 start_buf
, end_buf
);;
454 /* Concrete subclass to complain about buffer under-reads. */
456 class concrete_buffer_under_read
: public concrete_out_of_bounds
459 concrete_buffer_under_read (const region
*reg
, tree diag_arg
,
461 : concrete_out_of_bounds (reg
, diag_arg
, range
)
464 const char *get_kind () const final override
466 return "concrete_buffer_under_read";
469 bool emit (rich_location
*rich_loc
) final override
471 diagnostic_metadata m
;
474 switch (get_memory_space ())
477 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
478 "buffer under-read");
481 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
482 "stack-based buffer under-read");
485 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
486 "heap-based buffer under-read");
490 maybe_describe_array_bounds (rich_loc
->get_loc ());
494 label_text
describe_final_event (const evdesc::final_event
&ev
)
497 byte_size_t start
= m_out_of_bounds_range
.get_start_byte_offset ();
498 byte_size_t end
= m_out_of_bounds_range
.get_last_byte_offset ();
499 char start_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
500 print_dec (start
, start_buf
, SIGNED
);
501 char end_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
502 print_dec (end
, end_buf
, SIGNED
);
507 return ev
.formatted_print ("out-of-bounds read at byte %s but %qE"
508 " starts at byte 0", start_buf
,
510 return ev
.formatted_print ("out-of-bounds read at byte %s but region"
511 " starts at byte 0", start_buf
);
516 return ev
.formatted_print ("out-of-bounds read from byte %s till"
517 " byte %s but %qE starts at byte 0",
518 start_buf
, end_buf
, m_diag_arg
);
519 return ev
.formatted_print ("out-of-bounds read from byte %s till"
520 " byte %s but region starts at byte 0",
521 start_buf
, end_buf
);;
526 /* Abstract class to complain about out-of-bounds read/writes where
527 the values are symbolic. */
529 class symbolic_past_the_end
: public out_of_bounds
532 symbolic_past_the_end (const region
*reg
, tree diag_arg
, tree offset
,
533 tree num_bytes
, tree capacity
)
534 : out_of_bounds (reg
, diag_arg
),
536 m_num_bytes (num_bytes
),
537 m_capacity (capacity
)
541 subclass_equal_p (const pending_diagnostic
&base_other
) const final override
543 const symbolic_past_the_end
&other
544 (static_cast <const symbolic_past_the_end
&>(base_other
));
545 return (out_of_bounds::subclass_equal_p (other
)
546 && pending_diagnostic::same_tree_p (m_offset
, other
.m_offset
)
547 && pending_diagnostic::same_tree_p (m_num_bytes
, other
.m_num_bytes
)
548 && pending_diagnostic::same_tree_p (m_capacity
, other
.m_capacity
));
557 /* Concrete subclass to complain about overflows with symbolic values. */
559 class symbolic_buffer_overflow
: public symbolic_past_the_end
562 symbolic_buffer_overflow (const region
*reg
, tree diag_arg
, tree offset
,
563 tree num_bytes
, tree capacity
)
564 : symbolic_past_the_end (reg
, diag_arg
, offset
, num_bytes
, capacity
)
568 const char *get_kind () const final override
570 return "symbolic_buffer_overflow";
573 bool emit (rich_location
*rich_loc
) final override
575 diagnostic_metadata m
;
576 switch (get_memory_space ())
580 return warning_meta (rich_loc
, m
, get_controlling_option (),
584 return warning_meta (rich_loc
, m
, get_controlling_option (),
585 "stack-based buffer overflow");
588 return warning_meta (rich_loc
, m
, get_controlling_option (),
589 "heap-based buffer overflow");
594 describe_final_event (const evdesc::final_event
&ev
) final override
601 /* Known offset, known size. */
602 if (TREE_CODE (m_num_bytes
) == INTEGER_CST
)
604 /* Known offset, known constant size. */
605 if (pending_diagnostic::same_tree_p (m_num_bytes
,
608 /* Singular m_num_bytes. */
610 return ev
.formatted_print
611 ("write of %E byte at offset %qE exceeds %qE",
612 m_num_bytes
, m_offset
, m_diag_arg
);
614 return ev
.formatted_print
615 ("write of %E byte at offset %qE exceeds the buffer",
616 m_num_bytes
, m_offset
);
620 /* Plural m_num_bytes. */
622 return ev
.formatted_print
623 ("write of %E bytes at offset %qE exceeds %qE",
624 m_num_bytes
, m_offset
, m_diag_arg
);
626 return ev
.formatted_print
627 ("write of %E bytes at offset %qE exceeds the buffer",
628 m_num_bytes
, m_offset
);
633 /* Known offset, known symbolic size. */
635 return ev
.formatted_print
636 ("write of %qE bytes at offset %qE exceeds %qE",
637 m_num_bytes
, m_offset
, m_diag_arg
);
639 return ev
.formatted_print
640 ("write of %qE bytes at offset %qE exceeds the buffer",
641 m_num_bytes
, m_offset
);
646 /* Known offset, unknown size. */
648 return ev
.formatted_print ("write at offset %qE exceeds %qE",
649 m_offset
, m_diag_arg
);
651 return ev
.formatted_print ("write at offset %qE exceeds the"
652 " buffer", m_offset
);
655 /* Unknown offset. */
657 return ev
.formatted_print ("out-of-bounds write on %qE",
659 return ev
.formatted_print ("out-of-bounds write");
663 /* Concrete subclass to complain about over-reads with symbolic values. */
665 class symbolic_buffer_over_read
: public symbolic_past_the_end
668 symbolic_buffer_over_read (const region
*reg
, tree diag_arg
, tree offset
,
669 tree num_bytes
, tree capacity
)
670 : symbolic_past_the_end (reg
, diag_arg
, offset
, num_bytes
, capacity
)
674 const char *get_kind () const final override
676 return "symbolic_buffer_over_read";
679 bool emit (rich_location
*rich_loc
) final override
681 diagnostic_metadata m
;
683 switch (get_memory_space ())
687 return warning_meta (rich_loc
, m
, get_controlling_option (),
691 return warning_meta (rich_loc
, m
, get_controlling_option (),
692 "stack-based buffer over-read");
695 return warning_meta (rich_loc
, m
, get_controlling_option (),
696 "heap-based buffer over-read");
701 describe_final_event (const evdesc::final_event
&ev
) final override
708 /* Known offset, known size. */
709 if (TREE_CODE (m_num_bytes
) == INTEGER_CST
)
711 /* Known offset, known constant size. */
712 if (pending_diagnostic::same_tree_p (m_num_bytes
,
715 /* Singular m_num_bytes. */
717 return ev
.formatted_print
718 ("read of %E byte at offset %qE exceeds %qE",
719 m_num_bytes
, m_offset
, m_diag_arg
);
721 return ev
.formatted_print
722 ("read of %E byte at offset %qE exceeds the buffer",
723 m_num_bytes
, m_offset
);
727 /* Plural m_num_bytes. */
729 return ev
.formatted_print
730 ("read of %E bytes at offset %qE exceeds %qE",
731 m_num_bytes
, m_offset
, m_diag_arg
);
733 return ev
.formatted_print
734 ("read of %E bytes at offset %qE exceeds the buffer",
735 m_num_bytes
, m_offset
);
740 /* Known offset, known symbolic size. */
742 return ev
.formatted_print
743 ("read of %qE bytes at offset %qE exceeds %qE",
744 m_num_bytes
, m_offset
, m_diag_arg
);
746 return ev
.formatted_print
747 ("read of %qE bytes at offset %qE exceeds the buffer",
748 m_num_bytes
, m_offset
);
753 /* Known offset, unknown size. */
755 return ev
.formatted_print ("read at offset %qE exceeds %qE",
756 m_offset
, m_diag_arg
);
758 return ev
.formatted_print ("read at offset %qE exceeds the"
759 " buffer", m_offset
);
762 /* Unknown offset. */
764 return ev
.formatted_print ("out-of-bounds read on %qE",
766 return ev
.formatted_print ("out-of-bounds read");
770 /* Check whether an access is past the end of the BASE_REG. */
773 region_model::check_symbolic_bounds (const region
*base_reg
,
774 const svalue
*sym_byte_offset
,
775 const svalue
*num_bytes_sval
,
776 const svalue
*capacity
,
777 enum access_direction dir
,
778 region_model_context
*ctxt
) const
782 const svalue
*next_byte
783 = m_mgr
->get_or_create_binop (num_bytes_sval
->get_type (), PLUS_EXPR
,
784 sym_byte_offset
, num_bytes_sval
);
786 if (eval_condition (next_byte
, GT_EXPR
, capacity
).is_true ())
788 tree diag_arg
= get_representative_tree (base_reg
);
789 tree offset_tree
= get_representative_tree (sym_byte_offset
);
790 tree num_bytes_tree
= get_representative_tree (num_bytes_sval
);
791 tree capacity_tree
= get_representative_tree (capacity
);
798 ctxt
->warn (make_unique
<symbolic_buffer_over_read
> (base_reg
,
805 ctxt
->warn (make_unique
<symbolic_buffer_overflow
> (base_reg
,
816 maybe_get_integer_cst_tree (const svalue
*sval
)
818 tree cst_tree
= sval
->maybe_get_constant ();
819 if (cst_tree
&& TREE_CODE (cst_tree
) == INTEGER_CST
)
825 /* May complain when the access on REG is out-of-bounds. */
828 region_model::check_region_bounds (const region
*reg
,
829 enum access_direction dir
,
830 region_model_context
*ctxt
) const
834 /* Get the offset. */
835 region_offset reg_offset
= reg
->get_offset (m_mgr
);
836 const region
*base_reg
= reg_offset
.get_base_region ();
838 /* Bail out on symbolic regions.
839 (e.g. because the analyzer did not see previous offsets on the latter,
840 it might think that a negative access is before the buffer). */
841 if (base_reg
->symbolic_p ())
844 /* Find out how many bytes were accessed. */
845 const svalue
*num_bytes_sval
= reg
->get_byte_size_sval (m_mgr
);
846 tree num_bytes_tree
= maybe_get_integer_cst_tree (num_bytes_sval
);
847 /* Bail out if 0 bytes are accessed. */
848 if (num_bytes_tree
&& zerop (num_bytes_tree
))
851 /* Get the capacity of the buffer. */
852 const svalue
*capacity
= get_capacity (base_reg
);
853 tree cst_capacity_tree
= maybe_get_integer_cst_tree (capacity
);
855 /* The constant offset from a pointer is represented internally as a sizetype
856 but should be interpreted as a signed value here. The statement below
857 converts the offset from bits to bytes and then to a signed integer with
858 the same precision the sizetype has on the target system.
860 For example, this is needed for out-of-bounds-3.c test1 to pass when
861 compiled with a 64-bit gcc build targeting 32-bit systems. */
862 byte_offset_t offset
;
863 if (!reg_offset
.symbolic_p ())
864 offset
= wi::sext (reg_offset
.get_bit_offset () >> LOG2_BITS_PER_UNIT
,
865 TYPE_PRECISION (size_type_node
));
867 /* If either the offset or the number of bytes accessed are symbolic,
868 we have to reason about symbolic values. */
869 if (reg_offset
.symbolic_p () || !num_bytes_tree
)
871 const svalue
* byte_offset_sval
;
872 if (!reg_offset
.symbolic_p ())
874 tree offset_tree
= wide_int_to_tree (integer_type_node
, offset
);
876 = m_mgr
->get_or_create_constant_svalue (offset_tree
);
879 byte_offset_sval
= reg_offset
.get_symbolic_byte_offset ();
880 check_symbolic_bounds (base_reg
, byte_offset_sval
, num_bytes_sval
,
881 capacity
, dir
, ctxt
);
885 /* Otherwise continue to check with concrete values. */
886 byte_range
out (0, 0);
887 /* NUM_BYTES_TREE should always be interpreted as unsigned. */
888 byte_offset_t num_bytes_unsigned
= wi::to_offset (num_bytes_tree
);
889 byte_range
read_bytes (offset
, num_bytes_unsigned
);
890 /* If read_bytes has a subset < 0, we do have an underwrite. */
891 if (read_bytes
.falls_short_of_p (0, &out
))
893 tree diag_arg
= get_representative_tree (base_reg
);
900 ctxt
->warn (make_unique
<concrete_buffer_under_read
> (reg
, diag_arg
,
904 ctxt
->warn (make_unique
<concrete_buffer_underwrite
> (reg
, diag_arg
,
910 /* For accesses past the end, we do need a concrete capacity. No need to
911 do a symbolic check here because the inequality check does not reason
912 whether constants are greater than symbolic values. */
913 if (!cst_capacity_tree
)
916 byte_range
buffer (0, wi::to_offset (cst_capacity_tree
));
917 /* If READ_BYTES exceeds BUFFER, we do have an overflow. */
918 if (read_bytes
.exceeds_p (buffer
, &out
))
920 tree byte_bound
= wide_int_to_tree (size_type_node
,
921 buffer
.get_next_byte_offset ());
922 tree diag_arg
= get_representative_tree (base_reg
);
930 ctxt
->warn (make_unique
<concrete_buffer_over_read
> (reg
, diag_arg
,
934 ctxt
->warn (make_unique
<concrete_buffer_overflow
> (reg
, diag_arg
,
943 #endif /* #if ENABLE_ANALYZER */