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