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
22 #define INCLUDE_VECTOR
24 #include "coretypes.h"
25 #include "make-unique.h"
28 #include "basic-block.h"
31 #include "gimple-iterator.h"
32 #include "diagnostic-core.h"
33 #include "diagnostic-metadata.h"
34 #include "diagnostic-diagram.h"
35 #include "analyzer/analyzer.h"
36 #include "analyzer/analyzer-logging.h"
37 #include "analyzer/region-model.h"
38 #include "analyzer/checker-event.h"
39 #include "analyzer/checker-path.h"
40 #include "analyzer/access-diagram.h"
46 /* Abstract base class for all out-of-bounds warnings. */
48 class out_of_bounds
: public pending_diagnostic
51 class oob_region_creation_event_capacity
: public region_creation_event_capacity
54 oob_region_creation_event_capacity (tree capacity
,
55 const event_loc_info
&loc_info
,
57 : region_creation_event_capacity (capacity
,
62 void prepare_for_emission (checker_path
*path
,
63 pending_diagnostic
*pd
,
64 diagnostic_event_id_t emission_id
) override
66 region_creation_event_capacity::prepare_for_emission (path
,
69 m_oob
.m_region_creation_event_id
= emission_id
;
75 out_of_bounds (const region_model
&model
,
78 const svalue
*sval_hint
)
79 : m_model (model
), m_reg (reg
), m_diag_arg (diag_arg
), m_sval_hint (sval_hint
)
82 bool subclass_equal_p (const pending_diagnostic
&base_other
) const override
84 const out_of_bounds
&other
85 (static_cast <const out_of_bounds
&>(base_other
));
86 return (m_reg
== other
.m_reg
87 && pending_diagnostic::same_tree_p (m_diag_arg
, other
.m_diag_arg
));
90 int get_controlling_option () const final override
92 return OPT_Wanalyzer_out_of_bounds
;
95 void mark_interesting_stuff (interesting_t
*interest
) final override
97 interest
->add_region_creation (m_reg
->get_base_region ());
100 void add_region_creation_events (const region
*,
102 const event_loc_info
&loc_info
,
103 checker_path
&emission_path
) override
105 /* The memory space is described in the diagnostic message itself,
106 so we don't need an event for that. */
108 emission_path
.add_event
109 (make_unique
<oob_region_creation_event_capacity
> (capacity
, loc_info
,
113 virtual enum access_direction
get_dir () const = 0;
116 enum memory_space
get_memory_space () const
118 return m_reg
->get_memory_space ();
122 maybe_show_notes (location_t loc
, logger
*logger
) const
124 maybe_describe_array_bounds (loc
);
125 maybe_show_diagram (logger
);
128 /* Potentially add a note about valid ways to index this array, such
129 as (given "int arr[10];"):
130 note: valid subscripts for 'arr' are '[0]' to '[9]'
131 We print the '[' and ']' characters so as to express the valid
132 subscripts using C syntax, rather than just as byte ranges,
133 which hopefully is more clear to the user. */
135 maybe_describe_array_bounds (location_t loc
) const
139 tree t
= TREE_TYPE (m_diag_arg
);
142 if (TREE_CODE (t
) != ARRAY_TYPE
)
144 tree domain
= TYPE_DOMAIN (t
);
147 tree max_idx
= TYPE_MAX_VALUE (domain
);
150 tree min_idx
= TYPE_MIN_VALUE (domain
);
152 "valid subscripts for %qE are %<[%E]%> to %<[%E]%>",
153 m_diag_arg
, min_idx
, max_idx
);
157 maybe_show_diagram (logger
*logger
) const
159 access_operation
op (m_model
, get_dir (), *m_reg
, m_sval_hint
);
161 /* Don't attempt to make a diagram if there's no valid way of
162 accessing the base region (e.g. a 0-element array). */
163 if (op
.get_valid_bits ().empty_p ())
166 if (const text_art::theme
*theme
= global_dc
->m_diagrams
.m_theme
)
168 text_art::style_manager sm
;
169 text_art::canvas
canvas (make_access_diagram (op
, sm
, *theme
, logger
));
170 if (canvas
.get_size ().w
== 0 && canvas
.get_size ().h
== 0)
172 /* In lieu of exceptions, return a zero-sized diagram if there's
173 a problem. Give up if that's happened. */
176 diagnostic_diagram diagram
179 _("Diagram visualizing the predicted out-of-bounds access"));
180 diagnostic_emit_diagram (global_dc
, diagram
);
185 make_access_diagram (const access_operation
&op
,
186 text_art::style_manager
&sm
,
187 const text_art::theme
&theme
,
188 logger
*logger
) const
190 access_diagram
d (op
, m_region_creation_event_id
, sm
, theme
, logger
);
191 return d
.to_canvas (sm
);
194 region_model m_model
;
197 const svalue
*m_sval_hint
;
198 diagnostic_event_id_t m_region_creation_event_id
;
201 /* Abstract base class for all out-of-bounds warnings where the
202 out-of-bounds range is concrete. */
204 class concrete_out_of_bounds
: public out_of_bounds
207 concrete_out_of_bounds (const region_model
&model
,
208 const region
*reg
, tree diag_arg
,
209 byte_range out_of_bounds_range
,
210 const svalue
*sval_hint
)
211 : out_of_bounds (model
, reg
, diag_arg
, sval_hint
),
212 m_out_of_bounds_range (out_of_bounds_range
)
215 bool subclass_equal_p (const pending_diagnostic
&base_other
) const override
217 const concrete_out_of_bounds
&other
218 (static_cast <const concrete_out_of_bounds
&>(base_other
));
219 return (out_of_bounds::subclass_equal_p (other
)
220 && m_out_of_bounds_range
== other
.m_out_of_bounds_range
);
224 byte_range m_out_of_bounds_range
;
227 /* Abstract subclass to complaing about concrete out-of-bounds
228 past the end of the buffer. */
230 class concrete_past_the_end
: public concrete_out_of_bounds
233 concrete_past_the_end (const region_model
&model
,
234 const region
*reg
, tree diag_arg
, byte_range range
,
236 const svalue
*sval_hint
)
237 : concrete_out_of_bounds (model
, reg
, diag_arg
, range
, sval_hint
),
238 m_byte_bound (byte_bound
)
242 subclass_equal_p (const pending_diagnostic
&base_other
) const final override
244 const concrete_past_the_end
&other
245 (static_cast <const concrete_past_the_end
&>(base_other
));
246 return (concrete_out_of_bounds::subclass_equal_p (other
)
247 && pending_diagnostic::same_tree_p (m_byte_bound
,
248 other
.m_byte_bound
));
251 void add_region_creation_events (const region
*,
253 const event_loc_info
&loc_info
,
254 checker_path
&emission_path
) final override
256 if (m_byte_bound
&& TREE_CODE (m_byte_bound
) == INTEGER_CST
)
257 emission_path
.add_event
258 (make_unique
<oob_region_creation_event_capacity
> (m_byte_bound
,
267 /* Concrete subclass to complain about buffer overflows. */
269 class concrete_buffer_overflow
: public concrete_past_the_end
272 concrete_buffer_overflow (const region_model
&model
,
273 const region
*reg
, tree diag_arg
,
274 byte_range range
, tree byte_bound
,
275 const svalue
*sval_hint
)
276 : concrete_past_the_end (model
, reg
, diag_arg
, range
, byte_bound
, sval_hint
)
279 const char *get_kind () const final override
281 return "concrete_buffer_overflow";
284 bool emit (rich_location
*rich_loc
,
285 logger
*logger
) final override
287 diagnostic_metadata m
;
289 switch (get_memory_space ())
293 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
298 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
299 "stack-based buffer overflow");
303 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
304 "heap-based buffer overflow");
310 if (wi::fits_uhwi_p (m_out_of_bounds_range
.m_size_in_bytes
))
312 unsigned HOST_WIDE_INT num_bad_bytes
313 = m_out_of_bounds_range
.m_size_in_bytes
.to_uhwi ();
315 inform_n (rich_loc
->get_loc (),
317 "write of %wu byte to beyond the end of %qE",
318 "write of %wu bytes to beyond the end of %qE",
322 inform_n (rich_loc
->get_loc (),
324 "write of %wu byte to beyond the end of the region",
325 "write of %wu bytes to beyond the end of the region",
329 inform (rich_loc
->get_loc (),
330 "write to beyond the end of %qE",
333 maybe_show_notes (rich_loc
->get_loc (), logger
);
339 label_text
describe_final_event (const evdesc::final_event
&ev
)
342 byte_size_t start
= m_out_of_bounds_range
.get_start_byte_offset ();
343 byte_size_t end
= m_out_of_bounds_range
.get_last_byte_offset ();
344 char start_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
345 print_dec (start
, start_buf
, SIGNED
);
346 char end_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
347 print_dec (end
, end_buf
, SIGNED
);
352 return ev
.formatted_print ("out-of-bounds write at byte %s but %qE"
353 " ends at byte %E", start_buf
, m_diag_arg
,
355 return ev
.formatted_print ("out-of-bounds write at byte %s but region"
356 " ends at byte %E", start_buf
,
362 return ev
.formatted_print ("out-of-bounds write from byte %s till"
363 " byte %s but %qE ends at byte %E",
364 start_buf
, end_buf
, m_diag_arg
,
366 return ev
.formatted_print ("out-of-bounds write from byte %s till"
367 " byte %s but region ends at byte %E",
368 start_buf
, end_buf
, m_byte_bound
);
372 enum access_direction
get_dir () const final override
{ return DIR_WRITE
; }
375 /* Concrete subclass to complain about buffer over-reads. */
377 class concrete_buffer_over_read
: public concrete_past_the_end
380 concrete_buffer_over_read (const region_model
&model
,
381 const region
*reg
, tree diag_arg
,
382 byte_range range
, tree byte_bound
)
383 : concrete_past_the_end (model
, reg
, diag_arg
, range
, byte_bound
, NULL
)
386 const char *get_kind () const final override
388 return "concrete_buffer_over_read";
391 bool emit (rich_location
*rich_loc
, logger
*logger
) final override
393 diagnostic_metadata m
;
396 switch (get_memory_space ())
399 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
403 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
404 "stack-based buffer over-read");
407 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
408 "heap-based buffer over-read");
414 if (wi::fits_uhwi_p (m_out_of_bounds_range
.m_size_in_bytes
))
416 unsigned HOST_WIDE_INT num_bad_bytes
417 = m_out_of_bounds_range
.m_size_in_bytes
.to_uhwi ();
419 inform_n (rich_loc
->get_loc (),
421 "read of %wu byte from after the end of %qE",
422 "read of %wu bytes from after the end of %qE",
426 inform_n (rich_loc
->get_loc (),
428 "read of %wu byte from after the end of the region",
429 "read of %wu bytes from after the end of the region",
433 inform (rich_loc
->get_loc (),
434 "read from after the end of %qE",
437 maybe_show_notes (rich_loc
->get_loc (), logger
);
443 label_text
describe_final_event (const evdesc::final_event
&ev
)
446 byte_size_t start
= m_out_of_bounds_range
.get_start_byte_offset ();
447 byte_size_t end
= m_out_of_bounds_range
.get_last_byte_offset ();
448 char start_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
449 print_dec (start
, start_buf
, SIGNED
);
450 char end_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
451 print_dec (end
, end_buf
, SIGNED
);
456 return ev
.formatted_print ("out-of-bounds read at byte %s but %qE"
457 " ends at byte %E", start_buf
, m_diag_arg
,
459 return ev
.formatted_print ("out-of-bounds read at byte %s but region"
460 " ends at byte %E", start_buf
,
466 return ev
.formatted_print ("out-of-bounds read from byte %s till"
467 " byte %s but %qE ends at byte %E",
468 start_buf
, end_buf
, m_diag_arg
,
470 return ev
.formatted_print ("out-of-bounds read from byte %s till"
471 " byte %s but region ends at byte %E",
472 start_buf
, end_buf
, m_byte_bound
);
476 enum access_direction
get_dir () const final override
{ return DIR_READ
; }
479 /* Concrete subclass to complain about buffer underwrites. */
481 class concrete_buffer_underwrite
: public concrete_out_of_bounds
484 concrete_buffer_underwrite (const region_model
&model
,
485 const region
*reg
, tree diag_arg
,
487 const svalue
*sval_hint
)
488 : concrete_out_of_bounds (model
, reg
, diag_arg
, range
, sval_hint
)
491 const char *get_kind () const final override
493 return "concrete_buffer_underwrite";
496 bool emit (rich_location
*rich_loc
, logger
*logger
) final override
498 diagnostic_metadata m
;
501 switch (get_memory_space ())
504 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
505 "buffer underwrite");
508 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
509 "stack-based buffer underwrite");
512 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
513 "heap-based buffer underwrite");
517 maybe_show_notes (rich_loc
->get_loc (), logger
);
521 label_text
describe_final_event (const evdesc::final_event
&ev
)
524 byte_size_t start
= m_out_of_bounds_range
.get_start_byte_offset ();
525 byte_size_t end
= m_out_of_bounds_range
.get_last_byte_offset ();
526 char start_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
527 print_dec (start
, start_buf
, SIGNED
);
528 char end_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
529 print_dec (end
, end_buf
, SIGNED
);
534 return ev
.formatted_print ("out-of-bounds write at byte %s but %qE"
535 " starts at byte 0", start_buf
,
537 return ev
.formatted_print ("out-of-bounds write at byte %s but region"
538 " starts at byte 0", start_buf
);
543 return ev
.formatted_print ("out-of-bounds write from byte %s till"
544 " byte %s but %qE starts at byte 0",
545 start_buf
, end_buf
, m_diag_arg
);
546 return ev
.formatted_print ("out-of-bounds write from byte %s till"
547 " byte %s but region starts at byte 0",
548 start_buf
, end_buf
);;
552 enum access_direction
get_dir () const final override
{ return DIR_WRITE
; }
555 /* Concrete subclass to complain about buffer under-reads. */
557 class concrete_buffer_under_read
: public concrete_out_of_bounds
560 concrete_buffer_under_read (const region_model
&model
,
561 const region
*reg
, tree diag_arg
,
563 : concrete_out_of_bounds (model
, reg
, diag_arg
, range
, NULL
)
566 const char *get_kind () const final override
568 return "concrete_buffer_under_read";
571 bool emit (rich_location
*rich_loc
, logger
*logger
) final override
573 diagnostic_metadata m
;
576 switch (get_memory_space ())
579 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
580 "buffer under-read");
583 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
584 "stack-based buffer under-read");
587 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
588 "heap-based buffer under-read");
592 maybe_show_notes (rich_loc
->get_loc (), logger
);
596 label_text
describe_final_event (const evdesc::final_event
&ev
)
599 byte_size_t start
= m_out_of_bounds_range
.get_start_byte_offset ();
600 byte_size_t end
= m_out_of_bounds_range
.get_last_byte_offset ();
601 char start_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
602 print_dec (start
, start_buf
, SIGNED
);
603 char end_buf
[WIDE_INT_PRINT_BUFFER_SIZE
];
604 print_dec (end
, end_buf
, SIGNED
);
609 return ev
.formatted_print ("out-of-bounds read at byte %s but %qE"
610 " starts at byte 0", start_buf
,
612 return ev
.formatted_print ("out-of-bounds read at byte %s but region"
613 " starts at byte 0", start_buf
);
618 return ev
.formatted_print ("out-of-bounds read from byte %s till"
619 " byte %s but %qE starts at byte 0",
620 start_buf
, end_buf
, m_diag_arg
);
621 return ev
.formatted_print ("out-of-bounds read from byte %s till"
622 " byte %s but region starts at byte 0",
623 start_buf
, end_buf
);;
627 enum access_direction
get_dir () const final override
{ return DIR_READ
; }
630 /* Abstract class to complain about out-of-bounds read/writes where
631 the values are symbolic. */
633 class symbolic_past_the_end
: public out_of_bounds
636 symbolic_past_the_end (const region_model
&model
,
637 const region
*reg
, tree diag_arg
, tree offset
,
638 tree num_bytes
, tree capacity
,
639 const svalue
*sval_hint
)
640 : out_of_bounds (model
, reg
, diag_arg
, sval_hint
),
642 m_num_bytes (num_bytes
),
643 m_capacity (capacity
)
647 subclass_equal_p (const pending_diagnostic
&base_other
) const final override
649 const symbolic_past_the_end
&other
650 (static_cast <const symbolic_past_the_end
&>(base_other
));
651 return (out_of_bounds::subclass_equal_p (other
)
652 && pending_diagnostic::same_tree_p (m_offset
, other
.m_offset
)
653 && pending_diagnostic::same_tree_p (m_num_bytes
, other
.m_num_bytes
)
654 && pending_diagnostic::same_tree_p (m_capacity
, other
.m_capacity
));
663 /* Concrete subclass to complain about overflows with symbolic values. */
665 class symbolic_buffer_overflow
: public symbolic_past_the_end
668 symbolic_buffer_overflow (const region_model
&model
,
669 const region
*reg
, tree diag_arg
, tree offset
,
670 tree num_bytes
, tree capacity
,
671 const svalue
*sval_hint
)
672 : symbolic_past_the_end (model
, reg
, diag_arg
, offset
, num_bytes
, capacity
,
677 const char *get_kind () const final override
679 return "symbolic_buffer_overflow";
682 bool emit (rich_location
*rich_loc
, logger
*logger
) final override
684 diagnostic_metadata m
;
686 switch (get_memory_space ())
690 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
695 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
696 "stack-based buffer overflow");
700 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
701 "heap-based buffer overflow");
705 maybe_show_notes (rich_loc
->get_loc (), logger
);
710 describe_final_event (const evdesc::final_event
&ev
) final override
717 /* Known offset, known size. */
718 if (TREE_CODE (m_num_bytes
) == INTEGER_CST
)
720 /* Known offset, known constant size. */
721 if (pending_diagnostic::same_tree_p (m_num_bytes
,
724 /* Singular m_num_bytes. */
726 return ev
.formatted_print
727 ("write of %E byte at offset %qE exceeds %qE",
728 m_num_bytes
, m_offset
, m_diag_arg
);
730 return ev
.formatted_print
731 ("write of %E byte at offset %qE exceeds the buffer",
732 m_num_bytes
, m_offset
);
736 /* Plural m_num_bytes. */
738 return ev
.formatted_print
739 ("write of %E bytes at offset %qE exceeds %qE",
740 m_num_bytes
, m_offset
, m_diag_arg
);
742 return ev
.formatted_print
743 ("write of %E bytes at offset %qE exceeds the buffer",
744 m_num_bytes
, m_offset
);
749 /* Known offset, known symbolic size. */
751 return ev
.formatted_print
752 ("write of %qE bytes at offset %qE exceeds %qE",
753 m_num_bytes
, m_offset
, m_diag_arg
);
755 return ev
.formatted_print
756 ("write of %qE bytes at offset %qE exceeds the buffer",
757 m_num_bytes
, m_offset
);
762 /* Known offset, unknown size. */
764 return ev
.formatted_print ("write at offset %qE exceeds %qE",
765 m_offset
, m_diag_arg
);
767 return ev
.formatted_print ("write at offset %qE exceeds the"
768 " buffer", m_offset
);
771 /* Unknown offset. */
773 return ev
.formatted_print ("out-of-bounds write on %qE",
775 return ev
.formatted_print ("out-of-bounds write");
778 enum access_direction
get_dir () const final override
{ return DIR_WRITE
; }
781 /* Concrete subclass to complain about over-reads with symbolic values. */
783 class symbolic_buffer_over_read
: public symbolic_past_the_end
786 symbolic_buffer_over_read (const region_model
&model
,
787 const region
*reg
, tree diag_arg
, tree offset
,
788 tree num_bytes
, tree capacity
)
789 : symbolic_past_the_end (model
, reg
, diag_arg
, offset
, num_bytes
, capacity
,
794 const char *get_kind () const final override
796 return "symbolic_buffer_over_read";
799 bool emit (rich_location
*rich_loc
, logger
*logger
) final override
801 diagnostic_metadata m
;
804 switch (get_memory_space ())
808 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
813 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
814 "stack-based buffer over-read");
818 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
819 "heap-based buffer over-read");
823 maybe_show_notes (rich_loc
->get_loc (), logger
);
828 describe_final_event (const evdesc::final_event
&ev
) final override
835 /* Known offset, known size. */
836 if (TREE_CODE (m_num_bytes
) == INTEGER_CST
)
838 /* Known offset, known constant size. */
839 if (pending_diagnostic::same_tree_p (m_num_bytes
,
842 /* Singular m_num_bytes. */
844 return ev
.formatted_print
845 ("read of %E byte at offset %qE exceeds %qE",
846 m_num_bytes
, m_offset
, m_diag_arg
);
848 return ev
.formatted_print
849 ("read of %E byte at offset %qE exceeds the buffer",
850 m_num_bytes
, m_offset
);
854 /* Plural m_num_bytes. */
856 return ev
.formatted_print
857 ("read of %E bytes at offset %qE exceeds %qE",
858 m_num_bytes
, m_offset
, m_diag_arg
);
860 return ev
.formatted_print
861 ("read of %E bytes at offset %qE exceeds the buffer",
862 m_num_bytes
, m_offset
);
867 /* Known offset, known symbolic size. */
869 return ev
.formatted_print
870 ("read of %qE bytes at offset %qE exceeds %qE",
871 m_num_bytes
, m_offset
, m_diag_arg
);
873 return ev
.formatted_print
874 ("read of %qE bytes at offset %qE exceeds the buffer",
875 m_num_bytes
, m_offset
);
880 /* Known offset, unknown size. */
882 return ev
.formatted_print ("read at offset %qE exceeds %qE",
883 m_offset
, m_diag_arg
);
885 return ev
.formatted_print ("read at offset %qE exceeds the"
886 " buffer", m_offset
);
889 /* Unknown offset. */
891 return ev
.formatted_print ("out-of-bounds read on %qE",
893 return ev
.formatted_print ("out-of-bounds read");
896 enum access_direction
get_dir () const final override
{ return DIR_READ
; }
899 /* Check whether an access is past the end of the BASE_REG.
900 Return TRUE if the access was valid, FALSE otherwise. */
903 region_model::check_symbolic_bounds (const region
*base_reg
,
904 const svalue
*sym_byte_offset
,
905 const svalue
*num_bytes_sval
,
906 const svalue
*capacity
,
907 enum access_direction dir
,
908 const svalue
*sval_hint
,
909 region_model_context
*ctxt
) const
913 const svalue
*next_byte
914 = m_mgr
->get_or_create_binop (num_bytes_sval
->get_type (), PLUS_EXPR
,
915 sym_byte_offset
, num_bytes_sval
);
917 if (eval_condition (next_byte
, GT_EXPR
, capacity
).is_true ())
919 tree diag_arg
= get_representative_tree (base_reg
);
920 tree offset_tree
= get_representative_tree (sym_byte_offset
);
921 tree num_bytes_tree
= get_representative_tree (num_bytes_sval
);
922 tree capacity_tree
= get_representative_tree (capacity
);
923 const region
*offset_reg
= m_mgr
->get_offset_region (base_reg
,
926 const region
*sized_offset_reg
= m_mgr
->get_sized_region (offset_reg
,
935 gcc_assert (sval_hint
== nullptr);
936 ctxt
->warn (make_unique
<symbolic_buffer_over_read
> (*this,
945 ctxt
->warn (make_unique
<symbolic_buffer_overflow
> (*this,
960 maybe_get_integer_cst_tree (const svalue
*sval
)
962 tree cst_tree
= sval
->maybe_get_constant ();
963 if (cst_tree
&& TREE_CODE (cst_tree
) == INTEGER_CST
)
969 /* May complain when the access on REG is out-of-bounds.
970 Return TRUE if the access was valid, FALSE otherwise. */
973 region_model::check_region_bounds (const region
*reg
,
974 enum access_direction dir
,
975 const svalue
*sval_hint
,
976 region_model_context
*ctxt
) const
980 /* Get the offset. */
981 region_offset reg_offset
= reg
->get_offset (m_mgr
);
982 const region
*base_reg
= reg_offset
.get_base_region ();
984 /* Bail out on symbolic regions.
985 (e.g. because the analyzer did not see previous offsets on the latter,
986 it might think that a negative access is before the buffer). */
987 if (base_reg
->symbolic_p ())
990 /* Find out how many bytes were accessed. */
991 const svalue
*num_bytes_sval
= reg
->get_byte_size_sval (m_mgr
);
992 tree num_bytes_tree
= maybe_get_integer_cst_tree (num_bytes_sval
);
993 /* Bail out if 0 bytes are accessed. */
994 if (num_bytes_tree
&& zerop (num_bytes_tree
))
997 /* Get the capacity of the buffer. */
998 const svalue
*capacity
= get_capacity (base_reg
);
999 tree cst_capacity_tree
= maybe_get_integer_cst_tree (capacity
);
1001 /* The constant offset from a pointer is represented internally as a sizetype
1002 but should be interpreted as a signed value here. The statement below
1003 converts the offset from bits to bytes and then to a signed integer with
1004 the same precision the sizetype has on the target system.
1006 For example, this is needed for out-of-bounds-3.c test1 to pass when
1007 compiled with a 64-bit gcc build targeting 32-bit systems. */
1008 byte_offset_t offset
;
1009 if (!reg_offset
.symbolic_p ())
1010 offset
= wi::sext (reg_offset
.get_bit_offset () >> LOG2_BITS_PER_UNIT
,
1011 TYPE_PRECISION (size_type_node
));
1013 /* If either the offset or the number of bytes accessed are symbolic,
1014 we have to reason about symbolic values. */
1015 if (reg_offset
.symbolic_p () || !num_bytes_tree
)
1017 const svalue
* byte_offset_sval
;
1018 if (!reg_offset
.symbolic_p ())
1020 tree offset_tree
= wide_int_to_tree (integer_type_node
, offset
);
1022 = m_mgr
->get_or_create_constant_svalue (offset_tree
);
1025 byte_offset_sval
= reg_offset
.get_symbolic_byte_offset ();
1026 return check_symbolic_bounds (base_reg
, byte_offset_sval
, num_bytes_sval
,
1027 capacity
, dir
, sval_hint
, ctxt
);
1030 /* Otherwise continue to check with concrete values. */
1031 byte_range
out (0, 0);
1032 bool oob_safe
= true;
1033 /* NUM_BYTES_TREE should always be interpreted as unsigned. */
1034 byte_offset_t num_bytes_unsigned
= wi::to_offset (num_bytes_tree
);
1035 byte_range
read_bytes (offset
, num_bytes_unsigned
);
1036 /* If read_bytes has a subset < 0, we do have an underwrite. */
1037 if (read_bytes
.falls_short_of_p (0, &out
))
1039 tree diag_arg
= get_representative_tree (base_reg
);
1046 gcc_assert (sval_hint
== nullptr);
1047 ctxt
->warn (make_unique
<concrete_buffer_under_read
> (*this, reg
,
1053 ctxt
->warn (make_unique
<concrete_buffer_underwrite
> (*this,
1062 /* For accesses past the end, we do need a concrete capacity. No need to
1063 do a symbolic check here because the inequality check does not reason
1064 whether constants are greater than symbolic values. */
1065 if (!cst_capacity_tree
)
1068 byte_range
buffer (0, wi::to_offset (cst_capacity_tree
));
1069 /* If READ_BYTES exceeds BUFFER, we do have an overflow. */
1070 if (read_bytes
.exceeds_p (buffer
, &out
))
1072 tree byte_bound
= wide_int_to_tree (size_type_node
,
1073 buffer
.get_next_byte_offset ());
1074 tree diag_arg
= get_representative_tree (base_reg
);
1082 gcc_assert (sval_hint
== nullptr);
1083 ctxt
->warn (make_unique
<concrete_buffer_over_read
> (*this,
1089 ctxt
->warn (make_unique
<concrete_buffer_overflow
> (*this,
1102 #endif /* #if ENABLE_ANALYZER */