1 /* Test to exercise that -Warray-bounds warnings for memory and string
2    functions are issued even when they are declared in system headers
3    (i.e., not just when they are explicitly declared in the source
4    file.)
5    Also verify that the warnings are issued even for calls where the
6    source of the excessive array bound is in a different function than
7    the call.
8    { dg-do compile }
9    { dg-options "-O2 -Warray-bounds -Wno-stringop-overflow -fno-tree-vrp" } */
10 
11 #if __has_include (<stddef.h>)
12 #  include <stddef.h>
13 #else
14 /* For cross-compilers.  */
15 typedef __PTRDIFF_TYPE__   ptrdiff_t;
16 typedef __SIZE_TYPE__      size_t;
17 #endif
18 
19 #if __has_include (<string.h>)
20 #  include <string.h>
21 #  undef memcpy
22 #  undef strcat
23 #  undef strcpy
24 #  undef strncpy
25 #else
26 extern void* memcpy (void*, const void*, size_t);
27 extern char* strcat (char*, const char*);
28 extern char* strcpy (char*, const char*);
29 extern char* strncpy (char*, const char*, size_t);
30 #endif
31 
32 
33 #define MAX  (__SIZE_MAX__ / 2)
34 
35 void sink (void*);
36 
37 struct __attribute__ ((packed)) Array
38 {
39   char a13[13];
40   char a15[15];
41   char a17[17];
42 };
43 
44 /* Exercise memcpy out-of-bounds offsets with an array of known size.  */
45 
46 static void
47 wrap_memcpy_src_xsize (char *d, const char *s, ptrdiff_t i, size_t n)
48 {
49   memcpy (d, s + i, n);   /* { dg-warning "offset 46 is out of the bounds \\\[0, 45] of object .ar. with type .(struct )?Array." "memcpy" } */
50 }
51 
52 void call_memcpy_src_xsize (char *d, size_t n)
53 {
54   struct Array ar;
55   sink (&ar);
56   wrap_memcpy_src_xsize (d, ar.a13, 46, n);
57   sink (&ar);
58 }
59 
60 /* Exercise memcpy out-of-bounds offsets with an array of unknown size.  */
61 
62 static void
63 wrap_memcpy_src_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
64 {
65   memcpy (d, s + i, n);   /* { dg-warning "pointer overflow between offset \[0-9\]+ and size 3" "memcpy" } */
66 }
67 
68 void call_memcpy_src_diff_max (char *d, const char *s, size_t n)
69 {
70   wrap_memcpy_src_diff_max (d, s, MAX, 3);
71 }
72 
73 static void
74 wrap_memcpy_dst_xsize (char *d, const char *s, ptrdiff_t i, size_t n)
75 {
76   memcpy (d + i, s, n);   /* { dg-warning "offset 47 is out of the bounds \\\[0, 45] of object .ar1. with type .(struct )?Array." "memcpy" } */
77 }
78 
79 void call_memcpy_dst_xsize (const char *s, size_t n)
80 {
81   struct Array ar1;       /* { dg-message ".ar1. declared here" } */
82   sink (&ar1);
83   wrap_memcpy_dst_xsize (ar1.a15, s, 34, n);
84   sink (&ar1);
85 }
86 
87 static void
88 wrap_memcpy_dst_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
89 {
90   memcpy (d + i, s, n);   /* { dg-warning "offset -?\[0-9\]+ is out of the bounds \\\[0, 45] of object .ar2. with type .(struct )?Array." "memcpy" } */
91 }
92 
93 void call_memcpy_dst_diff_max (const char *s, size_t n)
94 {
95   struct Array ar2;       /* { dg-message ".ar2. declared here" } */
96   sink (&ar2);
97   wrap_memcpy_dst_diff_max (ar2.a15, s, MAX, n);
98   sink (&ar2);
99 }
100 
101 
102 static void wrap_strcat_src_xsize (char *d, const char *s, ptrdiff_t i)
103 {
104   strcat (d, s + i);   /* { dg-warning "offset 46 is out of the bounds \\\[0, 45] of object .ar3. with type .(struct )?Array." "strcat" } */
105 }
106 
107 void call_strcat_src_xsize (char *d)
108 {
109   struct Array ar3;       /* { dg-message ".ar3. declared here" } */
110   sink (&ar3);
111   wrap_strcat_src_xsize (d, ar3.a15, 15 + 17 + 1);
112   sink (&ar3);
113 }
114 
115 static void wrap_strcat_dst_xsize (char *d, const char *s, ptrdiff_t i)
116 {
117   strcat (d + i, s);   /* { dg-warning "offset 47 is out of the bounds \\\[0, 45] of object .ar4. with type .(struct )?Array." "strcat" } */
118 }
119 
120 void call_strcat_dst_xsize (const char *s)
121 {
122   struct Array ar4;       /* { dg-message ".ar4. declared here" } */
123   sink (&ar4);
124   wrap_strcat_dst_xsize (ar4.a15, s, 15 + 17 + 2);
125   sink (&ar4);
126 }
127 
128 
129 static void wrap_strcpy_src_xsize (char *d, const char *s, ptrdiff_t i)
130 {
131   strcpy (d, s + i);   /* { dg-warning "offset 48 is out of the bounds \\\[0, 45] of object .ar5. with type .(struct )?Array." "strcpy" } */
132 }
133 
134 void call_strcpy_src_xsize (char *d)
135 {
136   struct Array ar5;       /* { dg-message ".ar5. declared here" } */
137   sink (&ar5);
138   wrap_strcpy_src_xsize (d, ar5.a15, 15 + 17 + 3);
139   sink (&ar5);
140 }
141 
142 static void wrap_strcpy_dst_xsize (char *d, const char *s, ptrdiff_t i)
143 {
144   strcpy (d + i, s);   /* { dg-warning "offset 49 is out of the bounds \\\[0, 45] of object .ar6. with type .(struct )?Array." "strcpy" } */
145 }
146 
147 void call_strcpy_dst_xsize (const char *s)
148 {
149   struct Array ar6;       /* { dg-message ".ar6. declared here" } */
150   sink (&ar6);
151   wrap_strcpy_dst_xsize (ar6.a15, s, 15 + 17 + 4);
152   sink (&ar6);
153 }
154 
155 
156 /* Exercise strncpy out-of-bounds offsets with an array of known size.  */
157 
158 static void
159 wrap_strncpy_src_xsize (char *d, const char *s, ptrdiff_t i, size_t n)
160 {
161   strncpy (d, s + i, n);   /* { dg-warning "offset 46 is out of the bounds \\\[0, 45] of object .ar7. with type '(struct )?Array." "strncpy" } */
162 }
163 
164 void call_strncpy_src_xsize (char *d, size_t n)
165 {
166   struct Array ar7;       /* { dg-message ".ar7. declared here" } */
167   sink (&ar7);
168   wrap_strncpy_src_xsize (d, ar7.a17, 17 + 1, n);
169   sink (&ar7);
170 }
171 
172 /* Exercise strncpy out-of-bounds offsets with an array of unknown size.  */
173 
174 static void
175 wrap_strncpy_src_diff_max_m1 (char *d, const char *s, ptrdiff_t i, size_t n)
176 {
177   /* Unlike in the similar call to memcpy(), there is no pointer
178      overflow here because the size N is not added to the source
179      offset MAX - 1 (only 1 is for the access to its first element,
180      which is tested below).  */
181   strncpy (d, s + i, n);
182 }
183 
184 void call_strncpy_src_diff_max_m1 (char *d, const char *s, size_t n)
185 {
186   wrap_strncpy_src_diff_max_m1 (d, s, MAX - 1, 3);
187 }
188 
189 static void
190 wrap_strncpy_src_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
191 {
192   strncpy (d, s + i, n);  /* { dg-warning "pointer overflow between offset \[0-9\]+ and size \\\[1, 0]" } */
193 }
194 
195 void call_strncpy_src_diff_max (char *d, const char *s, size_t n)
196 {
197   wrap_strncpy_src_diff_max (d, s, MAX, 3);
198 }
199 
200 static void
201 wrap_strncpy_dst_xsize (char *d, const char *s, ptrdiff_t i, size_t n)
202 {
203   strncpy (d + i, s, n);   /* { dg-warning "offset 47 is out of the bounds \\\[0, 45] of object .ar8. with type .(struct )?Array." "strncpy" } */
204 }
205 
206 void call_strncpy_dst_xsize (const char *s, size_t n)
207 {
208   struct Array ar8;       /* { dg-message ".ar8. declared here" } */
209   sink (&ar8);
210   wrap_strncpy_dst_xsize (ar8.a17, s, 17 + 2, n);
211   sink (&ar8);
212 }
213 
214 static void
215 wrap_strncpy_dst_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
216 {
217   strncpy (d + i, s, n);   /* { dg-warning "offset -\[0-9\]+ is out of the bounds \\\[0, 45] of object .ar9. with type .(struct )?Array." "strncpy" } */
218 }
219 
220 void call_strncpy_dst_diff_max (const char *s, size_t n)
221 {
222   struct Array ar9;       /* { dg-message ".ar9. declared here" "strncpy" } */
223   sink (&ar9);
224   wrap_strncpy_dst_diff_max (ar9.a17, s, MAX, n);
225   sink (&ar9);
226 }
227 
228 static void
229 wrap_strncpy_dstarray_diff_neg (char *d, const char *s, ptrdiff_t i, size_t n)
230 {
231   strncpy (d + i, s, n);   /* { dg-warning "offset -\[0-9\]+ is out of the bounds \\\[0, 90] of object .ar10. with type .(struct )?Array ?\\\[2]." "strncpy" } */
232 }
233 
234 void call_strncpy_dstarray_diff_neg (const char *s, size_t n)
235 {
236   struct Array ar10[2];    /* { dg-message ".ar10. declared here" } */
237   sink (&ar10);
238 
239   int off = (char*)ar10[1].a17 - (char*)ar10 + 1;
240   wrap_strncpy_dstarray_diff_neg (ar10[1].a17, s, -off, n);
241 
242   sink (&ar10);
243 }
244