1 /* Bounds-checking of reads and writes to memory regions.
2 Copyright (C) 2019-2022 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 */