1 /* Test exercising -Wstringop-overread warnings for reading past the end. */
2 /* { dg-do compile } */
3 /* { dg-options "-O2 -Wstringop-overread -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 "specified bound 2 exceeds source size 1" "memchr" } */
77 memchr ("", i, 2); /* { dg-warning "specified bound 2 exceeds source size 1" "memchr" } */
78 memchr ("123", i, 5); /* { dg-warning "specified bound 5 exceeds source size 4" "memchr" } */
79 memchr (a, i, sizeof a + 1); /* { dg-warning "specified bound 5 exceeds source size 4" "memchr" } */
80
81 memcmp (p, "", 2); /* { dg-warning "specified bound 2 exceeds source size 1" "memcmp" } */
82 memcmp (p, "123", 5); /* { dg-warning "specified bound 5 exceeds source size 4" "memcmp" } */
83 memcmp (p, a, sizeof a + 1); /* { dg-warning "specified bound 5 exceeds source size 4" "memcmp" } */
84
85 size_t n = PTRDIFF_MAX + (size_t)1;
86 memchr (p, 1, n); /* { dg-warning "exceeds maximum object size" "memchr" } */
87 memcmp (p, q, n); /* { dg-warning "exceeds maximum object size" "memcmp" } */
88
89 n = SIZE_MAX;
90 memchr (p, 1, n); /* { dg-warning "exceeds maximum object size" "memchr" } */
91 memcmp (p, q, n); /* { dg-warning "exceeds maximum object size" "memcmp" } */
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 a region of size 4" "memcpy from allocated" } */
106
107 memcpy (p, &a[0], n); /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" } */
108
109 memcpy (p, &a[0].a, n); /* { dg-warning "reading between 8 and 32 bytes from a region of size " "memcpy from allocated" } */
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" } */
116
117 /* Verify memchr/memcmp. */
118 n = sizeof *b * 2 + 1;
119
120 memchr (b, 1, n); /* { dg-warning "specified bound 9 exceeds source size 8" "memchr from allocated" } */
121 memcmp (p, b, n); /* { dg-warning "specified bound 9 exceeds source size 8" "memcmp from allocated" } */
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 }