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