1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2014, STMicroelectronics International N.V. 4 */ 5 6 #define PROTOTYPES 7 8 /* 9 * BGET CONFIGURATION 10 * ================== 11 */ 12 /* #define BGET_ENABLE_ALL_OPTIONS */ 13 #ifdef BGET_ENABLE_OPTION 14 #define TestProg 20000 /* Generate built-in test program 15 if defined. The value specifies 16 how many buffer allocation attempts 17 the test program should make. */ 18 #endif 19 20 21 #ifdef __LP64__ 22 #define SizeQuant 16 23 #endif 24 #ifdef __ILP32__ 25 #define SizeQuant 8 26 #endif 27 /* Buffer allocation size quantum: 28 all buffers allocated are a 29 multiple of this size. This 30 MUST be a power of two. */ 31 32 #ifdef BGET_ENABLE_OPTION 33 #define BufDump 1 /* Define this symbol to enable the 34 bpoold() function which dumps the 35 buffers in a buffer pool. */ 36 37 #define BufValid 1 /* Define this symbol to enable the 38 bpoolv() function for validating 39 a buffer pool. */ 40 41 #define DumpData 1 /* Define this symbol to enable the 42 bufdump() function which allows 43 dumping the contents of an allocated 44 or free buffer. */ 45 46 #define BufStats 1 /* Define this symbol to enable the 47 bstats() function which calculates 48 the total free space in the buffer 49 pool, the largest available 50 buffer, and the total space 51 currently allocated. */ 52 53 #define FreeWipe 1 /* Wipe free buffers to a guaranteed 54 pattern of garbage to trip up 55 miscreants who attempt to use 56 pointers into released buffers. */ 57 58 #define BestFit 1 /* Use a best fit algorithm when 59 searching for space for an 60 allocation request. This uses 61 memory more efficiently, but 62 allocation will be much slower. */ 63 64 #define BECtl 1 /* Define this symbol to enable the 65 bectl() function for automatic 66 pool space control. */ 67 #endif 68 69 #ifdef MEM_DEBUG 70 #undef NDEBUG 71 #define DumpData 1 72 #define BufValid 1 73 #define FreeWipe 1 74 #endif 75 76 #ifdef CFG_WITH_STATS 77 #define BufStats 1 78 #endif 79 80 #include <compiler.h> 81 #include <malloc.h> 82 #include <stdbool.h> 83 #include <stdint.h> 84 #include <stdlib.h> 85 #include <stdlib_ext.h> 86 #include <string.h> 87 #include <trace.h> 88 #include <util.h> 89 90 #if defined(__KERNEL__) 91 /* Compiling for TEE Core */ 92 #include <kernel/asan.h> 93 #include <kernel/thread.h> 94 #include <kernel/spinlock.h> 95 #include <kernel/unwind.h> 96 97 static void tag_asan_free(void *buf, size_t len) 98 { 99 asan_tag_heap_free(buf, (uint8_t *)buf + len); 100 } 101 102 static void tag_asan_alloced(void *buf, size_t len) 103 { 104 asan_tag_access(buf, (uint8_t *)buf + len); 105 } 106 107 static void *memset_unchecked(void *s, int c, size_t n) 108 { 109 return asan_memset_unchecked(s, c, n); 110 } 111 112 static __maybe_unused void *memcpy_unchecked(void *dst, const void *src, 113 size_t n) 114 { 115 return asan_memcpy_unchecked(dst, src, n); 116 } 117 118 #else /*__KERNEL__*/ 119 /* Compiling for TA */ 120 121 static void tag_asan_free(void *buf __unused, size_t len __unused) 122 { 123 } 124 125 static void tag_asan_alloced(void *buf __unused, size_t len __unused) 126 { 127 } 128 129 static void *memset_unchecked(void *s, int c, size_t n) 130 { 131 return memset(s, c, n); 132 } 133 134 static __maybe_unused void *memcpy_unchecked(void *dst, const void *src, 135 size_t n) 136 { 137 return memcpy(dst, src, n); 138 } 139 140 #endif /*__KERNEL__*/ 141 142 #include "bget.c" /* this is ugly, but this is bget */ 143 144 struct malloc_pool { 145 void *buf; 146 size_t len; 147 }; 148 149 struct malloc_ctx { 150 struct bpoolset poolset; 151 struct malloc_pool *pool; 152 size_t pool_len; 153 #ifdef BufStats 154 struct malloc_stats mstats; 155 #endif 156 #ifdef __KERNEL__ 157 unsigned int spinlock; 158 #endif 159 }; 160 161 #ifdef __KERNEL__ 162 163 static uint32_t malloc_lock(struct malloc_ctx *ctx) 164 { 165 return cpu_spin_lock_xsave(&ctx->spinlock); 166 } 167 168 static void malloc_unlock(struct malloc_ctx *ctx, uint32_t exceptions) 169 { 170 cpu_spin_unlock_xrestore(&ctx->spinlock, exceptions); 171 } 172 173 #else /* __KERNEL__ */ 174 175 static uint32_t malloc_lock(struct malloc_ctx *ctx __unused) 176 { 177 return 0; 178 } 179 180 static void malloc_unlock(struct malloc_ctx *ctx __unused, 181 uint32_t exceptions __unused) 182 { 183 } 184 185 #endif /* __KERNEL__ */ 186 187 #define DEFINE_CTX(name) struct malloc_ctx name = \ 188 { .poolset = { .freelist = { {0, 0}, \ 189 {&name.poolset.freelist, \ 190 &name.poolset.freelist}}}} 191 192 static DEFINE_CTX(malloc_ctx); 193 194 #ifdef CFG_VIRTUALIZATION 195 static __nex_data DEFINE_CTX(nex_malloc_ctx); 196 #endif 197 198 static void print_oom(size_t req_size __maybe_unused, void *ctx __maybe_unused) 199 { 200 #if defined(__KERNEL__) && defined(CFG_CORE_DUMP_OOM) 201 EMSG("Memory allocation failed: size %zu context %p", req_size, ctx); 202 print_kernel_stack(); 203 #endif 204 } 205 206 #ifdef BufStats 207 208 static void raw_malloc_return_hook(void *p, size_t requested_size, 209 struct malloc_ctx *ctx) 210 { 211 if (ctx->poolset.totalloc > ctx->mstats.max_allocated) 212 ctx->mstats.max_allocated = ctx->poolset.totalloc; 213 214 if (!p) { 215 ctx->mstats.num_alloc_fail++; 216 print_oom(requested_size, ctx); 217 if (requested_size > ctx->mstats.biggest_alloc_fail) { 218 ctx->mstats.biggest_alloc_fail = requested_size; 219 ctx->mstats.biggest_alloc_fail_used = 220 ctx->poolset.totalloc; 221 } 222 } 223 } 224 225 static void gen_malloc_reset_stats(struct malloc_ctx *ctx) 226 { 227 uint32_t exceptions = malloc_lock(ctx); 228 229 ctx->mstats.max_allocated = 0; 230 ctx->mstats.num_alloc_fail = 0; 231 ctx->mstats.biggest_alloc_fail = 0; 232 ctx->mstats.biggest_alloc_fail_used = 0; 233 malloc_unlock(ctx, exceptions); 234 } 235 236 void malloc_reset_stats(void) 237 { 238 gen_malloc_reset_stats(&malloc_ctx); 239 } 240 241 static void gen_malloc_get_stats(struct malloc_ctx *ctx, 242 struct malloc_stats *stats) 243 { 244 uint32_t exceptions = malloc_lock(ctx); 245 246 memcpy_unchecked(stats, &ctx->mstats, sizeof(*stats)); 247 stats->allocated = ctx->poolset.totalloc; 248 malloc_unlock(ctx, exceptions); 249 } 250 251 void malloc_get_stats(struct malloc_stats *stats) 252 { 253 gen_malloc_get_stats(&malloc_ctx, stats); 254 } 255 256 #else /* BufStats */ 257 258 static void raw_malloc_return_hook(void *p, size_t requested_size, 259 struct malloc_ctx *ctx ) 260 { 261 if (!p) 262 print_oom(requested_size, ctx); 263 } 264 265 #endif /* BufStats */ 266 267 #ifdef BufValid 268 static void raw_malloc_validate_pools(struct malloc_ctx *ctx) 269 { 270 size_t n; 271 272 for (n = 0; n < ctx->pool_len; n++) 273 bpoolv(ctx->pool[n].buf); 274 } 275 #else 276 static void raw_malloc_validate_pools(struct malloc_ctx *ctx __unused) 277 { 278 } 279 #endif 280 281 struct bpool_iterator { 282 struct bfhead *next_buf; 283 size_t pool_idx; 284 }; 285 286 static void bpool_foreach_iterator_init(struct malloc_ctx *ctx, 287 struct bpool_iterator *iterator) 288 { 289 iterator->pool_idx = 0; 290 iterator->next_buf = BFH(ctx->pool[0].buf); 291 } 292 293 static bool bpool_foreach_pool(struct bpool_iterator *iterator, void **buf, 294 size_t *len, bool *isfree) 295 { 296 struct bfhead *b = iterator->next_buf; 297 bufsize bs = b->bh.bsize; 298 299 if (bs == ESent) 300 return false; 301 302 if (bs < 0) { 303 /* Allocated buffer */ 304 bs = -bs; 305 306 *isfree = false; 307 } else { 308 /* Free Buffer */ 309 *isfree = true; 310 311 /* Assert that the free list links are intact */ 312 assert(b->ql.blink->ql.flink == b); 313 assert(b->ql.flink->ql.blink == b); 314 } 315 316 *buf = (uint8_t *)b + sizeof(struct bhead); 317 *len = bs - sizeof(struct bhead); 318 319 iterator->next_buf = BFH((uint8_t *)b + bs); 320 return true; 321 } 322 323 static bool bpool_foreach(struct malloc_ctx *ctx, 324 struct bpool_iterator *iterator, void **buf) 325 { 326 while (true) { 327 size_t len; 328 bool isfree; 329 330 if (bpool_foreach_pool(iterator, buf, &len, &isfree)) { 331 if (isfree) 332 continue; 333 return true; 334 } 335 336 if ((iterator->pool_idx + 1) >= ctx->pool_len) 337 return false; 338 339 iterator->pool_idx++; 340 iterator->next_buf = BFH(ctx->pool[iterator->pool_idx].buf); 341 } 342 } 343 344 /* Convenience macro for looping over all allocated buffers */ 345 #define BPOOL_FOREACH(ctx, iterator, bp) \ 346 for (bpool_foreach_iterator_init((ctx),(iterator)); \ 347 bpool_foreach((ctx),(iterator), (bp));) 348 349 static void *raw_memalign(size_t hdr_size, size_t ftr_size, size_t alignment, 350 size_t pl_size, struct malloc_ctx *ctx) 351 { 352 void *ptr = NULL; 353 bufsize s; 354 355 if (!alignment || !IS_POWER_OF_TWO(alignment)) 356 return NULL; 357 358 raw_malloc_validate_pools(ctx); 359 360 /* Compute total size, excluding the header */ 361 if (ADD_OVERFLOW(pl_size, ftr_size, &s)) 362 goto out; 363 364 /* BGET doesn't like 0 sized allocations */ 365 if (!s) 366 s++; 367 368 ptr = bget(alignment, hdr_size, s, &ctx->poolset); 369 out: 370 raw_malloc_return_hook(ptr, pl_size, ctx); 371 372 return ptr; 373 } 374 375 static void *raw_malloc(size_t hdr_size, size_t ftr_size, size_t pl_size, 376 struct malloc_ctx *ctx) 377 { 378 /* 379 * Note that we're feeding SizeQ as alignment, this is the smallest 380 * alignment that bget() can use. 381 */ 382 return raw_memalign(hdr_size, ftr_size, SizeQ, pl_size, ctx); 383 } 384 385 static void raw_free(void *ptr, struct malloc_ctx *ctx, bool wipe) 386 { 387 raw_malloc_validate_pools(ctx); 388 389 if (ptr) 390 brel(ptr, &ctx->poolset, wipe); 391 } 392 393 static void *raw_calloc(size_t hdr_size, size_t ftr_size, size_t pl_nmemb, 394 size_t pl_size, struct malloc_ctx *ctx) 395 { 396 void *ptr = NULL; 397 bufsize s; 398 399 raw_malloc_validate_pools(ctx); 400 401 /* Compute total size, excluding hdr_size */ 402 if (MUL_OVERFLOW(pl_nmemb, pl_size, &s)) 403 goto out; 404 if (ADD_OVERFLOW(s, ftr_size, &s)) 405 goto out; 406 407 /* BGET doesn't like 0 sized allocations */ 408 if (!s) 409 s++; 410 411 ptr = bgetz(0, hdr_size, s, &ctx->poolset); 412 out: 413 raw_malloc_return_hook(ptr, pl_nmemb * pl_size, ctx); 414 415 return ptr; 416 } 417 418 static void *raw_realloc(void *ptr, size_t hdr_size, size_t ftr_size, 419 size_t pl_size, struct malloc_ctx *ctx) 420 { 421 void *p = NULL; 422 bufsize s; 423 424 /* Compute total size */ 425 if (ADD_OVERFLOW(pl_size, hdr_size, &s)) 426 goto out; 427 if (ADD_OVERFLOW(s, ftr_size, &s)) 428 goto out; 429 430 raw_malloc_validate_pools(ctx); 431 432 /* BGET doesn't like 0 sized allocations */ 433 if (!s) 434 s++; 435 436 p = bgetr(ptr, 0, 0, s, &ctx->poolset); 437 out: 438 raw_malloc_return_hook(p, pl_size, ctx); 439 440 return p; 441 } 442 443 /* Most of the stuff in this function is copied from bgetr() in bget.c */ 444 static __maybe_unused bufsize bget_buf_size(void *buf) 445 { 446 bufsize osize; /* Old size of buffer */ 447 struct bhead *b; 448 449 b = BH(((char *)buf) - sizeof(struct bhead)); 450 osize = -b->bsize; 451 #ifdef BECtl 452 if (osize == 0) { 453 /* Buffer acquired directly through acqfcn. */ 454 struct bdhead *bd; 455 456 bd = BDH(((char *)buf) - sizeof(struct bdhead)); 457 osize = bd->tsize - sizeof(struct bdhead) - bd->offs; 458 } else 459 #endif 460 osize -= sizeof(struct bhead); 461 assert(osize > 0); 462 return osize; 463 } 464 465 #ifdef ENABLE_MDBG 466 467 struct mdbg_hdr { 468 const char *fname; 469 uint16_t line; 470 uint32_t pl_size; 471 uint32_t magic; 472 #if defined(ARM64) 473 uint64_t pad; 474 #endif 475 }; 476 477 #define MDBG_HEADER_MAGIC 0xadadadad 478 #define MDBG_FOOTER_MAGIC 0xecececec 479 480 static size_t mdbg_get_ftr_size(size_t pl_size) 481 { 482 size_t ftr_pad = ROUNDUP(pl_size, sizeof(uint32_t)) - pl_size; 483 484 return ftr_pad + sizeof(uint32_t); 485 } 486 487 static uint32_t *mdbg_get_footer(struct mdbg_hdr *hdr) 488 { 489 uint32_t *footer; 490 491 footer = (uint32_t *)((uint8_t *)(hdr + 1) + hdr->pl_size + 492 mdbg_get_ftr_size(hdr->pl_size)); 493 footer--; 494 return footer; 495 } 496 497 static void mdbg_update_hdr(struct mdbg_hdr *hdr, const char *fname, 498 int lineno, size_t pl_size) 499 { 500 uint32_t *footer; 501 502 hdr->fname = fname; 503 hdr->line = lineno; 504 hdr->pl_size = pl_size; 505 hdr->magic = MDBG_HEADER_MAGIC; 506 507 footer = mdbg_get_footer(hdr); 508 *footer = MDBG_FOOTER_MAGIC; 509 } 510 511 static void *gen_mdbg_malloc(struct malloc_ctx *ctx, const char *fname, 512 int lineno, size_t size) 513 { 514 struct mdbg_hdr *hdr; 515 uint32_t exceptions = malloc_lock(ctx); 516 517 /* 518 * Check struct mdbg_hdr works with BGET_HDR_QUANTUM. 519 */ 520 COMPILE_TIME_ASSERT((sizeof(struct mdbg_hdr) % BGET_HDR_QUANTUM) == 0); 521 522 hdr = raw_malloc(sizeof(struct mdbg_hdr), 523 mdbg_get_ftr_size(size), size, ctx); 524 if (hdr) { 525 mdbg_update_hdr(hdr, fname, lineno, size); 526 hdr++; 527 } 528 529 malloc_unlock(ctx, exceptions); 530 return hdr; 531 } 532 533 static void assert_header(struct mdbg_hdr *hdr __maybe_unused) 534 { 535 assert(hdr->magic == MDBG_HEADER_MAGIC); 536 assert(*mdbg_get_footer(hdr) == MDBG_FOOTER_MAGIC); 537 } 538 539 static void gen_mdbg_free(struct malloc_ctx *ctx, void *ptr, bool wipe) 540 { 541 struct mdbg_hdr *hdr = ptr; 542 543 if (hdr) { 544 hdr--; 545 assert_header(hdr); 546 hdr->magic = 0; 547 *mdbg_get_footer(hdr) = 0; 548 raw_free(hdr, ctx, wipe); 549 } 550 } 551 552 static void free_helper(void *ptr, bool wipe) 553 { 554 uint32_t exceptions = malloc_lock(&malloc_ctx); 555 556 gen_mdbg_free(&malloc_ctx, ptr, wipe); 557 malloc_unlock(&malloc_ctx, exceptions); 558 } 559 560 static void *gen_mdbg_calloc(struct malloc_ctx *ctx, const char *fname, int lineno, 561 size_t nmemb, size_t size) 562 { 563 struct mdbg_hdr *hdr; 564 uint32_t exceptions = malloc_lock(ctx); 565 566 hdr = raw_calloc(sizeof(struct mdbg_hdr), 567 mdbg_get_ftr_size(nmemb * size), nmemb, size, 568 ctx); 569 if (hdr) { 570 mdbg_update_hdr(hdr, fname, lineno, nmemb * size); 571 hdr++; 572 } 573 malloc_unlock(ctx, exceptions); 574 return hdr; 575 } 576 577 static void *gen_mdbg_realloc_unlocked(struct malloc_ctx *ctx, const char *fname, 578 int lineno, void *ptr, size_t size) 579 { 580 struct mdbg_hdr *hdr = ptr; 581 582 if (hdr) { 583 hdr--; 584 assert_header(hdr); 585 } 586 hdr = raw_realloc(hdr, sizeof(struct mdbg_hdr), 587 mdbg_get_ftr_size(size), size, ctx); 588 if (hdr) { 589 mdbg_update_hdr(hdr, fname, lineno, size); 590 hdr++; 591 } 592 return hdr; 593 } 594 595 static void *gen_mdbg_realloc(struct malloc_ctx *ctx, const char *fname, 596 int lineno, void *ptr, size_t size) 597 { 598 void *p; 599 uint32_t exceptions = malloc_lock(ctx); 600 601 p = gen_mdbg_realloc_unlocked(ctx, fname, lineno, ptr, size); 602 malloc_unlock(ctx, exceptions); 603 return p; 604 } 605 606 #define realloc_unlocked(ctx, ptr, size) \ 607 gen_mdbg_realloc_unlocked(ctx, __FILE__, __LINE__, (ptr), (size)) 608 609 static void *gen_mdbg_memalign(struct malloc_ctx *ctx, const char *fname, 610 int lineno, size_t alignment, size_t size) 611 { 612 struct mdbg_hdr *hdr; 613 uint32_t exceptions = malloc_lock(ctx); 614 615 hdr = raw_memalign(sizeof(struct mdbg_hdr), mdbg_get_ftr_size(size), 616 alignment, size, ctx); 617 if (hdr) { 618 mdbg_update_hdr(hdr, fname, lineno, size); 619 hdr++; 620 } 621 malloc_unlock(ctx, exceptions); 622 return hdr; 623 } 624 625 626 static void *get_payload_start_size(void *raw_buf, size_t *size) 627 { 628 struct mdbg_hdr *hdr = raw_buf; 629 630 assert(bget_buf_size(hdr) >= hdr->pl_size); 631 *size = hdr->pl_size; 632 return hdr + 1; 633 } 634 635 static void gen_mdbg_check(struct malloc_ctx *ctx, int bufdump) 636 { 637 struct bpool_iterator itr; 638 void *b; 639 uint32_t exceptions = malloc_lock(ctx); 640 641 raw_malloc_validate_pools(ctx); 642 643 BPOOL_FOREACH(ctx, &itr, &b) { 644 struct mdbg_hdr *hdr = (struct mdbg_hdr *)b; 645 646 assert_header(hdr); 647 648 if (bufdump > 0) { 649 const char *fname = hdr->fname; 650 651 if (!fname) 652 fname = "unknown"; 653 654 IMSG("buffer: %d bytes %s:%d\n", 655 hdr->pl_size, fname, hdr->line); 656 } 657 } 658 659 malloc_unlock(ctx, exceptions); 660 } 661 662 void *mdbg_malloc(const char *fname, int lineno, size_t size) 663 { 664 return gen_mdbg_malloc(&malloc_ctx, fname, lineno, size); 665 } 666 667 void *mdbg_calloc(const char *fname, int lineno, size_t nmemb, size_t size) 668 { 669 return gen_mdbg_calloc(&malloc_ctx, fname, lineno, nmemb, size); 670 } 671 672 void *mdbg_realloc(const char *fname, int lineno, void *ptr, size_t size) 673 { 674 return gen_mdbg_realloc(&malloc_ctx, fname, lineno, ptr, size); 675 } 676 677 void *mdbg_memalign(const char *fname, int lineno, size_t alignment, 678 size_t size) 679 { 680 return gen_mdbg_memalign(&malloc_ctx, fname, lineno, alignment, size); 681 } 682 683 void mdbg_check(int bufdump) 684 { 685 gen_mdbg_check(&malloc_ctx, bufdump); 686 } 687 #else 688 689 void *malloc(size_t size) 690 { 691 void *p; 692 uint32_t exceptions = malloc_lock(&malloc_ctx); 693 694 p = raw_malloc(0, 0, size, &malloc_ctx); 695 malloc_unlock(&malloc_ctx, exceptions); 696 return p; 697 } 698 699 static void free_helper(void *ptr, bool wipe) 700 { 701 uint32_t exceptions = malloc_lock(&malloc_ctx); 702 703 raw_free(ptr, &malloc_ctx, wipe); 704 malloc_unlock(&malloc_ctx, exceptions); 705 } 706 707 void *calloc(size_t nmemb, size_t size) 708 { 709 void *p; 710 uint32_t exceptions = malloc_lock(&malloc_ctx); 711 712 p = raw_calloc(0, 0, nmemb, size, &malloc_ctx); 713 malloc_unlock(&malloc_ctx, exceptions); 714 return p; 715 } 716 717 static void *realloc_unlocked(struct malloc_ctx *ctx, void *ptr, 718 size_t size) 719 { 720 return raw_realloc(ptr, 0, 0, size, ctx); 721 } 722 723 void *realloc(void *ptr, size_t size) 724 { 725 void *p; 726 uint32_t exceptions = malloc_lock(&malloc_ctx); 727 728 p = realloc_unlocked(&malloc_ctx, ptr, size); 729 malloc_unlock(&malloc_ctx, exceptions); 730 return p; 731 } 732 733 void *memalign(size_t alignment, size_t size) 734 { 735 void *p; 736 uint32_t exceptions = malloc_lock(&malloc_ctx); 737 738 p = raw_memalign(0, 0, alignment, size, &malloc_ctx); 739 malloc_unlock(&malloc_ctx, exceptions); 740 return p; 741 } 742 743 static void *get_payload_start_size(void *ptr, size_t *size) 744 { 745 *size = bget_buf_size(ptr); 746 return ptr; 747 } 748 749 #endif 750 751 void free(void *ptr) 752 { 753 free_helper(ptr, false); 754 } 755 756 void free_wipe(void *ptr) 757 { 758 free_helper(ptr, true); 759 } 760 761 static void gen_malloc_add_pool(struct malloc_ctx *ctx, void *buf, size_t len) 762 { 763 void *p; 764 size_t l; 765 uint32_t exceptions; 766 uintptr_t start = (uintptr_t)buf; 767 uintptr_t end = start + len; 768 const size_t min_len = ((sizeof(struct malloc_pool) + (SizeQuant - 1)) & 769 (~(SizeQuant - 1))) + 770 sizeof(struct bhead) * 2; 771 772 773 start = ROUNDUP(start, SizeQuant); 774 end = ROUNDDOWN(end, SizeQuant); 775 assert(start < end); 776 777 if ((end - start) < min_len) { 778 DMSG("Skipping too small pool"); 779 return; 780 } 781 782 exceptions = malloc_lock(ctx); 783 784 tag_asan_free((void *)start, end - start); 785 bpool((void *)start, end - start, &ctx->poolset); 786 l = ctx->pool_len + 1; 787 p = realloc_unlocked(ctx, ctx->pool, sizeof(struct malloc_pool) * l); 788 assert(p); 789 ctx->pool = p; 790 ctx->pool[ctx->pool_len].buf = (void *)start; 791 ctx->pool[ctx->pool_len].len = end - start; 792 #ifdef BufStats 793 ctx->mstats.size += ctx->pool[ctx->pool_len].len; 794 #endif 795 ctx->pool_len = l; 796 malloc_unlock(ctx, exceptions); 797 } 798 799 static bool gen_malloc_buffer_is_within_alloced(struct malloc_ctx *ctx, 800 void *buf, size_t len) 801 { 802 struct bpool_iterator itr; 803 void *b; 804 uint8_t *start_buf = buf; 805 uint8_t *end_buf = start_buf + len; 806 bool ret = false; 807 uint32_t exceptions = malloc_lock(ctx); 808 809 raw_malloc_validate_pools(ctx); 810 811 /* Check for wrapping */ 812 if (start_buf > end_buf) 813 goto out; 814 815 BPOOL_FOREACH(ctx, &itr, &b) { 816 uint8_t *start_b; 817 uint8_t *end_b; 818 size_t s; 819 820 start_b = get_payload_start_size(b, &s); 821 end_b = start_b + s; 822 823 if (start_buf >= start_b && end_buf <= end_b) { 824 ret = true; 825 goto out; 826 } 827 } 828 829 out: 830 malloc_unlock(ctx, exceptions); 831 832 return ret; 833 } 834 835 static bool gen_malloc_buffer_overlaps_heap(struct malloc_ctx *ctx, 836 void *buf, size_t len) 837 { 838 uintptr_t buf_start = (uintptr_t) buf; 839 uintptr_t buf_end = buf_start + len; 840 size_t n; 841 bool ret = false; 842 uint32_t exceptions = malloc_lock(ctx); 843 844 raw_malloc_validate_pools(ctx); 845 846 for (n = 0; n < ctx->pool_len; n++) { 847 uintptr_t pool_start = (uintptr_t)ctx->pool[n].buf; 848 uintptr_t pool_end = pool_start + ctx->pool[n].len; 849 850 if (buf_start > buf_end || pool_start > pool_end) { 851 ret = true; /* Wrapping buffers, shouldn't happen */ 852 goto out; 853 } 854 855 if (buf_end > pool_start || buf_start < pool_end) { 856 ret = true; 857 goto out; 858 } 859 } 860 861 out: 862 malloc_unlock(ctx, exceptions); 863 return ret; 864 } 865 866 void malloc_add_pool(void *buf, size_t len) 867 { 868 gen_malloc_add_pool(&malloc_ctx, buf, len); 869 } 870 871 bool malloc_buffer_is_within_alloced(void *buf, size_t len) 872 { 873 return gen_malloc_buffer_is_within_alloced(&malloc_ctx, buf, len); 874 } 875 876 bool malloc_buffer_overlaps_heap(void *buf, size_t len) 877 { 878 return gen_malloc_buffer_overlaps_heap(&malloc_ctx, buf, len); 879 } 880 881 #ifdef CFG_VIRTUALIZATION 882 883 #ifndef ENABLE_MDBG 884 885 void *nex_malloc(size_t size) 886 { 887 void *p; 888 uint32_t exceptions = malloc_lock(&nex_malloc_ctx); 889 890 p = raw_malloc(0, 0, size, &nex_malloc_ctx); 891 malloc_unlock(&nex_malloc_ctx, exceptions); 892 return p; 893 } 894 895 void *nex_calloc(size_t nmemb, size_t size) 896 { 897 void *p; 898 uint32_t exceptions = malloc_lock(&nex_malloc_ctx); 899 900 p = raw_calloc(0, 0, nmemb, size, &nex_malloc_ctx); 901 malloc_unlock(&nex_malloc_ctx, exceptions); 902 return p; 903 } 904 905 void *nex_realloc(void *ptr, size_t size) 906 { 907 void *p; 908 uint32_t exceptions = malloc_lock(&nex_malloc_ctx); 909 910 p = realloc_unlocked(&nex_malloc_ctx, ptr, size); 911 malloc_unlock(&nex_malloc_ctx, exceptions); 912 return p; 913 } 914 915 void *nex_memalign(size_t alignment, size_t size) 916 { 917 void *p; 918 uint32_t exceptions = malloc_lock(&nex_malloc_ctx); 919 920 p = raw_memalign(0, 0, alignment, size, &nex_malloc_ctx); 921 malloc_unlock(&nex_malloc_ctx, exceptions); 922 return p; 923 } 924 925 void nex_free(void *ptr) 926 { 927 uint32_t exceptions = malloc_lock(&nex_malloc_ctx); 928 929 raw_free(ptr, &nex_malloc_ctx, false /* !wipe */); 930 malloc_unlock(&nex_malloc_ctx, exceptions); 931 } 932 933 #else /* ENABLE_MDBG */ 934 935 void *nex_mdbg_malloc(const char *fname, int lineno, size_t size) 936 { 937 return gen_mdbg_malloc(&nex_malloc_ctx, fname, lineno, size); 938 } 939 940 void *nex_mdbg_calloc(const char *fname, int lineno, size_t nmemb, size_t size) 941 { 942 return gen_mdbg_calloc(&nex_malloc_ctx, fname, lineno, nmemb, size); 943 } 944 945 void *nex_mdbg_realloc(const char *fname, int lineno, void *ptr, size_t size) 946 { 947 return gen_mdbg_realloc(&nex_malloc_ctx, fname, lineno, ptr, size); 948 } 949 950 void *nex_mdbg_memalign(const char *fname, int lineno, size_t alignment, 951 size_t size) 952 { 953 return gen_mdbg_memalign(&nex_malloc_ctx, fname, lineno, alignment, size); 954 } 955 956 void nex_mdbg_check(int bufdump) 957 { 958 gen_mdbg_check(&nex_malloc_ctx, bufdump); 959 } 960 961 void nex_free(void *ptr) 962 { 963 uint32_t exceptions = malloc_lock(&nex_malloc_ctx); 964 965 gen_mdbg_free(&nex_malloc_ctx, ptr, false /* !wipe */); 966 malloc_unlock(&nex_malloc_ctx, exceptions); 967 } 968 969 #endif /* ENABLE_MDBG */ 970 971 void nex_malloc_add_pool(void *buf, size_t len) 972 { 973 gen_malloc_add_pool(&nex_malloc_ctx, buf, len); 974 } 975 976 bool nex_malloc_buffer_is_within_alloced(void *buf, size_t len) 977 { 978 return gen_malloc_buffer_is_within_alloced(&nex_malloc_ctx, buf, len); 979 } 980 981 bool nex_malloc_buffer_overlaps_heap(void *buf, size_t len) 982 { 983 return gen_malloc_buffer_overlaps_heap(&nex_malloc_ctx, buf, len); 984 } 985 986 #ifdef BufStats 987 988 void nex_malloc_reset_stats(void) 989 { 990 gen_malloc_reset_stats(&nex_malloc_ctx); 991 } 992 993 void nex_malloc_get_stats(struct malloc_stats *stats) 994 { 995 gen_malloc_get_stats(&nex_malloc_ctx, stats); 996 } 997 998 #endif 999 1000 #endif 1001