1 /*
2 * Copyright (c) 2012, 2013 ARM Ltd
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
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the company may not be used to endorse or promote
14 * products derived from this software without specific prior written
15 * permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /* Implementation of <<malloc>> <<free>> <<calloc>> <<realloc>>, optional
30 * as to be reenterable.
31 *
32 * Interface documentation refer to malloc.c.
33 */
34
35 #define _DEFAULT_SOURCE
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdbool.h>
39 #include <errno.h>
40 #include <malloc.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <sys/config.h>
44 #include <sys/lock.h>
45 #include <stdint.h>
46
47 #if MALLOC_DEBUG
48 #include <assert.h>
49 #define MALLOC_LOCK do { __LIBC_LOCK(); __malloc_validate(); } while(0)
50 #define MALLOC_UNLOCK do { __malloc_validate(); __LIBC_UNLOCK(); } while(0)
51 #else
52 #define MALLOC_LOCK __LIBC_LOCK()
53 #define MALLOC_UNLOCK __LIBC_UNLOCK()
54 #undef assert
55 #define assert(x) ((void)0)
56 #endif
57
58 #ifndef MAX
59 #define MAX(a,b) ((a) >= (b) ? (a) : (b))
60 #endif
61
62 #if __SIZEOF_POINTER__ == __SIZEOF_LONG__
63 #define ALIGN_TO(size, align) \
64 (((size) + (align) -1L) & ~((align) -1L))
65 #else
66 #define ALIGN_TO(size, align) \
67 (((size) + (align) -1) & ~((align) -1))
68 #endif
69
70 #define ALIGN_PTR(ptr, align) (void *) (uintptr_t) ALIGN_TO((uintptr_t) ptr, align)
71
72 typedef struct {
73 char c;
74 union {
75 void *p;
76 double d;
77 long long ll;
78 size_t s;
79 } u;
80 } align_chunk_t;
81
82 typedef struct {
83 char c;
84 size_t s;
85 } align_head_t;
86
87 typedef struct malloc_chunk
88 {
89 /* --------------------------------------
90 * chunk->| size |
91 * mem_ptr->| When allocated: data |
92 * | When freed: pointer to next free |
93 * | chunk |
94 * --------------------------------------
95 *
96 * mem_ptr is aligned to MALLOC_CHUNK_ALIGN. That means that
97 * the chunk may not be aligned to MALLOC_CHUNK_ALIGN. But
98 * it will be aligned to MALLOC_HEAD_ALIGN.
99 *
100 * size is set so that a chunk starting at chunk+size will be
101 * aligned correctly
102 */
103
104 /* size of the allocated payload area */
105 size_t size;
106
107 /* pointer to next chunk */
108 struct malloc_chunk * next;
109 } chunk_t;
110
111 /* Alignment of allocated chunk. Compute the alignment required from a
112 * range of types */
113 #define MALLOC_CHUNK_ALIGN (offsetof(align_chunk_t, u))
114
115 /* Alignment of the header. Never larger than MALLOC_CHUNK_ALIGN */
116 #define MALLOC_HEAD_ALIGN (offsetof(align_head_t, s))
117
118 /* Size of malloc header. Keep it aligned. */
119 #define MALLOC_HEAD ALIGN_TO(sizeof(size_t), MALLOC_HEAD_ALIGN)
120
121 /* nominal "page size" */
122 #define MALLOC_PAGE_ALIGN (0x1000)
123
124 /* Minimum allocation size */
125 #define MALLOC_MINSIZE ALIGN_TO(sizeof(chunk_t), MALLOC_HEAD_ALIGN)
126
127 /* Maximum allocation size */
128 #define MALLOC_MAXSIZE (SIZE_MAX - (MALLOC_HEAD + 2*MALLOC_CHUNK_ALIGN))
129
130 /* Forward data declarations */
131 extern chunk_t * __malloc_free_list;
132 extern char * __malloc_sbrk_start;
133 extern char * __malloc_sbrk_top;
134
135 /* Forward function declarations */
136 void * malloc(size_t);
137 void free (void * free_p);
138 void cfree(void * ptr);
139 void * calloc(size_t n, size_t elem);
140 void malloc_stats(void);
141 size_t malloc_usable_size(void * ptr);
142 void * realloc(void * ptr, size_t size);
143 void * memalign(size_t align, size_t s);
144 int mallopt(int parameter_number, int parameter_value);
145 void * valloc(size_t s);
146 void * pvalloc(size_t s);
147 void __malloc_validate(void);
148 void __malloc_validate_block(chunk_t *r);
149 void * __malloc_sbrk_aligned(size_t s);
150 bool __malloc_grow_chunk(chunk_t *c, size_t new_size);
151
152 /* Work around compiler optimizing away stores to 'size' field before
153 * call to free.
154 */
155 #ifdef _HAVE_ALIAS_ATTRIBUTE
156 extern void __malloc_free(void *);
157 extern void *__malloc_malloc(size_t);
158 #else
159 #define __malloc_free(x) free(x)
160 #define __malloc_malloc(x) malloc(x)
161 #endif
162
163 /* convert storage pointer to chunk */
164 static inline chunk_t *
ptr_to_chunk(void * ptr)165 ptr_to_chunk(void * ptr)
166 {
167 return (chunk_t *) ((char *) ptr - MALLOC_HEAD);
168 }
169
170 /* convert chunk to storage pointer */
171 static inline void *
chunk_to_ptr(chunk_t * c)172 chunk_to_ptr(chunk_t *c)
173 {
174 return (char *) c + MALLOC_HEAD;
175 }
176
177 /* end of chunk -- address of first byte past chunk storage */
178 static inline void *
chunk_end(chunk_t * c)179 chunk_end(chunk_t *c)
180 {
181 return (char *) c + c->size;
182 }
183
184 /* chunk size needed to hold 'malloc_size' bytes */
185 static inline size_t
chunk_size(size_t malloc_size)186 chunk_size(size_t malloc_size)
187 {
188 /* Keep all blocks aligned */
189 malloc_size = ALIGN_TO(malloc_size, MALLOC_CHUNK_ALIGN);
190
191 /* Add space for header */
192 malloc_size += MALLOC_HEAD;
193
194 /* fill the gap between chunks */
195 malloc_size += (MALLOC_CHUNK_ALIGN - MALLOC_HEAD_ALIGN);
196
197 /* Make sure the requested size is big enough to hold a free chunk */
198 malloc_size = MAX(MALLOC_MINSIZE, malloc_size);
199 return malloc_size;
200 }
201
202 /* available storage in chunk */
203 static inline size_t
chunk_usable(chunk_t * c)204 chunk_usable(chunk_t *c)
205 {
206 return c->size - MALLOC_HEAD;
207 }
208
209 /* assign 'size' to the specified chunk and return it to the free
210 * pool */
211 static inline void
make_free_chunk(chunk_t * c,size_t size)212 make_free_chunk(chunk_t *c, size_t size)
213 {
214 c->size = size;
215 __malloc_free(chunk_to_ptr(c));
216 }
217
218 #ifdef DEFINE_MALLOC
219 /* List list header of free blocks */
220 chunk_t * __malloc_free_list;
221
222 /* Starting point of memory allocated from system */
223 char * __malloc_sbrk_start;
224 char * __malloc_sbrk_top;
225
226 /** Function __malloc_sbrk_aligned
227 * Algorithm:
228 * Use sbrk() to obtain more memory and ensure the storage is
229 * MALLOC_CHUNK_ALIGN aligned. Optimise for the case that it is
230 * already aligned - only ask for extra padding after we know we
231 * need it
232 */
__malloc_sbrk_aligned(size_t s)233 void* __malloc_sbrk_aligned(size_t s)
234 {
235 char *p, *align_p;
236
237 #ifdef __APPLE__
238 /* Mac OS X 'emulates' sbrk, but the
239 * parameter is int, not intptr_t or ptrdiff_t,
240 */
241 int d = (int) s;
242 if (d < 0 || (size_t) d != s)
243 return (void *)-1;
244 #else
245 ptrdiff_t d = (ptrdiff_t)s;
246
247 if (d < 0)
248 return (void *)-1;
249 #endif
250 p = sbrk(d);
251
252 /* sbrk returns -1 if fail to allocate */
253 if (p == (void *)-1)
254 return p;
255
256 __malloc_sbrk_top = p + s;
257
258 /* Adjust returned space so that the storage area
259 * is MALLOC_CHUNK_ALIGN aligned and the head is
260 * MALLOC_HEAD_ALIGN aligned.
261 */
262 align_p = (char*)ALIGN_PTR(p + MALLOC_HEAD, MALLOC_CHUNK_ALIGN) - MALLOC_HEAD;
263
264 if (align_p != p)
265 {
266 /* p is not aligned, ask for a few more bytes so that we have
267 * s bytes reserved from align_p. This should only occur for
268 * the first sbrk in a chunk of memory as all others should be
269 * aligned to the right value as chunk sizes are selected to
270 * make them abut in memory
271 */
272 intptr_t adjust = align_p - p;
273 char *extra = sbrk(adjust);
274 if (extra != p + s)
275 return (void *) -1;
276 __malloc_sbrk_top = extra + adjust;
277 }
278 if (__malloc_sbrk_start == NULL)
279 __malloc_sbrk_start = align_p;
280
281 return align_p;
282 }
283
284 bool
__malloc_grow_chunk(chunk_t * c,size_t new_size)285 __malloc_grow_chunk(chunk_t *c, size_t new_size)
286 {
287 char *chunk_e = chunk_end(c);
288
289 if (chunk_e != __malloc_sbrk_top)
290 return false;
291 size_t add_size = MAX(MALLOC_MINSIZE, new_size - c->size);
292
293 /* Ask for the extra memory needed */
294 char *heap = __malloc_sbrk_aligned(add_size);
295
296 /* Check if we got what we wanted */
297 if (heap == chunk_e)
298 {
299 /* Set size and return */
300 c->size += add_size;
301 return true;
302 }
303
304 if (heap != (char *) -1)
305 {
306 /* sbrk returned unexpected memory, free it */
307 make_free_chunk((chunk_t *) heap, add_size);
308 }
309 return false;
310 }
311
312 /** Function malloc
313 * Algorithm:
314 * Walk through the free list to find the first match. If fails to find
315 * one, call sbrk to allocate a new chunk_t.
316 */
malloc(size_t s)317 void * malloc(size_t s)
318 {
319 chunk_t **p, *r;
320 char * ptr;
321 size_t alloc_size;
322
323 if (s > MALLOC_MAXSIZE)
324 {
325 errno = ENOMEM;
326 return NULL;
327 }
328
329 alloc_size = chunk_size(s);
330
331 MALLOC_LOCK;
332
333 for (p = &__malloc_free_list; (r = *p) != NULL; p = &r->next)
334 {
335 if (r->size >= alloc_size)
336 {
337 size_t rem = r->size - alloc_size;
338
339 if (rem >= MALLOC_MINSIZE)
340 {
341 /* Find a chunk_t that much larger than required size, break
342 * it into two chunks and return the first one
343 */
344
345 chunk_t *s = (chunk_t *)((char *)r + alloc_size);
346 s->size = rem;
347 s->next = r->next;
348 *p = s;
349
350 r->size = alloc_size;
351 }
352 else
353 {
354 /* Find a chunk_t that is exactly the size or slightly bigger
355 * than requested size, just return this chunk_t
356 */
357 *p = r->next;
358 }
359 break;
360 }
361 if (!r->next && __malloc_grow_chunk(r, alloc_size))
362 {
363 /* Grow the last chunk in memory to the requested size,
364 * just return it
365 */
366 *p = r->next;
367 break;
368 }
369 }
370
371 /* Failed to find a appropriate chunk_t. Ask for more memory */
372 if (r == NULL)
373 {
374 r = __malloc_sbrk_aligned(alloc_size);
375
376 /* sbrk returns -1 if fail to allocate */
377 if (r == (void *)-1)
378 {
379 errno = ENOMEM;
380 MALLOC_UNLOCK;
381 return NULL;
382 }
383 r->size = alloc_size;
384 }
385
386 MALLOC_UNLOCK;
387
388 ptr = (char *)r + MALLOC_HEAD;
389
390 memset(ptr, '\0', alloc_size - MALLOC_HEAD);
391
392 return ptr;
393 }
394 #ifdef _HAVE_ALIAS_ATTRIBUTE
395 #pragma GCC diagnostic push
396 #ifndef __clang__
397 #pragma GCC diagnostic ignored "-Wmissing-attributes"
398 #endif
399 __strong_reference(malloc, __malloc_malloc);
400 #pragma GCC diagnostic pop
401 #endif
402 #endif /* DEFINE_MALLOC */
403
404 #ifdef DEFINE_FREE
405
406 #ifdef __GNUC__
407 #pragma GCC diagnostic ignored "-Wpragmas"
408 #pragma GCC diagnostic ignored "-Wunknown-warning-option"
409 #pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
410 #endif
411
412 /** Function free
413 * Implementation of libc free.
414 * Algorithm:
415 * Maintain a global free chunk_t single link list, headed by global
416 * variable __malloc_free_list.
417 * When free, insert the to-be-freed chunk_t into free list. The place to
418 * insert should make sure all chunks are sorted by address from low to
419 * high. Then merge with neighbor chunks if adjacent.
420 */
free(void * free_p)421 void free (void * free_p)
422 {
423 chunk_t * p_to_free;
424 chunk_t ** p, * r;
425
426 if (free_p == NULL) return;
427
428 p_to_free = ptr_to_chunk(free_p);
429 p_to_free->next = NULL;
430 #if MALLOC_DEBUG
431 __malloc_validate_block(p_to_free);
432 #endif
433
434 MALLOC_LOCK;
435
436 for (p = &__malloc_free_list; (r = *p) != NULL; p = &r->next)
437 {
438 /* Insert in address order */
439 if (p_to_free < r)
440 break;
441
442 /* Merge blocks together */
443 if (chunk_end(r) == p_to_free)
444 {
445 r->size += p_to_free->size;
446 p_to_free = r;
447 r = r->next;
448 goto no_insert;
449 }
450
451 /* Check for double free */
452 if (p_to_free == r)
453 {
454 errno = ENOMEM;
455 MALLOC_UNLOCK;
456 return;
457 }
458
459 }
460 p_to_free->next = r;
461 *p = p_to_free;
462
463 no_insert:
464
465 /* Merge blocks together */
466 if (chunk_end(p_to_free) == r)
467 {
468 p_to_free->size += r->size;
469 p_to_free->next = r->next;
470 }
471
472 MALLOC_UNLOCK;
473 }
474 #ifdef _HAVE_ALIAS_ATTRIBUTE
475 #pragma GCC diagnostic push
476 #ifndef __clang__
477 #pragma GCC diagnostic ignored "-Wmissing-attributes"
478 #endif
479 __strong_reference(free, __malloc_free);
480 __strong_reference(free, cfree);
481 #pragma GCC diagnostic pop
482 #endif
483 #endif /* DEFINE_FREE */
484
485 #ifdef DEFINE_CFREE
486 #ifndef _HAVE_ALIAS_ATTRIBUTE
cfree(void * ptr)487 void cfree(void * ptr)
488 {
489 free(ptr);
490 }
491 #endif
492 #endif /* DEFINE_CFREE */
493
494 #ifdef DEFINE_CALLOC
495 #include "mul_overflow.h"
496 /* Function calloc
497 *
498 * Implement calloc by multiplying sizes (with overflow check) and
499 * calling malloc (which sets to zero)
500 */
501
calloc(size_t n,size_t elem)502 void * calloc(size_t n, size_t elem)
503 {
504 size_t bytes;
505
506 if (mul_overflow (n, elem, &bytes))
507 {
508 errno = ENOMEM;
509 return NULL;
510 }
511 return malloc(bytes);
512 }
513 #endif /* DEFINE_CALLOC */
514
515 #ifdef DEFINE_REALLOC
516
517 /* Function realloc
518 *
519 * Implement either by merging adjacent free memory
520 * or by calling malloc/memcpy
521 */
realloc(void * ptr,size_t size)522 void * realloc(void * ptr, size_t size)
523 {
524 void * mem;
525
526 if (ptr == NULL)
527 return malloc(size);
528
529 if (size == 0)
530 {
531 free(ptr);
532 return NULL;
533 }
534
535 if (size > MALLOC_MAXSIZE)
536 {
537 errno = ENOMEM;
538 return NULL;
539 }
540
541 size_t new_size = chunk_size(size);
542 chunk_t *p_to_realloc = ptr_to_chunk(ptr);
543
544 #if MALLOC_DEBUG
545 __malloc_validate_block(p_to_realloc);
546 #endif
547
548 size_t old_size = p_to_realloc->size;
549
550 /* See if we can avoid allocating new memory
551 * when increasing the size
552 */
553 if (new_size > old_size)
554 {
555 void *chunk_e = chunk_end(p_to_realloc);
556
557 MALLOC_LOCK;
558
559 if (__malloc_grow_chunk(p_to_realloc, new_size))
560 {
561 /* clear new memory */
562 memset(chunk_e, '\0', new_size - old_size);
563 /* adjust chunk_t size */
564 old_size = new_size;
565 }
566 else
567 {
568 chunk_t **p, *r;
569
570 /* Check to see if there's a chunk_t of free space just past
571 * the current block, merge it in in case that's useful
572 */
573 for (p = &__malloc_free_list; (r = *p) != NULL; p = &r->next)
574 {
575 if (r == chunk_e)
576 {
577 size_t r_size = r->size;
578
579 /* remove R from the free list */
580 *p = r->next;
581
582 /* clear the memory from r */
583 memset(r, '\0', r_size);
584
585 /* add it's size to our block */
586 old_size += r_size;
587 p_to_realloc->size = old_size;
588 break;
589 }
590 if (p_to_realloc < r)
591 break;
592 }
593 }
594
595 MALLOC_UNLOCK;
596 }
597
598 if (new_size <= old_size)
599 {
600 size_t extra = old_size - new_size;
601
602 /* If there's enough space left over, split it out
603 * and free it
604 */
605 if (extra >= MALLOC_MINSIZE) {
606 p_to_realloc->size = new_size;
607 make_free_chunk(chunk_end(p_to_realloc), extra);
608 }
609 return ptr;
610 }
611
612 /* No short cuts, allocate new memory and copy */
613
614 mem = malloc(size);
615 if (!mem)
616 return NULL;
617
618 memcpy(mem, ptr, old_size - MALLOC_HEAD);
619 free(ptr);
620
621 return mem;
622 }
623 #endif /* DEFINE_REALLOC */
624
625 #ifdef DEFINE_MALLINFO
626
627 volatile chunk_t *__malloc_block;
628
629 void
__malloc_validate_block(chunk_t * r)630 __malloc_validate_block(chunk_t *r)
631 {
632 __malloc_block = r;
633 assert (ALIGN_PTR(chunk_to_ptr(r), MALLOC_CHUNK_ALIGN) == chunk_to_ptr(r));
634 assert (ALIGN_PTR(r, MALLOC_HEAD_ALIGN) == r);
635 assert (r->size >= MALLOC_MINSIZE);
636 assert (r->size < 0x80000000UL);
637 assert (ALIGN_TO(r->size, MALLOC_HEAD_ALIGN) == r->size);
638 }
639
640 void
__malloc_validate(void)641 __malloc_validate(void)
642 {
643 chunk_t *r;
644
645 for (r = __malloc_free_list; r; r = r->next) {
646 __malloc_validate_block(r);
647 assert (r->next == NULL || (char *) r + r->size < (char *) r->next);
648 }
649 }
650
mallinfo(void)651 struct mallinfo mallinfo(void)
652 {
653 char * sbrk_now;
654 chunk_t * pf;
655 size_t free_size = 0;
656 size_t total_size;
657 size_t ordblks = 0;
658 struct mallinfo current_mallinfo = {};
659
660 MALLOC_LOCK;
661
662 __malloc_validate();
663
664 if (__malloc_sbrk_start == NULL) total_size = 0;
665 else {
666 sbrk_now = __malloc_sbrk_top;
667
668 if (sbrk_now == NULL)
669 total_size = (size_t)-1;
670 else
671 total_size = (size_t) (sbrk_now - __malloc_sbrk_start);
672 }
673
674 for (pf = __malloc_free_list; pf; pf = pf->next) {
675 ordblks++;
676 free_size += pf->size;
677 }
678
679 current_mallinfo.ordblks = ordblks;
680 current_mallinfo.arena = total_size;
681 current_mallinfo.fordblks = free_size;
682 current_mallinfo.uordblks = total_size - free_size;
683
684 MALLOC_UNLOCK;
685 return current_mallinfo;
686 }
687 #endif /* DEFINE_MALLINFO */
688
689 #ifdef DEFINE_MALLOC_STATS
690
malloc_stats(void)691 void malloc_stats(void)
692 {
693 struct mallinfo current_mallinfo;
694
695 current_mallinfo = mallinfo();
696 fprintf(stderr, "max system bytes = %10lu\n",
697 (long) current_mallinfo.arena);
698 fprintf(stderr, "system bytes = %10lu\n",
699 (long) current_mallinfo.arena);
700 fprintf(stderr, "in use bytes = %10lu\n",
701 (long) current_mallinfo.uordblks);
702 fprintf(stderr, "free blocks = %10lu\n",
703 (long) current_mallinfo.ordblks);
704 }
705 #endif /* DEFINE_MALLOC_STATS */
706
707 #ifdef DEFINE_MALLOC_USABLE_SIZE
malloc_usable_size(void * ptr)708 size_t malloc_usable_size(void * ptr)
709 {
710 return chunk_usable(ptr_to_chunk(ptr));
711 }
712 #endif /* DEFINE_MALLOC_USABLE_SIZE */
713
714 #ifdef DEFINE_MEMALIGN
715 /* Function memalign
716 * Allocate memory block aligned at specific boundary.
717 * align: required alignment. Must be power of 2. Return NULL
718 * if not power of 2. Undefined behavior is bigger than
719 * pointer value range.
720 * s: required size.
721 * Return: allocated memory pointer aligned to align
722 * Algorithm: Malloc a big enough block, padding pointer to aligned
723 * address, then truncate and free the tail if too big.
724 * Record the offset of align pointer and original pointer
725 * in the padding area.
726 */
memalign(size_t align,size_t s)727 void * memalign(size_t align, size_t s)
728 {
729 chunk_t * chunk_p;
730 size_t offset, size_with_padding;
731 char * allocated, * aligned_p;
732
733 /* Return NULL if align isn't power of 2 */
734 if ((align & (align-1)) != 0)
735 {
736 errno = EINVAL;
737 return NULL;
738 }
739
740 align = MAX(align, MALLOC_MINSIZE);
741
742 if (s > MALLOC_MAXSIZE - align)
743 {
744 errno = ENOMEM;
745 return NULL;
746 }
747
748 s = ALIGN_TO(MAX(s,1), MALLOC_CHUNK_ALIGN);
749
750 /* Make sure there's space to align the allocation and split
751 * off chunk_t from the front
752 */
753 size_with_padding = s + align + MALLOC_MINSIZE;
754
755 allocated = __malloc_malloc(size_with_padding);
756 if (allocated == NULL) return NULL;
757
758 chunk_p = ptr_to_chunk(allocated);
759
760 aligned_p = ALIGN_PTR(allocated, align);
761
762 offset = (size_t) (aligned_p - allocated);
763
764 /* Split off the front piece if necessary */
765 if (offset)
766 {
767 if (offset < MALLOC_MINSIZE) {
768 aligned_p += align;
769 offset += align;
770 }
771
772 chunk_t *new_chunk_p = ptr_to_chunk(aligned_p);
773 new_chunk_p->size = chunk_p->size - offset;
774
775 make_free_chunk(chunk_p, offset);
776
777 chunk_p = new_chunk_p;
778 }
779
780 offset = chunk_p->size - chunk_size(s);
781
782 /* Split off the back piece if large enough */
783 if (offset >= MALLOC_MINSIZE)
784 {
785 chunk_p->size -= offset;
786
787 make_free_chunk((chunk_t *) chunk_end(chunk_p), offset);
788 }
789 return aligned_p;
790 }
791 #ifdef _HAVE_ALIAS_ATTRIBUTE
792 __strong_reference(memalign, aligned_alloc);
793 #endif
794 #endif /* DEFINE_MEMALIGN */
795
796 #ifdef DEFINE_MALLOPT
mallopt(int parameter_number,int parameter_value)797 int mallopt(int parameter_number, int parameter_value)
798 {
799 (void) parameter_number;
800 (void) parameter_value;
801 return 0;
802 }
803 #endif /* DEFINE_MALLOPT */
804
805 #ifdef DEFINE_VALLOC
valloc(size_t s)806 void * valloc(size_t s)
807 {
808 return memalign(MALLOC_PAGE_ALIGN, s);
809 }
810 #endif /* DEFINE_VALLOC */
811
812 #ifdef DEFINE_PVALLOC
pvalloc(size_t s)813 void * pvalloc(size_t s)
814 {
815 if (s > MALLOC_MAXSIZE - MALLOC_PAGE_ALIGN)
816 {
817 errno = ENOMEM;
818 return NULL;
819 }
820
821 return valloc(ALIGN_TO(s, MALLOC_PAGE_ALIGN));
822 }
823 #endif /* DEFINE_PVALLOC */
824
825 #ifdef DEFINE_GETPAGESIZE
getpagesize(void)826 int getpagesize(void)
827 {
828 return MALLOC_PAGE_ALIGN;
829 }
830 #endif /* DEFINE_GETPAGESIZE */
831
832 #ifdef DEFINE_POSIX_MEMALIGN
posix_memalign(void ** memptr,size_t align,size_t size)833 int posix_memalign(void **memptr, size_t align, size_t size)
834 {
835 /* Return EINVAL if align isn't power of 2 or not a multiple of a pointer size */
836 if ((align & (align-1)) != 0 || align % sizeof(void*) != 0 || align == 0)
837 return EINVAL;
838
839 void *mem = memalign(align, size);
840
841 if (!mem)
842 return ENOMEM;
843
844 *memptr = mem;
845 return 0;
846 }
847 #endif
848