Update from upstream to 2.4.0 version
[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(
121                         THREAD_EXCP_NATIVE_INTR | THREAD_EXCP_FOREIGN_INTR);
122         cpu_spin_lock(&__malloc_spinlock);
123         return exceptions;
124 }
125
126 static void malloc_unlock(uint32_t exceptions)
127 {
128         cpu_spin_unlock(&__malloc_spinlock);
129         thread_unmask_exceptions(exceptions);
130 }
131
132 static void tag_asan_free(void *buf, size_t len)
133 {
134         asan_tag_heap_free(buf, (uint8_t *)buf + len);
135 }
136
137 static void tag_asan_alloced(void *buf, size_t len)
138 {
139         asan_tag_access(buf, (uint8_t *)buf + len);
140 }
141
142 #else /*__KERNEL__*/
143 /* Compiling for TA */
144 static uint32_t malloc_lock(void)
145 {
146         return 0;
147 }
148
149 static void malloc_unlock(uint32_t exceptions __unused)
150 {
151 }
152
153 static void tag_asan_free(void *buf __unused, size_t len __unused)
154 {
155 }
156
157 static void tag_asan_alloced(void *buf __unused, size_t len __unused)
158 {
159 }
160 #endif /*__KERNEL__*/
161
162 #include "bget.c"               /* this is ugly, but this is bget */
163
164 struct malloc_pool {
165         void *buf;
166         size_t len;
167 };
168
169 static struct malloc_pool *malloc_pool;
170 static size_t malloc_pool_len;
171
172 #ifdef BufStats
173
174 static struct malloc_stats mstats;
175
176 static void raw_malloc_return_hook(void *p, size_t requested_size)
177 {
178         if (totalloc > mstats.max_allocated)
179                 mstats.max_allocated = totalloc;
180
181         if (!p) {
182                 mstats.num_alloc_fail++;
183                 if (requested_size > mstats.biggest_alloc_fail) {
184                         mstats.biggest_alloc_fail = requested_size;
185                         mstats.biggest_alloc_fail_used = totalloc;
186                 }
187         }
188 }
189
190 void malloc_reset_stats(void)
191 {
192         unsigned int exceptions = malloc_lock();
193
194         mstats.max_allocated = 0;
195         mstats.num_alloc_fail = 0;
196         mstats.biggest_alloc_fail = 0;
197         mstats.biggest_alloc_fail_used = 0;
198         malloc_unlock(exceptions);
199 }
200
201 void malloc_get_stats(struct malloc_stats *stats)
202 {
203         uint32_t exceptions = malloc_lock();
204
205         memcpy(stats, &mstats, sizeof(*stats));
206         stats->allocated = totalloc;
207         malloc_unlock(exceptions);
208 }
209
210 #else /* BufStats */
211
212 static void raw_malloc_return_hook(void *p __unused, size_t requested_size __unused)
213 {
214 }
215
216 #endif /* BufStats */
217
218 #ifdef BufValid
219 static void raw_malloc_validate_pools(void)
220 {
221         size_t n;
222
223         for (n = 0; n < malloc_pool_len; n++)
224                 bpoolv(malloc_pool[n].buf);
225 }
226 #else
227 static void raw_malloc_validate_pools(void)
228 {
229 }
230 #endif
231
232 struct bpool_iterator {
233         struct bfhead *next_buf;
234         size_t pool_idx;
235 };
236
237 static void bpool_foreach_iterator_init(struct bpool_iterator *iterator)
238 {
239         iterator->pool_idx = 0;
240         iterator->next_buf = BFH(malloc_pool[0].buf);
241 }
242
243 static bool bpool_foreach_pool(struct bpool_iterator *iterator, void **buf,
244                 size_t *len, bool *isfree)
245 {
246         struct bfhead *b = iterator->next_buf;
247         bufsize bs = b->bh.bsize;
248
249         if (bs == ESent)
250                 return false;
251
252         if (bs < 0) {
253                 /* Allocated buffer */
254                 bs = -bs;
255
256                 *isfree = false;
257         } else {
258                 /* Free Buffer */
259                 *isfree = true;
260
261                 /* Assert that the free list links are intact */
262                 assert(b->ql.blink->ql.flink == b);
263                 assert(b->ql.flink->ql.blink == b);
264         }
265
266         *buf = (uint8_t *)b + sizeof(struct bhead);
267         *len = bs - sizeof(struct bhead);
268
269         iterator->next_buf = BFH((uint8_t *)b + bs);
270         return true;
271 }
272
273 static bool bpool_foreach(struct bpool_iterator *iterator, void **buf)
274 {
275         while (true) {
276                 size_t len;
277                 bool isfree;
278
279                 if (bpool_foreach_pool(iterator, buf, &len, &isfree)) {
280                         if (isfree)
281                                 continue;
282                         return true;
283                 }
284
285                 if ((iterator->pool_idx + 1) >= malloc_pool_len)
286                         return false;
287
288                 iterator->pool_idx++;
289                 iterator->next_buf = BFH(malloc_pool[iterator->pool_idx].buf);
290         }
291 }
292
293 /* Convenience macro for looping over all allocated buffers */
294 #define BPOOL_FOREACH(iterator, bp) \
295                 for (bpool_foreach_iterator_init((iterator)); \
296                         bpool_foreach((iterator), (bp));)
297
298 static void *raw_malloc(size_t hdr_size, size_t ftr_size, size_t pl_size)
299 {
300         void *ptr = NULL;
301         size_t s = hdr_size + ftr_size + pl_size;
302
303         /*
304          * Make sure that malloc has correct alignment of returned buffers.
305          * The assumption is that uintptr_t will be as wide as the largest
306          * required alignment of any type.
307          */
308         COMPILE_TIME_ASSERT(SizeQuant >= sizeof(uintptr_t));
309
310         raw_malloc_validate_pools();
311
312         /* Check wrapping */
313         if (s < pl_size)
314                 goto out;
315
316         /* BGET doesn't like 0 sized allocations */
317         if (!s)
318                 s++;
319
320         ptr = bget(s);
321 out:
322         raw_malloc_return_hook(ptr, pl_size);
323
324         return ptr;
325 }
326
327 static void raw_free(void *ptr)
328 {
329         raw_malloc_validate_pools();
330
331         if (ptr)
332                 brel(ptr);
333 }
334
335 static void *raw_calloc(size_t hdr_size, size_t ftr_size, size_t pl_nmemb,
336                 size_t pl_size)
337 {
338         size_t s = hdr_size + ftr_size + pl_nmemb * pl_size;
339         void *ptr = NULL;
340
341         raw_malloc_validate_pools();
342
343         /* Check wrapping */
344         if (s < pl_nmemb || s < pl_size)
345                 goto out;
346
347         /* BGET doesn't like 0 sized allocations */
348         if (!s)
349                 s++;
350
351         ptr = bgetz(s);
352 out:
353         raw_malloc_return_hook(ptr, pl_nmemb * pl_size);
354
355         return ptr;
356 }
357
358 static void *raw_realloc(void *ptr, size_t hdr_size, size_t ftr_size,
359                 size_t pl_size)
360 {
361         size_t s = hdr_size + ftr_size + pl_size;
362         void *p = NULL;
363
364         /* Check wrapping */
365         if (s < pl_size)
366                 goto out;
367
368         raw_malloc_validate_pools();
369
370         /* BGET doesn't like 0 sized allocations */
371         if (!s)
372                 s++;
373
374         p = bgetr(ptr, s);
375 out:
376         raw_malloc_return_hook(p, pl_size);
377
378         return p;
379 }
380
381 static void create_free_block(struct bfhead *bf, bufsize size, struct bhead *bn)
382 {
383         assert(BH((char *)bf + size) == bn);
384         assert(bn->bsize < 0); /* Next block should be allocated */
385         /* Next block shouldn't already have free block in front */
386         assert(bn->prevfree == 0);
387
388         /* Create the free buf header */
389         bf->bh.bsize = size;
390         bf->bh.prevfree = 0;
391
392         /* Update next block to point to the new free buf header */
393         bn->prevfree = size;
394
395         /* Insert the free buffer on the free list */
396         assert(freelist.ql.blink->ql.flink == &freelist);
397         assert(freelist.ql.flink->ql.blink == &freelist);
398         bf->ql.flink = &freelist;
399         bf->ql.blink = freelist.ql.blink;
400         freelist.ql.blink = bf;
401         bf->ql.blink->ql.flink = bf;
402 }
403
404 static void brel_before(char *orig_buf, char *new_buf)
405 {
406         struct bfhead *bf;
407         struct bhead *b;
408         bufsize size;
409         bufsize orig_size;
410
411         assert(orig_buf < new_buf);
412         /* There has to be room for the freebuf header */
413         size = (bufsize)(new_buf - orig_buf);
414         assert(size >= (SizeQ + sizeof(struct bhead)));
415
416         /* Point to head of original buffer */
417         bf = BFH(orig_buf - sizeof(struct bhead));
418         orig_size = -bf->bh.bsize; /* negative since it's an allocated buffer */
419
420         /* Point to head of the becoming new allocated buffer */
421         b = BH(new_buf - sizeof(struct bhead));
422
423         if (bf->bh.prevfree != 0) {
424                 /* Previous buffer is free, consolidate with that buffer */
425                 struct bfhead *bfp;
426
427                 /* Update the previous free buffer */
428                 bfp = BFH((char *)bf - bf->bh.prevfree);
429                 assert(bfp->bh.bsize == bf->bh.prevfree);
430                 bfp->bh.bsize += size;
431
432                 /* Make a new allocated buffer header */
433                 b->prevfree = bfp->bh.bsize;
434                 /* Make it negative since it's an allocated buffer */
435                 b->bsize = -(orig_size - size);
436         } else {
437                 /*
438                  * Previous buffer is allocated, create a new buffer and
439                  * insert on the free list.
440                  */
441
442                 /* Make it negative since it's an allocated buffer */
443                 b->bsize = -(orig_size - size);
444
445                 create_free_block(bf, size, b);
446         }
447
448 #ifdef BufStats
449         totalloc -= size;
450         assert(totalloc >= 0);
451 #endif
452 }
453
454 static void brel_after(char *buf, bufsize size)
455 {
456         struct bhead *b = BH(buf - sizeof(struct bhead));
457         struct bhead *bn;
458         bufsize new_size = size;
459         bufsize free_size;
460
461         /* Select the size in the same way as in bget() */
462         if (new_size < SizeQ)
463                 new_size = SizeQ;
464 #ifdef SizeQuant
465 #if SizeQuant > 1
466         new_size = (new_size + (SizeQuant - 1)) & (~(SizeQuant - 1));
467 #endif
468 #endif
469         new_size += sizeof(struct bhead);
470         assert(new_size <= -b->bsize);
471
472         /*
473          * Check if there's enough space at the end of the buffer to be
474          * able to free anything.
475          */
476         free_size = -b->bsize - new_size;
477         if (free_size < SizeQ + sizeof(struct bhead))
478                 return;
479
480         bn = BH((char *)b - b->bsize);
481         /*
482          * Set the new size of the buffer;
483          */
484         b->bsize = -new_size;
485         if (bn->bsize > 0) {
486                 /* Next buffer is free, consolidate with that buffer */
487                 struct bfhead *bfn = BFH(bn);
488                 struct bfhead *nbf = BFH((char *)b + new_size);
489                 struct bhead *bnn = BH((char *)bn + bn->bsize);
490
491                 assert(bfn->bh.prevfree == 0);
492                 assert(bnn->prevfree == bfn->bh.bsize);
493
494                 /* Construct the new free header */
495                 nbf->bh.prevfree = 0;
496                 nbf->bh.bsize = bfn->bh.bsize + free_size;
497
498                 /* Update the buffer after this to point to this header */
499                 bnn->prevfree += free_size;
500
501                 /*
502                  * Unlink the previous free buffer and link the new free
503                  * buffer.
504                  */
505                 assert(bfn->ql.blink->ql.flink == bfn);
506                 assert(bfn->ql.flink->ql.blink == bfn);
507
508                 /* Assing blink and flink from old free buffer */
509                 nbf->ql.blink = bfn->ql.blink;
510                 nbf->ql.flink = bfn->ql.flink;
511
512                 /* Replace the old free buffer with the new one */
513                 nbf->ql.blink->ql.flink = nbf;
514                 nbf->ql.flink->ql.blink = nbf;
515         } else {
516                 /* New buffer is allocated, create a new free buffer */
517                 create_free_block(BFH((char *)b + new_size), free_size, bn);
518         }
519
520 #ifdef BufStats
521         totalloc -= free_size;
522         assert(totalloc >= 0);
523 #endif
524
525 }
526
527 static void *raw_memalign(size_t hdr_size, size_t ftr_size, size_t alignment,
528                 size_t size)
529 {
530         size_t s;
531         uintptr_t b;
532
533         raw_malloc_validate_pools();
534
535         if (!IS_POWER_OF_TWO(alignment))
536                 return NULL;
537
538         /*
539          * Normal malloc with headers always returns something SizeQuant
540          * aligned.
541          */
542         if (alignment <= SizeQuant)
543                 return raw_malloc(hdr_size, ftr_size, size);
544
545         s = hdr_size + ftr_size + alignment + size +
546             SizeQ + sizeof(struct bhead);
547
548         /* Check wapping */
549         if (s < alignment || s < size)
550                 return NULL;
551
552         b = (uintptr_t)bget(s);
553         if (!b)
554                 goto out;
555
556         if ((b + hdr_size) & (alignment - 1)) {
557                 /*
558                  * Returned buffer is not aligned as requested if the
559                  * hdr_size is added. Find an offset into the buffer
560                  * that is far enough in to the buffer to be able to free
561                  * what's in front.
562                  */
563                 uintptr_t p;
564
565                 /*
566                  * Find the point where the buffer including supplied
567                  * header size should start.
568                  */
569                 p = b + hdr_size + alignment;
570                 p &= ~(alignment - 1);
571                 p -= hdr_size;
572                 if ((p - b) < (SizeQ + sizeof(struct bhead)))
573                         p += alignment;
574                 assert((p + hdr_size + ftr_size + size) <= (b + s));
575
576                 /* Free the front part of the buffer */
577                 brel_before((void *)b, (void *)p);
578
579                 /* Set the new start of the buffer */
580                 b = p;
581         }
582
583         /*
584          * Since b is now aligned, release what we don't need at the end of
585          * the buffer.
586          */
587         brel_after((void *)b, hdr_size + ftr_size + size);
588 out:
589         raw_malloc_return_hook((void *)b, size);
590
591         return (void *)b;
592 }
593
594 /* Most of the stuff in this function is copied from bgetr() in bget.c */
595 static __maybe_unused bufsize bget_buf_size(void *buf)
596 {
597         bufsize osize;          /* Old size of buffer */
598         struct bhead *b;
599
600         b = BH(((char *)buf) - sizeof(struct bhead));
601         osize = -b->bsize;
602 #ifdef BECtl
603         if (osize == 0) {
604                 /*  Buffer acquired directly through acqfcn. */
605                 struct bdhead *bd;
606
607                 bd = BDH(((char *)buf) - sizeof(struct bdhead));
608                 osize = bd->tsize - sizeof(struct bdhead);
609         } else
610 #endif
611                 osize -= sizeof(struct bhead);
612         assert(osize > 0);
613         return osize;
614 }
615
616 #ifdef ENABLE_MDBG
617
618 struct mdbg_hdr {
619         const char *fname;
620         uint16_t line;
621         uint32_t pl_size;
622         uint32_t magic;
623 #if defined(ARM64)
624         uint64_t pad;
625 #endif
626 };
627
628 #define MDBG_HEADER_MAGIC       0xadadadad
629 #define MDBG_FOOTER_MAGIC       0xecececec
630
631 static size_t mdbg_get_ftr_size(size_t pl_size)
632 {
633         size_t ftr_pad = ROUNDUP(pl_size, sizeof(uint32_t)) - pl_size;
634
635         return ftr_pad + sizeof(uint32_t);
636 }
637
638 static uint32_t *mdbg_get_footer(struct mdbg_hdr *hdr)
639 {
640         uint32_t *footer;
641
642         footer = (uint32_t *)((uint8_t *)(hdr + 1) + hdr->pl_size +
643                               mdbg_get_ftr_size(hdr->pl_size));
644         footer--;
645         return footer;
646 }
647
648 static void mdbg_update_hdr(struct mdbg_hdr *hdr, const char *fname,
649                 int lineno, size_t pl_size)
650 {
651         uint32_t *footer;
652
653         hdr->fname = fname;
654         hdr->line = lineno;
655         hdr->pl_size = pl_size;
656         hdr->magic = MDBG_HEADER_MAGIC;
657
658         footer = mdbg_get_footer(hdr);
659         *footer = MDBG_FOOTER_MAGIC;
660 }
661
662 void *mdbg_malloc(const char *fname, int lineno, size_t size)
663 {
664         struct mdbg_hdr *hdr;
665         uint32_t exceptions = malloc_lock();
666
667         /*
668          * Check struct mdbg_hdr doesn't get bad alignment.
669          * This is required by C standard: the buffer returned from
670          * malloc() should be aligned with a fundamental alignment.
671          * For ARM32, the required alignment is 8. For ARM64, it is 16.
672          */
673         COMPILE_TIME_ASSERT(
674                 (sizeof(struct mdbg_hdr) % (__alignof(uintptr_t) * 2)) == 0);
675
676         hdr = raw_malloc(sizeof(struct mdbg_hdr),
677                           mdbg_get_ftr_size(size), size);
678         if (hdr) {
679                 mdbg_update_hdr(hdr, fname, lineno, size);
680                 hdr++;
681         }
682
683         malloc_unlock(exceptions);
684         return hdr;
685 }
686
687 static void assert_header(struct mdbg_hdr *hdr __maybe_unused)
688 {
689         assert(hdr->magic == MDBG_HEADER_MAGIC);
690         assert(*mdbg_get_footer(hdr) == MDBG_FOOTER_MAGIC);
691 }
692
693 static void mdbg_free(void *ptr)
694 {
695         struct mdbg_hdr *hdr = ptr;
696
697         if (hdr) {
698                 hdr--;
699                 assert_header(hdr);
700                 hdr->magic = 0;
701                 *mdbg_get_footer(hdr) = 0;
702                 raw_free(hdr);
703         }
704 }
705
706 void free(void *ptr)
707 {
708         uint32_t exceptions = malloc_lock();
709
710         mdbg_free(ptr);
711         malloc_unlock(exceptions);
712 }
713
714 void *mdbg_calloc(const char *fname, int lineno, size_t nmemb, size_t size)
715 {
716         struct mdbg_hdr *hdr;
717         uint32_t exceptions = malloc_lock();
718
719         hdr = raw_calloc(sizeof(struct mdbg_hdr),
720                           mdbg_get_ftr_size(nmemb * size), nmemb, size);
721         if (hdr) {
722                 mdbg_update_hdr(hdr, fname, lineno, nmemb * size);
723                 hdr++;
724         }
725         malloc_unlock(exceptions);
726         return hdr;
727 }
728
729 static void *mdbg_realloc_unlocked(const char *fname, int lineno,
730                             void *ptr, size_t size)
731 {
732         struct mdbg_hdr *hdr = ptr;
733
734         if (hdr) {
735                 hdr--;
736                 assert_header(hdr);
737         }
738         hdr = raw_realloc(hdr, sizeof(struct mdbg_hdr),
739                            mdbg_get_ftr_size(size), size);
740         if (hdr) {
741                 mdbg_update_hdr(hdr, fname, lineno, size);
742                 hdr++;
743         }
744         return hdr;
745 }
746
747 void *mdbg_realloc(const char *fname, int lineno, void *ptr, size_t size)
748 {
749         void *p;
750         uint32_t exceptions = malloc_lock();
751
752         p = mdbg_realloc_unlocked(fname, lineno, ptr, size);
753         malloc_unlock(exceptions);
754         return p;
755 }
756
757 #define realloc_unlocked(ptr, size) \
758                 mdbg_realloc_unlocked(__FILE__, __LINE__, (ptr), (size))
759
760 void *mdbg_memalign(const char *fname, int lineno, size_t alignment,
761                 size_t size)
762 {
763         struct mdbg_hdr *hdr;
764         uint32_t exceptions = malloc_lock();
765
766         hdr = raw_memalign(sizeof(struct mdbg_hdr), mdbg_get_ftr_size(size),
767                            alignment, size);
768         if (hdr) {
769                 mdbg_update_hdr(hdr, fname, lineno, size);
770                 hdr++;
771         }
772         malloc_unlock(exceptions);
773         return hdr;
774 }
775
776
777 static void *get_payload_start_size(void *raw_buf, size_t *size)
778 {
779         struct mdbg_hdr *hdr = raw_buf;
780
781         assert(bget_buf_size(hdr) >= hdr->pl_size);
782         *size = hdr->pl_size;
783         return hdr + 1;
784 }
785
786 void mdbg_check(int bufdump)
787 {
788         struct bpool_iterator itr;
789         void *b;
790         uint32_t exceptions = malloc_lock();
791
792         raw_malloc_validate_pools();
793
794         BPOOL_FOREACH(&itr, &b) {
795                 struct mdbg_hdr *hdr = (struct mdbg_hdr *)b;
796
797                 assert_header(hdr);
798
799                 if (bufdump > 0) {
800                         const char *fname = hdr->fname;
801
802                         if (!fname)
803                                 fname = "unknown";
804
805                         IMSG("buffer: %d bytes %s:%d\n",
806                                 hdr->pl_size, fname, hdr->line);
807                 }
808         }
809
810         malloc_unlock(exceptions);
811 }
812
813 #else
814
815 void *malloc(size_t size)
816 {
817         void *p;
818         uint32_t exceptions = malloc_lock();
819
820         p = raw_malloc(0, 0, size);
821         malloc_unlock(exceptions);
822         return p;
823 }
824
825 void free(void *ptr)
826 {
827         uint32_t exceptions = malloc_lock();
828
829         raw_free(ptr);
830         malloc_unlock(exceptions);
831 }
832
833 void *calloc(size_t nmemb, size_t size)
834 {
835         void *p;
836         uint32_t exceptions = malloc_lock();
837
838         p = raw_calloc(0, 0, nmemb, size);
839         malloc_unlock(exceptions);
840         return p;
841 }
842
843 static void *realloc_unlocked(void *ptr, size_t size)
844 {
845         return raw_realloc(ptr, 0, 0, size);
846 }
847
848 void *realloc(void *ptr, size_t size)
849 {
850         void *p;
851         uint32_t exceptions = malloc_lock();
852
853         p = realloc_unlocked(ptr, size);
854         malloc_unlock(exceptions);
855         return p;
856 }
857
858 void *memalign(size_t alignment, size_t size)
859 {
860         void *p;
861         uint32_t exceptions = malloc_lock();
862
863         p = raw_memalign(0, 0, alignment, size);
864         malloc_unlock(exceptions);
865         return p;
866 }
867
868 static void *get_payload_start_size(void *ptr, size_t *size)
869 {
870         *size = bget_buf_size(ptr);
871         return ptr;
872 }
873
874 #endif
875
876 void malloc_add_pool(void *buf, size_t len)
877 {
878         void *p;
879         size_t l;
880         uint32_t exceptions;
881         uintptr_t start = (uintptr_t)buf;
882         uintptr_t end = start + len;
883         const size_t min_len = ((sizeof(struct malloc_pool) + (SizeQuant - 1)) &
884                                         (~(SizeQuant - 1))) +
885                                 sizeof(struct bhead) * 2;
886
887
888         start = ROUNDUP(start, SizeQuant);
889         end = ROUNDDOWN(end, SizeQuant);
890         assert(start < end);
891
892         if ((end - start) < min_len) {
893                 DMSG("Skipping too small pool");
894                 return;
895         }
896
897         exceptions = malloc_lock();
898         tag_asan_free((void *)start, end - start);
899         bpool((void *)start, end - start);
900         l = malloc_pool_len + 1;
901         p = realloc_unlocked(malloc_pool, sizeof(struct malloc_pool) * l);
902         assert(p);
903         malloc_pool = p;
904         malloc_pool[malloc_pool_len].buf = (void *)start;
905         malloc_pool[malloc_pool_len].len = end - start;
906 #ifdef BufStats
907         mstats.size += malloc_pool[malloc_pool_len].len;
908 #endif
909         malloc_pool_len = l;
910         malloc_unlock(exceptions);
911 }
912
913 bool malloc_buffer_is_within_alloced(void *buf, size_t len)
914 {
915         struct bpool_iterator itr;
916         void *b;
917         uint8_t *start_buf = buf;
918         uint8_t *end_buf = start_buf + len;
919         bool ret = false;
920         uint32_t exceptions = malloc_lock();
921
922         raw_malloc_validate_pools();
923
924         /* Check for wrapping */
925         if (start_buf > end_buf)
926                 goto out;
927
928         BPOOL_FOREACH(&itr, &b) {
929                 uint8_t *start_b;
930                 uint8_t *end_b;
931                 size_t s;
932
933                 start_b = get_payload_start_size(b, &s);
934                 end_b = start_b + s;
935
936                 if (start_buf >= start_b && end_buf <= end_b) {
937                         ret = true;
938                         goto out;
939                 }
940         }
941
942 out:
943         malloc_unlock(exceptions);
944
945         return ret;
946 }
947
948 bool malloc_buffer_overlaps_heap(void *buf, size_t len)
949 {
950         uintptr_t buf_start = (uintptr_t) buf;
951         uintptr_t buf_end = buf_start + len;
952         size_t n;
953         bool ret = false;
954         uint32_t exceptions = malloc_lock();
955
956         raw_malloc_validate_pools();
957
958         for (n = 0; n < malloc_pool_len; n++) {
959                 uintptr_t pool_start = (uintptr_t)malloc_pool[n].buf;
960                 uintptr_t pool_end = pool_start + malloc_pool[n].len;
961
962                 if (buf_start > buf_end || pool_start > pool_end) {
963                         ret = true;     /* Wrapping buffers, shouldn't happen */
964                         goto out;
965                 }
966
967                 if (buf_end > pool_start || buf_start < pool_end) {
968                         ret = true;
969                         goto out;
970                 }
971         }
972
973 out:
974         malloc_unlock(exceptions);
975         return ret;
976 }