1 /* PR middle-end/91582 - missing heap overflow detection for strcpy
2    { dg-do compile }
3    { dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */
4 
5 #include "range.h"
6 
7 #define INT_MAX     __INT_MAX__
8 #define INT_MIN     (-INT_MAX - 1)
9 
10 #define ATTR(...)   __attribute__ ((__VA_ARGS__))
11 #define NOIPA       ATTR (noipa)
12 
13 extern void* alloca (size_t);
14 extern void* calloc (size_t, size_t);
15 extern void* malloc (size_t);
16 
17 extern ATTR (alloc_size (1), malloc) char* alloc1 (size_t);
18 extern ATTR (alloc_size (1, 2), malloc) char* alloc2 (size_t, size_t);
19 
20 extern char* strcpy (char*, const char*);
21 
22 void sink (void*, ...);
23 
24 
25 /* Verify warning in stores to an object of variable size N in a known
26    range, at an offset (N + I) with a constant I.  */
27 
same_size_and_offset_idx_cst(void)28 void same_size_and_offset_idx_cst (void)
29 {
30 #define T(size, off, idx) do {			\
31     size_t n_ = size;				\
32     ptrdiff_t i_ = idx;				\
33     char *p_ = alloc1 (n_);			\
34     p_ += off;					\
35     p_[i_] = 0;					\
36     sink (p_);					\
37   } while (0)
38 
39   {
40     const size_t n = UR (2, 3);
41 
42     T (n, n, -4);   // { dg-warning "writing 1 byte into a region of size 0" }
43                     // { dg-message "at offset \\\[-2, -1] into destination object of size \\\[2, 3] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
44     T (n, n, -3);
45     T (n, n, -2);
46     T (n, n, -1);
47     T (n, n,  0);
48     T (n, n,  1);   // { dg-warning "writing 1 byte into a region of size 0" }
49                     // { dg-message "at offset 3 into destination object of size \\\[2, 3] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
50   }
51 
52   {
53     const size_t n = UR (3, 4);
54 
55     T (n, n, -5);   // { dg-warning "writing 1 byte into a region of size 0" }
56                     // { dg-message "at offset \\\[-2, -1] into destination object of size \\\[3, 4] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
57     T (n, n, -4);
58     T (n, n, -3);
59     T (n, n, -2);
60     T (n, n, -1);
61     T (n, n,  0);
62     T (n, n,  1);   // { dg-warning "writing 1 byte into a region of size 0" }
63                     // { dg-message "at offset 4 into destination object of size \\\[3, 4] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
64   }
65 
66   {
67     const size_t n = UR (5, SIZE_MAX - 2);
68     T (n, n, -1);
69     T (n, n, -1);
70     T (n, n, -1);
71     T (n, n, -1);
72   }
73 }
74 
75 
76 /* Verify warning in stores to an object of variable size N in a known
77    range, at an offset (M + I) with a variable M in some range and
78    constant I.  */
79 
different_size_and_offset_idx_cst(void)80 void different_size_and_offset_idx_cst (void)
81 {
82   {
83     const size_t n = UR (2, 3);
84     const size_t i = UR (1, 2);
85 
86     T (n, i, -4);   // { dg-warning "writing 1 byte into a region of size 0" }
87                     // { dg-message "at offset \\\[-3, -2] into destination object of size \\\[2, 3] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
88     T (n, i, -3);   // { dg-warning "writing 1 byte into a region of size 0" }
89                     // { dg-message "at offset \\\[-2, -1] into destination object of size \\\[2, 3] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
90     T (n, i, -2);
91     T (n, i, -1);
92     T (n, i,  0);
93     T (n, i,  1);
94     T (n, i,  2);   // { dg-warning "writing 1 byte into a region of size 0" }
95                     // { dg-message "at offset 3 into destination object of size \\\[2, 3] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
96   }
97 
98   {
99     const size_t n = UR (3, 4);
100     const size_t i = UR (2, 5);
101 
102     T (n, i, -6);   // { dg-warning "writing 1 byte into a region of size 0" }
103                     // { dg-message "at offset \\\[-4, -2] into destination object of size \\\[3, 4] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
104 
105     /* The offset -5 is necessarily invalid even if the sum (i - 5) is (or
106        could be) in bounds because it implies that the intermediate offset
107        (p + i) is out of bounds.  */
108     T (n, i, -5);   // { dg-warning "writing 1 byte into a region of size 0 " }
109     T (n, i, -4);
110     T (n, i, -3);
111     T (n, i, -2);
112     T (n, i, -1);
113     T (n, i,  0);
114     T (n, i,  1);
115     T (n, i,  2);   // { dg-warning "writing 1 byte into a region of size 0" }
116                     // { dg-message "at offset 4 into destination object of size \\\[3, 4] allocated by 'alloc1'" "note" { target *-*-* } .-1 }
117   }
118 }
119 
120 
121 /* Verify warning in stores to an object of variable size N in a known
122    range, at an offset (M + I) with a variable M in some range and
123    constant I.  */
different_size_and_offset_idx_var(void)124 void different_size_and_offset_idx_var (void)
125 {
126   {
127     const size_t n = UR (3, 4);
128     const size_t i = UR (1, 2);
129 
130     T (n, i, SR (DIFF_MIN, 0));
131     T (n, i, SR (      -3, 0));
132     T (n, i, SR (      -1, 0));
133     T (n, i, SR (       0, 1));
134     T (n, i, SR (       1, 2));
135     T (n, i, SR (       2, 3));
136     T (n, i, SR (       3, 4));    // { dg-warning "\\\[-Wstringop-overflow" }
137                                    // { dg-message "at offset 4 into destination object of size \\\[3, 4] allocated by 'alloc1'" "pr92940 note: offset addition" { target *-*-* } .-1 }
138  }
139 }
140 
141 
ptr_add_2(int n,int i0,int i1)142 void ptr_add_2 (int n, int i0, int i1)
143 {
144   if (n < 1 || 2 < n) n = 2;
145 
146   if (i0 < 0 || 1 < i0) i0 = 0;
147   if (i1 < 1 || 2 < i1) i1 = 1;
148 
149   char *p = (char*)__builtin_malloc (n);
150   char *q = p;
151 
152   q += i0;
153   q[0] = 0;   // p[0]
154   q += i1;
155   q[0] = 1;   // p[1]
156   q[1] = 2;   // p[2]     // { dg-warning "\\\[-Wstringop-overflow" }
157 
158   sink (p, q);
159 }
160 
ptr_add_3(int n,int i0,int i1,int i2)161 void ptr_add_3 (int n, int i0, int i1, int i2)
162 {
163   if (n < 3 || 4 < n) n = 3;
164 
165   if (i0 < 0 || 1 < i0) i0 = 0;
166   if (i1 < 1 || 2 < i1) i1 = 1;
167   if (i2 < 2 || 3 < i2) i2 = 2;
168 
169   char *p = (char*)__builtin_malloc (n);
170   char *q = p;
171 
172   q += i0;
173   q[0] = 0;   // p[0]
174   q += i1;
175   q[0] = 1;   // p[1]
176   q[1] = 2;   // p[2]
177   q += i2;
178   q[0] = 3;   // p[3]
179   q[1] = 4;   // p[4]     // { dg-warning "\\\[-Wstringop-overflow" }
180 
181   sink (p, q);
182 }
183 
ptr_add_4(int n,int i0,int i1,int i2,int i3)184 void ptr_add_4 (int n, int i0, int i1, int i2, int i3)
185 {
186   if (n < 7 || 8 < n) n = 7;
187 
188   if (i0 < 0 || 1 < i0) i0 = 0;
189   if (i1 < 1 || 2 < i1) i1 = 1;
190   if (i2 < 2 || 3 < i2) i2 = 2;
191   if (i3 < 3 || 4 < i3) i3 = 3;
192 
193   char *p = (char*)__builtin_malloc (n);
194   char *q = p;
195 
196   q += i0;
197   q[0] = 0;   // p[0]
198   q += i1;
199   q[0] = 1;   // p[1]
200   q[1] = 2;   // p[2]
201   q += i2;
202   q[0] = 3;   // p[3]
203   q[1] = 4;   // p[4]
204   q[2] = 5;   // p[5]
205   q += i3;
206   q[0] = 6;   // p[6]
207   q[1] = 7;   // p[7]
208   q[2] = 8;   // p[8]     // { dg-warning "\\\[-Wstringop-overflow" }
209 
210   sink (p, q);
211 }
212 
ptr_sub_from_end(int n,int i0,int i1,int i2,int i3)213 void ptr_sub_from_end (int n, int i0, int i1, int i2, int i3)
214 {
215   if (n < 1 || 2 < n) n = 2;
216 
217   char *p = (char*)__builtin_malloc (n);
218   char *q = p;
219 
220   // The following isn't diagnosed due to a bug/limitation.
221   q += n;      //  N=1     N=2
222   q[-1] = 0;   // p[0]    p[1]
223   q[-2] = 1;   // p[-1]   p[0]
224   q[-3] = 2;   // p[-2]   p[-1]   // { dg-warning "\\\[-Wstringop-overflow" "pr92939: negative offset from end" }
225 
226   /* The following isn't diagnosed because the warning doesn't recognize
227      the index below as necessarily having the same value as the size
228      argument to malloc.  All it considers is the range.  */
229   q[0] = 2;                       // { dg-warning "\\\[-Wstringop-overflow" "pr92937: store just past the end" { xfail *-*-* } }
230   q[1] = 3;                       // { dg-warning "\\\[-Wstringop-overflow" }
231 
232   sink (p, q);
233 }
234