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 *,
72 tree fndecl, int depth,
73 checker_path &emission_path) override
75 /* The memory space is described in the diagnostic message itself,
76 so we don't need an event for that. */
78 emission_path.add_event
79 (make_unique<region_creation_event_capacity> (capacity,
84 enum memory_space get_memory_space () const
86 return m_reg->get_memory_space ();
89 /* Potentially add a note about valid ways to index this array, such
90 as (given "int arr[10];"):
91 note: valid subscripts for 'arr' are '[0]' to '[9]'
92 We print the '[' and ']' characters so as to express the valid
93 subscripts using C syntax, rather than just as byte ranges,
94 which hopefully is more clear to the user. */
96 maybe_describe_array_bounds (location_t loc) const
100 tree t = TREE_TYPE (m_diag_arg);
103 if (TREE_CODE (t) != ARRAY_TYPE)
105 tree domain = TYPE_DOMAIN (t);
108 tree max_idx = TYPE_MAX_VALUE (domain);
111 tree min_idx = TYPE_MIN_VALUE (domain);
113 "valid subscripts for %qE are %<[%E]%> to %<[%E]%>",
114 m_diag_arg, min_idx, max_idx);
121 /* Abstract base class for all out-of-bounds warnings where the
122 out-of-bounds range is concrete. */
124 class concrete_out_of_bounds : public out_of_bounds
127 concrete_out_of_bounds (const region *reg, tree diag_arg,
128 byte_range out_of_bounds_range)
129 : out_of_bounds (reg, diag_arg),
130 m_out_of_bounds_range (out_of_bounds_range)
133 bool subclass_equal_p (const pending_diagnostic &base_other) const override
135 const concrete_out_of_bounds &other
136 (static_cast <const concrete_out_of_bounds &>(base_other));
137 return (out_of_bounds::subclass_equal_p (other)
138 && m_out_of_bounds_range == other.m_out_of_bounds_range);
142 byte_range m_out_of_bounds_range;
145 /* Abstract subclass to complaing about concrete out-of-bounds
146 past the end of the buffer. */
148 class concrete_past_the_end : public concrete_out_of_bounds
151 concrete_past_the_end (const region *reg, tree diag_arg, byte_range range,
153 : concrete_out_of_bounds (reg, diag_arg, range), m_byte_bound (byte_bound)
157 subclass_equal_p (const pending_diagnostic &base_other) const final override
159 const concrete_past_the_end &other
160 (static_cast <const concrete_past_the_end &>(base_other));
161 return (concrete_out_of_bounds::subclass_equal_p (other)
162 && pending_diagnostic::same_tree_p (m_byte_bound,
163 other.m_byte_bound));
166 void add_region_creation_events (const region *,
169 tree fndecl, int depth,
170 checker_path &emission_path) final override
172 if (m_byte_bound && TREE_CODE (m_byte_bound) == INTEGER_CST)
173 emission_path.add_event
174 (make_unique<region_creation_event_capacity> (m_byte_bound,
175 loc, fndecl, depth));
182 /* Concrete subclass to complain about buffer overflows. */
184 class concrete_buffer_overflow : public concrete_past_the_end
187 concrete_buffer_overflow (const region *reg, tree diag_arg,
188 byte_range range, tree byte_bound)
189 : concrete_past_the_end (reg, diag_arg, range, byte_bound)
192 const char *get_kind () const final override
194 return "concrete_buffer_overflow";
197 bool emit (rich_location *rich_loc) final override
199 diagnostic_metadata m;
201 switch (get_memory_space ())
205 warned = warning_meta (rich_loc, m, get_controlling_option (),
210 warned = warning_meta (rich_loc, m, get_controlling_option (),
211 "stack-based buffer overflow");
215 warned = warning_meta (rich_loc, m, get_controlling_option (),
216 "heap-based buffer overflow");
222 if (wi::fits_uhwi_p (m_out_of_bounds_range.m_size_in_bytes))
224 unsigned HOST_WIDE_INT num_bad_bytes
225 = m_out_of_bounds_range.m_size_in_bytes.to_uhwi ();
227 inform_n (rich_loc->get_loc (),
229 "write of %wu byte to beyond the end of %qE",
230 "write of %wu bytes to beyond the end of %qE",
234 inform_n (rich_loc->get_loc (),
236 "write of %wu byte to beyond the end of the region",
237 "write of %wu bytes to beyond the end of the region",
241 inform (rich_loc->get_loc (),
242 "write to beyond the end of %qE",
245 maybe_describe_array_bounds (rich_loc->get_loc ());
251 label_text describe_final_event (const evdesc::final_event &ev)
254 byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
255 byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
256 char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
257 print_dec (start, start_buf, SIGNED);
258 char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
259 print_dec (end, end_buf, SIGNED);
264 return ev.formatted_print ("out-of-bounds write at byte %s but %qE"
265 " ends at byte %E", start_buf, m_diag_arg,
267 return ev.formatted_print ("out-of-bounds write at byte %s but region"
268 " ends at byte %E", start_buf,
274 return ev.formatted_print ("out-of-bounds write from byte %s till"
275 " byte %s but %qE ends at byte %E",
276 start_buf, end_buf, m_diag_arg,
278 return ev.formatted_print ("out-of-bounds write from byte %s till"
279 " byte %s but region ends at byte %E",
280 start_buf, end_buf, m_byte_bound);
285 /* Concrete subclass to complain about buffer over-reads. */
287 class concrete_buffer_over_read : public concrete_past_the_end
290 concrete_buffer_over_read (const region *reg, tree diag_arg,
291 byte_range range, tree byte_bound)
292 : concrete_past_the_end (reg, diag_arg, range, byte_bound)
295 const char *get_kind () const final override
297 return "concrete_buffer_over_read";
300 bool emit (rich_location *rich_loc) final override
302 diagnostic_metadata m;
305 switch (get_memory_space ())
308 warned = warning_meta (rich_loc, m, get_controlling_option (),
312 warned = warning_meta (rich_loc, m, get_controlling_option (),
313 "stack-based buffer over-read");
316 warned = warning_meta (rich_loc, m, get_controlling_option (),
317 "heap-based buffer over-read");
323 if (wi::fits_uhwi_p (m_out_of_bounds_range.m_size_in_bytes))
325 unsigned HOST_WIDE_INT num_bad_bytes
326 = m_out_of_bounds_range.m_size_in_bytes.to_uhwi ();
328 inform_n (rich_loc->get_loc (),
330 "read of %wu byte from after the end of %qE",
331 "read of %wu bytes from after the end of %qE",
335 inform_n (rich_loc->get_loc (),
337 "read of %wu byte from after the end of the region",
338 "read of %wu bytes from after the end of the region",
342 inform (rich_loc->get_loc (),
343 "read from after the end of %qE",
346 maybe_describe_array_bounds (rich_loc->get_loc ());
352 label_text describe_final_event (const evdesc::final_event &ev)
355 byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
356 byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
357 char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
358 print_dec (start, start_buf, SIGNED);
359 char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
360 print_dec (end, end_buf, SIGNED);
365 return ev.formatted_print ("out-of-bounds read at byte %s but %qE"
366 " ends at byte %E", start_buf, m_diag_arg,
368 return ev.formatted_print ("out-of-bounds read at byte %s but region"
369 " ends at byte %E", start_buf,
375 return ev.formatted_print ("out-of-bounds read from byte %s till"
376 " byte %s but %qE ends at byte %E",
377 start_buf, end_buf, m_diag_arg,
379 return ev.formatted_print ("out-of-bounds read from byte %s till"
380 " byte %s but region ends at byte %E",
381 start_buf, end_buf, m_byte_bound);
386 /* Concrete subclass to complain about buffer underwrites. */
388 class concrete_buffer_underwrite : public concrete_out_of_bounds
391 concrete_buffer_underwrite (const region *reg, tree diag_arg,
393 : concrete_out_of_bounds (reg, diag_arg, range)
396 const char *get_kind () const final override
398 return "concrete_buffer_underwrite";
401 bool emit (rich_location *rich_loc) final override
403 diagnostic_metadata m;
406 switch (get_memory_space ())
409 warned = warning_meta (rich_loc, m, get_controlling_option (),
410 "buffer underwrite");
413 warned = warning_meta (rich_loc, m, get_controlling_option (),
414 "stack-based buffer underwrite");
417 warned = warning_meta (rich_loc, m, get_controlling_option (),
418 "heap-based buffer underwrite");
422 maybe_describe_array_bounds (rich_loc->get_loc ());
426 label_text describe_final_event (const evdesc::final_event &ev)
429 byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
430 byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
431 char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
432 print_dec (start, start_buf, SIGNED);
433 char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
434 print_dec (end, end_buf, SIGNED);
439 return ev.formatted_print ("out-of-bounds write at byte %s but %qE"
440 " starts at byte 0", start_buf,
442 return ev.formatted_print ("out-of-bounds write at byte %s but region"
443 " starts at byte 0", start_buf);
448 return ev.formatted_print ("out-of-bounds write from byte %s till"
449 " byte %s but %qE starts at byte 0",
450 start_buf, end_buf, m_diag_arg);
451 return ev.formatted_print ("out-of-bounds write from byte %s till"
452 " byte %s but region starts at byte 0",
453 start_buf, end_buf);;
458 /* Concrete subclass to complain about buffer under-reads. */
460 class concrete_buffer_under_read : public concrete_out_of_bounds
463 concrete_buffer_under_read (const region *reg, tree diag_arg,
465 : concrete_out_of_bounds (reg, diag_arg, range)
468 const char *get_kind () const final override
470 return "concrete_buffer_under_read";
473 bool emit (rich_location *rich_loc) final override
475 diagnostic_metadata m;
478 switch (get_memory_space ())
481 warned = warning_meta (rich_loc, m, get_controlling_option (),
482 "buffer under-read");
485 warned = warning_meta (rich_loc, m, get_controlling_option (),
486 "stack-based buffer under-read");
489 warned = warning_meta (rich_loc, m, get_controlling_option (),
490 "heap-based buffer under-read");
494 maybe_describe_array_bounds (rich_loc->get_loc ());
498 label_text describe_final_event (const evdesc::final_event &ev)
501 byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
502 byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
503 char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
504 print_dec (start, start_buf, SIGNED);
505 char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
506 print_dec (end, end_buf, SIGNED);
511 return ev.formatted_print ("out-of-bounds read at byte %s but %qE"
512 " starts at byte 0", start_buf,
514 return ev.formatted_print ("out-of-bounds read at byte %s but region"
515 " starts at byte 0", start_buf);
520 return ev.formatted_print ("out-of-bounds read from byte %s till"
521 " byte %s but %qE starts at byte 0",
522 start_buf, end_buf, m_diag_arg);
523 return ev.formatted_print ("out-of-bounds read from byte %s till"
524 " byte %s but region starts at byte 0",
525 start_buf, end_buf);;
530 /* Abstract class to complain about out-of-bounds read/writes where
531 the values are symbolic. */
533 class symbolic_past_the_end : public out_of_bounds
536 symbolic_past_the_end (const region *reg, tree diag_arg, tree offset,
537 tree num_bytes, tree capacity)
538 : out_of_bounds (reg, diag_arg),
540 m_num_bytes (num_bytes),
541 m_capacity (capacity)
545 subclass_equal_p (const pending_diagnostic &base_other) const final override
547 const symbolic_past_the_end &other
548 (static_cast <const symbolic_past_the_end &>(base_other));
549 return (out_of_bounds::subclass_equal_p (other)
550 && pending_diagnostic::same_tree_p (m_offset, other.m_offset)
551 && pending_diagnostic::same_tree_p (m_num_bytes, other.m_num_bytes)
552 && pending_diagnostic::same_tree_p (m_capacity, other.m_capacity));
561 /* Concrete subclass to complain about overflows with symbolic values. */
563 class symbolic_buffer_overflow : public symbolic_past_the_end
566 symbolic_buffer_overflow (const region *reg, tree diag_arg, tree offset,
567 tree num_bytes, tree capacity)
568 : symbolic_past_the_end (reg, diag_arg, offset, num_bytes, capacity)
572 const char *get_kind () const final override
574 return "symbolic_buffer_overflow";
577 bool emit (rich_location *rich_loc) final override
579 diagnostic_metadata m;
580 switch (get_memory_space ())
584 return warning_meta (rich_loc, m, get_controlling_option (),
588 return warning_meta (rich_loc, m, get_controlling_option (),
589 "stack-based buffer overflow");
592 return warning_meta (rich_loc, m, get_controlling_option (),
593 "heap-based buffer overflow");
598 describe_final_event (const evdesc::final_event &ev) final override
605 /* Known offset, known size. */
606 if (TREE_CODE (m_num_bytes) == INTEGER_CST)
608 /* Known offset, known constant size. */
609 if (pending_diagnostic::same_tree_p (m_num_bytes,
612 /* Singular m_num_bytes. */
614 return ev.formatted_print
615 ("write of %E byte at offset %qE exceeds %qE",
616 m_num_bytes, m_offset, m_diag_arg);
618 return ev.formatted_print
619 ("write of %E byte at offset %qE exceeds the buffer",
620 m_num_bytes, m_offset);
624 /* Plural m_num_bytes. */
626 return ev.formatted_print
627 ("write of %E bytes at offset %qE exceeds %qE",
628 m_num_bytes, m_offset, m_diag_arg);
630 return ev.formatted_print
631 ("write of %E bytes at offset %qE exceeds the buffer",
632 m_num_bytes, m_offset);
637 /* Known offset, known symbolic size. */
639 return ev.formatted_print
640 ("write of %qE bytes at offset %qE exceeds %qE",
641 m_num_bytes, m_offset, m_diag_arg);
643 return ev.formatted_print
644 ("write of %qE bytes at offset %qE exceeds the buffer",
645 m_num_bytes, m_offset);
650 /* Known offset, unknown size. */
652 return ev.formatted_print ("write at offset %qE exceeds %qE",
653 m_offset, m_diag_arg);
655 return ev.formatted_print ("write at offset %qE exceeds the"
656 " buffer", m_offset);
659 /* Unknown offset. */
661 return ev.formatted_print ("out-of-bounds write on %qE",
663 return ev.formatted_print ("out-of-bounds write");
667 /* Concrete subclass to complain about over-reads with symbolic values. */
669 class symbolic_buffer_over_read : public symbolic_past_the_end
672 symbolic_buffer_over_read (const region *reg, tree diag_arg, tree offset,
673 tree num_bytes, tree capacity)
674 : symbolic_past_the_end (reg, diag_arg, offset, num_bytes, capacity)
678 const char *get_kind () const final override
680 return "symbolic_buffer_over_read";
683 bool emit (rich_location *rich_loc) final override
685 diagnostic_metadata m;
687 switch (get_memory_space ())
691 return warning_meta (rich_loc, m, get_controlling_option (),
695 return warning_meta (rich_loc, m, get_controlling_option (),
696 "stack-based buffer over-read");
699 return warning_meta (rich_loc, m, get_controlling_option (),
700 "heap-based buffer over-read");
705 describe_final_event (const evdesc::final_event &ev) final override
712 /* Known offset, known size. */
713 if (TREE_CODE (m_num_bytes) == INTEGER_CST)
715 /* Known offset, known constant size. */
716 if (pending_diagnostic::same_tree_p (m_num_bytes,
719 /* Singular m_num_bytes. */
721 return ev.formatted_print
722 ("read of %E byte at offset %qE exceeds %qE",
723 m_num_bytes, m_offset, m_diag_arg);
725 return ev.formatted_print
726 ("read of %E byte at offset %qE exceeds the buffer",
727 m_num_bytes, m_offset);
731 /* Plural m_num_bytes. */
733 return ev.formatted_print
734 ("read of %E bytes at offset %qE exceeds %qE",
735 m_num_bytes, m_offset, m_diag_arg);
737 return ev.formatted_print
738 ("read of %E bytes at offset %qE exceeds the buffer",
739 m_num_bytes, m_offset);
744 /* Known offset, known symbolic size. */
746 return ev.formatted_print
747 ("read of %qE bytes at offset %qE exceeds %qE",
748 m_num_bytes, m_offset, m_diag_arg);
750 return ev.formatted_print
751 ("read of %qE bytes at offset %qE exceeds the buffer",
752 m_num_bytes, m_offset);
757 /* Known offset, unknown size. */
759 return ev.formatted_print ("read at offset %qE exceeds %qE",
760 m_offset, m_diag_arg);
762 return ev.formatted_print ("read at offset %qE exceeds the"
763 " buffer", m_offset);
766 /* Unknown offset. */
768 return ev.formatted_print ("out-of-bounds read on %qE",
770 return ev.formatted_print ("out-of-bounds read");
774 /* Check whether an access is past the end of the BASE_REG. */
777 region_model::check_symbolic_bounds (const region *base_reg,
778 const svalue *sym_byte_offset,
779 const svalue *num_bytes_sval,
780 const svalue *capacity,
781 enum access_direction dir,
782 region_model_context *ctxt) const
786 const svalue *next_byte
787 = m_mgr->get_or_create_binop (num_bytes_sval->get_type (), PLUS_EXPR,
788 sym_byte_offset, num_bytes_sval);
790 if (eval_condition (next_byte, GT_EXPR, capacity).is_true ())
792 tree diag_arg = get_representative_tree (base_reg);
793 tree offset_tree = get_representative_tree (sym_byte_offset);
794 tree num_bytes_tree = get_representative_tree (num_bytes_sval);
795 tree capacity_tree = get_representative_tree (capacity);
802 ctxt->warn (make_unique<symbolic_buffer_over_read> (base_reg,
809 ctxt->warn (make_unique<symbolic_buffer_overflow> (base_reg,
820 maybe_get_integer_cst_tree (const svalue *sval)
822 tree cst_tree = sval->maybe_get_constant ();
823 if (cst_tree && TREE_CODE (cst_tree) == INTEGER_CST)
829 /* May complain when the access on REG is out-of-bounds. */
832 region_model::check_region_bounds (const region *reg,
833 enum access_direction dir,
834 region_model_context *ctxt) const
838 /* Get the offset. */
839 region_offset reg_offset = reg->get_offset (m_mgr);
840 const region *base_reg = reg_offset.get_base_region ();
842 /* Bail out on symbolic regions.
843 (e.g. because the analyzer did not see previous offsets on the latter,
844 it might think that a negative access is before the buffer). */
845 if (base_reg->symbolic_p ())
848 /* Find out how many bytes were accessed. */
849 const svalue *num_bytes_sval = reg->get_byte_size_sval (m_mgr);
850 tree num_bytes_tree = maybe_get_integer_cst_tree (num_bytes_sval);
851 /* Bail out if 0 bytes are accessed. */
852 if (num_bytes_tree && zerop (num_bytes_tree))
855 /* Get the capacity of the buffer. */
856 const svalue *capacity = get_capacity (base_reg);
857 tree cst_capacity_tree = maybe_get_integer_cst_tree (capacity);
859 /* The constant offset from a pointer is represented internally as a sizetype
860 but should be interpreted as a signed value here. The statement below
861 converts the offset from bits to bytes and then to a signed integer with
862 the same precision the sizetype has on the target system.
864 For example, this is needed for out-of-bounds-3.c test1 to pass when
865 compiled with a 64-bit gcc build targeting 32-bit systems. */
866 byte_offset_t offset;
867 if (!reg_offset.symbolic_p ())
868 offset = wi::sext (reg_offset.get_bit_offset () >> LOG2_BITS_PER_UNIT,
869 TYPE_PRECISION (size_type_node));
871 /* If either the offset or the number of bytes accessed are symbolic,
872 we have to reason about symbolic values. */
873 if (reg_offset.symbolic_p () || !num_bytes_tree)
875 const svalue* byte_offset_sval;
876 if (!reg_offset.symbolic_p ())
878 tree offset_tree = wide_int_to_tree (integer_type_node, offset);
880 = m_mgr->get_or_create_constant_svalue (offset_tree);
883 byte_offset_sval = reg_offset.get_symbolic_byte_offset ();
884 check_symbolic_bounds (base_reg, byte_offset_sval, num_bytes_sval,
885 capacity, dir, ctxt);
889 /* Otherwise continue to check with concrete values. */
890 byte_range out (0, 0);
891 /* NUM_BYTES_TREE should always be interpreted as unsigned. */
892 byte_offset_t num_bytes_unsigned = wi::to_offset (num_bytes_tree);
893 byte_range read_bytes (offset, num_bytes_unsigned);
894 /* If read_bytes has a subset < 0, we do have an underwrite. */
895 if (read_bytes.falls_short_of_p (0, &out))
897 tree diag_arg = get_representative_tree (base_reg);
904 ctxt->warn (make_unique<concrete_buffer_under_read> (reg, diag_arg,
908 ctxt->warn (make_unique<concrete_buffer_underwrite> (reg, diag_arg,
914 /* For accesses past the end, we do need a concrete capacity. No need to
915 do a symbolic check here because the inequality check does not reason
916 whether constants are greater than symbolic values. */
917 if (!cst_capacity_tree)
920 byte_range buffer (0, wi::to_offset (cst_capacity_tree));
921 /* If READ_BYTES exceeds BUFFER, we do have an overflow. */
922 if (read_bytes.exceeds_p (buffer, &out))
924 tree byte_bound = wide_int_to_tree (size_type_node,
925 buffer.get_next_byte_offset ());
926 tree diag_arg = get_representative_tree (base_reg);
934 ctxt->warn (make_unique<concrete_buffer_over_read> (reg, diag_arg,
938 ctxt->warn (make_unique<concrete_buffer_overflow> (reg, diag_arg,
947 #endif /* #if ENABLE_ANALYZER */