OSAllocatorPosix.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. * Copyright (C) 2010 Apple Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
  14. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  15. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
  17. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  23. * THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "config.h"
  26. #include "OSAllocator.h"
  27. #if OS(UNIX)
  28. #include "PageAllocation.h"
  29. #include <errno.h>
  30. #include <sys/mman.h>
  31. #include <wtf/Assertions.h>
  32. namespace WTF {
  33. void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
  34. {
  35. #if OS(QNX)
  36. UNUSED_PARAM(usage);
  37. UNUSED_PARAM(writable);
  38. UNUSED_PARAM(executable);
  39. UNUSED_PARAM(includesGuardPages);
  40. // Reserve memory with PROT_NONE and MAP_LAZY so it isn't committed now.
  41. void* result = mmap(0, bytes, PROT_NONE, MAP_LAZY | MAP_PRIVATE | MAP_ANON, -1, 0);
  42. if (result == MAP_FAILED)
  43. CRASH();
  44. #elif OS(LINUX)
  45. UNUSED_PARAM(usage);
  46. UNUSED_PARAM(writable);
  47. UNUSED_PARAM(executable);
  48. UNUSED_PARAM(includesGuardPages);
  49. void* result = mmap(0, bytes, PROT_NONE, MAP_NORESERVE | MAP_PRIVATE | MAP_ANON, -1, 0);
  50. if (result == MAP_FAILED)
  51. CRASH();
  52. madvise(result, bytes, MADV_DONTNEED);
  53. #else
  54. void* result = reserveAndCommit(bytes, usage, writable, executable, includesGuardPages);
  55. #if HAVE(MADV_FREE_REUSE)
  56. // To support the "reserve then commit" model, we have to initially decommit.
  57. while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
  58. #endif
  59. #endif // OS(QNX)
  60. return result;
  61. }
  62. void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
  63. {
  64. // All POSIX reservations start out logically committed.
  65. int protection = PROT_READ;
  66. if (writable)
  67. protection |= PROT_WRITE;
  68. if (executable)
  69. protection |= PROT_EXEC;
  70. int flags = MAP_PRIVATE | MAP_ANON;
  71. #if PLATFORM(IOS)
  72. if (executable)
  73. flags |= MAP_JIT;
  74. #endif
  75. #if OS(DARWIN)
  76. int fd = usage;
  77. #else
  78. UNUSED_PARAM(usage);
  79. int fd = -1;
  80. #endif
  81. void* result = 0;
  82. #if (OS(DARWIN) && CPU(X86_64))
  83. if (executable) {
  84. ASSERT(includesGuardPages);
  85. // Cook up an address to allocate at, using the following recipe:
  86. // 17 bits of zero, stay in userspace kids.
  87. // 26 bits of randomness for ASLR.
  88. // 21 bits of zero, at least stay aligned within one level of the pagetables.
  89. //
  90. // But! - as a temporary workaround for some plugin problems (rdar://problem/6812854),
  91. // for now instead of 2^26 bits of ASLR lets stick with 25 bits of randomization plus
  92. // 2^24, which should put up somewhere in the middle of userspace (in the address range
  93. // 0x200000000000 .. 0x5fffffffffff).
  94. intptr_t randomLocation = 0;
  95. randomLocation = arc4random() & ((1 << 25) - 1);
  96. randomLocation += (1 << 24);
  97. randomLocation <<= 21;
  98. result = reinterpret_cast<void*>(randomLocation);
  99. }
  100. #endif
  101. result = mmap(result, bytes, protection, flags, fd, 0);
  102. if (result == MAP_FAILED) {
  103. #if ENABLE(LLINT)
  104. if (executable)
  105. result = 0;
  106. else
  107. #endif
  108. CRASH();
  109. }
  110. if (result && includesGuardPages) {
  111. // We use mmap to remap the guardpages rather than using mprotect as
  112. // mprotect results in multiple references to the code region. This
  113. // breaks the madvise based mechanism we use to return physical memory
  114. // to the OS.
  115. mmap(result, pageSize(), PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, fd, 0);
  116. mmap(static_cast<char*>(result) + bytes - pageSize(), pageSize(), PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, fd, 0);
  117. }
  118. return result;
  119. }
  120. void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
  121. {
  122. #if OS(QNX)
  123. int protection = PROT_READ;
  124. if (writable)
  125. protection |= PROT_WRITE;
  126. if (executable)
  127. protection |= PROT_EXEC;
  128. if (MAP_FAILED == mmap(address, bytes, protection, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0))
  129. CRASH();
  130. #elif OS(LINUX)
  131. int protection = PROT_READ;
  132. if (writable)
  133. protection |= PROT_WRITE;
  134. if (executable)
  135. protection |= PROT_EXEC;
  136. if (mprotect(address, bytes, protection))
  137. CRASH();
  138. madvise(address, bytes, MADV_WILLNEED);
  139. #elif HAVE(MADV_FREE_REUSE)
  140. UNUSED_PARAM(writable);
  141. UNUSED_PARAM(executable);
  142. while (madvise(address, bytes, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { }
  143. #else
  144. // Non-MADV_FREE_REUSE reservations automatically commit on demand.
  145. UNUSED_PARAM(address);
  146. UNUSED_PARAM(bytes);
  147. UNUSED_PARAM(writable);
  148. UNUSED_PARAM(executable);
  149. #endif
  150. }
  151. void OSAllocator::decommit(void* address, size_t bytes)
  152. {
  153. #if OS(QNX)
  154. // Use PROT_NONE and MAP_LAZY to decommit the pages.
  155. mmap(address, bytes, PROT_NONE, MAP_FIXED | MAP_LAZY | MAP_PRIVATE | MAP_ANON, -1, 0);
  156. #elif OS(LINUX)
  157. madvise(address, bytes, MADV_DONTNEED);
  158. if (mprotect(address, bytes, PROT_NONE))
  159. CRASH();
  160. #elif HAVE(MADV_FREE_REUSE)
  161. while (madvise(address, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
  162. #elif HAVE(MADV_FREE)
  163. while (madvise(address, bytes, MADV_FREE) == -1 && errno == EAGAIN) { }
  164. #elif HAVE(MADV_DONTNEED)
  165. while (madvise(address, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { }
  166. #else
  167. UNUSED_PARAM(address);
  168. UNUSED_PARAM(bytes);
  169. #endif
  170. }
  171. void OSAllocator::releaseDecommitted(void* address, size_t bytes)
  172. {
  173. int result = munmap(address, bytes);
  174. if (result == -1)
  175. CRASH();
  176. }
  177. } // namespace WTF
  178. #endif // OS(UNIX)