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