]>
Commit | Line | Data |
---|---|---|
ee92e7ba MS |
1 | /* Test exercising -Wrawmem-overflow and -Wstringop-overflow warnings. */ |
2 | /* { dg-do compile } */ | |
3 | /* { dg-options "-O2 -Wstringop-overflow=2" } */ | |
4 | ||
5 | #define offsetof(type, mem) __builtin_offsetof (type, mem) | |
6 | ||
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)) | |
10 | ||
11 | ||
12 | typedef __SIZE_TYPE__ size_t; | |
13 | extern void* memcpy (void*, const void*, size_t); | |
14 | extern void* memset (void*, int, __SIZE_TYPE__); | |
15 | ||
16 | ||
17 | struct A { char a, b; }; | |
18 | struct B { struct A a; char c, d; }; | |
19 | ||
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*, ...); | |
24 | ||
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); | |
29 | ||
30 | /* Return a random unsigned value between MIN and MAX. */ | |
31 | ||
32 | static inline size_t | |
33 | range (size_t min, size_t max) | |
34 | { | |
35 | const size_t val = random_unsigned_value (); | |
36 | return val < min || max < val ? min : val; | |
37 | } | |
38 | ||
39 | ||
40 | void test_memop_warn_object (const void *src) | |
41 | { | |
42 | unsigned n = range (17, 29); | |
43 | ||
44 | struct A a[2]; | |
45 | ||
46 | /* At both -Wstringop-overflow=2, like at 1, the destination of functions | |
47 | that operate on raw memory is considered to be the whole array and its | |
48 | size is therefore sizeof a. */ | |
49 | memcpy (&a[0], src, n); /* { dg-warning "writing between 17 and 29 bytes into a region of size 4 overflows the destination" } */ | |
50 | escape (a); | |
51 | } | |
52 | ||
53 | void test_memop_warn_subobject (const void *src) | |
54 | { | |
55 | unsigned n = range (17, 31); | |
56 | ||
57 | struct B b[2]; | |
58 | ||
59 | /* At -Wrawmem-overflow=2 the destination is considered to be | |
60 | the member sobobject of the first array element and its size | |
61 | is therefore sizeof b[0].a. */ | |
62 | memcpy (&b[0].a, src, n); /* { dg-warning "writing between 17 and 31 bytes into a region of size 8 overflows the destination" } */ | |
63 | ||
64 | escape (b); | |
65 | } | |
66 | ||
67 | void test_memop_nowarn_subobject (void) | |
68 | { | |
69 | struct B b[2]; | |
70 | ||
71 | /* The following idiom of clearing multiple members of a struct | |
72 | has been seen in a few places in the Linux kernel. Verify | |
73 | that a warning is not issued for it. */ | |
74 | memset (&b[0].c, 0, sizeof b[0] - offsetof (struct B, c)); | |
75 | ||
76 | escape (b); | |
77 | } | |
78 | ||
79 | struct C { char a[3], b; }; | |
80 | struct D { struct C c; char d, e; }; | |
81 | ||
82 | extern char* strncpy (char*, const char*, __SIZE_TYPE__); | |
83 | ||
84 | void test_stringop_warn_object (const char *str) | |
85 | { | |
86 | unsigned n = range (2 * sizeof (struct D), 32); | |
87 | ||
88 | struct C c[2]; | |
89 | ||
90 | /* Similarly, at -Wstringop-overflow=2 the destination is considered | |
91 | to be the array member of the first element of the array c and its | |
92 | size is therefore sizeof c[0].a. */ | |
93 | strncpy (c[0].a, "123", n); /* { dg-warning "writing between 12 and 32 bytes into a region of size 3 overflows the destination" } */ | |
94 | escape (c); | |
95 | ||
96 | strncpy (c[0].a, str, n); /* { dg-warning "writing between 12 and 32 bytes into a region of size 3 overflows the destination" } */ | |
97 | escape (c); | |
98 | } | |
99 | ||
100 | void test_stringop_warn_subobject (const char *src) | |
101 | { | |
102 | unsigned n = range (2 * sizeof (struct D), 32); | |
103 | ||
104 | struct D d[2]; | |
105 | ||
106 | /* Same as above. */ | |
107 | strncpy (d[0].c.a, "123", n); /* { dg-warning "writing between 12 and 32 bytes into a region of size 3 overflows the destination" } */ | |
108 | escape (d); | |
109 | ||
110 | strncpy (d[0].c.a, src, n); /* { dg-warning "writing between 12 and 32 bytes into a region of size 3 overflows the destination" } */ | |
111 | escape (d); | |
112 | } |