• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <limits.h>
2 #include <stdint.h>
3 #include <errno.h>
4 #include <sys/mman.h>
5 #include "libc.h"
6 #include "syscall.h"
7 #include "malloc_impl.h"
8 
9 #include <sys/prctl.h>
10 
11 /* This function returns true if the interval [old,new]
12  * intersects the 'len'-sized interval below &libc.auxv
13  * (interpreted as the main-thread stack) or below &b
14  * (the current stack). It is used to defend against
15  * buggy brk implementations that can cross the stack. */
16 
traverses_stack_p(uintptr_t old,uintptr_t new)17 static int traverses_stack_p(uintptr_t old, uintptr_t new)
18 {
19 	const uintptr_t len = 8<<20;
20 	uintptr_t a, b;
21 
22 	b = (uintptr_t)libc.auxv;
23 	a = b > len ? b-len : 0;
24 	if (new>a && old<b) return 1;
25 
26 	b = (uintptr_t)&b;
27 	a = b > len ? b-len : 0;
28 	if (new>a && old<b) return 1;
29 
30 	return 0;
31 }
32 
33 /* Expand the heap in-place if brk can be used, or otherwise via mmap,
34  * using an exponential lower bound on growth by mmap to make
35  * fragmentation asymptotically irrelevant. The size argument is both
36  * an input and an output, since the caller needs to know the size
37  * allocated, which will be larger than requested due to page alignment
38  * and mmap minimum size rules. The caller is responsible for locking
39  * to prevent concurrent calls. */
40 
__expand_heap(size_t * pn)41 void *__expand_heap(size_t *pn)
42 {
43 	static uintptr_t brk;
44 	static unsigned mmap_step;
45 	size_t n = *pn;
46 
47 	if (n > SIZE_MAX/2 - PAGE_SIZE) {
48 		errno = ENOMEM;
49 		return 0;
50 	}
51 	n += -n & PAGE_SIZE-1;
52 
53 	if (!brk) {
54 		brk = __syscall(SYS_brk, 0);
55 		brk += -brk & PAGE_SIZE-1;
56 	}
57 
58 	if (n < SIZE_MAX-brk && !traverses_stack_p(brk, brk+n)
59 	    && __syscall(SYS_brk, brk+n)==brk+n) {
60 		*pn = n;
61 		brk += n;
62 		return (void *)(brk-n);
63 	}
64 
65 	size_t min = (size_t)PAGE_SIZE << mmap_step/2;
66 	if (n < min) n = min;
67 	void *area = __mmap(0, n, PROT_READ|PROT_WRITE,
68 		MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
69 	if (area == MAP_FAILED) return 0;
70 	prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, area, n, "native_heap:musl");
71 
72 	*pn = n;
73 	mmap_step++;
74 	return area;
75 }
76