expand_heap.c 1.8 KB

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