PR middle-end/85602 - -Wsizeof-pointer-memaccess for strncat with size of source
[official-gcc.git] / gcc / testsuite / gcc.dg / builtin-stringop-chk-5.c
blob489f88077d44f7db0ed5f0e5df33f22878a5287b
1 /* Test exercising -Wrawmem-overflow and -Wstringop-overflow warnings. */
2 /* { dg-do compile } */
3 /* { dg-options "-O2 -Wstringop-overflow=1" } */
5 #define offsetof(type, mem) __builtin_offsetof (type, mem)
7 /* Return the number of bytes from member MEM of TYPE to the end
8 of object OBJ. */
9 #define offsetfrom(type, obj, mem) (sizeof (obj) - offsetof (type, mem))
12 typedef __SIZE_TYPE__ size_t;
13 extern void* memcpy (void*, const void*, size_t);
14 extern void* memset (void*, int, __SIZE_TYPE__);
17 struct A { char a, b; };
18 struct B { struct A a; char c, d; };
20 /* Function to call to "escape" pointers from tests below to prevent
21 GCC from assuming the values of the objects they point to stay
22 the unchanged. */
23 void escape (void*, ...);
25 /* Function to "generate" a random number each time it's called. Declared
26 (but not defined) and used to prevent GCC from making assumptions about
27 their values based on the variables uses in the tested expressions. */
28 size_t random_unsigned_value (void);
30 /* Return a random unsigned value between MIN and MAX. */
32 static inline size_t
33 range (size_t min, size_t max)
35 const size_t val = random_unsigned_value ();
36 return val < min || max < val ? min : val;
39 /* Verify that writing past the end of a local array is diagnosed. */
41 void test_memop_warn_local (const void *src)
43 size_t n;
45 n = range (8, 32);
47 struct A a[2];
49 memcpy (a, src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" } */
50 escape (a, src);
52 /* At -Wrawmem-overflow=1 the destination is considered to be
53 the whole array and its size is therefore sizeof a. */
54 memcpy (&a[0], src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" } */
55 escape (a, src);
57 /* Verify the same as above but by writing into the first mmeber
58 of the first element of the array. */
59 memcpy (&a[0].a, src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" } */
60 escape (a, src);
62 n = range (12, 32);
64 struct B b[2];
66 memcpy (&b[0], src, n); /* { dg-warning "writing between 12 and 32 bytes into a region of size 8 overflows the destination" } */
67 escape (b);
69 /* The following idiom of clearing multiple members of a struct is
70 used in a few places in the Linux kernel. Verify that a warning
71 is issued for it when it writes past the end of the array object. */
72 memset (&b[0].a.b, 0, offsetfrom (struct B, b, a.b) + 1); /* { dg-warning "writing 8 bytes into a region of size 7" } */
73 escape (b);
75 memset (&b->a.b, 0, offsetfrom (struct B, b, a.b) + 1); /* { dg-warning "writing 8 bytes into a region of size 7" } */
76 escape (b);
78 memset (&b[0].c, 0, offsetfrom (struct B, b, c) + 1); /* { dg-warning "writing 7 bytes into a region of size 6" } */
79 escape (b);
81 memset (&b->c, 0, offsetfrom (struct B, b, c) + 1); /* { dg-warning "writing 7 bytes into a region of size 6" } */
82 escape (b);
84 memset (&b[0].d, 0, offsetfrom (struct B, b, d) + 1); /* { dg-warning "writing 6 bytes into a region of size 5" } */
85 escape (b);
87 memset (&b->d, 0, offsetfrom (struct B, b, d) + 1); /* { dg-warning "writing 6 bytes into a region of size 5" } */
88 escape (b);
90 /* Same as above but clearing just elements of the second element
91 of the array. */
92 memset (&b[1].a.b, 0, offsetfrom (struct B, b[1], a.b) + 1); /* { dg-warning "writing 4 bytes into a region of size 3" } */
93 escape (b);
95 memset (&b[1].c, 0, offsetfrom (struct B, b[1], c) + 1); /* { dg-warning "writing 3 bytes into a region of size 2" } */
96 escape (b);
98 memset (&b[1].d, 0, offsetfrom (struct B, b[1], d) + 1); /* { dg-warning "writing 2 bytes into a region of size 1" } */
99 escape (b);
102 /* Verify that writing past the end of a dynamically allocated array
103 of known size is diagnosed. */
105 void test_memop_warn_alloc (const void *src)
107 size_t n;
109 n = range (8, 32);
111 struct A *a = __builtin_malloc (sizeof *a * 2);
113 memcpy (a, src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" "memcpy into allocated" { xfail *-*-*} } */
114 escape (a, src);
116 /* At -Wrawmem-overflow=1 the destination is considered to be
117 the whole array and its size is therefore sizeof a. */
118 memcpy (&a[0], src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" "memcpy into allocated" { xfail *-*-*} } */
119 escape (a, src);
121 /* Verify the same as above but by writing into the first mmeber
122 of the first element of the array. */
123 memcpy (&a[0].a, src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" "memcpy into allocated" { xfail *-*-*} } */
124 escape (a, src);
126 n = range (12, 32);
128 struct B *b = __builtin_malloc (sizeof *b * 2);
130 memcpy (&b[0], src, n); /* { dg-warning "writing between 12 and 32 bytes into a region of size 8 overflows the destination" "memcpy into allocated" { xfail *-*-*} } */
131 escape (b);
133 /* The following idiom of clearing multiple members of a struct is
134 used in a few places in the Linux kernel. Verify that a warning
135 is issued for it when it writes past the end of the array object. */
136 memset (&b[0].a.b, 0, offsetfrom (struct B, b, a.b) + 1); /* { dg-warning "writing 8 bytes into a region of size 7" "memcpy into allocated" { xfail *-*-*} } */
137 escape (b);
139 memset (&b->a.b, 0, offsetfrom (struct B, b, a.b) + 1); /* { dg-warning "writing 8 bytes into a region of size 7" "memcpy into allocated" { xfail *-*-*} } */
140 escape (b);
142 memset (&b[0].c, 0, offsetfrom (struct B, b, c) + 1); /* { dg-warning "writing 7 bytes into a region of size 6" "memcpy into allocated" { xfail *-*-*} } */
143 escape (b);
145 memset (&b->c, 0, offsetfrom (struct B, b, c) + 1); /* { dg-warning "writing 7 bytes into a region of size 6" "memcpy into allocated" { xfail *-*-*} } */
146 escape (b);
148 memset (&b[0].d, 0, offsetfrom (struct B, b, d) + 1); /* { dg-warning "writing 6 bytes into a region of size 5" "memcpy into allocated" { xfail *-*-*} } */
149 escape (b);
151 memset (&b->d, 0, offsetfrom (struct B, b, d) + 1); /* { dg-warning "writing 6 bytes into a region of size 5" "memcpy into allocated" { xfail *-*-*} } */
152 escape (b);
154 /* Same as above but clearing just elements of the second element
155 of the array. */
156 memset (&b[1].a.b, 0, offsetfrom (struct B, b[1], a.b) + 1); /* { dg-warning "writing 4 bytes into a region of size 3" "memcpy into allocated" { xfail *-*-*} } */
157 escape (b);
159 memset (&b[1].c, 0, offsetfrom (struct B, b[1], c) + 1); /* { dg-warning "writing 3 bytes into a region of size 2" "memcpy into allocated" { xfail *-*-*} } */
160 escape (b);
162 memset (&b[1].d, 0, offsetfrom (struct B, b[1], d) + 1); /* { dg-warning "writing 2 bytes into a region of size 1" "memcpy into allocated" { xfail *-*-*} } */
163 escape (b);
167 void test_memop_nowarn (const void *src)
169 struct B b[2];
171 size_t n = range (sizeof b, 32);
173 /* Verify that clearing the whole array is not diagnosed regardless
174 of whether the expression pointing to its beginning is obtained
175 from the array itself or its first member(s). */
176 memcpy (b, src, n);
177 escape (b);
179 memcpy (&b[0], src, n);
180 escape (b);
182 memcpy (&b[0].a, src, n);
183 escape (b, src);
185 memcpy (&b[0].a.a, src, n);
186 escape (b, src);
188 /* Clearing multiple elements of an array of structs. */
189 memset (&b[0].a.b, 0, sizeof b - offsetof (struct B, a.b));
190 escape (b);
192 memset (&b->a.b, 0, sizeof b - offsetof (struct B, a.b));
193 escape (b);
195 memset (&b[0].c, 0, sizeof b - offsetof (struct B, c));
196 escape (b);
198 memset (&b->c, 0, sizeof b - offsetof (struct B, c));
199 escape (b);
201 memset (&b[0].d, 0, sizeof b - offsetof (struct B, d));
202 escape (b);
204 memset (&b->d, 0, sizeof b - offsetof (struct B, d));
205 escape (b);
207 /* Same as above but clearing just elements of the second element
208 of the array. */
209 memset (&b[1].a.b, 0, sizeof b[1] - offsetof (struct B, a.b));
210 escape (b);
212 memset (&b[1].c, 0, sizeof b[1] - offsetof (struct B, c));
213 escape (b);
215 memset (&b[1].d, 0, sizeof b[1] - offsetof (struct B, d));
216 escape (b);
220 /* The foollowing function could specify in its API that it takes
221 an array of exactly two elements, as shown below. Verify that
222 writing into both elements is not diagnosed. */
223 void test_memop_nowarn_arg (struct A[2], const void*);
225 void test_memop_nowarn_arg (struct A *a, const void *src)
227 memcpy (a, src, 2 * sizeof *a);
228 escape (a, src);
230 memcpy (a, src, range (2 * sizeof *a, 123));
231 escape (a, src);
235 struct C { char a[3], b; };
236 struct D { struct C c; char d, e; };
238 extern char* strncpy (char*, const char*, __SIZE_TYPE__);
240 void test_stringop_warn (void)
242 size_t n = range (2 * sizeof (struct D) + 1, 33);
244 struct C c[2];
246 /* Similarly, at -Wstringop-overflow=1 the destination is considered
247 to be the whole array and its size is therefore sizeof c. */
248 strncpy (c[0].a, "123", n); /* { dg-warning "writing between 13 and 33 bytes into a region of size 8 overflows the destination" } */
250 escape (c);
254 void test_stringop_nowarn (void)
256 struct D d[2];
258 strncpy (d[0].c.a, "123", range (sizeof d, 32));
259 escape (d);