1 | /* Tests for struct alloc_buffer. |
2 | Copyright (C) 2017-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <arpa/inet.h> |
20 | #include <alloc_buffer.h> |
21 | #include <stdio.h> |
22 | #include <stdlib.h> |
23 | #include <string.h> |
24 | #include <support/check.h> |
25 | #include <support/support.h> |
26 | #include <support/test-driver.h> |
27 | |
28 | /* Return true if PTR is sufficiently aligned for TYPE. */ |
29 | #define IS_ALIGNED(ptr, type) \ |
30 | ((((uintptr_t) ptr) & (__alloc_buffer_assert_align (__alignof (type)) - 1)) \ |
31 | == 0) |
32 | |
33 | /* Structure with non-power-of-two size. */ |
34 | struct twelve |
35 | { |
36 | uint32_t buffer[3] __attribute__ ((aligned (4))); |
37 | }; |
38 | _Static_assert (sizeof (struct twelve) == 12, "struct twelve" ); |
39 | _Static_assert (__alignof__ (struct twelve) == 4, "struct twelve" ); |
40 | |
41 | /* Check for success obtaining empty arrays. Does not assume the |
42 | buffer is empty. */ |
43 | static void |
44 | test_empty_array (struct alloc_buffer refbuf) |
45 | { |
46 | bool refbuf_failed = alloc_buffer_has_failed (buf: &refbuf); |
47 | if (test_verbose) |
48 | printf (format: "info: %s: current=0x%llx end=0x%llx refbuf_failed=%d\n" , |
49 | __func__, (unsigned long long) refbuf.__alloc_buffer_current, |
50 | (unsigned long long) refbuf.__alloc_buffer_end, refbuf_failed); |
51 | { |
52 | struct alloc_buffer buf = refbuf; |
53 | TEST_VERIFY ((alloc_buffer_alloc_bytes (&buf, 0) == NULL) |
54 | == refbuf_failed); |
55 | TEST_VERIFY (alloc_buffer_has_failed (&buf) == refbuf_failed); |
56 | } |
57 | { |
58 | struct alloc_buffer buf = refbuf; |
59 | TEST_VERIFY ((alloc_buffer_alloc_array (&buf, char, 0) == NULL) |
60 | == refbuf_failed); |
61 | TEST_VERIFY (alloc_buffer_has_failed (&buf) == refbuf_failed); |
62 | } |
63 | /* The following tests can fail due to the need for aligning the |
64 | returned pointer. */ |
65 | { |
66 | struct alloc_buffer buf = refbuf; |
67 | bool expect_failure = refbuf_failed |
68 | || !IS_ALIGNED (alloc_buffer_next (&buf, void), double); |
69 | double *ptr = alloc_buffer_alloc_array (&buf, double, 0); |
70 | TEST_VERIFY (IS_ALIGNED (ptr, double)); |
71 | TEST_VERIFY ((ptr == NULL) == expect_failure); |
72 | TEST_VERIFY (alloc_buffer_has_failed (&buf) == expect_failure); |
73 | } |
74 | { |
75 | struct alloc_buffer buf = refbuf; |
76 | bool expect_failure = refbuf_failed |
77 | || !IS_ALIGNED (alloc_buffer_next (&buf, void), struct twelve); |
78 | struct twelve *ptr = alloc_buffer_alloc_array (&buf, struct twelve, 0); |
79 | TEST_VERIFY (IS_ALIGNED (ptr, struct twelve)); |
80 | TEST_VERIFY ((ptr == NULL) == expect_failure); |
81 | TEST_VERIFY (alloc_buffer_has_failed (&buf) == expect_failure); |
82 | } |
83 | } |
84 | |
85 | /* Test allocation of impossibly large arrays. */ |
86 | static void |
87 | test_impossible_array (struct alloc_buffer refbuf) |
88 | { |
89 | if (test_verbose) |
90 | printf (format: "info: %s: current=0x%llx end=0x%llx\n" , |
91 | __func__, (unsigned long long) refbuf.__alloc_buffer_current, |
92 | (unsigned long long) refbuf.__alloc_buffer_end); |
93 | static const size_t counts[] = |
94 | { SIZE_MAX, SIZE_MAX - 1, SIZE_MAX - 2, SIZE_MAX - 3, SIZE_MAX - 4, |
95 | SIZE_MAX / 2, SIZE_MAX / 2 + 1, SIZE_MAX / 2 - 1, 0}; |
96 | |
97 | for (int i = 0; counts[i] != 0; ++i) |
98 | { |
99 | size_t count = counts[i]; |
100 | if (test_verbose) |
101 | printf (format: "info: %s: count=%zu\n" , __func__, count); |
102 | { |
103 | struct alloc_buffer buf = refbuf; |
104 | TEST_VERIFY (alloc_buffer_alloc_bytes (&buf, count) == NULL); |
105 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
106 | } |
107 | { |
108 | struct alloc_buffer buf = refbuf; |
109 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, char, count) == NULL); |
110 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
111 | } |
112 | { |
113 | struct alloc_buffer buf = refbuf; |
114 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, short, count) == NULL); |
115 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
116 | } |
117 | { |
118 | struct alloc_buffer buf = refbuf; |
119 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, double, count) == NULL); |
120 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
121 | } |
122 | { |
123 | struct alloc_buffer buf = refbuf; |
124 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, struct twelve, count) |
125 | == NULL); |
126 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
127 | } |
128 | } |
129 | } |
130 | |
131 | /* Check for failure to obtain anything from a failed buffer. */ |
132 | static void |
133 | test_after_failure (struct alloc_buffer refbuf) |
134 | { |
135 | if (test_verbose) |
136 | printf (format: "info: %s: current=0x%llx end=0x%llx\n" , |
137 | __func__, (unsigned long long) refbuf.__alloc_buffer_current, |
138 | (unsigned long long) refbuf.__alloc_buffer_end); |
139 | TEST_VERIFY (alloc_buffer_has_failed (&refbuf)); |
140 | { |
141 | struct alloc_buffer buf = refbuf; |
142 | alloc_buffer_add_byte (buf: &buf, b: 17); |
143 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
144 | } |
145 | { |
146 | struct alloc_buffer buf = refbuf; |
147 | TEST_VERIFY (alloc_buffer_alloc (&buf, char) == NULL); |
148 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
149 | } |
150 | { |
151 | struct alloc_buffer buf = refbuf; |
152 | TEST_VERIFY (alloc_buffer_alloc (&buf, double) == NULL); |
153 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
154 | } |
155 | { |
156 | struct alloc_buffer buf = refbuf; |
157 | TEST_VERIFY (alloc_buffer_alloc (&buf, struct twelve) == NULL); |
158 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
159 | } |
160 | |
161 | test_impossible_array (refbuf); |
162 | for (int count = 0; count <= 4; ++count) |
163 | { |
164 | { |
165 | struct alloc_buffer buf = refbuf; |
166 | TEST_VERIFY (alloc_buffer_alloc_bytes (&buf, count) == NULL); |
167 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
168 | } |
169 | { |
170 | struct alloc_buffer buf = refbuf; |
171 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, char, count) == NULL); |
172 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
173 | } |
174 | { |
175 | struct alloc_buffer buf = refbuf; |
176 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, double, count) == NULL); |
177 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
178 | } |
179 | { |
180 | struct alloc_buffer buf = refbuf; |
181 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, struct twelve, count) |
182 | == NULL); |
183 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
184 | } |
185 | } |
186 | } |
187 | |
188 | static void |
189 | test_empty (struct alloc_buffer refbuf) |
190 | { |
191 | TEST_VERIFY (alloc_buffer_size (&refbuf) == 0); |
192 | if (alloc_buffer_next (&refbuf, void) != NULL) |
193 | TEST_VERIFY (!alloc_buffer_has_failed (&refbuf)); |
194 | test_empty_array (refbuf); |
195 | test_impossible_array (refbuf); |
196 | |
197 | /* Failure to obtain non-empty objects. */ |
198 | { |
199 | struct alloc_buffer buf = refbuf; |
200 | alloc_buffer_add_byte (buf: &buf, b: 17); |
201 | test_after_failure (refbuf: buf); |
202 | } |
203 | { |
204 | struct alloc_buffer buf = refbuf; |
205 | TEST_VERIFY (alloc_buffer_alloc (&buf, char) == NULL); |
206 | test_after_failure (refbuf: buf); |
207 | } |
208 | { |
209 | struct alloc_buffer buf = refbuf; |
210 | TEST_VERIFY (alloc_buffer_alloc (&buf, double) == NULL); |
211 | test_after_failure (refbuf: buf); |
212 | } |
213 | { |
214 | struct alloc_buffer buf = refbuf; |
215 | TEST_VERIFY (alloc_buffer_alloc (&buf, struct twelve) == NULL); |
216 | test_after_failure (refbuf: buf); |
217 | } |
218 | { |
219 | struct alloc_buffer buf = refbuf; |
220 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, char, 1) == NULL); |
221 | test_after_failure (refbuf: buf); |
222 | } |
223 | { |
224 | struct alloc_buffer buf = refbuf; |
225 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, double, 1) == NULL); |
226 | test_after_failure (refbuf: buf); |
227 | } |
228 | { |
229 | struct alloc_buffer buf = refbuf; |
230 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, struct twelve, 1) == NULL); |
231 | test_after_failure (refbuf: buf); |
232 | } |
233 | } |
234 | |
235 | static void |
236 | test_size_1 (struct alloc_buffer refbuf) |
237 | { |
238 | TEST_VERIFY (!alloc_buffer_has_failed (&refbuf)); |
239 | TEST_VERIFY (alloc_buffer_size (&refbuf) == 1); |
240 | test_empty_array (refbuf); |
241 | test_impossible_array (refbuf); |
242 | |
243 | /* Success adding a single byte. */ |
244 | { |
245 | struct alloc_buffer buf = refbuf; |
246 | alloc_buffer_add_byte (buf: &buf, b: 17); |
247 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
248 | test_empty (refbuf: buf); |
249 | } |
250 | TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "\x11" , 1) == 0); |
251 | { |
252 | struct alloc_buffer buf = refbuf; |
253 | signed char *ptr = alloc_buffer_alloc (&buf, signed char); |
254 | TEST_VERIFY_EXIT (ptr != NULL); |
255 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
256 | *ptr = 126; |
257 | test_empty (refbuf: buf); |
258 | } |
259 | TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "\176" , 1) == 0); |
260 | { |
261 | struct alloc_buffer buf = refbuf; |
262 | char *ptr = alloc_buffer_alloc_array (&buf, char, 1); |
263 | TEST_VERIFY_EXIT (ptr != NULL); |
264 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
265 | *ptr = (char) 253; |
266 | test_empty (refbuf: buf); |
267 | } |
268 | TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "\xfd" , 1) == 0); |
269 | |
270 | /* Failure with larger objects. */ |
271 | { |
272 | struct alloc_buffer buf = refbuf; |
273 | TEST_VERIFY (alloc_buffer_alloc (&buf, short) == NULL); |
274 | test_after_failure (refbuf: buf); |
275 | } |
276 | { |
277 | struct alloc_buffer buf = refbuf; |
278 | TEST_VERIFY (alloc_buffer_alloc (&buf, double) == NULL); |
279 | test_after_failure (refbuf: buf); |
280 | } |
281 | { |
282 | struct alloc_buffer buf = refbuf; |
283 | TEST_VERIFY (alloc_buffer_alloc (&buf, struct twelve) == NULL); |
284 | test_after_failure (refbuf: buf); |
285 | } |
286 | { |
287 | struct alloc_buffer buf = refbuf; |
288 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, short, 1) == NULL); |
289 | test_after_failure (refbuf: buf); |
290 | } |
291 | { |
292 | struct alloc_buffer buf = refbuf; |
293 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, double, 1) == NULL); |
294 | test_after_failure (refbuf: buf); |
295 | } |
296 | { |
297 | struct alloc_buffer buf = refbuf; |
298 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, struct twelve, 1) == NULL); |
299 | test_after_failure (refbuf: buf); |
300 | } |
301 | } |
302 | |
303 | static void |
304 | test_size_2 (struct alloc_buffer refbuf) |
305 | { |
306 | TEST_VERIFY (!alloc_buffer_has_failed (&refbuf)); |
307 | TEST_VERIFY (alloc_buffer_size (&refbuf) == 2); |
308 | TEST_VERIFY (IS_ALIGNED (alloc_buffer_next (&refbuf, void), short)); |
309 | test_empty_array (refbuf); |
310 | test_impossible_array (refbuf); |
311 | |
312 | /* Success adding two bytes. */ |
313 | { |
314 | struct alloc_buffer buf = refbuf; |
315 | alloc_buffer_add_byte (buf: &buf, b: '@'); |
316 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
317 | test_size_1 (refbuf: buf); |
318 | } |
319 | TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "@\xfd" , 2) == 0); |
320 | { |
321 | struct alloc_buffer buf = refbuf; |
322 | signed char *ptr = alloc_buffer_alloc (&buf, signed char); |
323 | TEST_VERIFY_EXIT (ptr != NULL); |
324 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
325 | *ptr = 'A'; |
326 | test_size_1 (refbuf: buf); |
327 | } |
328 | TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "A\xfd" , 2) == 0); |
329 | { |
330 | struct alloc_buffer buf = refbuf; |
331 | char *ptr = alloc_buffer_alloc_array (&buf, char, 1); |
332 | TEST_VERIFY_EXIT (ptr != NULL); |
333 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
334 | *ptr = 'B'; |
335 | test_size_1 (refbuf: buf); |
336 | } |
337 | TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "B\xfd" , 2) == 0); |
338 | { |
339 | struct alloc_buffer buf = refbuf; |
340 | unsigned short *ptr = alloc_buffer_alloc (&buf, unsigned short); |
341 | TEST_VERIFY_EXIT (ptr != NULL); |
342 | TEST_VERIFY (IS_ALIGNED (ptr, unsigned short)); |
343 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
344 | *ptr = htons (0x12f4); |
345 | test_empty (refbuf: buf); |
346 | } |
347 | TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "\x12\xf4" , 2) == 0); |
348 | { |
349 | struct alloc_buffer buf = refbuf; |
350 | unsigned short *ptr = alloc_buffer_alloc_array (&buf, unsigned short, 1); |
351 | TEST_VERIFY_EXIT (ptr != NULL); |
352 | TEST_VERIFY (IS_ALIGNED (ptr, unsigned short)); |
353 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
354 | *ptr = htons (0x13f5); |
355 | test_empty (refbuf: buf); |
356 | } |
357 | TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "\x13\xf5" , 2) == 0); |
358 | { |
359 | struct alloc_buffer buf = refbuf; |
360 | char *ptr = alloc_buffer_alloc_array (&buf, char, 2); |
361 | TEST_VERIFY_EXIT (ptr != NULL); |
362 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
363 | memcpy (ptr, "12" , 2); |
364 | test_empty (refbuf: buf); |
365 | } |
366 | TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "12" , 2) == 0); |
367 | } |
368 | |
369 | static void |
370 | test_misaligned (char pad) |
371 | { |
372 | enum { SIZE = 23 }; |
373 | char *backing = xmalloc (n: SIZE + 2); |
374 | backing[0] = ~pad; |
375 | backing[SIZE + 1] = pad; |
376 | struct alloc_buffer refbuf = alloc_buffer_create (start: backing + 1, size: SIZE); |
377 | |
378 | { |
379 | struct alloc_buffer buf = refbuf; |
380 | short *ptr = alloc_buffer_alloc_array (&buf, short, SIZE / sizeof (short)); |
381 | TEST_VERIFY_EXIT (ptr != NULL); |
382 | TEST_VERIFY (IS_ALIGNED (ptr, short)); |
383 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
384 | for (int i = 0; i < SIZE / sizeof (short); ++i) |
385 | ptr[i] = htons (0xff01 + i); |
386 | TEST_VERIFY (memcmp (ptr, |
387 | "\xff\x01\xff\x02\xff\x03\xff\x04" |
388 | "\xff\x05\xff\x06\xff\x07\xff\x08" |
389 | "\xff\x09\xff\x0a\xff\x0b" , 22) == 0); |
390 | } |
391 | { |
392 | struct alloc_buffer buf = refbuf; |
393 | uint32_t *ptr = alloc_buffer_alloc_array |
394 | (&buf, uint32_t, SIZE / sizeof (uint32_t)); |
395 | TEST_VERIFY_EXIT (ptr != NULL); |
396 | TEST_VERIFY (IS_ALIGNED (ptr, uint32_t)); |
397 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
398 | for (int i = 0; i < SIZE / sizeof (uint32_t); ++i) |
399 | ptr[i] = htonl (0xf1e2d301 + i); |
400 | TEST_VERIFY (memcmp (ptr, |
401 | "\xf1\xe2\xd3\x01\xf1\xe2\xd3\x02" |
402 | "\xf1\xe2\xd3\x03\xf1\xe2\xd3\x04" |
403 | "\xf1\xe2\xd3\x05" , 20) == 0); |
404 | } |
405 | { |
406 | struct alloc_buffer buf = refbuf; |
407 | struct twelve *ptr = alloc_buffer_alloc (&buf, struct twelve); |
408 | TEST_VERIFY_EXIT (ptr != NULL); |
409 | TEST_VERIFY (IS_ALIGNED (ptr, struct twelve)); |
410 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
411 | ptr->buffer[0] = htonl (0x11223344); |
412 | ptr->buffer[1] = htonl (0x55667788); |
413 | ptr->buffer[2] = htonl (0x99aabbcc); |
414 | TEST_VERIFY (memcmp (ptr, |
415 | "\x11\x22\x33\x44" |
416 | "\x55\x66\x77\x88" |
417 | "\x99\xaa\xbb\xcc" , 12) == 0); |
418 | } |
419 | { |
420 | static const double nums[] = { 1, 2 }; |
421 | struct alloc_buffer buf = refbuf; |
422 | double *ptr = alloc_buffer_alloc_array (&buf, double, 2); |
423 | TEST_VERIFY_EXIT (ptr != NULL); |
424 | TEST_VERIFY (IS_ALIGNED (ptr, double)); |
425 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
426 | ptr[0] = nums[0]; |
427 | ptr[1] = nums[1]; |
428 | TEST_VERIFY (memcmp (ptr, nums, sizeof (nums)) == 0); |
429 | } |
430 | |
431 | /* Verify that padding was not overwritten. */ |
432 | TEST_VERIFY (backing[0] == (char) ~pad); |
433 | TEST_VERIFY (backing[SIZE + 1] == pad); |
434 | free (ptr: backing); |
435 | } |
436 | |
437 | /* Check that overflow during alignment is handled properly. */ |
438 | static void |
439 | test_large_misaligned (void) |
440 | { |
441 | uintptr_t minus1 = -1; |
442 | uintptr_t start = minus1 & ~0xfe; |
443 | struct alloc_buffer refbuf = alloc_buffer_create (start: (void *) start, size: 16); |
444 | TEST_VERIFY (!alloc_buffer_has_failed (&refbuf)); |
445 | |
446 | struct __attribute__ ((aligned (256))) align256 |
447 | { |
448 | int dymmy; |
449 | }; |
450 | |
451 | { |
452 | struct alloc_buffer buf = refbuf; |
453 | TEST_VERIFY (alloc_buffer_alloc (&buf, struct align256) == NULL); |
454 | test_after_failure (refbuf: buf); |
455 | } |
456 | for (int count = 0; count < 3; ++count) |
457 | { |
458 | struct alloc_buffer buf = refbuf; |
459 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, struct align256, count) |
460 | == NULL); |
461 | test_after_failure (refbuf: buf); |
462 | } |
463 | } |
464 | |
465 | /* Check behavior of large allocations. */ |
466 | static void |
467 | test_large (void) |
468 | { |
469 | { |
470 | /* Allocation which wraps around. */ |
471 | struct alloc_buffer buf = { 1, SIZE_MAX }; |
472 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, char, SIZE_MAX) == NULL); |
473 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
474 | } |
475 | |
476 | { |
477 | /* Successful very large allocation. */ |
478 | struct alloc_buffer buf = { 1, SIZE_MAX }; |
479 | uintptr_t val = (uintptr_t) alloc_buffer_alloc_array |
480 | (&buf, char, SIZE_MAX - 1); |
481 | TEST_VERIFY (val == 1); |
482 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
483 | test_empty (refbuf: buf); |
484 | } |
485 | |
486 | { |
487 | typedef char __attribute__ ((aligned (2))) char2; |
488 | |
489 | /* Overflow in array size computation. */ |
490 | struct alloc_buffer buf = { 1, SIZE_MAX }; |
491 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, char2, SIZE_MAX - 1) == NULL); |
492 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
493 | |
494 | /* Successful allocation after alignment. */ |
495 | buf = (struct alloc_buffer) { 1, SIZE_MAX }; |
496 | uintptr_t val = (uintptr_t) alloc_buffer_alloc_array |
497 | (&buf, char2, SIZE_MAX - 2); |
498 | TEST_VERIFY (val == 2); |
499 | test_empty (refbuf: buf); |
500 | |
501 | /* Alignment behavior near the top of the address space. */ |
502 | buf = (struct alloc_buffer) { SIZE_MAX, SIZE_MAX }; |
503 | TEST_VERIFY (alloc_buffer_next (&buf, char2) == NULL); |
504 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
505 | buf = (struct alloc_buffer) { SIZE_MAX, SIZE_MAX }; |
506 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, char2, 0) == NULL); |
507 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
508 | } |
509 | |
510 | { |
511 | typedef short __attribute__ ((aligned (2))) short2; |
512 | |
513 | /* Test overflow in size computation. */ |
514 | struct alloc_buffer buf = { 1, SIZE_MAX }; |
515 | TEST_VERIFY (alloc_buffer_alloc_array (&buf, short2, SIZE_MAX / 2) |
516 | == NULL); |
517 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
518 | |
519 | /* A slightly smaller array fits within the allocation. */ |
520 | buf = (struct alloc_buffer) { 2, SIZE_MAX - 1 }; |
521 | uintptr_t val = (uintptr_t) alloc_buffer_alloc_array |
522 | (&buf, short2, SIZE_MAX / 2 - 1); |
523 | TEST_VERIFY (val == 2); |
524 | test_empty (refbuf: buf); |
525 | } |
526 | } |
527 | |
528 | static void |
529 | test_copy_bytes (void) |
530 | { |
531 | char backing[4]; |
532 | { |
533 | memset (backing, '@', sizeof (backing)); |
534 | struct alloc_buffer buf = alloc_buffer_create (start: backing, size: sizeof (backing)); |
535 | alloc_buffer_copy_bytes (buf: &buf, src: "1" , size: 1); |
536 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
537 | TEST_VERIFY (alloc_buffer_size (&buf) == 3); |
538 | TEST_VERIFY (memcmp (backing, "1@@@" , 4) == 0); |
539 | } |
540 | { |
541 | memset (backing, '@', sizeof (backing)); |
542 | struct alloc_buffer buf = alloc_buffer_create (start: backing, size: sizeof (backing)); |
543 | alloc_buffer_copy_bytes (buf: &buf, src: "12" , size: 3); |
544 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
545 | TEST_VERIFY (alloc_buffer_size (&buf) == 1); |
546 | TEST_VERIFY (memcmp (backing, "12\0@" , 4) == 0); |
547 | } |
548 | { |
549 | memset (backing, '@', sizeof (backing)); |
550 | struct alloc_buffer buf = alloc_buffer_create (start: backing, size: sizeof (backing)); |
551 | alloc_buffer_copy_bytes (buf: &buf, src: "1234" , size: 4); |
552 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
553 | TEST_VERIFY (alloc_buffer_size (&buf) == 0); |
554 | TEST_VERIFY (memcmp (backing, "1234" , 4) == 0); |
555 | } |
556 | { |
557 | memset (backing, '@', sizeof (backing)); |
558 | struct alloc_buffer buf = alloc_buffer_create (start: backing, size: sizeof (backing)); |
559 | alloc_buffer_copy_bytes (buf: &buf, src: "1234" , size: 5); |
560 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
561 | TEST_VERIFY (memcmp (backing, "@@@@" , 4) == 0); |
562 | } |
563 | { |
564 | memset (backing, '@', sizeof (backing)); |
565 | struct alloc_buffer buf = alloc_buffer_create (start: backing, size: sizeof (backing)); |
566 | alloc_buffer_copy_bytes (buf: &buf, src: "1234" , size: -1); |
567 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
568 | TEST_VERIFY (memcmp (backing, "@@@@" , 4) == 0); |
569 | } |
570 | } |
571 | |
572 | static void |
573 | test_copy_string (void) |
574 | { |
575 | char backing[4]; |
576 | { |
577 | memset (backing, '@', sizeof (backing)); |
578 | struct alloc_buffer buf = alloc_buffer_create (start: backing, size: sizeof (backing)); |
579 | const char *p = alloc_buffer_copy_string (buf: &buf, src: "" ); |
580 | TEST_VERIFY (p == backing); |
581 | TEST_VERIFY (strcmp (p, "" ) == 0); |
582 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
583 | TEST_VERIFY (alloc_buffer_size (&buf) == 3); |
584 | TEST_VERIFY (memcmp (backing, "\0@@@" , 4) == 0); |
585 | } |
586 | { |
587 | memset (backing, '@', sizeof (backing)); |
588 | struct alloc_buffer buf = alloc_buffer_create (start: backing, size: sizeof (backing)); |
589 | const char *p = alloc_buffer_copy_string (buf: &buf, src: "1" ); |
590 | TEST_VERIFY (p == backing); |
591 | TEST_VERIFY (strcmp (p, "1" ) == 0); |
592 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
593 | TEST_VERIFY (alloc_buffer_size (&buf) == 2); |
594 | TEST_VERIFY (memcmp (backing, "1\0@@" , 4) == 0); |
595 | } |
596 | { |
597 | memset (backing, '@', sizeof (backing)); |
598 | struct alloc_buffer buf = alloc_buffer_create (start: backing, size: sizeof (backing)); |
599 | const char *p = alloc_buffer_copy_string (buf: &buf, src: "12" ); |
600 | TEST_VERIFY (p == backing); |
601 | TEST_VERIFY (strcmp (p, "12" ) == 0); |
602 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
603 | TEST_VERIFY (alloc_buffer_size (&buf) == 1); |
604 | TEST_VERIFY (memcmp (backing, "12\0@" , 4) == 0); |
605 | } |
606 | { |
607 | memset (backing, '@', sizeof (backing)); |
608 | struct alloc_buffer buf = alloc_buffer_create (start: backing, size: sizeof (backing)); |
609 | const char *p = alloc_buffer_copy_string (buf: &buf, src: "123" ); |
610 | TEST_VERIFY (p == backing); |
611 | TEST_VERIFY (strcmp (p, "123" ) == 0); |
612 | TEST_VERIFY (!alloc_buffer_has_failed (&buf)); |
613 | TEST_VERIFY (alloc_buffer_size (&buf) == 0); |
614 | TEST_VERIFY (memcmp (backing, "123" , 4) == 0); |
615 | } |
616 | { |
617 | memset (backing, '@', sizeof (backing)); |
618 | struct alloc_buffer buf = alloc_buffer_create (start: backing, size: sizeof (backing)); |
619 | TEST_VERIFY (alloc_buffer_copy_string (&buf, "1234" ) == NULL); |
620 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
621 | TEST_VERIFY (memcmp (backing, "@@@@" , 4) == 0); |
622 | } |
623 | { |
624 | memset (backing, '@', sizeof (backing)); |
625 | struct alloc_buffer buf = alloc_buffer_create (start: backing, size: sizeof (backing)); |
626 | TEST_VERIFY (alloc_buffer_copy_string (&buf, "12345" ) == NULL); |
627 | TEST_VERIFY (alloc_buffer_has_failed (&buf)); |
628 | TEST_VERIFY (memcmp (backing, "@@@@" , 4) == 0); |
629 | } |
630 | } |
631 | |
632 | static int |
633 | do_test (void) |
634 | { |
635 | test_empty (refbuf: alloc_buffer_create (NULL, size: 0)); |
636 | test_empty (refbuf: alloc_buffer_create (start: (char *) "" , size: 0)); |
637 | test_empty (refbuf: alloc_buffer_create (start: (void *) 1, size: 0)); |
638 | |
639 | { |
640 | void *ptr = (void *) "" ; /* Cannot be freed. */ |
641 | struct alloc_buffer buf = alloc_buffer_allocate (size: 1, pptr: &ptr); |
642 | test_size_1 (refbuf: buf); |
643 | free (ptr: ptr); /* Should have been overwritten. */ |
644 | } |
645 | |
646 | { |
647 | void *ptr= (void *) "" ; /* Cannot be freed. */ |
648 | struct alloc_buffer buf = alloc_buffer_allocate (size: 2, pptr: &ptr); |
649 | test_size_2 (refbuf: buf); |
650 | free (ptr: ptr); /* Should have been overwritten. */ |
651 | } |
652 | |
653 | test_misaligned (pad: 0); |
654 | test_misaligned (pad: 0xc7); |
655 | test_misaligned (pad: 0xff); |
656 | |
657 | test_large_misaligned (); |
658 | test_large (); |
659 | test_copy_bytes (); |
660 | test_copy_string (); |
661 | |
662 | return 0; |
663 | } |
664 | |
665 | #include <support/test-driver.c> |
666 | |