1 | // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm %s -o - 2>&1 | FileCheck %s |
2 | // RUN: %clang_cc1 -DDYNAMIC -triple x86_64-apple-darwin -emit-llvm %s -o - 2>&1 | FileCheck %s |
3 | |
4 | #ifdef DYNAMIC |
5 | #define OBJECT_SIZE_BUILTIN __builtin_dynamic_object_size |
6 | #else |
7 | #define OBJECT_SIZE_BUILTIN __builtin_object_size |
8 | #endif |
9 | |
10 | #define NULL ((void *)0) |
11 | |
12 | int gi; |
13 | |
14 | typedef unsigned long size_t; |
15 | |
16 | // CHECK-DAG-RE: define void @my_malloc({{.*}}) #[[MALLOC_ATTR_NUMBER:[0-9]+]] |
17 | // N.B. LLVM's allocsize arguments are base-0, whereas ours are base-1 (for |
18 | // compat with GCC) |
19 | // CHECK-DAG-RE: attributes #[[MALLOC_ATTR_NUMBER]] = {.*allocsize(0).*} |
20 | void *my_malloc(size_t) __attribute__((alloc_size(1))); |
21 | |
22 | // CHECK-DAG-RE: define void @my_calloc({{.*}}) #[[CALLOC_ATTR_NUMBER:[0-9]+]] |
23 | // CHECK-DAG-RE: attributes #[[CALLOC_ATTR_NUMBER]] = {.*allocsize(0, 1).*} |
24 | void *my_calloc(size_t, size_t) __attribute__((alloc_size(1, 2))); |
25 | |
26 | // CHECK-LABEL: @test1 |
27 | void test1() { |
28 | void *const vp = my_malloc(100); |
29 | // CHECK: store i32 100 |
30 | gi = OBJECT_SIZE_BUILTIN(vp, 0); |
31 | // CHECK: store i32 100 |
32 | gi = OBJECT_SIZE_BUILTIN(vp, 1); |
33 | // CHECK: store i32 100 |
34 | gi = OBJECT_SIZE_BUILTIN(vp, 2); |
35 | // CHECK: store i32 100 |
36 | gi = OBJECT_SIZE_BUILTIN(vp, 3); |
37 | |
38 | void *const arr = my_calloc(100, 5); |
39 | // CHECK: store i32 500 |
40 | gi = OBJECT_SIZE_BUILTIN(arr, 0); |
41 | // CHECK: store i32 500 |
42 | gi = OBJECT_SIZE_BUILTIN(arr, 1); |
43 | // CHECK: store i32 500 |
44 | gi = OBJECT_SIZE_BUILTIN(arr, 2); |
45 | // CHECK: store i32 500 |
46 | gi = OBJECT_SIZE_BUILTIN(arr, 3); |
47 | |
48 | // CHECK: store i32 100 |
49 | gi = OBJECT_SIZE_BUILTIN(my_malloc(100), 0); |
50 | // CHECK: store i32 100 |
51 | gi = OBJECT_SIZE_BUILTIN(my_malloc(100), 1); |
52 | // CHECK: store i32 100 |
53 | gi = OBJECT_SIZE_BUILTIN(my_malloc(100), 2); |
54 | // CHECK: store i32 100 |
55 | gi = OBJECT_SIZE_BUILTIN(my_malloc(100), 3); |
56 | |
57 | // CHECK: store i32 500 |
58 | gi = OBJECT_SIZE_BUILTIN(my_calloc(100, 5), 0); |
59 | // CHECK: store i32 500 |
60 | gi = OBJECT_SIZE_BUILTIN(my_calloc(100, 5), 1); |
61 | // CHECK: store i32 500 |
62 | gi = OBJECT_SIZE_BUILTIN(my_calloc(100, 5), 2); |
63 | // CHECK: store i32 500 |
64 | gi = OBJECT_SIZE_BUILTIN(my_calloc(100, 5), 3); |
65 | |
66 | void *const zeroPtr = my_malloc(0); |
67 | // CHECK: store i32 0 |
68 | gi = OBJECT_SIZE_BUILTIN(zeroPtr, 0); |
69 | // CHECK: store i32 0 |
70 | gi = OBJECT_SIZE_BUILTIN(my_malloc(0), 0); |
71 | |
72 | void *const zeroArr1 = my_calloc(0, 1); |
73 | void *const zeroArr2 = my_calloc(1, 0); |
74 | // CHECK: store i32 0 |
75 | gi = OBJECT_SIZE_BUILTIN(zeroArr1, 0); |
76 | // CHECK: store i32 0 |
77 | gi = OBJECT_SIZE_BUILTIN(zeroArr2, 0); |
78 | // CHECK: store i32 0 |
79 | gi = OBJECT_SIZE_BUILTIN(my_calloc(1, 0), 0); |
80 | // CHECK: store i32 0 |
81 | gi = OBJECT_SIZE_BUILTIN(my_calloc(0, 1), 0); |
82 | } |
83 | |
84 | // CHECK-LABEL: @test2 |
85 | void test2() { |
86 | void *const vp = my_malloc(gi); |
87 | // CHECK: @llvm.objectsize |
88 | gi = OBJECT_SIZE_BUILTIN(vp, 0); |
89 | |
90 | void *const arr1 = my_calloc(gi, 1); |
91 | // CHECK: @llvm.objectsize |
92 | gi = OBJECT_SIZE_BUILTIN(arr1, 0); |
93 | |
94 | void *const arr2 = my_calloc(1, gi); |
95 | // CHECK: @llvm.objectsize |
96 | gi = OBJECT_SIZE_BUILTIN(arr2, 0); |
97 | } |
98 | |
99 | // CHECK-LABEL: @test3 |
100 | void test3() { |
101 | char *const buf = (char *)my_calloc(100, 5); |
102 | // CHECK: store i32 500 |
103 | gi = OBJECT_SIZE_BUILTIN(buf, 0); |
104 | // CHECK: store i32 500 |
105 | gi = OBJECT_SIZE_BUILTIN(buf, 1); |
106 | // CHECK: store i32 500 |
107 | gi = OBJECT_SIZE_BUILTIN(buf, 2); |
108 | // CHECK: store i32 500 |
109 | gi = OBJECT_SIZE_BUILTIN(buf, 3); |
110 | } |
111 | |
112 | struct Data { |
113 | int a; |
114 | int t[10]; |
115 | char pad[3]; |
116 | char end[1]; |
117 | }; |
118 | |
119 | // CHECK-LABEL: @test5 |
120 | void test5() { |
121 | struct Data *const data = my_malloc(sizeof(*data)); |
122 | // CHECK: store i32 48 |
123 | gi = OBJECT_SIZE_BUILTIN(data, 0); |
124 | // CHECK: store i32 48 |
125 | gi = OBJECT_SIZE_BUILTIN(data, 1); |
126 | // CHECK: store i32 48 |
127 | gi = OBJECT_SIZE_BUILTIN(data, 2); |
128 | // CHECK: store i32 48 |
129 | gi = OBJECT_SIZE_BUILTIN(data, 3); |
130 | |
131 | // CHECK: store i32 40 |
132 | gi = OBJECT_SIZE_BUILTIN(&data->t[1], 0); |
133 | // CHECK: store i32 36 |
134 | gi = OBJECT_SIZE_BUILTIN(&data->t[1], 1); |
135 | // CHECK: store i32 40 |
136 | gi = OBJECT_SIZE_BUILTIN(&data->t[1], 2); |
137 | // CHECK: store i32 36 |
138 | gi = OBJECT_SIZE_BUILTIN(&data->t[1], 3); |
139 | |
140 | struct Data *const arr = my_calloc(sizeof(*data), 2); |
141 | // CHECK: store i32 96 |
142 | gi = OBJECT_SIZE_BUILTIN(arr, 0); |
143 | // CHECK: store i32 96 |
144 | gi = OBJECT_SIZE_BUILTIN(arr, 1); |
145 | // CHECK: store i32 96 |
146 | gi = OBJECT_SIZE_BUILTIN(arr, 2); |
147 | // CHECK: store i32 96 |
148 | gi = OBJECT_SIZE_BUILTIN(arr, 3); |
149 | |
150 | // CHECK: store i32 88 |
151 | gi = OBJECT_SIZE_BUILTIN(&arr->t[1], 0); |
152 | // CHECK: store i32 36 |
153 | gi = OBJECT_SIZE_BUILTIN(&arr->t[1], 1); |
154 | // CHECK: store i32 88 |
155 | gi = OBJECT_SIZE_BUILTIN(&arr->t[1], 2); |
156 | // CHECK: store i32 36 |
157 | gi = OBJECT_SIZE_BUILTIN(&arr->t[1], 3); |
158 | } |
159 | |
160 | // CHECK-LABEL: @test6 |
161 | void test6() { |
162 | // Things that would normally trigger conservative estimates don't need to do |
163 | // so when we know the source of the allocation. |
164 | struct Data *const data = my_malloc(sizeof(*data) + 10); |
165 | // CHECK: store i32 11 |
166 | gi = OBJECT_SIZE_BUILTIN(data->end, 0); |
167 | // CHECK: store i32 11 |
168 | gi = OBJECT_SIZE_BUILTIN(data->end, 1); |
169 | // CHECK: store i32 11 |
170 | gi = OBJECT_SIZE_BUILTIN(data->end, 2); |
171 | // CHECK: store i32 11 |
172 | gi = OBJECT_SIZE_BUILTIN(data->end, 3); |
173 | |
174 | struct Data *const arr = my_calloc(sizeof(*arr) + 5, 3); |
175 | // AFAICT, GCC treats malloc and calloc identically. So, we should do the |
176 | // same. |
177 | // |
178 | // Additionally, GCC ignores the initial array index when determining whether |
179 | // we're writing off the end of an alloc_size base. e.g. |
180 | // arr[0].end |
181 | // arr[1].end |
182 | // arr[2].end |
183 | // ...Are all considered "writing off the end", because there's no way to tell |
184 | // with high accuracy if the user meant "allocate a single N-byte `Data`", |
185 | // or "allocate M smaller `Data`s with extra padding". |
186 | |
187 | // CHECK: store i32 112 |
188 | gi = OBJECT_SIZE_BUILTIN(arr->end, 0); |
189 | // CHECK: store i32 112 |
190 | gi = OBJECT_SIZE_BUILTIN(arr->end, 1); |
191 | // CHECK: store i32 112 |
192 | gi = OBJECT_SIZE_BUILTIN(arr->end, 2); |
193 | // CHECK: store i32 112 |
194 | gi = OBJECT_SIZE_BUILTIN(arr->end, 3); |
195 | |
196 | // CHECK: store i32 112 |
197 | gi = OBJECT_SIZE_BUILTIN(arr[0].end, 0); |
198 | // CHECK: store i32 112 |
199 | gi = OBJECT_SIZE_BUILTIN(arr[0].end, 1); |
200 | // CHECK: store i32 112 |
201 | gi = OBJECT_SIZE_BUILTIN(arr[0].end, 2); |
202 | // CHECK: store i32 112 |
203 | gi = OBJECT_SIZE_BUILTIN(arr[0].end, 3); |
204 | |
205 | // CHECK: store i32 64 |
206 | gi = OBJECT_SIZE_BUILTIN(arr[1].end, 0); |
207 | // CHECK: store i32 64 |
208 | gi = OBJECT_SIZE_BUILTIN(arr[1].end, 1); |
209 | // CHECK: store i32 64 |
210 | gi = OBJECT_SIZE_BUILTIN(arr[1].end, 2); |
211 | // CHECK: store i32 64 |
212 | gi = OBJECT_SIZE_BUILTIN(arr[1].end, 3); |
213 | |
214 | // CHECK: store i32 16 |
215 | gi = OBJECT_SIZE_BUILTIN(arr[2].end, 0); |
216 | // CHECK: store i32 16 |
217 | gi = OBJECT_SIZE_BUILTIN(arr[2].end, 1); |
218 | // CHECK: store i32 16 |
219 | gi = OBJECT_SIZE_BUILTIN(arr[2].end, 2); |
220 | // CHECK: store i32 16 |
221 | gi = OBJECT_SIZE_BUILTIN(arr[2].end, 3); |
222 | } |
223 | |
224 | // CHECK-LABEL: @test7 |
225 | void test7() { |
226 | struct Data *const data = my_malloc(sizeof(*data) + 5); |
227 | // CHECK: store i32 9 |
228 | gi = OBJECT_SIZE_BUILTIN(data->pad, 0); |
229 | // CHECK: store i32 3 |
230 | gi = OBJECT_SIZE_BUILTIN(data->pad, 1); |
231 | // CHECK: store i32 9 |
232 | gi = OBJECT_SIZE_BUILTIN(data->pad, 2); |
233 | // CHECK: store i32 3 |
234 | gi = OBJECT_SIZE_BUILTIN(data->pad, 3); |
235 | } |
236 | |
237 | // CHECK-LABEL: @test8 |
238 | void test8() { |
239 | // Non-const pointers aren't currently supported. |
240 | void *buf = my_calloc(100, 5); |
241 | // CHECK: @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false, i1 true, i1 |
242 | gi = OBJECT_SIZE_BUILTIN(buf, 0); |
243 | // CHECK: @llvm.objectsize |
244 | gi = OBJECT_SIZE_BUILTIN(buf, 1); |
245 | // CHECK: @llvm.objectsize |
246 | gi = OBJECT_SIZE_BUILTIN(buf, 2); |
247 | // CHECK: store i32 0 |
248 | gi = OBJECT_SIZE_BUILTIN(buf, 3); |
249 | } |
250 | |
251 | // CHECK-LABEL: @test9 |
252 | void test9() { |
253 | // Check to be sure that we unwrap things correctly. |
254 | short *const buf0 = (my_malloc(100)); |
255 | short *const buf1 = (short*)(my_malloc(100)); |
256 | short *const buf2 = ((short*)(my_malloc(100))); |
257 | |
258 | // CHECK: store i32 100 |
259 | gi = OBJECT_SIZE_BUILTIN(buf0, 0); |
260 | // CHECK: store i32 100 |
261 | gi = OBJECT_SIZE_BUILTIN(buf1, 0); |
262 | // CHECK: store i32 100 |
263 | gi = OBJECT_SIZE_BUILTIN(buf2, 0); |
264 | } |
265 | |
266 | // CHECK-LABEL: @test10 |
267 | void test10() { |
268 | // Yay overflow |
269 | short *const arr = my_calloc((size_t)-1 / 2 + 1, 2); |
270 | // CHECK: @llvm.objectsize |
271 | gi = OBJECT_SIZE_BUILTIN(arr, 0); |
272 | // CHECK: @llvm.objectsize |
273 | gi = OBJECT_SIZE_BUILTIN(arr, 1); |
274 | // CHECK: @llvm.objectsize |
275 | gi = OBJECT_SIZE_BUILTIN(arr, 2); |
276 | // CHECK: store i32 0 |
277 | gi = OBJECT_SIZE_BUILTIN(arr, 3); |
278 | |
279 | // As an implementation detail, CharUnits can't handle numbers greater than or |
280 | // equal to 2**63. Realistically, this shouldn't be a problem, but we should |
281 | // be sure we don't emit crazy results for this case. |
282 | short *const buf = my_malloc((size_t)-1); |
283 | // CHECK: @llvm.objectsize |
284 | gi = OBJECT_SIZE_BUILTIN(buf, 0); |
285 | // CHECK: @llvm.objectsize |
286 | gi = OBJECT_SIZE_BUILTIN(buf, 1); |
287 | // CHECK: @llvm.objectsize |
288 | gi = OBJECT_SIZE_BUILTIN(buf, 2); |
289 | // CHECK: store i32 0 |
290 | gi = OBJECT_SIZE_BUILTIN(buf, 3); |
291 | |
292 | short *const arr_big = my_calloc((size_t)-1 / 2 - 1, 2); |
293 | // CHECK: @llvm.objectsize |
294 | gi = OBJECT_SIZE_BUILTIN(arr_big, 0); |
295 | // CHECK: @llvm.objectsize |
296 | gi = OBJECT_SIZE_BUILTIN(arr_big, 1); |
297 | // CHECK: @llvm.objectsize |
298 | gi = OBJECT_SIZE_BUILTIN(arr_big, 2); |
299 | // CHECK: store i32 0 |
300 | gi = OBJECT_SIZE_BUILTIN(arr_big, 3); |
301 | } |
302 | |
303 | void *my_tiny_malloc(char) __attribute__((alloc_size(1))); |
304 | void *my_tiny_calloc(char, char) __attribute__((alloc_size(1, 2))); |
305 | |
306 | // CHECK-LABEL: @test11 |
307 | void test11() { |
308 | void *const vp = my_tiny_malloc(100); |
309 | // CHECK: store i32 100 |
310 | gi = OBJECT_SIZE_BUILTIN(vp, 0); |
311 | // CHECK: store i32 100 |
312 | gi = OBJECT_SIZE_BUILTIN(vp, 1); |
313 | // CHECK: store i32 100 |
314 | gi = OBJECT_SIZE_BUILTIN(vp, 2); |
315 | // CHECK: store i32 100 |
316 | gi = OBJECT_SIZE_BUILTIN(vp, 3); |
317 | |
318 | // N.B. This causes char overflow, but not size_t overflow, so it should be |
319 | // supported. |
320 | void *const arr = my_tiny_calloc(100, 5); |
321 | // CHECK: store i32 500 |
322 | gi = OBJECT_SIZE_BUILTIN(arr, 0); |
323 | // CHECK: store i32 500 |
324 | gi = OBJECT_SIZE_BUILTIN(arr, 1); |
325 | // CHECK: store i32 500 |
326 | gi = OBJECT_SIZE_BUILTIN(arr, 2); |
327 | // CHECK: store i32 500 |
328 | gi = OBJECT_SIZE_BUILTIN(arr, 3); |
329 | } |
330 | |
331 | void *my_signed_malloc(long) __attribute__((alloc_size(1))); |
332 | void *my_signed_calloc(long, long) __attribute__((alloc_size(1, 2))); |
333 | |
334 | // CHECK-LABEL: @test12 |
335 | void test12() { |
336 | // CHECK: store i32 100 |
337 | gi = OBJECT_SIZE_BUILTIN(my_signed_malloc(100), 0); |
338 | // CHECK: store i32 500 |
339 | gi = OBJECT_SIZE_BUILTIN(my_signed_calloc(100, 5), 0); |
340 | |
341 | void *const vp = my_signed_malloc(-2); |
342 | // CHECK: @llvm.objectsize |
343 | gi = OBJECT_SIZE_BUILTIN(vp, 0); |
344 | // N.B. These get lowered to -1 because the function calls may have |
345 | // side-effects, and we can't determine the objectsize. |
346 | // CHECK: store i32 -1 |
347 | gi = OBJECT_SIZE_BUILTIN(my_signed_malloc(-2), 0); |
348 | |
349 | void *const arr1 = my_signed_calloc(-2, 1); |
350 | void *const arr2 = my_signed_calloc(1, -2); |
351 | // CHECK: @llvm.objectsize |
352 | gi = OBJECT_SIZE_BUILTIN(arr1, 0); |
353 | // CHECK: @llvm.objectsize |
354 | gi = OBJECT_SIZE_BUILTIN(arr2, 0); |
355 | // CHECK: store i32 -1 |
356 | gi = OBJECT_SIZE_BUILTIN(my_signed_calloc(1, -2), 0); |
357 | // CHECK: store i32 -1 |
358 | gi = OBJECT_SIZE_BUILTIN(my_signed_calloc(-2, 1), 0); |
359 | } |
360 | |