Update baseline symbols for hppa-linux.
[official-gcc.git] / gcc / analyzer / bounds-checking.cc
blobf49cf7cf2af0a0b3fa0862f66867f0ecde3f6e63
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)
9 any later version.
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/>. */
20 #include "config.h"
21 #define INCLUDE_MEMORY
22 #define INCLUDE_VECTOR
23 #include "system.h"
24 #include "coretypes.h"
25 #include "make-unique.h"
26 #include "tree.h"
27 #include "function.h"
28 #include "basic-block.h"
29 #include "intl.h"
30 #include "gimple.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"
42 #if ENABLE_ANALYZER
44 namespace ana {
46 /* Abstract base class for all out-of-bounds warnings. */
48 class out_of_bounds : public pending_diagnostic
50 public:
51 class oob_region_creation_event_capacity : public region_creation_event_capacity
53 public:
54 oob_region_creation_event_capacity (tree capacity,
55 const event_loc_info &loc_info,
56 out_of_bounds &oob)
57 : region_creation_event_capacity (capacity,
58 loc_info),
59 m_oob (oob)
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,
67 pd,
68 emission_id);
69 m_oob.m_region_creation_event_id = emission_id;
71 private:
72 out_of_bounds &m_oob;
75 out_of_bounds (const region_model &model,
76 const region *reg,
77 tree diag_arg,
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 *,
101 tree capacity,
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. */
107 if (capacity)
108 emission_path.add_event
109 (make_unique<oob_region_creation_event_capacity> (capacity, loc_info,
110 *this));
113 virtual enum access_direction get_dir () const = 0;
115 protected:
116 enum memory_space get_memory_space () const
118 return m_reg->get_memory_space ();
121 void
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. */
134 void
135 maybe_describe_array_bounds (location_t loc) const
137 if (!m_diag_arg)
138 return;
139 tree t = TREE_TYPE (m_diag_arg);
140 if (!t)
141 return;
142 if (TREE_CODE (t) != ARRAY_TYPE)
143 return;
144 tree domain = TYPE_DOMAIN (t);
145 if (!domain)
146 return;
147 tree max_idx = TYPE_MAX_VALUE (domain);
148 if (!max_idx)
149 return;
150 tree min_idx = TYPE_MIN_VALUE (domain);
151 inform (loc,
152 "valid subscripts for %qE are %<[%E]%> to %<[%E]%>",
153 m_diag_arg, min_idx, max_idx);
156 void
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 ())
164 return;
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. */
174 return;
176 diagnostic_diagram diagram
177 (canvas,
178 /* Alt text. */
179 _("Diagram visualizing the predicted out-of-bounds access"));
180 diagnostic_emit_diagram (global_dc, diagram);
184 text_art::canvas
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;
195 const region *m_reg;
196 tree m_diag_arg;
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
206 public:
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);
223 protected:
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
232 public:
233 concrete_past_the_end (const region_model &model,
234 const region *reg, tree diag_arg, byte_range range,
235 tree byte_bound,
236 const svalue *sval_hint)
237 : concrete_out_of_bounds (model, reg, diag_arg, range, sval_hint),
238 m_byte_bound (byte_bound)
241 bool
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 *,
252 tree,
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,
259 loc_info,
260 *this));
263 protected:
264 tree m_byte_bound;
267 /* Concrete subclass to complain about buffer overflows. */
269 class concrete_buffer_overflow : public concrete_past_the_end
271 public:
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;
288 bool warned;
289 switch (get_memory_space ())
291 default:
292 m.add_cwe (787);
293 warned = warning_meta (rich_loc, m, get_controlling_option (),
294 "buffer overflow");
295 break;
296 case MEMSPACE_STACK:
297 m.add_cwe (121);
298 warned = warning_meta (rich_loc, m, get_controlling_option (),
299 "stack-based buffer overflow");
300 break;
301 case MEMSPACE_HEAP:
302 m.add_cwe (122);
303 warned = warning_meta (rich_loc, m, get_controlling_option (),
304 "heap-based buffer overflow");
305 break;
308 if (warned)
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 ();
314 if (m_diag_arg)
315 inform_n (rich_loc->get_loc (),
316 num_bad_bytes,
317 "write of %wu byte to beyond the end of %qE",
318 "write of %wu bytes to beyond the end of %qE",
319 num_bad_bytes,
320 m_diag_arg);
321 else
322 inform_n (rich_loc->get_loc (),
323 num_bad_bytes,
324 "write of %wu byte to beyond the end of the region",
325 "write of %wu bytes to beyond the end of the region",
326 num_bad_bytes);
328 else if (m_diag_arg)
329 inform (rich_loc->get_loc (),
330 "write to beyond the end of %qE",
331 m_diag_arg);
333 maybe_show_notes (rich_loc->get_loc (), logger);
336 return warned;
339 label_text describe_final_event (const evdesc::final_event &ev)
340 final override
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);
349 if (start == end)
351 if (m_diag_arg)
352 return ev.formatted_print ("out-of-bounds write at byte %s but %qE"
353 " ends at byte %E", start_buf, m_diag_arg,
354 m_byte_bound);
355 return ev.formatted_print ("out-of-bounds write at byte %s but region"
356 " ends at byte %E", start_buf,
357 m_byte_bound);
359 else
361 if (m_diag_arg)
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,
365 m_byte_bound);
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
379 public:
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;
394 bool warned;
395 m.add_cwe (126);
396 switch (get_memory_space ())
398 default:
399 warned = warning_meta (rich_loc, m, get_controlling_option (),
400 "buffer over-read");
401 break;
402 case MEMSPACE_STACK:
403 warned = warning_meta (rich_loc, m, get_controlling_option (),
404 "stack-based buffer over-read");
405 break;
406 case MEMSPACE_HEAP:
407 warned = warning_meta (rich_loc, m, get_controlling_option (),
408 "heap-based buffer over-read");
409 break;
412 if (warned)
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 ();
418 if (m_diag_arg)
419 inform_n (rich_loc->get_loc (),
420 num_bad_bytes,
421 "read of %wu byte from after the end of %qE",
422 "read of %wu bytes from after the end of %qE",
423 num_bad_bytes,
424 m_diag_arg);
425 else
426 inform_n (rich_loc->get_loc (),
427 num_bad_bytes,
428 "read of %wu byte from after the end of the region",
429 "read of %wu bytes from after the end of the region",
430 num_bad_bytes);
432 else if (m_diag_arg)
433 inform (rich_loc->get_loc (),
434 "read from after the end of %qE",
435 m_diag_arg);
437 maybe_show_notes (rich_loc->get_loc (), logger);
440 return warned;
443 label_text describe_final_event (const evdesc::final_event &ev)
444 final override
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);
453 if (start == end)
455 if (m_diag_arg)
456 return ev.formatted_print ("out-of-bounds read at byte %s but %qE"
457 " ends at byte %E", start_buf, m_diag_arg,
458 m_byte_bound);
459 return ev.formatted_print ("out-of-bounds read at byte %s but region"
460 " ends at byte %E", start_buf,
461 m_byte_bound);
463 else
465 if (m_diag_arg)
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,
469 m_byte_bound);
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
483 public:
484 concrete_buffer_underwrite (const region_model &model,
485 const region *reg, tree diag_arg,
486 byte_range range,
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;
499 bool warned;
500 m.add_cwe (124);
501 switch (get_memory_space ())
503 default:
504 warned = warning_meta (rich_loc, m, get_controlling_option (),
505 "buffer underwrite");
506 break;
507 case MEMSPACE_STACK:
508 warned = warning_meta (rich_loc, m, get_controlling_option (),
509 "stack-based buffer underwrite");
510 break;
511 case MEMSPACE_HEAP:
512 warned = warning_meta (rich_loc, m, get_controlling_option (),
513 "heap-based buffer underwrite");
514 break;
516 if (warned)
517 maybe_show_notes (rich_loc->get_loc (), logger);
518 return warned;
521 label_text describe_final_event (const evdesc::final_event &ev)
522 final override
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);
531 if (start == end)
533 if (m_diag_arg)
534 return ev.formatted_print ("out-of-bounds write at byte %s but %qE"
535 " starts at byte 0", start_buf,
536 m_diag_arg);
537 return ev.formatted_print ("out-of-bounds write at byte %s but region"
538 " starts at byte 0", start_buf);
540 else
542 if (m_diag_arg)
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
559 public:
560 concrete_buffer_under_read (const region_model &model,
561 const region *reg, tree diag_arg,
562 byte_range range)
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;
574 bool warned;
575 m.add_cwe (127);
576 switch (get_memory_space ())
578 default:
579 warned = warning_meta (rich_loc, m, get_controlling_option (),
580 "buffer under-read");
581 break;
582 case MEMSPACE_STACK:
583 warned = warning_meta (rich_loc, m, get_controlling_option (),
584 "stack-based buffer under-read");
585 break;
586 case MEMSPACE_HEAP:
587 warned = warning_meta (rich_loc, m, get_controlling_option (),
588 "heap-based buffer under-read");
589 break;
591 if (warned)
592 maybe_show_notes (rich_loc->get_loc (), logger);
593 return warned;
596 label_text describe_final_event (const evdesc::final_event &ev)
597 final override
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);
606 if (start == end)
608 if (m_diag_arg)
609 return ev.formatted_print ("out-of-bounds read at byte %s but %qE"
610 " starts at byte 0", start_buf,
611 m_diag_arg);
612 return ev.formatted_print ("out-of-bounds read at byte %s but region"
613 " starts at byte 0", start_buf);
615 else
617 if (m_diag_arg)
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
635 public:
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),
641 m_offset (offset),
642 m_num_bytes (num_bytes),
643 m_capacity (capacity)
646 bool
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));
657 protected:
658 tree m_offset;
659 tree m_num_bytes;
660 tree m_capacity;
663 /* Concrete subclass to complain about overflows with symbolic values. */
665 class symbolic_buffer_overflow : public symbolic_past_the_end
667 public:
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,
673 sval_hint)
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;
685 bool warned;
686 switch (get_memory_space ())
688 default:
689 m.add_cwe (787);
690 warned = warning_meta (rich_loc, m, get_controlling_option (),
691 "buffer overflow");
692 break;
693 case MEMSPACE_STACK:
694 m.add_cwe (121);
695 warned = warning_meta (rich_loc, m, get_controlling_option (),
696 "stack-based buffer overflow");
697 break;
698 case MEMSPACE_HEAP:
699 m.add_cwe (122);
700 warned = warning_meta (rich_loc, m, get_controlling_option (),
701 "heap-based buffer overflow");
702 break;
704 if (warned)
705 maybe_show_notes (rich_loc->get_loc (), logger);
706 return warned;
709 label_text
710 describe_final_event (const evdesc::final_event &ev) final override
712 if (m_offset)
714 /* Known offset. */
715 if (m_num_bytes)
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,
722 integer_one_node))
724 /* Singular m_num_bytes. */
725 if (m_diag_arg)
726 return ev.formatted_print
727 ("write of %E byte at offset %qE exceeds %qE",
728 m_num_bytes, m_offset, m_diag_arg);
729 else
730 return ev.formatted_print
731 ("write of %E byte at offset %qE exceeds the buffer",
732 m_num_bytes, m_offset);
734 else
736 /* Plural m_num_bytes. */
737 if (m_diag_arg)
738 return ev.formatted_print
739 ("write of %E bytes at offset %qE exceeds %qE",
740 m_num_bytes, m_offset, m_diag_arg);
741 else
742 return ev.formatted_print
743 ("write of %E bytes at offset %qE exceeds the buffer",
744 m_num_bytes, m_offset);
747 else
749 /* Known offset, known symbolic size. */
750 if (m_diag_arg)
751 return ev.formatted_print
752 ("write of %qE bytes at offset %qE exceeds %qE",
753 m_num_bytes, m_offset, m_diag_arg);
754 else
755 return ev.formatted_print
756 ("write of %qE bytes at offset %qE exceeds the buffer",
757 m_num_bytes, m_offset);
760 else
762 /* Known offset, unknown size. */
763 if (m_diag_arg)
764 return ev.formatted_print ("write at offset %qE exceeds %qE",
765 m_offset, m_diag_arg);
766 else
767 return ev.formatted_print ("write at offset %qE exceeds the"
768 " buffer", m_offset);
771 /* Unknown offset. */
772 if (m_diag_arg)
773 return ev.formatted_print ("out-of-bounds write on %qE",
774 m_diag_arg);
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
785 public:
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,
790 NULL)
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;
802 m.add_cwe (126);
803 bool warned;
804 switch (get_memory_space ())
806 default:
807 m.add_cwe (787);
808 warned = warning_meta (rich_loc, m, get_controlling_option (),
809 "buffer over-read");
810 break;
811 case MEMSPACE_STACK:
812 m.add_cwe (121);
813 warned = warning_meta (rich_loc, m, get_controlling_option (),
814 "stack-based buffer over-read");
815 break;
816 case MEMSPACE_HEAP:
817 m.add_cwe (122);
818 warned = warning_meta (rich_loc, m, get_controlling_option (),
819 "heap-based buffer over-read");
820 break;
822 if (warned)
823 maybe_show_notes (rich_loc->get_loc (), logger);
824 return warned;
827 label_text
828 describe_final_event (const evdesc::final_event &ev) final override
830 if (m_offset)
832 /* Known offset. */
833 if (m_num_bytes)
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,
840 integer_one_node))
842 /* Singular m_num_bytes. */
843 if (m_diag_arg)
844 return ev.formatted_print
845 ("read of %E byte at offset %qE exceeds %qE",
846 m_num_bytes, m_offset, m_diag_arg);
847 else
848 return ev.formatted_print
849 ("read of %E byte at offset %qE exceeds the buffer",
850 m_num_bytes, m_offset);
852 else
854 /* Plural m_num_bytes. */
855 if (m_diag_arg)
856 return ev.formatted_print
857 ("read of %E bytes at offset %qE exceeds %qE",
858 m_num_bytes, m_offset, m_diag_arg);
859 else
860 return ev.formatted_print
861 ("read of %E bytes at offset %qE exceeds the buffer",
862 m_num_bytes, m_offset);
865 else
867 /* Known offset, known symbolic size. */
868 if (m_diag_arg)
869 return ev.formatted_print
870 ("read of %qE bytes at offset %qE exceeds %qE",
871 m_num_bytes, m_offset, m_diag_arg);
872 else
873 return ev.formatted_print
874 ("read of %qE bytes at offset %qE exceeds the buffer",
875 m_num_bytes, m_offset);
878 else
880 /* Known offset, unknown size. */
881 if (m_diag_arg)
882 return ev.formatted_print ("read at offset %qE exceeds %qE",
883 m_offset, m_diag_arg);
884 else
885 return ev.formatted_print ("read at offset %qE exceeds the"
886 " buffer", m_offset);
889 /* Unknown offset. */
890 if (m_diag_arg)
891 return ev.formatted_print ("out-of-bounds read on %qE",
892 m_diag_arg);
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. */
902 bool
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
911 gcc_assert (ctxt);
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,
924 NULL_TREE,
925 sym_byte_offset);
926 const region *sized_offset_reg = m_mgr->get_sized_region (offset_reg,
927 NULL_TREE,
928 num_bytes_sval);
929 switch (dir)
931 default:
932 gcc_unreachable ();
933 break;
934 case DIR_READ:
935 gcc_assert (sval_hint == nullptr);
936 ctxt->warn (make_unique<symbolic_buffer_over_read> (*this,
937 sized_offset_reg,
938 diag_arg,
939 offset_tree,
940 num_bytes_tree,
941 capacity_tree));
942 return false;
943 break;
944 case DIR_WRITE:
945 ctxt->warn (make_unique<symbolic_buffer_overflow> (*this,
946 sized_offset_reg,
947 diag_arg,
948 offset_tree,
949 num_bytes_tree,
950 capacity_tree,
951 sval_hint));
952 return false;
953 break;
956 return true;
959 static tree
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)
964 return cst_tree;
966 return NULL_TREE;
969 /* May complain when the access on REG is out-of-bounds.
970 Return TRUE if the access was valid, FALSE otherwise. */
972 bool
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
978 gcc_assert (ctxt);
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 /* Find out how many bytes were accessed. */
985 const svalue *num_bytes_sval = reg->get_byte_size_sval (m_mgr);
986 tree num_bytes_tree = maybe_get_integer_cst_tree (num_bytes_sval);
987 /* Bail out if 0 bytes are accessed. */
988 if (num_bytes_tree && zerop (num_bytes_tree))
989 return true;
991 /* Get the capacity of the buffer. */
992 const svalue *capacity = get_capacity (base_reg);
993 tree cst_capacity_tree = maybe_get_integer_cst_tree (capacity);
995 /* The constant offset from a pointer is represented internally as a sizetype
996 but should be interpreted as a signed value here. The statement below
997 converts the offset from bits to bytes and then to a signed integer with
998 the same precision the sizetype has on the target system.
1000 For example, this is needed for out-of-bounds-3.c test1 to pass when
1001 compiled with a 64-bit gcc build targeting 32-bit systems. */
1002 byte_offset_t offset;
1003 if (!reg_offset.symbolic_p ())
1004 offset = wi::sext (reg_offset.get_bit_offset () >> LOG2_BITS_PER_UNIT,
1005 TYPE_PRECISION (size_type_node));
1007 /* If any of the base region, the offset, or the number of bytes accessed
1008 are symbolic, we have to reason about symbolic values. */
1009 if (base_reg->symbolic_p () || reg_offset.symbolic_p () || !num_bytes_tree)
1011 const svalue* byte_offset_sval;
1012 if (!reg_offset.symbolic_p ())
1014 tree offset_tree = wide_int_to_tree (integer_type_node, offset);
1015 byte_offset_sval
1016 = m_mgr->get_or_create_constant_svalue (offset_tree);
1018 else
1019 byte_offset_sval = reg_offset.get_symbolic_byte_offset ();
1020 return check_symbolic_bounds (base_reg, byte_offset_sval, num_bytes_sval,
1021 capacity, dir, sval_hint, ctxt);
1024 /* Otherwise continue to check with concrete values. */
1025 byte_range out (0, 0);
1026 bool oob_safe = true;
1027 /* NUM_BYTES_TREE should always be interpreted as unsigned. */
1028 byte_offset_t num_bytes_unsigned = wi::to_offset (num_bytes_tree);
1029 byte_range read_bytes (offset, num_bytes_unsigned);
1030 /* If read_bytes has a subset < 0, we do have an underwrite. */
1031 if (read_bytes.falls_short_of_p (0, &out))
1033 tree diag_arg = get_representative_tree (base_reg);
1034 switch (dir)
1036 default:
1037 gcc_unreachable ();
1038 break;
1039 case DIR_READ:
1040 gcc_assert (sval_hint == nullptr);
1041 ctxt->warn (make_unique<concrete_buffer_under_read> (*this, reg,
1042 diag_arg,
1043 out));
1044 oob_safe = false;
1045 break;
1046 case DIR_WRITE:
1047 ctxt->warn (make_unique<concrete_buffer_underwrite> (*this,
1048 reg, diag_arg,
1049 out,
1050 sval_hint));
1051 oob_safe = false;
1052 break;
1056 /* For accesses past the end, we do need a concrete capacity. No need to
1057 do a symbolic check here because the inequality check does not reason
1058 whether constants are greater than symbolic values. */
1059 if (!cst_capacity_tree)
1060 return oob_safe;
1062 byte_range buffer (0, wi::to_offset (cst_capacity_tree));
1063 /* If READ_BYTES exceeds BUFFER, we do have an overflow. */
1064 if (read_bytes.exceeds_p (buffer, &out))
1066 tree byte_bound = wide_int_to_tree (size_type_node,
1067 buffer.get_next_byte_offset ());
1068 tree diag_arg = get_representative_tree (base_reg);
1070 switch (dir)
1072 default:
1073 gcc_unreachable ();
1074 break;
1075 case DIR_READ:
1076 gcc_assert (sval_hint == nullptr);
1077 ctxt->warn (make_unique<concrete_buffer_over_read> (*this,
1078 reg, diag_arg,
1079 out, byte_bound));
1080 oob_safe = false;
1081 break;
1082 case DIR_WRITE:
1083 ctxt->warn (make_unique<concrete_buffer_overflow> (*this,
1084 reg, diag_arg,
1085 out, byte_bound,
1086 sval_hint));
1087 oob_safe = false;
1088 break;
1091 return oob_safe;
1094 } // namespace ana
1096 #endif /* #if ENABLE_ANALYZER */