17f183fea21ae81a980682bcb2776aa332f5bc5c
[platform/upstream/gcc.git] / gcc / analyzer / bounds-checking.cc
1 /* Bounds-checking of reads and writes to memory regions.
2    Copyright (C) 2019-2022 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
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.
10
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.
15
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/>.  */
19
20 #include "config.h"
21 #define INCLUDE_MEMORY
22 #include "system.h"
23 #include "coretypes.h"
24 #include "make-unique.h"
25 #include "tree.h"
26 #include "function.h"
27 #include "basic-block.h"
28 #include "gimple.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"
37
38 #if ENABLE_ANALYZER
39
40 namespace ana {
41
42 /* Abstract base class for all out-of-bounds warnings.  */
43
44 class out_of_bounds : public pending_diagnostic
45 {
46 public:
47   out_of_bounds (const region *reg, tree diag_arg)
48   : m_reg (reg), m_diag_arg (diag_arg)
49   {}
50
51   bool subclass_equal_p (const pending_diagnostic &base_other) const override
52   {
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));
57   }
58
59   int get_controlling_option () const final override
60   {
61     return OPT_Wanalyzer_out_of_bounds;
62   }
63
64   void mark_interesting_stuff (interesting_t *interest) final override
65   {
66     interest->add_region_creation (m_reg);
67   }
68
69   void add_region_creation_events (const region *,
70                                    tree capacity,
71                                    location_t loc,
72                                    tree fndecl, int depth,
73                                    checker_path &emission_path) override
74   {
75     /* The memory space is described in the diagnostic message itself,
76        so we don't need an event for that.  */
77     if (capacity)
78       emission_path.add_event
79         (make_unique<region_creation_event_capacity> (capacity,
80                                                       loc, fndecl, depth));
81   }
82
83 protected:
84   enum memory_space get_memory_space () const
85   {
86     return m_reg->get_memory_space ();
87   }
88
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.  */
95   void
96   maybe_describe_array_bounds (location_t loc) const
97   {
98     if (!m_diag_arg)
99       return;
100     tree t = TREE_TYPE (m_diag_arg);
101     if (!t)
102       return;
103     if (TREE_CODE (t) != ARRAY_TYPE)
104       return;
105     tree domain = TYPE_DOMAIN (t);
106     if (!domain)
107       return;
108     tree max_idx = TYPE_MAX_VALUE (domain);
109     if (!max_idx)
110       return;
111     tree min_idx = TYPE_MIN_VALUE (domain);
112     inform (loc,
113             "valid subscripts for %qE are %<[%E]%> to %<[%E]%>",
114             m_diag_arg, min_idx, max_idx);
115   }
116
117   const region *m_reg;
118   tree m_diag_arg;
119 };
120
121 /* Abstract base class for all out-of-bounds warnings where the
122    out-of-bounds range is concrete.  */
123
124 class concrete_out_of_bounds : public out_of_bounds
125 {
126 public:
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)
131   {}
132
133   bool subclass_equal_p (const pending_diagnostic &base_other) const override
134   {
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);
139   }
140
141 protected:
142   byte_range m_out_of_bounds_range;
143 };
144
145 /* Abstract subclass to complaing about concrete out-of-bounds
146    past the end of the buffer.  */
147
148 class concrete_past_the_end : public concrete_out_of_bounds
149 {
150 public:
151   concrete_past_the_end (const region *reg, tree diag_arg, byte_range range,
152                          tree byte_bound)
153   : concrete_out_of_bounds (reg, diag_arg, range), m_byte_bound (byte_bound)
154   {}
155
156   bool
157   subclass_equal_p (const pending_diagnostic &base_other) const final override
158   {
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));
164   }
165
166   void add_region_creation_events (const region *,
167                                    tree,
168                                    location_t loc,
169                                    tree fndecl, int depth,
170                                    checker_path &emission_path) final override
171   {
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));
176   }
177
178 protected:
179   tree m_byte_bound;
180 };
181
182 /* Concrete subclass to complain about buffer overflows.  */
183
184 class concrete_buffer_overflow : public concrete_past_the_end
185 {
186 public:
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)
190   {}
191
192   const char *get_kind () const final override
193   {
194     return "concrete_buffer_overflow";
195   }
196
197   bool emit (rich_location *rich_loc) final override
198   {
199     diagnostic_metadata m;
200     bool warned;
201     switch (get_memory_space ())
202       {
203       default:
204         m.add_cwe (787);
205         warned = warning_meta (rich_loc, m, get_controlling_option (),
206                                "buffer overflow");
207         break;
208       case MEMSPACE_STACK:
209         m.add_cwe (121);
210         warned = warning_meta (rich_loc, m, get_controlling_option (),
211                                "stack-based buffer overflow");
212         break;
213       case MEMSPACE_HEAP:
214         m.add_cwe (122);
215         warned = warning_meta (rich_loc, m, get_controlling_option (),
216                                "heap-based buffer overflow");
217         break;
218       }
219
220     if (warned)
221       {
222         if (wi::fits_uhwi_p (m_out_of_bounds_range.m_size_in_bytes))
223           {
224             unsigned HOST_WIDE_INT num_bad_bytes
225               = m_out_of_bounds_range.m_size_in_bytes.to_uhwi ();
226             if (m_diag_arg)
227               inform_n (rich_loc->get_loc (),
228                         num_bad_bytes,
229                         "write of %wu byte to beyond the end of %qE",
230                         "write of %wu bytes to beyond the end of %qE",
231                         num_bad_bytes,
232                         m_diag_arg);
233             else
234               inform_n (rich_loc->get_loc (),
235                         num_bad_bytes,
236                         "write of %wu byte to beyond the end of the region",
237                         "write of %wu bytes to beyond the end of the region",
238                         num_bad_bytes);
239           }
240         else if (m_diag_arg)
241           inform (rich_loc->get_loc (),
242                   "write to beyond the end of %qE",
243                   m_diag_arg);
244
245         maybe_describe_array_bounds (rich_loc->get_loc ());
246       }
247
248     return warned;
249   }
250
251   label_text describe_final_event (const evdesc::final_event &ev)
252   final override
253   {
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);
260
261     if (start == end)
262       {
263         if (m_diag_arg)
264           return ev.formatted_print ("out-of-bounds write at byte %s but %qE"
265                                      " ends at byte %E", start_buf, m_diag_arg,
266                                                          m_byte_bound);
267         return ev.formatted_print ("out-of-bounds write at byte %s but region"
268                                    " ends at byte %E", start_buf,
269                                                        m_byte_bound);
270       }
271     else
272       {
273         if (m_diag_arg)
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,
277                                      m_byte_bound);
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);
281       }
282   }
283 };
284
285 /* Concrete subclass to complain about buffer over-reads.  */
286
287 class concrete_buffer_over_read : public concrete_past_the_end
288 {
289 public:
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)
293   {}
294
295   const char *get_kind () const final override
296   {
297     return "concrete_buffer_over_read";
298   }
299
300   bool emit (rich_location *rich_loc) final override
301   {
302     diagnostic_metadata m;
303     bool warned;
304     m.add_cwe (126);
305     switch (get_memory_space ())
306       {
307       default:
308         warned = warning_meta (rich_loc, m, get_controlling_option (),
309                                "buffer over-read");
310         break;
311       case MEMSPACE_STACK:
312         warned = warning_meta (rich_loc, m, get_controlling_option (),
313                                "stack-based buffer over-read");
314         break;
315       case MEMSPACE_HEAP:
316         warned = warning_meta (rich_loc, m, get_controlling_option (),
317                                "heap-based buffer over-read");
318         break;
319       }
320
321     if (warned)
322       {
323         if (wi::fits_uhwi_p (m_out_of_bounds_range.m_size_in_bytes))
324           {
325             unsigned HOST_WIDE_INT num_bad_bytes
326               = m_out_of_bounds_range.m_size_in_bytes.to_uhwi ();
327             if (m_diag_arg)
328               inform_n (rich_loc->get_loc (),
329                         num_bad_bytes,
330                         "read of %wu byte from after the end of %qE",
331                         "read of %wu bytes from after the end of %qE",
332                         num_bad_bytes,
333                         m_diag_arg);
334             else
335               inform_n (rich_loc->get_loc (),
336                         num_bad_bytes,
337                         "read of %wu byte from after the end of the region",
338                         "read of %wu bytes from after the end of the region",
339                         num_bad_bytes);
340           }
341         else if (m_diag_arg)
342           inform (rich_loc->get_loc (),
343                   "read from after the end of %qE",
344                   m_diag_arg);
345
346         maybe_describe_array_bounds (rich_loc->get_loc ());
347       }
348
349     return warned;
350   }
351
352   label_text describe_final_event (const evdesc::final_event &ev)
353   final override
354   {
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);
361
362     if (start == end)
363       {
364         if (m_diag_arg)
365           return ev.formatted_print ("out-of-bounds read at byte %s but %qE"
366                                      " ends at byte %E", start_buf, m_diag_arg,
367                                                          m_byte_bound);
368         return ev.formatted_print ("out-of-bounds read at byte %s but region"
369                                    " ends at byte %E", start_buf,
370                                                        m_byte_bound);
371       }
372     else
373       {
374         if (m_diag_arg)
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,
378                                      m_byte_bound);
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);
382       }
383   }
384 };
385
386 /* Concrete subclass to complain about buffer underwrites.  */
387
388 class concrete_buffer_underwrite : public concrete_out_of_bounds
389 {
390 public:
391   concrete_buffer_underwrite (const region *reg, tree diag_arg,
392                               byte_range range)
393   : concrete_out_of_bounds (reg, diag_arg, range)
394   {}
395
396   const char *get_kind () const final override
397   {
398     return "concrete_buffer_underwrite";
399   }
400
401   bool emit (rich_location *rich_loc) final override
402   {
403     diagnostic_metadata m;
404     bool warned;
405     m.add_cwe (124);
406     switch (get_memory_space ())
407       {
408       default:
409         warned = warning_meta (rich_loc, m, get_controlling_option (),
410                                "buffer underwrite");
411         break;
412       case MEMSPACE_STACK:
413         warned = warning_meta (rich_loc, m, get_controlling_option (),
414                                "stack-based buffer underwrite");
415         break;
416       case MEMSPACE_HEAP:
417         warned = warning_meta (rich_loc, m, get_controlling_option (),
418                                "heap-based buffer underwrite");
419         break;
420       }
421     if (warned)
422       maybe_describe_array_bounds (rich_loc->get_loc ());
423     return warned;
424   }
425
426   label_text describe_final_event (const evdesc::final_event &ev)
427   final override
428   {
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);
435
436     if (start == end)
437       {
438         if (m_diag_arg)
439           return ev.formatted_print ("out-of-bounds write at byte %s but %qE"
440                                      " starts at byte 0", start_buf,
441                                                           m_diag_arg);
442         return ev.formatted_print ("out-of-bounds write at byte %s but region"
443                                    " starts at byte 0", start_buf);
444       }
445     else
446       {
447         if (m_diag_arg)
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);;
454       }
455   }
456 };
457
458 /* Concrete subclass to complain about buffer under-reads.  */
459
460 class concrete_buffer_under_read : public concrete_out_of_bounds
461 {
462 public:
463   concrete_buffer_under_read (const region *reg, tree diag_arg,
464                               byte_range range)
465   : concrete_out_of_bounds (reg, diag_arg, range)
466   {}
467
468   const char *get_kind () const final override
469   {
470     return "concrete_buffer_under_read";
471   }
472
473   bool emit (rich_location *rich_loc) final override
474   {
475     diagnostic_metadata m;
476     bool warned;
477     m.add_cwe (127);
478     switch (get_memory_space ())
479       {
480       default:
481         warned = warning_meta (rich_loc, m, get_controlling_option (),
482                                "buffer under-read");
483         break;
484       case MEMSPACE_STACK:
485         warned = warning_meta (rich_loc, m, get_controlling_option (),
486                                "stack-based buffer under-read");
487         break;
488       case MEMSPACE_HEAP:
489         warned = warning_meta (rich_loc, m, get_controlling_option (),
490                                "heap-based buffer under-read");
491         break;
492       }
493     if (warned)
494       maybe_describe_array_bounds (rich_loc->get_loc ());
495     return warned;
496   }
497
498   label_text describe_final_event (const evdesc::final_event &ev)
499   final override
500   {
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);
507
508     if (start == end)
509       {
510         if (m_diag_arg)
511           return ev.formatted_print ("out-of-bounds read at byte %s but %qE"
512                                      " starts at byte 0", start_buf,
513                                                           m_diag_arg);
514         return ev.formatted_print ("out-of-bounds read at byte %s but region"
515                                   " starts at byte 0", start_buf);
516       }
517     else
518       {
519         if (m_diag_arg)
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);;
526       }
527   }
528 };
529
530 /* Abstract class to complain about out-of-bounds read/writes where
531    the values are symbolic.  */
532
533 class symbolic_past_the_end : public out_of_bounds
534 {
535 public:
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),
539     m_offset (offset),
540     m_num_bytes (num_bytes),
541     m_capacity (capacity)
542   {}
543
544   bool
545   subclass_equal_p (const pending_diagnostic &base_other) const final override
546   {
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));
553   }
554
555 protected:
556   tree m_offset;
557   tree m_num_bytes;
558   tree m_capacity;
559 };
560
561 /* Concrete subclass to complain about overflows with symbolic values.  */
562
563 class symbolic_buffer_overflow : public symbolic_past_the_end
564 {
565 public:
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)
569   {
570   }
571
572   const char *get_kind () const final override
573   {
574     return "symbolic_buffer_overflow";
575   }
576
577   bool emit (rich_location *rich_loc) final override
578   {
579     diagnostic_metadata m;
580     switch (get_memory_space ())
581       {
582       default:
583         m.add_cwe (787);
584         return warning_meta (rich_loc, m, get_controlling_option (),
585                              "buffer overflow");
586       case MEMSPACE_STACK:
587         m.add_cwe (121);
588         return warning_meta (rich_loc, m, get_controlling_option (),
589                              "stack-based buffer overflow");
590       case MEMSPACE_HEAP:
591         m.add_cwe (122);
592         return warning_meta (rich_loc, m, get_controlling_option (),
593                              "heap-based buffer overflow");
594       }
595   }
596
597   label_text
598   describe_final_event (const evdesc::final_event &ev) final override
599   {
600     if (m_offset)
601       {
602         /* Known offset.  */
603         if (m_num_bytes)
604           {
605             /* Known offset, known size.  */
606             if (TREE_CODE (m_num_bytes) == INTEGER_CST)
607               {
608                 /* Known offset, known constant size.  */
609                 if (pending_diagnostic::same_tree_p (m_num_bytes,
610                                                      integer_one_node))
611                   {
612                     /* Singular m_num_bytes.  */
613                     if (m_diag_arg)
614                       return ev.formatted_print
615                         ("write of %E byte at offset %qE exceeds %qE",
616                          m_num_bytes, m_offset, m_diag_arg);
617                     else
618                       return ev.formatted_print
619                         ("write of %E byte at offset %qE exceeds the buffer",
620                          m_num_bytes, m_offset);
621                   }
622                 else
623                   {
624                     /* Plural m_num_bytes.  */
625                     if (m_diag_arg)
626                       return ev.formatted_print
627                         ("write of %E bytes at offset %qE exceeds %qE",
628                          m_num_bytes, m_offset, m_diag_arg);
629                     else
630                       return ev.formatted_print
631                         ("write of %E bytes at offset %qE exceeds the buffer",
632                          m_num_bytes, m_offset);
633                   }
634               }
635             else
636               {
637                 /* Known offset, known symbolic size.  */
638                 if (m_diag_arg)
639                   return ev.formatted_print
640                     ("write of %qE bytes at offset %qE exceeds %qE",
641                      m_num_bytes, m_offset, m_diag_arg);
642                 else
643                   return ev.formatted_print
644                     ("write of %qE bytes at offset %qE exceeds the buffer",
645                      m_num_bytes, m_offset);
646               }
647           }
648         else
649           {
650             /* Known offset, unknown size.  */
651             if (m_diag_arg)
652               return ev.formatted_print ("write at offset %qE exceeds %qE",
653                                          m_offset, m_diag_arg);
654             else
655               return ev.formatted_print ("write at offset %qE exceeds the"
656                                          " buffer", m_offset);
657           }
658       }
659     /* Unknown offset.  */
660     if (m_diag_arg)
661       return ev.formatted_print ("out-of-bounds write on %qE",
662                                  m_diag_arg);
663     return ev.formatted_print ("out-of-bounds write");
664   }
665 };
666
667 /* Concrete subclass to complain about over-reads with symbolic values.  */
668
669 class symbolic_buffer_over_read : public symbolic_past_the_end
670 {
671 public:
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)
675   {
676   }
677
678   const char *get_kind () const final override
679   {
680     return "symbolic_buffer_over_read";
681   }
682
683   bool emit (rich_location *rich_loc) final override
684   {
685     diagnostic_metadata m;
686     m.add_cwe (126);
687     switch (get_memory_space ())
688       {
689       default:
690         m.add_cwe (787);
691         return warning_meta (rich_loc, m, get_controlling_option (),
692                              "buffer over-read");
693       case MEMSPACE_STACK:
694         m.add_cwe (121);
695         return warning_meta (rich_loc, m, get_controlling_option (),
696                              "stack-based buffer over-read");
697       case MEMSPACE_HEAP:
698         m.add_cwe (122);
699         return warning_meta (rich_loc, m, get_controlling_option (),
700                              "heap-based buffer over-read");
701       }
702   }
703
704   label_text
705   describe_final_event (const evdesc::final_event &ev) final override
706   {
707     if (m_offset)
708       {
709         /* Known offset.  */
710         if (m_num_bytes)
711           {
712             /* Known offset, known size.  */
713             if (TREE_CODE (m_num_bytes) == INTEGER_CST)
714               {
715                 /* Known offset, known constant size.  */
716                 if (pending_diagnostic::same_tree_p (m_num_bytes,
717                                                      integer_one_node))
718                   {
719                     /* Singular m_num_bytes.  */
720                     if (m_diag_arg)
721                       return ev.formatted_print
722                         ("read of %E byte at offset %qE exceeds %qE",
723                          m_num_bytes, m_offset, m_diag_arg);
724                     else
725                       return ev.formatted_print
726                         ("read of %E byte at offset %qE exceeds the buffer",
727                          m_num_bytes, m_offset);
728                   }
729                 else
730                   {
731                     /* Plural m_num_bytes.  */
732                     if (m_diag_arg)
733                       return ev.formatted_print
734                         ("read of %E bytes at offset %qE exceeds %qE",
735                          m_num_bytes, m_offset, m_diag_arg);
736                     else
737                       return ev.formatted_print
738                         ("read of %E bytes at offset %qE exceeds the buffer",
739                          m_num_bytes, m_offset);
740                   }
741               }
742             else
743               {
744                 /* Known offset, known symbolic size.  */
745                 if (m_diag_arg)
746                   return ev.formatted_print
747                     ("read of %qE bytes at offset %qE exceeds %qE",
748                      m_num_bytes, m_offset, m_diag_arg);
749                 else
750                   return ev.formatted_print
751                     ("read of %qE bytes at offset %qE exceeds the buffer",
752                      m_num_bytes, m_offset);
753               }
754           }
755         else
756           {
757             /* Known offset, unknown size.  */
758             if (m_diag_arg)
759               return ev.formatted_print ("read at offset %qE exceeds %qE",
760                                          m_offset, m_diag_arg);
761             else
762               return ev.formatted_print ("read at offset %qE exceeds the"
763                                          " buffer", m_offset);
764           }
765       }
766     /* Unknown offset.  */
767     if (m_diag_arg)
768       return ev.formatted_print ("out-of-bounds read on %qE",
769                                  m_diag_arg);
770     return ev.formatted_print ("out-of-bounds read");
771   }
772 };
773
774 /* Check whether an access is past the end of the BASE_REG.  */
775
776 void
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
783 {
784   gcc_assert (ctxt);
785
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);
789
790   if (eval_condition (next_byte, GT_EXPR, capacity).is_true ())
791     {
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);
796       switch (dir)
797         {
798         default:
799           gcc_unreachable ();
800           break;
801         case DIR_READ:
802           ctxt->warn (make_unique<symbolic_buffer_over_read> (base_reg,
803                                                               diag_arg,
804                                                               offset_tree,
805                                                               num_bytes_tree,
806                                                               capacity_tree));
807           break;
808         case DIR_WRITE:
809           ctxt->warn (make_unique<symbolic_buffer_overflow> (base_reg,
810                                                              diag_arg,
811                                                              offset_tree,
812                                                              num_bytes_tree,
813                                                              capacity_tree));
814           break;
815         }
816     }
817 }
818
819 static tree
820 maybe_get_integer_cst_tree (const svalue *sval)
821 {
822   tree cst_tree = sval->maybe_get_constant ();
823   if (cst_tree && TREE_CODE (cst_tree) == INTEGER_CST)
824     return cst_tree;
825
826   return NULL_TREE;
827 }
828
829 /* May complain when the access on REG is out-of-bounds.  */
830
831 void
832 region_model::check_region_bounds (const region *reg,
833                                    enum access_direction dir,
834                                    region_model_context *ctxt) const
835 {
836   gcc_assert (ctxt);
837
838   /* Get the offset.  */
839   region_offset reg_offset = reg->get_offset (m_mgr);
840   const region *base_reg = reg_offset.get_base_region ();
841
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 ())
846     return;
847
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))
853     return;
854
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);
858
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.
863
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));
870
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)
874     {
875       const svalue* byte_offset_sval;
876       if (!reg_offset.symbolic_p ())
877         {
878           tree offset_tree = wide_int_to_tree (integer_type_node, offset);
879           byte_offset_sval
880             = m_mgr->get_or_create_constant_svalue (offset_tree);
881         }
882       else
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);
886       return;
887     }
888
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))
896     {
897       tree diag_arg = get_representative_tree (base_reg);
898       switch (dir)
899         {
900         default:
901           gcc_unreachable ();
902           break;
903         case DIR_READ:
904           ctxt->warn (make_unique<concrete_buffer_under_read> (reg, diag_arg,
905                                                                out));
906           break;
907         case DIR_WRITE:
908           ctxt->warn (make_unique<concrete_buffer_underwrite> (reg, diag_arg,
909                                                                out));
910           break;
911         }
912     }
913
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)
918     return;
919
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))
923     {
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);
927
928       switch (dir)
929         {
930         default:
931           gcc_unreachable ();
932           break;
933         case DIR_READ:
934           ctxt->warn (make_unique<concrete_buffer_over_read> (reg, diag_arg,
935                                                               out, byte_bound));
936           break;
937         case DIR_WRITE:
938           ctxt->warn (make_unique<concrete_buffer_overflow> (reg, diag_arg,
939                                                              out, byte_bound));
940           break;
941         }
942     }
943 }
944
945 } // namespace ana
946
947 #endif /* #if ENABLE_ANALYZER */