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