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
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
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. */
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
)
49 memcpy (a
, src
, n
); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" } */
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" } */
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" } */
66 memcpy (&b
[0], src
, n
); /* { dg-warning "writing between 12 and 32 bytes into a region of size 8 overflows the destination" } */
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" } */
75 memset (&b
->a
.b
, 0, offsetfrom (struct B
, b
, a
.b
) + 1); /* { dg-warning "writing 8 bytes into a region of size 7" } */
78 memset (&b
[0].c
, 0, offsetfrom (struct B
, b
, c
) + 1); /* { dg-warning "writing 7 bytes into a region of size 6" } */
81 memset (&b
->c
, 0, offsetfrom (struct B
, b
, c
) + 1); /* { dg-warning "writing 7 bytes into a region of size 6" } */
84 memset (&b
[0].d
, 0, offsetfrom (struct B
, b
, d
) + 1); /* { dg-warning "writing 6 bytes into a region of size 5" } */
87 memset (&b
->d
, 0, offsetfrom (struct B
, b
, d
) + 1); /* { dg-warning "writing 6 bytes into a region of size 5" } */
90 /* Same as above but clearing just elements of the second element
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" } */
95 memset (&b
[1].c
, 0, offsetfrom (struct B
, b
[1], c
) + 1); /* { dg-warning "writing 3 bytes into a region of size 2" } */
98 memset (&b
[1].d
, 0, offsetfrom (struct B
, b
[1], d
) + 1); /* { dg-warning "writing 2 bytes into a region of size 1" } */
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
)
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 *-*-*} } */
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 *-*-*} } */
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 *-*-*} } */
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 *-*-*} } */
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 *-*-*} } */
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 *-*-*} } */
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 *-*-*} } */
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 *-*-*} } */
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 *-*-*} } */
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 *-*-*} } */
154 /* Same as above but clearing just elements of the second element
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 *-*-*} } */
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 *-*-*} } */
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 *-*-*} } */
167 void test_memop_nowarn (const void *src
)
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). */
179 memcpy (&b
[0], src
, n
);
182 memcpy (&b
[0].a
, src
, n
);
185 memcpy (&b
[0].a
.a
, src
, n
);
188 /* Clearing multiple elements of an array of structs. */
189 memset (&b
[0].a
.b
, 0, sizeof b
- offsetof (struct B
, a
.b
));
192 memset (&b
->a
.b
, 0, sizeof b
- offsetof (struct B
, a
.b
));
195 memset (&b
[0].c
, 0, sizeof b
- offsetof (struct B
, c
));
198 memset (&b
->c
, 0, sizeof b
- offsetof (struct B
, c
));
201 memset (&b
[0].d
, 0, sizeof b
- offsetof (struct B
, d
));
204 memset (&b
->d
, 0, sizeof b
- offsetof (struct B
, d
));
207 /* Same as above but clearing just elements of the second element
209 memset (&b
[1].a
.b
, 0, sizeof b
[1] - offsetof (struct B
, a
.b
));
212 memset (&b
[1].c
, 0, sizeof b
[1] - offsetof (struct B
, c
));
215 memset (&b
[1].d
, 0, sizeof b
[1] - offsetof (struct B
, d
));
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
);
230 memcpy (a
, src
, range (2 * sizeof *a
, 123));
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);
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" } */
254 void test_stringop_nowarn (void)
258 strncpy (d
[0].c
.a
, "123", range (sizeof d
, 32));