Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2019 Intel Corporation
3 : : */
4 : :
5 : : #define ALLOW_INTERNAL_API
6 : :
7 : : #include "test.h"
8 : :
9 : : #include <stdio.h>
10 : : #include <stdint.h>
11 : : #include <string.h>
12 : : #include <stdarg.h>
13 : : #include <errno.h>
14 : : #include <stdlib.h>
15 : : #ifndef RTE_EXEC_ENV_WINDOWS
16 : : #include <sys/mman.h>
17 : : #endif
18 : : #include <sys/queue.h>
19 : : #include <unistd.h>
20 : :
21 : : #include <rte_common.h>
22 : : #include <rte_memory.h>
23 : : #include <rte_per_lcore.h>
24 : : #include <rte_launch.h>
25 : : #include <rte_eal.h>
26 : : #include <rte_lcore.h>
27 : : #include <rte_malloc.h>
28 : : #include <rte_cycles.h>
29 : : #include <rte_random.h>
30 : : #include <rte_eal_paging.h>
31 : : #include <rte_string_fns.h>
32 : :
33 : : #define N 10000
34 : :
35 : : static int
36 : : is_mem_on_socket(int32_t socket);
37 : :
38 : : static int32_t
39 : : addr_to_socket(void *addr);
40 : :
41 : : /*
42 : : * Malloc
43 : : * ======
44 : : *
45 : : * Allocate some dynamic memory from heap (3 areas). Check that areas
46 : : * don't overlap and that alignment constraints match. This test is
47 : : * done many times on different lcores simultaneously.
48 : : */
49 : :
50 : : /* Test if memory overlaps: return 1 if true, or 0 if false. */
51 : : static int
52 : : is_memory_overlap(void *p1, size_t len1, void *p2, size_t len2)
53 : : {
54 : 10030 : uintptr_t ptr1 = (uintptr_t)p1;
55 : 20060 : uintptr_t ptr2 = (uintptr_t)p2;
56 : :
57 [ - + - - : 30090 : if (ptr2 >= ptr1 && (ptr2 - ptr1) < len1)
- + - - -
+ - - - +
- - - + -
- - + -
- ]
58 : : return 1;
59 [ + - - + : 30090 : else if (ptr2 < ptr1 && (ptr1 - ptr2) < len2)
+ - - + +
- - + + -
- + + - -
+ + - -
+ ]
60 : : return 1;
61 : : return 0;
62 : : }
63 : :
64 : : static int
65 : : is_aligned(void *p, int align)
66 : : {
67 : : uintptr_t addr = (uintptr_t)p;
68 : : unsigned mask = align - 1;
69 : :
70 : : if (addr & mask)
71 : : return 0;
72 : : return 1;
73 : : }
74 : :
75 : : static int
76 : 1 : test_align_overlap_per_lcore(__rte_unused void *arg)
77 : : {
78 : : const unsigned align1 = 8,
79 : : align2 = 64,
80 : : align3 = 2048;
81 : : unsigned i,j;
82 : : void *p1 = NULL, *p2 = NULL, *p3 = NULL;
83 : : int ret = 0;
84 : :
85 [ + + ]: 10001 : for (i = 0; i < N; i++) {
86 : 10000 : p1 = rte_zmalloc("dummy", 1000, align1);
87 [ + - ]: 10000 : if (!p1){
88 : : printf("rte_zmalloc returned NULL (i=%u)\n", i);
89 : : ret = -1;
90 : 0 : break;
91 : : }
92 [ + + ]: 10010000 : for(j = 0; j < 1000 ; j++) {
93 [ - + ]: 10000000 : if( *(char *)p1 != 0) {
94 : : printf("rte_zmalloc didn't zero the allocated memory\n");
95 : : ret = -1;
96 : : }
97 : : }
98 : 10000 : p2 = rte_malloc("dummy", 1000, align2);
99 [ - + ]: 10000 : if (!p2){
100 : : printf("rte_malloc returned NULL (i=%u)\n", i);
101 : : ret = -1;
102 : 0 : rte_free(p1);
103 : 0 : break;
104 : : }
105 : 10000 : p3 = rte_malloc("dummy", 1000, align3);
106 [ - + ]: 10000 : if (!p3){
107 : : printf("rte_malloc returned NULL (i=%u)\n", i);
108 : : ret = -1;
109 : 0 : rte_free(p1);
110 : 0 : rte_free(p2);
111 : 0 : break;
112 : : }
113 : : if (is_memory_overlap(p1, 1000, p2, 1000)) {
114 : : printf("p1 and p2 overlaps\n");
115 : : ret = -1;
116 : : }
117 : : if (is_memory_overlap(p2, 1000, p3, 1000)) {
118 : : printf("p2 and p3 overlaps\n");
119 : : ret = -1;
120 : : }
121 : : if (is_memory_overlap(p1, 1000, p3, 1000)) {
122 : : printf("p1 and p3 overlaps\n");
123 : : ret = -1;
124 : : }
125 : : if (!is_aligned(p1, align1)) {
126 : : printf("p1 is not aligned\n");
127 : : ret = -1;
128 : : }
129 : : if (!is_aligned(p2, align2)) {
130 : : printf("p2 is not aligned\n");
131 : : ret = -1;
132 : : }
133 : : if (!is_aligned(p3, align3)) {
134 : : printf("p3 is not aligned\n");
135 : : ret = -1;
136 : : }
137 : 10000 : rte_free(p1);
138 : 10000 : rte_free(p2);
139 : 10000 : rte_free(p3);
140 : : }
141 : 1 : rte_malloc_dump_stats(stdout, "dummy");
142 : :
143 : 1 : return ret;
144 : : }
145 : :
146 : : static int
147 : 1 : test_align_overlap(void)
148 : : {
149 : : unsigned int lcore_id;
150 : : int ret = 0;
151 : :
152 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
153 : 1 : rte_eal_remote_launch(test_align_overlap_per_lcore, NULL, lcore_id);
154 : : }
155 : :
156 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
157 [ - + ]: 1 : if (rte_eal_wait_lcore(lcore_id) < 0)
158 : : ret = -1;
159 : : }
160 : :
161 : 1 : return ret;
162 : : }
163 : :
164 : : static int
165 : 1 : test_reordered_free_per_lcore(__rte_unused void *arg)
166 : : {
167 : : const unsigned align1 = 8,
168 : : align2 = 64,
169 : : align3 = 2048;
170 : : unsigned i,j;
171 : : void *p1, *p2, *p3;
172 : : int ret = 0;
173 : :
174 [ + + ]: 31 : for (i = 0; i < 30; i++) {
175 : 30 : p1 = rte_zmalloc("dummy", 1000, align1);
176 [ + - ]: 30 : if (!p1){
177 : : printf("rte_zmalloc returned NULL (i=%u)\n", i);
178 : : ret = -1;
179 : 0 : break;
180 : : }
181 [ + + ]: 30030 : for(j = 0; j < 1000 ; j++) {
182 [ - + ]: 30000 : if( *(char *)p1 != 0) {
183 : : printf("rte_zmalloc didn't zero the allocated memory\n");
184 : : ret = -1;
185 : : }
186 : : }
187 : : /* use calloc to allocate 1000 16-byte items this time */
188 : 30 : p2 = rte_calloc("dummy", 1000, 16, align2);
189 : : /* for third request use regular malloc again */
190 : 30 : p3 = rte_malloc("dummy", 1000, align3);
191 [ - + ]: 30 : if (!p2 || !p3){
192 : : printf("rte_malloc returned NULL (i=%u)\n", i);
193 : : ret = -1;
194 : 0 : break;
195 : : }
196 : : if (is_memory_overlap(p1, 1000, p2, 1000)) {
197 : : printf("p1 and p2 overlaps\n");
198 : : ret = -1;
199 : : }
200 : : if (is_memory_overlap(p2, 1000, p3, 1000)) {
201 : : printf("p2 and p3 overlaps\n");
202 : : ret = -1;
203 : : }
204 : : if (is_memory_overlap(p1, 1000, p3, 1000)) {
205 : : printf("p1 and p3 overlaps\n");
206 : : ret = -1;
207 : : }
208 : : if (!is_aligned(p1, align1)) {
209 : : printf("p1 is not aligned\n");
210 : : ret = -1;
211 : : }
212 : : if (!is_aligned(p2, align2)) {
213 : : printf("p2 is not aligned\n");
214 : : ret = -1;
215 : : }
216 : : if (!is_aligned(p3, align3)) {
217 : : printf("p3 is not aligned\n");
218 : : ret = -1;
219 : : }
220 : : /* try freeing in every possible order */
221 [ + + + + : 30 : switch (i%6){
+ + ]
222 : 5 : case 0:
223 : 5 : rte_free(p1);
224 : 5 : rte_free(p2);
225 : 5 : rte_free(p3);
226 : 5 : break;
227 : 5 : case 1:
228 : 5 : rte_free(p1);
229 : 5 : rte_free(p3);
230 : 5 : rte_free(p2);
231 : 5 : break;
232 : 5 : case 2:
233 : 5 : rte_free(p2);
234 : 5 : rte_free(p1);
235 : 5 : rte_free(p3);
236 : 5 : break;
237 : 5 : case 3:
238 : 5 : rte_free(p2);
239 : 5 : rte_free(p3);
240 : 5 : rte_free(p1);
241 : 5 : break;
242 : 5 : case 4:
243 : 5 : rte_free(p3);
244 : 5 : rte_free(p1);
245 : 5 : rte_free(p2);
246 : 5 : break;
247 : 5 : case 5:
248 : 5 : rte_free(p3);
249 : 5 : rte_free(p2);
250 : 5 : rte_free(p1);
251 : 5 : break;
252 : : }
253 : : }
254 : 1 : rte_malloc_dump_stats(stdout, "dummy");
255 : :
256 : 1 : return ret;
257 : : }
258 : :
259 : : static int
260 : 1 : test_reordered_free(void)
261 : : {
262 : : unsigned int lcore_id;
263 : : int ret = 0;
264 : :
265 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
266 : 1 : rte_eal_remote_launch(test_reordered_free_per_lcore, NULL, lcore_id);
267 : : }
268 : :
269 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
270 [ - + ]: 1 : if (rte_eal_wait_lcore(lcore_id) < 0)
271 : : ret = -1;
272 : : }
273 : 1 : return ret;
274 : : }
275 : :
276 : : static int
277 : 1 : test_multi_alloc_statistics(void)
278 : : {
279 : : int ret = -1; /* default return is error, cleared at end on success */
280 : : int socket = 0;
281 : : struct rte_malloc_socket_stats pre_stats, post_stats ,first_stats, second_stats;
282 : : size_t size = 2048;
283 : : int align = 1024;
284 : : int overhead = 0;
285 : 1 : const size_t pgsz = rte_mem_page_size();
286 : : const size_t heap_size = (1 << 22);
287 : :
288 [ - + ]: 1 : if (pgsz > heap_size) {
289 : : printf("Page size (%zu) is bigger than heap size, skipping alloc stats test\n",
290 : : pgsz);
291 : 0 : return TEST_SKIPPED;
292 : : }
293 [ - + ]: 1 : if (heap_size % pgsz != 0) {
294 : : printf("Heap size (%zu) is not a multiple of page size (%zu), skipping alloc stats test\n",
295 : : heap_size, pgsz);
296 : 0 : return TEST_SKIPPED;
297 : : }
298 : :
299 [ - + ]: 1 : if (rte_malloc_heap_create(__func__) != 0) {
300 : : printf("Failed to create test malloc heap\n");
301 : 0 : goto end;
302 : : }
303 : :
304 : : /* Allocate some memory using malloc and add it to our test heap. */
305 : 1 : void *unaligned_memory = malloc(heap_size + pgsz);
306 [ - + ]: 1 : if (unaligned_memory == NULL) {
307 : : printf("Failed to allocate memory\n");
308 : 0 : goto cleanup_empty_heap;
309 : : }
310 : 1 : void *memory = RTE_PTR_ALIGN(unaligned_memory, pgsz);
311 [ - + ]: 1 : if (rte_malloc_heap_memory_add(__func__, memory, heap_size, NULL,
312 : 1 : heap_size / pgsz, pgsz) != 0) {
313 : : printf("Failed to add memory to heap\n");
314 : 0 : goto cleanup_allocated_memory;
315 : : }
316 : 1 : socket = rte_malloc_heap_get_socket(__func__);
317 [ - + ]: 1 : if (socket < 0) {
318 : : printf("Failed to get socket for test malloc heap.\n");
319 : 0 : goto cleanup_all;
320 : : }
321 : :
322 : : /* Dynamically calculate the overhead by allocating one cacheline and
323 : : * then comparing what was allocated from the heap.
324 : : */
325 : 1 : rte_malloc_get_socket_stats(socket, &pre_stats);
326 : :
327 : 1 : void *dummy = rte_malloc_socket(NULL, RTE_CACHE_LINE_SIZE, 0, socket);
328 [ - + ]: 1 : if (dummy == NULL)
329 : 0 : goto cleanup_all;
330 : :
331 : 1 : rte_malloc_get_socket_stats(socket, &post_stats);
332 : :
333 : : /* after subtracting cache line, remainder is overhead */
334 : 1 : overhead = post_stats.heap_allocsz_bytes - pre_stats.heap_allocsz_bytes;
335 : : overhead -= RTE_CACHE_LINE_SIZE;
336 : :
337 : 1 : rte_free(dummy);
338 : :
339 : : /* Now start the real tests */
340 : 1 : rte_malloc_get_socket_stats(socket, &pre_stats);
341 : :
342 : 1 : void *p1 = rte_malloc_socket("stats", size , align, socket);
343 [ - + ]: 1 : if (!p1)
344 : 0 : goto cleanup_all;
345 : :
346 : 1 : rte_free(p1);
347 : 1 : rte_malloc_dump_stats(stdout, "stats");
348 : :
349 : 1 : rte_malloc_get_socket_stats(socket,&post_stats);
350 : : /* Check statistics reported are correct */
351 : : /* All post stats should be equal to pre stats after alloc freed */
352 [ + - ]: 1 : if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) ||
353 [ + - ]: 1 : (post_stats.heap_freesz_bytes != pre_stats.heap_freesz_bytes) ||
354 [ + - ]: 1 : (post_stats.heap_allocsz_bytes != pre_stats.heap_allocsz_bytes) ||
355 [ - + ]: 1 : (post_stats.alloc_count != pre_stats.alloc_count) ||
356 : : (post_stats.free_count != pre_stats.free_count)) {
357 : : printf("Malloc statistics are incorrect - freed alloc\n");
358 : 0 : goto cleanup_all;
359 : : }
360 : : /* Check two consecutive allocations */
361 : : size = 1024;
362 : : align = 0;
363 : 1 : rte_malloc_get_socket_stats(socket,&pre_stats);
364 : 1 : void *p2 = rte_malloc_socket("add", size ,align, socket);
365 [ - + ]: 1 : if (!p2)
366 : 0 : goto cleanup_all;
367 : 1 : rte_malloc_get_socket_stats(socket,&first_stats);
368 : :
369 : 1 : void *p3 = rte_malloc_socket("add2", size,align, socket);
370 [ - + ]: 1 : if (!p3)
371 : 0 : goto cleanup_all;
372 : :
373 : 1 : rte_malloc_get_socket_stats(socket,&second_stats);
374 : :
375 : 1 : rte_free(p2);
376 : 1 : rte_free(p3);
377 : :
378 : : /* After freeing both allocations check stats return to original */
379 : 1 : rte_malloc_get_socket_stats(socket, &post_stats);
380 : :
381 [ - + ]: 1 : if(second_stats.heap_totalsz_bytes != first_stats.heap_totalsz_bytes) {
382 : : printf("Incorrect heap statistics: Total size \n");
383 : 0 : goto cleanup_all;
384 : : }
385 : : /* Check allocated size is equal to two additions plus overhead */
386 : 1 : if(second_stats.heap_allocsz_bytes !=
387 [ - + ]: 1 : size + overhead + first_stats.heap_allocsz_bytes) {
388 : : printf("Incorrect heap statistics: Allocated size \n");
389 : 0 : goto cleanup_all;
390 : : }
391 : : /* Check that allocation count increments correctly i.e. +1 */
392 [ - + ]: 1 : if (second_stats.alloc_count != first_stats.alloc_count + 1) {
393 : : printf("Incorrect heap statistics: Allocated count \n");
394 : 0 : goto cleanup_all;
395 : : }
396 : :
397 [ - + ]: 1 : if (second_stats.free_count != first_stats.free_count){
398 : : printf("Incorrect heap statistics: Free count \n");
399 : 0 : goto cleanup_all;
400 : : }
401 : :
402 : : /* Make sure that we didn't touch our greatest chunk: 2 * 11M) */
403 [ - + ]: 1 : if (post_stats.greatest_free_size != pre_stats.greatest_free_size) {
404 : : printf("Incorrect heap statistics: Greatest free size \n");
405 : 0 : goto cleanup_all;
406 : : }
407 : : /* Free size must equal the original free size minus the new allocation*/
408 [ - + ]: 1 : if (first_stats.heap_freesz_bytes <= second_stats.heap_freesz_bytes) {
409 : : printf("Incorrect heap statistics: Free size \n");
410 : 0 : goto cleanup_all;
411 : : }
412 : :
413 [ + - ]: 1 : if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) ||
414 [ + - ]: 1 : (post_stats.heap_freesz_bytes != pre_stats.heap_freesz_bytes) ||
415 [ + - ]: 1 : (post_stats.heap_allocsz_bytes != pre_stats.heap_allocsz_bytes) ||
416 [ - + ]: 1 : (post_stats.alloc_count != pre_stats.alloc_count) ||
417 : : (post_stats.free_count != pre_stats.free_count)) {
418 : : printf("Malloc statistics are incorrect - freed alloc\n");
419 : 0 : goto cleanup_all;
420 : : }
421 : :
422 : : /* set return value as success before cleanup */
423 : : ret = 0;
424 : :
425 : : /* cleanup */
426 : 1 : cleanup_all:
427 : 1 : rte_malloc_heap_memory_remove(__func__, memory, heap_size);
428 : 1 : cleanup_allocated_memory:
429 : 1 : free(unaligned_memory);
430 : 1 : cleanup_empty_heap:
431 : 1 : rte_malloc_heap_destroy(__func__);
432 : : end:
433 : : return ret;
434 : : }
435 : :
436 : : #ifdef RTE_EXEC_ENV_WINDOWS
437 : : static int
438 : : test_realloc(void)
439 : : {
440 : : return TEST_SKIPPED;
441 : : }
442 : : #else
443 : :
444 : : static int
445 : 1 : test_realloc_socket(int socket)
446 : : {
447 : 1 : const char hello_str[] = "Hello, world!";
448 : : const unsigned size1 = 1024;
449 : : const unsigned size2 = size1 + 1024;
450 : : const unsigned size3 = size2;
451 : : const unsigned size4 = size3 + 1024;
452 : :
453 : : /* test data is the same even if element is moved*/
454 : 1 : char *ptr1 = rte_zmalloc_socket(
455 : : NULL, size1, RTE_CACHE_LINE_SIZE, socket);
456 [ - + ]: 1 : if (!ptr1){
457 : : printf("NULL pointer returned from rte_zmalloc\n");
458 : 0 : return -1;
459 : : }
460 : : strlcpy(ptr1, hello_str, size1);
461 : 1 : char *ptr2 = rte_realloc_socket(
462 : : ptr1, size2, RTE_CACHE_LINE_SIZE, socket);
463 [ - + ]: 1 : if (!ptr2){
464 : 0 : rte_free(ptr1);
465 : : printf("NULL pointer returned from rte_realloc\n");
466 : 0 : return -1;
467 : : }
468 [ - + ]: 1 : if (ptr1 == ptr2){
469 : : printf("unexpected - ptr1 == ptr2\n");
470 : : }
471 [ - + ]: 1 : if (strcmp(ptr2, hello_str) != 0){
472 : : printf("Error - lost data from pointed area\n");
473 : 0 : rte_free(ptr2);
474 : 0 : return -1;
475 : : }
476 : : unsigned i;
477 [ + + ]: 1012 : for (i = strnlen(hello_str, sizeof(hello_str)); i < size1; i++)
478 [ - + ]: 1011 : if (ptr2[i] != 0){
479 : : printf("Bad data in realloc\n");
480 : 0 : rte_free(ptr2);
481 : 0 : return -1;
482 : : }
483 : : /* now allocate third element, free the second
484 : : * and resize third. It should not move. (ptr1 is now invalid)
485 : : */
486 : 1 : char *ptr3 = rte_zmalloc_socket(
487 : : NULL, size3, RTE_CACHE_LINE_SIZE, socket);
488 [ - + ]: 1 : if (!ptr3){
489 : : printf("NULL pointer returned from rte_zmalloc\n");
490 : 0 : rte_free(ptr2);
491 : 0 : return -1;
492 : : }
493 [ + + ]: 2049 : for (i = 0; i < size3; i++)
494 [ - + ]: 2048 : if (ptr3[i] != 0){
495 : : printf("Bad data in zmalloc\n");
496 : 0 : rte_free(ptr3);
497 : 0 : rte_free(ptr2);
498 : 0 : return -1;
499 : : }
500 : 1 : rte_free(ptr2);
501 : : /* first resize to half the size of the freed block */
502 : 1 : char *ptr4 = rte_realloc_socket(
503 : : ptr3, size4, RTE_CACHE_LINE_SIZE, socket);
504 [ - + ]: 1 : if (!ptr4){
505 : : printf("NULL pointer returned from rte_realloc\n");
506 : 0 : rte_free(ptr3);
507 : 0 : return -1;
508 : : }
509 [ - + ]: 1 : if (ptr3 != ptr4){
510 : : printf("Unexpected - ptr4 != ptr3\n");
511 : 0 : rte_free(ptr4);
512 : 0 : return -1;
513 : : }
514 : : /* now resize again to the full size of the freed block */
515 : 1 : ptr4 = rte_realloc_socket(ptr3, size3 + size2 + size1,
516 : : RTE_CACHE_LINE_SIZE, socket);
517 [ - + ]: 1 : if (ptr3 != ptr4){
518 : : printf("Unexpected - ptr4 != ptr3 on second resize\n");
519 : 0 : rte_free(ptr4);
520 : 0 : return -1;
521 : : }
522 : 1 : rte_free(ptr4);
523 : :
524 : : /* now try a resize to a smaller size, see if it works */
525 : : const unsigned size5 = 1024;
526 : : const unsigned size6 = size5 / 2;
527 : 1 : char *ptr5 = rte_malloc_socket(
528 : : NULL, size5, RTE_CACHE_LINE_SIZE, socket);
529 [ - + ]: 1 : if (!ptr5){
530 : : printf("NULL pointer returned from rte_malloc\n");
531 : 0 : return -1;
532 : : }
533 : 1 : char *ptr6 = rte_realloc_socket(
534 : : ptr5, size6, RTE_CACHE_LINE_SIZE, socket);
535 [ - + ]: 1 : if (!ptr6){
536 : : printf("NULL pointer returned from rte_realloc\n");
537 : 0 : rte_free(ptr5);
538 : 0 : return -1;
539 : : }
540 [ - + ]: 1 : if (ptr5 != ptr6){
541 : : printf("Error, resizing to a smaller size moved data\n");
542 : 0 : rte_free(ptr6);
543 : 0 : return -1;
544 : : }
545 : 1 : rte_free(ptr6);
546 : :
547 : : /* check for behaviour changing alignment */
548 : : const unsigned size7 = 1024;
549 : : const unsigned orig_align = RTE_CACHE_LINE_SIZE;
550 : : unsigned new_align = RTE_CACHE_LINE_SIZE * 2;
551 : 1 : char *ptr7 = rte_malloc_socket(NULL, size7, orig_align, socket);
552 [ - + ]: 1 : if (!ptr7){
553 : : printf("NULL pointer returned from rte_malloc\n");
554 : 0 : return -1;
555 : : }
556 : : /* calc an alignment we don't already have */
557 [ + + ]: 5 : while(RTE_PTR_ALIGN(ptr7, new_align) == ptr7)
558 : 4 : new_align *= 2;
559 : 1 : char *ptr8 = rte_realloc_socket(ptr7, size7, new_align, socket);
560 [ - + ]: 1 : if (!ptr8){
561 : : printf("NULL pointer returned from rte_realloc\n");
562 : 0 : rte_free(ptr7);
563 : 0 : return -1;
564 : : }
565 [ - + ]: 1 : if (RTE_PTR_ALIGN(ptr8, new_align) != ptr8){
566 : : printf("Failure to re-align data\n");
567 : 0 : rte_free(ptr8);
568 : 0 : return -1;
569 : : }
570 : 1 : rte_free(ptr8);
571 : :
572 : : /* test behaviour when there is a free block after current one,
573 : : * but its not big enough
574 : : */
575 : : unsigned size9 = 1024, size10 = 1024;
576 : : unsigned size11 = size9 + size10 + 256;
577 : 1 : char *ptr9 = rte_malloc_socket(
578 : : NULL, size9, RTE_CACHE_LINE_SIZE, socket);
579 [ - + ]: 1 : if (!ptr9){
580 : : printf("NULL pointer returned from rte_malloc\n");
581 : 0 : return -1;
582 : : }
583 : 1 : char *ptr10 = rte_malloc_socket(
584 : : NULL, size10, RTE_CACHE_LINE_SIZE, socket);
585 [ - + ]: 1 : if (!ptr10){
586 : : printf("NULL pointer returned from rte_malloc\n");
587 : 0 : return -1;
588 : : }
589 : 1 : rte_free(ptr9);
590 : 1 : char *ptr11 = rte_realloc_socket(
591 : : ptr10, size11, RTE_CACHE_LINE_SIZE, socket);
592 [ - + ]: 1 : if (!ptr11){
593 : : printf("NULL pointer returned from rte_realloc\n");
594 : 0 : rte_free(ptr10);
595 : 0 : return -1;
596 : : }
597 [ - + ]: 1 : if (ptr11 == ptr10){
598 : : printf("Error, unexpected that realloc has not created new buffer\n");
599 : 0 : rte_free(ptr11);
600 : 0 : return -1;
601 : : }
602 : 1 : rte_free(ptr11);
603 : :
604 : : /* check we don't crash if we pass null to realloc
605 : : * We should get a malloc of the size requested*/
606 : : const size_t size12 = 1024;
607 : : size_t size12_check;
608 : 1 : char *ptr12 = rte_realloc_socket(
609 : : NULL, size12, RTE_CACHE_LINE_SIZE, socket);
610 [ - + ]: 1 : if (!ptr12){
611 : : printf("NULL pointer returned from rte_realloc\n");
612 : 0 : return -1;
613 : : }
614 [ + - ]: 1 : if (rte_malloc_validate(ptr12, &size12_check) < 0 ||
615 [ - + ]: 1 : size12_check != size12){
616 : 0 : rte_free(ptr12);
617 : 0 : return -1;
618 : : }
619 : 1 : rte_free(ptr12);
620 : :
621 : : /* do the same, but for regular memory */
622 : 1 : ptr12 = rte_realloc(NULL, size12, RTE_CACHE_LINE_SIZE);
623 [ - + ]: 1 : if (!ptr12) {
624 : : printf("NULL pointer returned from rte_realloc\n");
625 : 0 : return -1;
626 : : }
627 [ + - ]: 1 : if (rte_malloc_validate(ptr12, &size12_check) < 0 ||
628 [ - + ]: 1 : size12_check != size12) {
629 : 0 : rte_free(ptr12);
630 : 0 : return -1;
631 : : }
632 : 1 : rte_free(ptr12);
633 : :
634 : 1 : return 0;
635 : : }
636 : :
637 : : static int
638 : 1 : test_realloc_numa(void)
639 : : {
640 : : /* check realloc_socket part */
641 : : int32_t socket_count = 0, socket_allocated, socket;
642 : : void *ptr1, *ptr2;
643 : : int ret = -1;
644 : : size_t size = 1024;
645 : :
646 : : ptr1 = NULL;
647 [ + + ]: 33 : for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
648 [ + + ]: 32 : if (is_mem_on_socket(socket)) {
649 : : int j = 2;
650 : :
651 : 2 : socket_count++;
652 [ + + ]: 6 : while (j--) {
653 : : /* j == 1 -> resizing */
654 : 4 : ptr2 = rte_realloc_socket(ptr1, size,
655 : : RTE_CACHE_LINE_SIZE,
656 : : socket);
657 [ - + ]: 4 : if (ptr2 == NULL) {
658 : : printf("NULL pointer returned from rte_realloc_socket\n");
659 : 0 : goto end;
660 : : }
661 : :
662 : : ptr1 = ptr2;
663 : : socket_allocated = addr_to_socket(ptr2);
664 [ - + ]: 4 : if (socket_allocated != socket) {
665 : : printf("Requested socket (%d) doesn't mach allocated one (%d)\n",
666 : : socket, socket_allocated);
667 : 0 : goto end;
668 : : }
669 : 4 : size += RTE_CACHE_LINE_SIZE;
670 : : }
671 : : }
672 : : }
673 : :
674 : : /* Print warning if only a single socket, but don't fail the test */
675 [ - + ]: 1 : if (socket_count < 2)
676 : : printf("WARNING: realloc_socket test needs memory on multiple sockets!\n");
677 : :
678 : : ret = 0;
679 : 1 : end:
680 : 1 : rte_free(ptr1);
681 : 1 : return ret;
682 : : }
683 : :
684 : : static int
685 : 1 : test_realloc(void)
686 : : {
687 : : const char *heap_name = "realloc_heap";
688 : : int realloc_heap_socket;
689 : : unsigned int mem_sz = 1U << 13; /* 8K */
690 : 1 : unsigned int page_sz = sysconf(_SC_PAGESIZE);
691 : : void *mem;
692 : : int ret;
693 : :
694 : : /* page size may be bigger than total mem size, so adjust */
695 : 1 : mem_sz = RTE_MAX(mem_sz, page_sz);
696 : :
697 : : /*
698 : : * the realloc tests depend on specific layout of underlying memory, so
699 : : * to prevent accidental failures to do fragmented main heap, we will
700 : : * do all of our tests on an artificially created memory.
701 : : */
702 [ - + ]: 1 : if (rte_malloc_heap_create(heap_name) != 0) {
703 : : printf("Failed to create external heap\n");
704 : : ret = -1;
705 : 0 : goto end;
706 : : }
707 : 1 : realloc_heap_socket = rte_malloc_heap_get_socket(heap_name);
708 : :
709 : 1 : mem = mmap(NULL, mem_sz, PROT_READ | PROT_WRITE,
710 : : MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
711 [ - + ]: 1 : if (mem == MAP_FAILED) {
712 : : printf("Failed to allocate memory for external heap\n");
713 : : ret = -1;
714 : 0 : goto heap_destroy;
715 : : }
716 : :
717 [ - + ]: 1 : if (rte_malloc_heap_memory_add(
718 : : heap_name, mem, mem_sz, NULL, 0, page_sz) != 0) {
719 : : printf("Failed to add memory to external heap\n");
720 : : ret = -1;
721 : 0 : goto mem_free;
722 : : }
723 : :
724 : : /* run the socket-bound tests */
725 : 1 : ret = test_realloc_socket(realloc_heap_socket);
726 [ - + ]: 1 : if (ret != 0)
727 : 0 : goto mem_remove;
728 : :
729 : : /* now, run the NUMA node tests */
730 : 1 : ret = test_realloc_numa();
731 : :
732 : 1 : mem_remove:
733 : 1 : rte_malloc_heap_memory_remove(heap_name, mem, mem_sz);
734 : 1 : mem_free:
735 : 1 : munmap(mem, mem_sz);
736 : 1 : heap_destroy:
737 : 1 : rte_malloc_heap_destroy(heap_name);
738 : 1 : end:
739 : 1 : return ret;
740 : : }
741 : :
742 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
743 : :
744 : : static int
745 : 1 : test_random_alloc_free(void *_ __rte_unused)
746 : : {
747 : : struct mem_list {
748 : : struct mem_list *next;
749 : : char data[0];
750 : : } *list_head = NULL;
751 : : unsigned i;
752 : : unsigned count = 0;
753 : :
754 [ + + ]: 10001 : for (i = 0; i < N; i++){
755 : : unsigned free_mem = 0;
756 : : size_t allocated_size;
757 [ + + ]: 59862 : while (!free_mem){
758 : 49862 : const unsigned mem_size = sizeof(struct mem_list) + \
759 : 49862 : rte_rand() % (64 * 1024);
760 : 49862 : const unsigned align = 1 << (rte_rand() % 12); /* up to 4k alignment */
761 : 49862 : struct mem_list *entry = rte_malloc(NULL,
762 : : mem_size, align);
763 [ + - ]: 49862 : if (entry == NULL)
764 : 0 : return -1;
765 [ + - ]: 49862 : if (RTE_PTR_ALIGN(entry, align)!= entry)
766 : : return -1;
767 [ + - ]: 49862 : if (rte_malloc_validate(entry, &allocated_size) == -1
768 [ + - ]: 49862 : || allocated_size < mem_size)
769 : : return -1;
770 : 49862 : memset(entry->data, rte_lcore_id(),
771 : : mem_size - sizeof(*entry));
772 : 49862 : entry->next = list_head;
773 [ + - ]: 49862 : if (rte_malloc_validate(entry, NULL) == -1)
774 : : return -1;
775 : : list_head = entry;
776 : :
777 : 49862 : count++;
778 : : /* switch to freeing the memory with a 20% probability */
779 : 49862 : free_mem = ((rte_rand() % 10) >= 8);
780 : : }
781 [ + + ]: 59862 : while (list_head){
782 : : struct mem_list *entry = list_head;
783 : 49862 : list_head = list_head->next;
784 : 49862 : rte_free(entry);
785 : : }
786 : : }
787 : : printf("Lcore %u allocated/freed %u blocks\n", rte_lcore_id(), count);
788 : 1 : return 0;
789 : : }
790 : :
791 : : static int
792 : 1 : test_random(void)
793 : : {
794 : : unsigned int lcore_id;
795 : : int ret = 0;
796 : :
797 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
798 : 1 : rte_eal_remote_launch(test_random_alloc_free, NULL, lcore_id);
799 : : }
800 : :
801 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
802 [ - + ]: 1 : if (rte_eal_wait_lcore(lcore_id) < 0)
803 : : ret = -1;
804 : : }
805 : 1 : return ret;
806 : : }
807 : :
808 : : #define err_return() do { \
809 : : printf("%s: %d - Error\n", __func__, __LINE__); \
810 : : goto err_return; \
811 : : } while (0)
812 : :
813 : : static int
814 : 1 : test_rte_malloc_validate(void)
815 : : {
816 : : const size_t request_size = 1024;
817 : : size_t allocated_size;
818 : 1 : char *data_ptr = rte_malloc(NULL, request_size, RTE_CACHE_LINE_SIZE);
819 : : #ifdef RTE_MALLOC_DEBUG
820 : : int retval;
821 : : char *over_write_vals = NULL;
822 : : #endif
823 : :
824 [ - + ]: 1 : if (data_ptr == NULL) {
825 : : printf("%s: %d - Allocation error\n", __func__, __LINE__);
826 : 0 : return -1;
827 : : }
828 : :
829 : : /* check that a null input returns -1 */
830 [ - + ]: 1 : if (rte_malloc_validate(NULL, NULL) != -1)
831 : 0 : err_return();
832 : :
833 : : /* check that we get ok on a valid pointer */
834 [ - + ]: 1 : if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
835 : 0 : err_return();
836 : :
837 : : /* check that the returned size is ok */
838 [ - + ]: 1 : if (allocated_size < request_size)
839 : 0 : err_return();
840 : :
841 : : #ifdef RTE_MALLOC_DEBUG
842 : :
843 : : /****** change the header to be bad */
844 : : char save_buf[64];
845 : : over_write_vals = (char *)((uintptr_t)data_ptr - sizeof(save_buf));
846 : : /* first save the data as a backup before overwriting it */
847 : : memcpy(save_buf, over_write_vals, sizeof(save_buf));
848 : : memset(over_write_vals, 1, sizeof(save_buf));
849 : : /* then run validate */
850 : : retval = rte_malloc_validate(data_ptr, NULL);
851 : : /* finally restore the data again */
852 : : memcpy(over_write_vals, save_buf, sizeof(save_buf));
853 : : /* check we previously had an error */
854 : : if (retval != -1)
855 : : err_return();
856 : :
857 : : /* check all ok again */
858 : : if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
859 : : err_return();
860 : :
861 : : /**** change the trailer to be bad */
862 : : over_write_vals = (char *)((uintptr_t)data_ptr + allocated_size);
863 : : /* first save the data as a backup before overwriting it */
864 : : memcpy(save_buf, over_write_vals, sizeof(save_buf));
865 : : memset(over_write_vals, 1, sizeof(save_buf));
866 : : /* then run validate */
867 : : retval = rte_malloc_validate(data_ptr, NULL);
868 : : /* finally restore the data again */
869 : : memcpy(over_write_vals, save_buf, sizeof(save_buf));
870 : : if (retval != -1)
871 : : err_return();
872 : :
873 : : /* check all ok again */
874 : : if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
875 : : err_return();
876 : : #endif
877 : :
878 : 1 : rte_free(data_ptr);
879 : 1 : return 0;
880 : :
881 : 0 : err_return:
882 : : /*clean up */
883 : 0 : rte_free(data_ptr);
884 : 0 : return -1;
885 : : }
886 : :
887 : : static int
888 : 1 : test_zero_aligned_alloc(void)
889 : : {
890 : 1 : char *p1 = rte_malloc(NULL,1024, 0);
891 [ - + ]: 1 : if (!p1)
892 : 0 : goto err_return;
893 [ - + ]: 1 : if (!rte_is_aligned(p1, RTE_CACHE_LINE_SIZE))
894 : 0 : goto err_return;
895 : 1 : rte_free(p1);
896 : 1 : return 0;
897 : :
898 : 0 : err_return:
899 : : /*clean up */
900 : 0 : rte_free(p1);
901 : 0 : return -1;
902 : : }
903 : :
904 : : static int
905 : 1 : test_malloc_bad_params(void)
906 : : {
907 : : const char *type = NULL;
908 : : size_t size = 0;
909 : : unsigned align = RTE_CACHE_LINE_SIZE;
910 : :
911 : : /* rte_malloc expected to return null with inappropriate size */
912 : 1 : char *bad_ptr = rte_malloc(type, size, align);
913 [ - + ]: 1 : if (bad_ptr != NULL)
914 : 0 : goto err_return;
915 : :
916 : : /* rte_realloc expected to return null with inappropriate size */
917 : 1 : bad_ptr = rte_realloc(NULL, size, align);
918 [ - + ]: 1 : if (bad_ptr != NULL)
919 : 0 : goto err_return;
920 : :
921 : : /* rte_malloc expected to return null with inappropriate alignment */
922 : : align = 17;
923 : : size = 1024;
924 : :
925 : 1 : bad_ptr = rte_malloc(type, size, align);
926 [ - + ]: 1 : if (bad_ptr != NULL)
927 : 0 : goto err_return;
928 : :
929 : : /* rte_realloc expected to return null with inappropriate alignment */
930 : 1 : bad_ptr = rte_realloc(NULL, size, align);
931 [ - + ]: 1 : if (bad_ptr != NULL)
932 : 0 : goto err_return;
933 : :
934 : : #if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
935 : : /* this test can not be built, will get trapped at compile time! */
936 : : #else
937 : : /* rte_malloc expected to return null with size will cause overflow */
938 : : align = RTE_CACHE_LINE_SIZE;
939 : : size = (size_t)-8;
940 : :
941 : : bad_ptr = rte_malloc(type, size, align);
942 : : if (bad_ptr != NULL)
943 : : goto err_return;
944 : :
945 : : bad_ptr = rte_realloc(NULL, size, align);
946 : : if (bad_ptr != NULL)
947 : : goto err_return;
948 : : #endif
949 : : return 0;
950 : :
951 : 0 : err_return:
952 : : /* clean up pointer */
953 : 0 : rte_free(bad_ptr);
954 : 0 : return -1;
955 : : }
956 : :
957 : : static int
958 : 156 : check_socket_mem(const struct rte_memseg_list *msl, void *arg)
959 : : {
960 : : int32_t *socket = arg;
961 : :
962 [ + + ]: 156 : if (msl->external)
963 : : return 0;
964 : :
965 : 126 : return *socket == msl->socket_id;
966 : : }
967 : :
968 : : /* Check if memory is available on a specific socket */
969 : : static int
970 : : is_mem_on_socket(int32_t socket)
971 : : {
972 : 32 : return rte_memseg_list_walk(check_socket_mem, &socket);
973 : : }
974 : :
975 : :
976 : : /*
977 : : * Find what socket a memory address is on. Only works for addresses within
978 : : * memsegs, not heap or stack...
979 : : */
980 : : static int32_t
981 : : addr_to_socket(void * addr)
982 : : {
983 : 13 : const struct rte_memseg *ms = rte_mem_virt2memseg(addr, NULL);
984 [ + - + - : 13 : return ms == NULL ? -1 : ms->socket_id;
+ - + - ]
985 : :
986 : : }
987 : :
988 : : /* Test using rte_[c|m|zm]alloc_socket() on a specific socket */
989 : : static int
990 : 33 : test_alloc_single_socket(int32_t socket)
991 : : {
992 : : const char *type = NULL;
993 : : const size_t size = 10;
994 : : const unsigned align = 0;
995 : : char *mem = NULL;
996 : : int32_t desired_socket = (socket == SOCKET_ID_ANY) ?
997 [ + + ]: 33 : (int32_t)rte_socket_id() : socket;
998 : :
999 : : /* Test rte_calloc_socket() */
1000 : 33 : mem = rte_calloc_socket(type, size, sizeof(char), align, socket);
1001 [ + + ]: 33 : if (mem == NULL)
1002 : : return -1;
1003 [ - + ]: 3 : if (addr_to_socket(mem) != desired_socket) {
1004 : 0 : rte_free(mem);
1005 : 0 : return -1;
1006 : : }
1007 : 3 : rte_free(mem);
1008 : :
1009 : : /* Test rte_malloc_socket() */
1010 : 3 : mem = rte_malloc_socket(type, size, align, socket);
1011 [ + - ]: 3 : if (mem == NULL)
1012 : : return -1;
1013 [ - + ]: 3 : if (addr_to_socket(mem) != desired_socket) {
1014 : 0 : rte_free(mem);
1015 : 0 : return -1;
1016 : : }
1017 : 3 : rte_free(mem);
1018 : :
1019 : : /* Test rte_zmalloc_socket() */
1020 : 3 : mem = rte_zmalloc_socket(type, size, align, socket);
1021 [ + - ]: 3 : if (mem == NULL)
1022 : : return -1;
1023 [ - + ]: 3 : if (addr_to_socket(mem) != desired_socket) {
1024 : 0 : rte_free(mem);
1025 : 0 : return -1;
1026 : : }
1027 : 3 : rte_free(mem);
1028 : :
1029 : 3 : return 0;
1030 : : }
1031 : :
1032 : : static int
1033 : 1 : test_alloc_socket(void)
1034 : : {
1035 : : unsigned socket_count = 0;
1036 : : unsigned i;
1037 : :
1038 [ + - ]: 1 : if (test_alloc_single_socket(SOCKET_ID_ANY) < 0)
1039 : : return -1;
1040 : :
1041 [ + + ]: 33 : for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
1042 [ + + ]: 32 : if (is_mem_on_socket(i)) {
1043 : 2 : socket_count++;
1044 [ - + ]: 2 : if (test_alloc_single_socket(i) < 0) {
1045 : : printf("Fail: rte_malloc_socket(..., %u) did not succeed\n",
1046 : : i);
1047 : 0 : return -1;
1048 : : }
1049 : : }
1050 : : else {
1051 [ - + ]: 30 : if (test_alloc_single_socket(i) == 0) {
1052 : : printf("Fail: rte_malloc_socket(..., %u) succeeded\n",
1053 : : i);
1054 : 0 : return -1;
1055 : : }
1056 : : }
1057 : : }
1058 : :
1059 : : /* Print warning if only a single socket, but don't fail the test */
1060 [ - + ]: 1 : if (socket_count < 2) {
1061 : : printf("WARNING: alloc_socket test needs memory on multiple sockets!\n");
1062 : : }
1063 : :
1064 : : return 0;
1065 : : }
1066 : :
1067 : : static int
1068 : 1 : run_rte_free_sensitive(void *arg)
1069 : : {
1070 : 1 : rte_free_sensitive(arg);
1071 : 1 : return 0;
1072 : : }
1073 : :
1074 : : /* Check that memory freed is zero now.
1075 : : * Need to disable address sanitizer since use after free is intentional here.
1076 : : */
1077 : : __rte_no_asan
1078 : : static int
1079 : : check_free_memory_is_zero(const char *data, size_t sz)
1080 : : {
1081 [ + + ]: 129 : for (unsigned int i = 0; i < sz; i++)
1082 [ + - ]: 128 : if (data[i] != 0)
1083 : : return 0;
1084 : : return 1;
1085 : : }
1086 : :
1087 : : static int
1088 : 1 : test_free_sensitive(void)
1089 : : {
1090 : : #define SENSITIVE_KEY_SIZE 128
1091 : :
1092 [ - + ]: 1 : if (rte_lcore_count() < 2) {
1093 : : printf("Need multiple cores to run memzero explicit test.\n");
1094 : 0 : return TEST_SKIPPED;
1095 : : }
1096 : :
1097 : 1 : unsigned int worker_lcore_id = rte_get_next_lcore(-1, 1, 0);
1098 [ - + ]: 1 : TEST_ASSERT(worker_lcore_id < RTE_MAX_LCORE, "get_next_lcore failed");
1099 : :
1100 : : /* Allocate a buffer and fill with sensitive data */
1101 : 1 : char *key = rte_zmalloc("dummy", SENSITIVE_KEY_SIZE, 0);
1102 [ - + ]: 1 : TEST_ASSERT(key != NULL, "rte_zmalloc failed");
1103 : 1 : rte_strscpy(key, "Super secret key", SENSITIVE_KEY_SIZE);
1104 : :
1105 : : /* Pass that data to worker thread to free */
1106 : 1 : int rc = rte_eal_remote_launch(run_rte_free_sensitive, key, worker_lcore_id);
1107 [ - + ]: 1 : TEST_ASSERT(rc == 0, "Worker thread launch failed");
1108 : :
1109 : : /* Wait for worker */
1110 : 1 : rte_eal_mp_wait_lcore();
1111 : :
1112 [ - + ]: 1 : TEST_ASSERT(check_free_memory_is_zero(key, SENSITIVE_KEY_SIZE),
1113 : : "rte_free_sensitive data not zero");
1114 : :
1115 : : return 0;
1116 : : }
1117 : :
1118 : : static struct unit_test_suite test_suite = {
1119 : : .suite_name = "Malloc test suite",
1120 : : .unit_test_cases = {
1121 : : TEST_CASE(test_zero_aligned_alloc),
1122 : : TEST_CASE(test_malloc_bad_params),
1123 : : TEST_CASE(test_realloc),
1124 : : TEST_CASE(test_align_overlap),
1125 : : TEST_CASE(test_reordered_free),
1126 : : TEST_CASE(test_random),
1127 : : TEST_CASE(test_rte_malloc_validate),
1128 : : TEST_CASE(test_alloc_socket),
1129 : : TEST_CASE(test_multi_alloc_statistics),
1130 : : TEST_CASE(test_free_sensitive),
1131 : : TEST_CASES_END()
1132 : : }
1133 : : };
1134 : :
1135 : : static int
1136 : 1 : test_malloc(void)
1137 : : {
1138 : 1 : return unit_test_suite_runner(&test_suite);
1139 : : }
1140 : :
1141 : 302 : REGISTER_FAST_TEST(malloc_autotest, NOHUGE_SKIP, ASAN_OK, test_malloc);
|