1570af302Sopenharmony_ci#include <stdlib.h> 2570af302Sopenharmony_ci#include <stdint.h> 3570af302Sopenharmony_ci#include <limits.h> 4570af302Sopenharmony_ci#include <errno.h> 5570af302Sopenharmony_ci#include <sys/mman.h> 6570af302Sopenharmony_ci#include "libc.h" 7570af302Sopenharmony_ci#include "lock.h" 8570af302Sopenharmony_ci#include "syscall.h" 9570af302Sopenharmony_ci#include "fork_impl.h" 10570af302Sopenharmony_ci 11570af302Sopenharmony_ci#ifdef USE_JEMALLOC 12570af302Sopenharmony_ciextern void* je_malloc(size_t size); 13570af302Sopenharmony_ci#endif 14570af302Sopenharmony_ci 15570af302Sopenharmony_ci#define ALIGN 16 16570af302Sopenharmony_ci 17570af302Sopenharmony_ci/* This function returns true if the interval [old,new] 18570af302Sopenharmony_ci * intersects the 'len'-sized interval below &libc.auxv 19570af302Sopenharmony_ci * (interpreted as the main-thread stack) or below &b 20570af302Sopenharmony_ci * (the current stack). It is used to defend against 21570af302Sopenharmony_ci * buggy brk implementations that can cross the stack. */ 22570af302Sopenharmony_ci 23570af302Sopenharmony_cistatic int traverses_stack_p(uintptr_t old, uintptr_t new) 24570af302Sopenharmony_ci{ 25570af302Sopenharmony_ci const uintptr_t len = 8<<20; 26570af302Sopenharmony_ci uintptr_t a, b; 27570af302Sopenharmony_ci 28570af302Sopenharmony_ci b = (uintptr_t)libc.auxv; 29570af302Sopenharmony_ci a = b > len ? b-len : 0; 30570af302Sopenharmony_ci if (new>a && old<b) return 1; 31570af302Sopenharmony_ci 32570af302Sopenharmony_ci b = (uintptr_t)&b; 33570af302Sopenharmony_ci a = b > len ? b-len : 0; 34570af302Sopenharmony_ci if (new>a && old<b) return 1; 35570af302Sopenharmony_ci 36570af302Sopenharmony_ci return 0; 37570af302Sopenharmony_ci} 38570af302Sopenharmony_ci 39570af302Sopenharmony_cistatic volatile int lock[1]; 40570af302Sopenharmony_civolatile int *const __bump_lockptr = lock; 41570af302Sopenharmony_ci 42570af302Sopenharmony_cistatic void *__simple_malloc(size_t n) 43570af302Sopenharmony_ci{ 44570af302Sopenharmony_ci static uintptr_t brk, cur, end; 45570af302Sopenharmony_ci static unsigned mmap_step; 46570af302Sopenharmony_ci size_t align=1; 47570af302Sopenharmony_ci void *p; 48570af302Sopenharmony_ci 49570af302Sopenharmony_ci if (n > SIZE_MAX/2) { 50570af302Sopenharmony_ci errno = ENOMEM; 51570af302Sopenharmony_ci return 0; 52570af302Sopenharmony_ci } 53570af302Sopenharmony_ci 54570af302Sopenharmony_ci if (!n) n++; 55570af302Sopenharmony_ci while (align<n && align<ALIGN) 56570af302Sopenharmony_ci align += align; 57570af302Sopenharmony_ci 58570af302Sopenharmony_ci LOCK(lock); 59570af302Sopenharmony_ci 60570af302Sopenharmony_ci cur += -cur & align-1; 61570af302Sopenharmony_ci 62570af302Sopenharmony_ci if (n > end-cur) { 63570af302Sopenharmony_ci size_t req = n - (end-cur) + PAGE_SIZE-1 & -PAGE_SIZE; 64570af302Sopenharmony_ci 65570af302Sopenharmony_ci if (!cur) { 66570af302Sopenharmony_ci brk = __syscall(SYS_brk, 0); 67570af302Sopenharmony_ci brk += -brk & PAGE_SIZE-1; 68570af302Sopenharmony_ci cur = end = brk; 69570af302Sopenharmony_ci } 70570af302Sopenharmony_ci 71570af302Sopenharmony_ci if (brk == end && req < SIZE_MAX-brk 72570af302Sopenharmony_ci && !traverses_stack_p(brk, brk+req) 73570af302Sopenharmony_ci && __syscall(SYS_brk, brk+req)==brk+req) { 74570af302Sopenharmony_ci brk = end += req; 75570af302Sopenharmony_ci } else { 76570af302Sopenharmony_ci int new_area = 0; 77570af302Sopenharmony_ci req = n + PAGE_SIZE-1 & -PAGE_SIZE; 78570af302Sopenharmony_ci /* Only make a new area rather than individual mmap 79570af302Sopenharmony_ci * if wasted space would be over 1/8 of the map. */ 80570af302Sopenharmony_ci if (req-n > req/8) { 81570af302Sopenharmony_ci /* Geometric area size growth up to 64 pages, 82570af302Sopenharmony_ci * bounding waste by 1/8 of the area. */ 83570af302Sopenharmony_ci size_t min = PAGE_SIZE<<(mmap_step/2); 84570af302Sopenharmony_ci if (min-n > end-cur) { 85570af302Sopenharmony_ci if (req < min) { 86570af302Sopenharmony_ci req = min; 87570af302Sopenharmony_ci if (mmap_step < 12) 88570af302Sopenharmony_ci mmap_step++; 89570af302Sopenharmony_ci } 90570af302Sopenharmony_ci new_area = 1; 91570af302Sopenharmony_ci } 92570af302Sopenharmony_ci } 93570af302Sopenharmony_ci void *mem = __mmap(0, req, PROT_READ|PROT_WRITE, 94570af302Sopenharmony_ci MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 95570af302Sopenharmony_ci if (mem == MAP_FAILED || !new_area) { 96570af302Sopenharmony_ci UNLOCK(lock); 97570af302Sopenharmony_ci return mem==MAP_FAILED ? 0 : mem; 98570af302Sopenharmony_ci } 99570af302Sopenharmony_ci cur = (uintptr_t)mem; 100570af302Sopenharmony_ci end = cur + req; 101570af302Sopenharmony_ci } 102570af302Sopenharmony_ci } 103570af302Sopenharmony_ci 104570af302Sopenharmony_ci p = (void *)cur; 105570af302Sopenharmony_ci cur += n; 106570af302Sopenharmony_ci UNLOCK(lock); 107570af302Sopenharmony_ci return p; 108570af302Sopenharmony_ci} 109570af302Sopenharmony_ci 110570af302Sopenharmony_ciweak_alias(__simple_malloc, __libc_malloc_impl); 111570af302Sopenharmony_ci 112570af302Sopenharmony_civoid *__libc_malloc(size_t n) 113570af302Sopenharmony_ci{ 114570af302Sopenharmony_ci return __libc_malloc_impl(n); 115570af302Sopenharmony_ci} 116570af302Sopenharmony_ci 117570af302Sopenharmony_cistatic void *default_malloc(size_t n) 118570af302Sopenharmony_ci{ 119570af302Sopenharmony_ci#ifdef USE_JEMALLOC 120570af302Sopenharmony_ci return je_malloc(n); 121570af302Sopenharmony_ci#endif 122570af302Sopenharmony_ci return __libc_malloc_impl(n); 123570af302Sopenharmony_ci} 124570af302Sopenharmony_ci 125570af302Sopenharmony_ciweak_alias(default_malloc, malloc); 126