111
|
1 /* Test exercising -Wstringop-overflow warnings for reading past the end. */
|
|
2 /* { dg-do compile } */
|
|
3 /* { dg-options "-O2 -Wstringop-overflow=1 -ftrack-macro-expansion=0" } */
|
|
4
|
|
5 #define PTRDIFF_MAX __PTRDIFF_MAX__
|
|
6 #define SIZE_MAX __SIZE_MAX__
|
|
7
|
|
8 #define offsetof(type, mem) __builtin_offsetof (type, mem)
|
|
9
|
|
10 /* Return the number of bytes from member MEM of TYPE to the end
|
|
11 of object OBJ. */
|
|
12 #define offsetfrom(type, obj, mem) (sizeof (obj) - offsetof (type, mem))
|
|
13
|
|
14
|
|
15 typedef __SIZE_TYPE__ size_t;
|
|
16 extern void* memchr (const void*, int, size_t);
|
|
17 extern int memcmp (const void*, const void*, size_t);
|
|
18 extern void* memcpy (void*, const void*, size_t);
|
|
19 extern void* memmove (void*, const void*, size_t);
|
|
20 extern void* mempcpy (void*, const void*, size_t);
|
|
21
|
|
22 #define memchr(d, s, n) sink (memchr (d, s, n))
|
|
23 #define memcmp(d, s, n) sink (d, memcmp (d, s, n))
|
|
24 #define memcpy(d, s, n) sink (memcpy (d, s, n))
|
|
25 #define memmove(d, s, n) sink (memmove (d, s, n))
|
|
26 #define mempcpy(d, s, n) sink (mempcpy (d, s, n))
|
|
27
|
|
28 struct A { char a, b; };
|
|
29 struct B { struct A a; char c, d; };
|
|
30
|
|
31 /* Function to call to "escape" pointers from tests below to prevent
|
|
32 GCC from assuming the values of the objects they point to stay
|
|
33 the unchanged. */
|
|
34 void sink (void*, ...);
|
|
35
|
|
36 /* Function to "generate" a random number each time it's called. Declared
|
|
37 (but not defined) and used to prevent GCC from making assumptions about
|
|
38 their values based on the variables uses in the tested expressions. */
|
|
39 size_t random_unsigned_value (void);
|
|
40
|
|
41 /* Return a random unsigned value between MIN and MAX. */
|
|
42
|
|
43 static inline size_t
|
|
44 range (size_t min, size_t max)
|
|
45 {
|
|
46 const size_t val = random_unsigned_value ();
|
|
47 return val < min || max < val ? min : val;
|
|
48 }
|
|
49
|
|
50 #define R(min, max) range (min, max)
|
|
51
|
|
52 /* Verify that reading beyond the end of a local array is diagnosed. */
|
|
53
|
|
54 void test_memop_warn_local (void *p, const void *q)
|
|
55 {
|
|
56 memcpy (p, "1234", R (6, 7)); /* { dg-warning "reading between 6 and 7 bytes from a region of size 5" } */
|
|
57
|
|
58 struct A a[2];
|
|
59
|
|
60 memcpy (p, a, R (7, 8)); /* { dg-warning "reading between 7 and 8 bytes from a region of size 4" } */
|
|
61
|
|
62 /* At -Wstringop-overflow=1 the destination is considered to be
|
|
63 the whole array and its size is therefore sizeof a. */
|
|
64 memcpy (p, &a[0], R (8, 9)); /* { dg-warning "reading between 8 and 9 bytes from a region of size 4" } */
|
|
65
|
|
66 /* Verify the same as above but by reading from the first mmeber
|
|
67 of the first element of the array. */
|
|
68 memcpy (p, &a[0].a, R (8, 9)); /* { dg-warning "reading between 8 and 9 bytes from a region of size 4" } */
|
|
69
|
|
70 struct B b[2];
|
|
71
|
|
72 memcpy (p, &b[0], R (12, 32)); /* { dg-warning "reading between 12 and 32 bytes from a region of size 8" } */
|
|
73
|
|
74 /* Verify memchr/memcmp. */
|
|
75 int i = R (0, 255);
|
|
76 memchr ("", i, 2); /* { dg-warning "reading 2 bytes from a region of size 1" } */
|
|
77 memchr ("", i, 2); /* { dg-warning "reading 2 bytes from a region of size 1" } */
|
|
78 memchr ("123", i, 5); /* { dg-warning "reading 5 bytes from a region of size 4" } */
|
|
79 memchr (a, i, sizeof a + 1); /* { dg-warning "reading 5 bytes from a region of size 4" } */
|
|
80
|
|
81 memcmp (p, "", 2); /* { dg-warning "reading 2 bytes from a region of size 1" } */
|
|
82 memcmp (p, "123", 5); /* { dg-warning "reading 5 bytes from a region of size 4" } */
|
|
83 memcmp (p, a, sizeof a + 1); /* { dg-warning "reading 5 bytes from a region of size 4" } */
|
|
84
|
|
85 size_t n = PTRDIFF_MAX + (size_t)1;
|
|
86 memchr (p, 1, n); /* { dg-warning "exceeds maximum object size" } */
|
|
87 memcmp (p, q, n); /* { dg-warning "exceeds maximum object size" } */
|
|
88
|
|
89 n = SIZE_MAX;
|
|
90 memchr (p, 1, n); /* { dg-warning "exceeds maximum object size" } */
|
|
91 memcmp (p, q, n); /* { dg-warning "exceeds maximum object size" } */
|
|
92 }
|
|
93
|
|
94 /* Verify that reading beyond the end of a dynamically allocated array
|
|
95 of known size is diagnosed. */
|
|
96
|
|
97 void test_memop_warn_alloc (void *p)
|
|
98 {
|
|
99 size_t n;
|
|
100
|
|
101 n = range (8, 32);
|
|
102
|
|
103 struct A *a = __builtin_malloc (sizeof *a * 2);
|
|
104
|
|
105 memcpy (p, a, n); /* { dg-warning "reading between 8 and 32 bytes from region of size 4" "memcpy from allocated" { xfail *-*-*} } */
|
|
106
|
|
107 memcpy (p, &a[0], n); /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" { xfail *-*-*} } */
|
|
108
|
|
109 memcpy (p, &a[0].a, n); /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" { xfail *-*-*} } */
|
|
110
|
|
111 n = range (12, 32);
|
|
112
|
|
113 struct B *b = __builtin_malloc (sizeof *b * 2);
|
|
114
|
|
115 memcpy (p, &b[0], n); /* { dg-warning "reading between 12 and 32 bytes from a region of size 8" "memcpy from allocated" { xfail *-*-*} } */
|
|
116
|
|
117 /* Verify memchr/memcmp. */
|
|
118 n = sizeof *b * 2 + 1;
|
|
119
|
|
120 memchr (b, 1, n); /* { dg-warning "reading 5 bytes from a region of size 4" "memcmp from allocated" { xfail *-*-* } } */
|
|
121 memcmp (p, b, n); /* { dg-warning "reading 5 bytes from a region of size 4" "memcmp from allocated" { xfail *-*-* } } */
|
|
122 }
|
|
123
|
|
124
|
|
125 void test_memop_nowarn (void *p)
|
|
126 {
|
|
127 struct B b[2];
|
|
128
|
|
129 size_t n = range (sizeof b, 32);
|
|
130
|
|
131 /* Verify that copying the whole array is not diagnosed regardless
|
|
132 of whether the expression pointing to its beginning is obtained
|
|
133 from the array itself or its first member(s). */
|
|
134 memcpy (p, b, n);
|
|
135
|
|
136 memcpy (p, &b[0], n);
|
|
137
|
|
138 memcpy (p, &b[0].a, n);
|
|
139
|
|
140 memcpy (p, &b[0].a.a, n);
|
|
141
|
|
142 /* Verify that memchr/memcmp doesn't cause a warning. */
|
|
143 memchr (p, 1, n);
|
|
144 memchr (b, 2, n);
|
|
145 memchr (&b[0], 3, n);
|
|
146 memchr (&b[0].a, 4, n);
|
|
147 memchr (&b[0].a.a, 5, n);
|
|
148 memchr ("01234567", R (0, 255), n);
|
|
149
|
|
150 memcmp (p, p, n);
|
|
151 memcmp (p, b, n);
|
|
152 memcmp (p, &b[0], n);
|
|
153 memcmp (p, &b[0].a, n);
|
|
154 memcmp (p, &b[0].a.a, n);
|
|
155 memcmp (p, "01234567", n);
|
|
156 }
|
|
157
|
|
158
|
|
159 /* The following function could specify in its API that it takes
|
|
160 an array of exactly two elements, as shown below (or simply be
|
|
161 called with such an array). Verify that reading from both
|
|
162 elements is not diagnosed. */
|
|
163 void test_memop_nowarn_arg (void*, const struct A[2]);
|
|
164
|
|
165 void test_memop_nowarn_arg (void *p, const struct A *a)
|
|
166 {
|
|
167 memcpy (p, a, 2 * sizeof *a);
|
|
168
|
|
169 memcpy (p, a, range (2 * sizeof *a, 123));
|
|
170
|
|
171 memchr (p, 1, 1234);
|
|
172 memcmp (p, a, 1234);
|
|
173 }
|