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 /** Function free
407 * Implementation of libc free.
408 * Algorithm:
409 * Maintain a global free chunk_t single link list, headed by global
410 * variable __malloc_free_list.
411 * When free, insert the to-be-freed chunk_t into free list. The place to
412 * insert should make sure all chunks are sorted by address from low to
413 * high. Then merge with neighbor chunks if adjacent.
414 */
free(void * free_p)415 void free (void * free_p)
416 {
417 chunk_t * p_to_free;
418 chunk_t ** p, * r;
419
420 if (free_p == NULL) return;
421
422 p_to_free = ptr_to_chunk(free_p);
423 p_to_free->next = NULL;
424 #if MALLOC_DEBUG
425 __malloc_validate_block(p_to_free);
426 #endif
427
428 MALLOC_LOCK;
429
430 for (p = &__malloc_free_list; (r = *p) != NULL; p = &r->next)
431 {
432 /* Insert in address order */
433 if (p_to_free < r)
434 break;
435
436 /* Merge blocks together */
437 if (chunk_end(r) == p_to_free)
438 {
439 r->size += p_to_free->size;
440 p_to_free = r;
441 r = r->next;
442 goto no_insert;
443 }
444
445 /* Check for double free */
446 if (p_to_free == r)
447 {
448 errno = ENOMEM;
449 MALLOC_UNLOCK;
450 return;
451 }
452
453 }
454 p_to_free->next = r;
455 *p = p_to_free;
456
457 no_insert:
458
459 /* Merge blocks together */
460 if (chunk_end(p_to_free) == r)
461 {
462 p_to_free->size += r->size;
463 p_to_free->next = r->next;
464 }
465
466 MALLOC_UNLOCK;
467 }
468 #ifdef _HAVE_ALIAS_ATTRIBUTE
469 #pragma GCC diagnostic push
470 #ifndef __clang__
471 #pragma GCC diagnostic ignored "-Wmissing-attributes"
472 #endif
473 __strong_reference(free, __malloc_free);
474 __strong_reference(free, cfree);
475 #pragma GCC diagnostic pop
476 #endif
477 #endif /* DEFINE_FREE */
478
479 #ifdef DEFINE_CFREE
480 #ifndef _HAVE_ALIAS_ATTRIBUTE
cfree(void * ptr)481 void cfree(void * ptr)
482 {
483 free(ptr);
484 }
485 #endif
486 #endif /* DEFINE_CFREE */
487
488 #ifdef DEFINE_CALLOC
489 #include "mul_overflow.h"
490 /* Function calloc
491 *
492 * Implement calloc by multiplying sizes (with overflow check) and
493 * calling malloc (which sets to zero)
494 */
495
calloc(size_t n,size_t elem)496 void * calloc(size_t n, size_t elem)
497 {
498 size_t bytes;
499
500 if (mul_overflow (n, elem, &bytes))
501 {
502 errno = ENOMEM;
503 return NULL;
504 }
505 return malloc(bytes);
506 }
507 #endif /* DEFINE_CALLOC */
508
509 #ifdef DEFINE_REALLOC
510
511 /* Function realloc
512 *
513 * Implement either by merging adjacent free memory
514 * or by calling malloc/memcpy
515 */
realloc(void * ptr,size_t size)516 void * realloc(void * ptr, size_t size)
517 {
518 void * mem;
519
520 if (ptr == NULL)
521 return malloc(size);
522
523 if (size == 0)
524 {
525 free(ptr);
526 return NULL;
527 }
528
529 if (size > MALLOC_MAXSIZE)
530 {
531 errno = ENOMEM;
532 return NULL;
533 }
534
535 size_t new_size = chunk_size(size);
536 chunk_t *p_to_realloc = ptr_to_chunk(ptr);
537
538 #if MALLOC_DEBUG
539 __malloc_validate_block(p_to_realloc);
540 #endif
541
542 size_t old_size = p_to_realloc->size;
543
544 /* See if we can avoid allocating new memory
545 * when increasing the size
546 */
547 if (new_size > old_size)
548 {
549 void *chunk_e = chunk_end(p_to_realloc);
550
551 MALLOC_LOCK;
552
553 if (__malloc_grow_chunk(p_to_realloc, new_size))
554 {
555 /* clear new memory */
556 memset(chunk_e, '\0', new_size - old_size);
557 /* adjust chunk_t size */
558 old_size = new_size;
559 }
560 else
561 {
562 chunk_t **p, *r;
563
564 /* Check to see if there's a chunk_t of free space just past
565 * the current block, merge it in in case that's useful
566 */
567 for (p = &__malloc_free_list; (r = *p) != NULL; p = &r->next)
568 {
569 if (r == chunk_e)
570 {
571 size_t r_size = r->size;
572
573 /* remove R from the free list */
574 *p = r->next;
575
576 /* clear the memory from r */
577 memset(r, '\0', r_size);
578
579 /* add it's size to our block */
580 old_size += r_size;
581 p_to_realloc->size = old_size;
582 break;
583 }
584 if (p_to_realloc < r)
585 break;
586 }
587 }
588
589 MALLOC_UNLOCK;
590 }
591
592 if (new_size <= old_size)
593 {
594 size_t extra = old_size - new_size;
595
596 /* If there's enough space left over, split it out
597 * and free it
598 */
599 if (extra >= MALLOC_MINSIZE) {
600 p_to_realloc->size = new_size;
601 make_free_chunk(chunk_end(p_to_realloc), extra);
602 }
603 return ptr;
604 }
605
606 /* No short cuts, allocate new memory and copy */
607
608 mem = malloc(size);
609 if (!mem)
610 return NULL;
611
612 memcpy(mem, ptr, old_size - MALLOC_HEAD);
613 free(ptr);
614
615 return mem;
616 }
617 #endif /* DEFINE_REALLOC */
618
619 #ifdef DEFINE_MALLINFO
620
621 volatile chunk_t *__malloc_block;
622
623 void
__malloc_validate_block(chunk_t * r)624 __malloc_validate_block(chunk_t *r)
625 {
626 __malloc_block = r;
627 assert (ALIGN_PTR(chunk_to_ptr(r), MALLOC_CHUNK_ALIGN) == chunk_to_ptr(r));
628 assert (ALIGN_PTR(r, MALLOC_HEAD_ALIGN) == r);
629 assert (r->size >= MALLOC_MINSIZE);
630 assert (r->size < 0x80000000UL);
631 assert (ALIGN_TO(r->size, MALLOC_HEAD_ALIGN) == r->size);
632 }
633
634 void
__malloc_validate(void)635 __malloc_validate(void)
636 {
637 chunk_t *r;
638
639 for (r = __malloc_free_list; r; r = r->next) {
640 __malloc_validate_block(r);
641 assert (r->next == NULL || (char *) r + r->size < (char *) r->next);
642 }
643 }
644
mallinfo(void)645 struct mallinfo mallinfo(void)
646 {
647 char * sbrk_now;
648 chunk_t * pf;
649 size_t free_size = 0;
650 size_t total_size;
651 size_t ordblks = 0;
652 struct mallinfo current_mallinfo;
653
654 MALLOC_LOCK;
655
656 __malloc_validate();
657
658 if (__malloc_sbrk_start == NULL) total_size = 0;
659 else {
660 sbrk_now = __malloc_sbrk_top;
661
662 if (sbrk_now == NULL)
663 total_size = (size_t)-1;
664 else
665 total_size = (size_t) (sbrk_now - __malloc_sbrk_start);
666 }
667
668 for (pf = __malloc_free_list; pf; pf = pf->next) {
669 ordblks++;
670 free_size += pf->size;
671 }
672
673 current_mallinfo.ordblks = ordblks;
674 current_mallinfo.arena = total_size;
675 current_mallinfo.fordblks = free_size;
676 current_mallinfo.uordblks = total_size - free_size;
677
678 MALLOC_UNLOCK;
679 return current_mallinfo;
680 }
681 #endif /* DEFINE_MALLINFO */
682
683 #ifdef DEFINE_MALLOC_STATS
684
malloc_stats(void)685 void malloc_stats(void)
686 {
687 struct mallinfo current_mallinfo;
688
689 current_mallinfo = mallinfo();
690 fprintf(stderr, "max system bytes = %10lu\n",
691 (long) current_mallinfo.arena);
692 fprintf(stderr, "system bytes = %10lu\n",
693 (long) current_mallinfo.arena);
694 fprintf(stderr, "in use bytes = %10lu\n",
695 (long) current_mallinfo.uordblks);
696 fprintf(stderr, "free blocks = %10lu\n",
697 (long) current_mallinfo.ordblks);
698 }
699 #endif /* DEFINE_MALLOC_STATS */
700
701 #ifdef DEFINE_MALLOC_USABLE_SIZE
malloc_usable_size(void * ptr)702 size_t malloc_usable_size(void * ptr)
703 {
704 return chunk_usable(ptr_to_chunk(ptr));
705 }
706 #endif /* DEFINE_MALLOC_USABLE_SIZE */
707
708 #ifdef DEFINE_MEMALIGN
709 /* Function memalign
710 * Allocate memory block aligned at specific boundary.
711 * align: required alignment. Must be power of 2. Return NULL
712 * if not power of 2. Undefined behavior is bigger than
713 * pointer value range.
714 * s: required size.
715 * Return: allocated memory pointer aligned to align
716 * Algorithm: Malloc a big enough block, padding pointer to aligned
717 * address, then truncate and free the tail if too big.
718 * Record the offset of align pointer and original pointer
719 * in the padding area.
720 */
memalign(size_t align,size_t s)721 void * memalign(size_t align, size_t s)
722 {
723 chunk_t * chunk_p;
724 size_t offset, size_with_padding;
725 char * allocated, * aligned_p;
726
727 /* Return NULL if align isn't power of 2 */
728 if ((align & (align-1)) != 0)
729 {
730 errno = EINVAL;
731 return NULL;
732 }
733
734 align = MAX(align, MALLOC_MINSIZE);
735
736 if (s > MALLOC_MAXSIZE - align)
737 {
738 errno = ENOMEM;
739 return NULL;
740 }
741
742 s = ALIGN_TO(MAX(s,1), MALLOC_CHUNK_ALIGN);
743
744 /* Make sure there's space to align the allocation and split
745 * off chunk_t from the front
746 */
747 size_with_padding = s + align + MALLOC_MINSIZE;
748
749 allocated = __malloc_malloc(size_with_padding);
750 if (allocated == NULL) return NULL;
751
752 chunk_p = ptr_to_chunk(allocated);
753
754 aligned_p = ALIGN_PTR(allocated, align);
755
756 offset = (size_t) (aligned_p - allocated);
757
758 /* Split off the front piece if necessary */
759 if (offset)
760 {
761 if (offset < MALLOC_MINSIZE) {
762 aligned_p += align;
763 offset += align;
764 }
765
766 chunk_t *new_chunk_p = ptr_to_chunk(aligned_p);
767 new_chunk_p->size = chunk_p->size - offset;
768
769 make_free_chunk(chunk_p, offset);
770
771 chunk_p = new_chunk_p;
772 }
773
774 offset = chunk_p->size - chunk_size(s);
775
776 /* Split off the back piece if large enough */
777 if (offset >= MALLOC_MINSIZE)
778 {
779 chunk_p->size -= offset;
780
781 make_free_chunk((chunk_t *) chunk_end(chunk_p), offset);
782 }
783 return aligned_p;
784 }
785 #ifdef _HAVE_ALIAS_ATTRIBUTE
786 __strong_reference(memalign, aligned_alloc);
787 #endif
788 #endif /* DEFINE_MEMALIGN */
789
790 #ifdef DEFINE_MALLOPT
mallopt(int parameter_number,int parameter_value)791 int mallopt(int parameter_number, int parameter_value)
792 {
793 (void) parameter_number;
794 (void) parameter_value;
795 return 0;
796 }
797 #endif /* DEFINE_MALLOPT */
798
799 #ifdef DEFINE_VALLOC
valloc(size_t s)800 void * valloc(size_t s)
801 {
802 return memalign(MALLOC_PAGE_ALIGN, s);
803 }
804 #endif /* DEFINE_VALLOC */
805
806 #ifdef DEFINE_PVALLOC
pvalloc(size_t s)807 void * pvalloc(size_t s)
808 {
809 if (s > MALLOC_MAXSIZE - MALLOC_PAGE_ALIGN)
810 {
811 errno = ENOMEM;
812 return NULL;
813 }
814
815 return valloc(ALIGN_TO(s, MALLOC_PAGE_ALIGN));
816 }
817 #endif /* DEFINE_PVALLOC */
818
819 #ifdef DEFINE_GETPAGESIZE
getpagesize(void)820 int getpagesize(void)
821 {
822 return MALLOC_PAGE_ALIGN;
823 }
824 #endif /* DEFINE_GETPAGESIZE */
825
826 #ifdef DEFINE_POSIX_MEMALIGN
posix_memalign(void ** memptr,size_t align,size_t size)827 int posix_memalign(void **memptr, size_t align, size_t size)
828 {
829 /* Return EINVAL if align isn't power of 2 or not a multiple of a pointer size */
830 if ((align & (align-1)) != 0 || align % sizeof(void*) != 0 || align == 0)
831 return EINVAL;
832
833 void *mem = memalign(align, size);
834
835 if (!mem)
836 return ENOMEM;
837
838 *memptr = mem;
839 return 0;
840 }
841 #endif
842