OLD | NEW |
| (Empty) |
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 | |
26 #include "config.h" | |
27 #include "OSAllocator.h" | |
28 | |
29 #if OS(UNIX) | |
30 | |
31 #include "PageAllocation.h" | |
32 #include <errno.h> | |
33 #include <sys/mman.h> | |
34 #include <wtf/Assertions.h> | |
35 #include <wtf/UnusedParam.h> | |
36 | |
37 namespace WTF { | |
38 | |
39 void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable,
bool executable, bool includesGuardPages) | |
40 { | |
41 #if OS(QNX) | |
42 // Reserve memory with PROT_NONE and MAP_LAZY so it isn't committed now. | |
43 void* result = mmap(0, bytes, PROT_NONE, MAP_LAZY | MAP_PRIVATE | MAP_ANON,
-1, 0); | |
44 if (result == MAP_FAILED) | |
45 CRASH(); | |
46 #elif OS(LINUX) | |
47 UNUSED_PARAM(usage); | |
48 UNUSED_PARAM(writable); | |
49 UNUSED_PARAM(executable); | |
50 UNUSED_PARAM(includesGuardPages); | |
51 | |
52 void* result = mmap(0, bytes, PROT_NONE, MAP_NORESERVE | MAP_PRIVATE | MAP_A
NON, -1, 0); | |
53 if (result == MAP_FAILED) | |
54 CRASH(); | |
55 madvise(result, bytes, MADV_DONTNEED); | |
56 #else | |
57 void* result = reserveAndCommit(bytes, usage, writable, executable, includes
GuardPages); | |
58 #if HAVE(MADV_FREE_REUSE) | |
59 // To support the "reserve then commit" model, we have to initially decommit
. | |
60 while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN)
{ } | |
61 #endif | |
62 | |
63 #endif // OS(QNX) | |
64 | |
65 return result; | |
66 } | |
67 | |
68 void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bo
ol executable, bool includesGuardPages) | |
69 { | |
70 // All POSIX reservations start out logically committed. | |
71 int protection = PROT_READ; | |
72 if (writable) | |
73 protection |= PROT_WRITE; | |
74 if (executable) | |
75 protection |= PROT_EXEC; | |
76 | |
77 int flags = MAP_PRIVATE | MAP_ANON; | |
78 | |
79 #if OS(DARWIN) | |
80 int fd = usage; | |
81 #else | |
82 UNUSED_PARAM(usage); | |
83 int fd = -1; | |
84 #endif | |
85 | |
86 void* result = 0; | |
87 #if (OS(DARWIN) && CPU(X86_64)) | |
88 if (executable) { | |
89 ASSERT(includesGuardPages); | |
90 // Cook up an address to allocate at, using the following recipe: | |
91 // 17 bits of zero, stay in userspace kids. | |
92 // 26 bits of randomness for ASLR. | |
93 // 21 bits of zero, at least stay aligned within one level of the page
tables. | |
94 // | |
95 // But! - as a temporary workaround for some plugin problems (rdar://pro
blem/6812854), | |
96 // for now instead of 2^26 bits of ASLR lets stick with 25 bits of rando
mization plus | |
97 // 2^24, which should put up somewhere in the middle of userspace (in th
e address range | |
98 // 0x200000000000 .. 0x5fffffffffff). | |
99 intptr_t randomLocation = 0; | |
100 randomLocation = arc4random() & ((1 << 25) - 1); | |
101 randomLocation += (1 << 24); | |
102 randomLocation <<= 21; | |
103 result = reinterpret_cast<void*>(randomLocation); | |
104 } | |
105 #endif | |
106 | |
107 result = mmap(result, bytes, protection, flags, fd, 0); | |
108 if (result == MAP_FAILED) { | |
109 #if ENABLE(LLINT) | |
110 if (executable) | |
111 result = 0; | |
112 else | |
113 #endif | |
114 CRASH(); | |
115 } | |
116 if (result && includesGuardPages) { | |
117 // We use mmap to remap the guardpages rather than using mprotect as | |
118 // mprotect results in multiple references to the code region. This | |
119 // breaks the madvise based mechanism we use to return physical memory | |
120 // to the OS. | |
121 mmap(result, pageSize(), PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON,
fd, 0); | |
122 mmap(static_cast<char*>(result) + bytes - pageSize(), pageSize(), PROT_N
ONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, fd, 0); | |
123 } | |
124 return result; | |
125 } | |
126 | |
127 void OSAllocator::commit(void* address, size_t bytes, bool writable, bool execut
able) | |
128 { | |
129 #if OS(QNX) | |
130 int protection = PROT_READ; | |
131 if (writable) | |
132 protection |= PROT_WRITE; | |
133 if (executable) | |
134 protection |= PROT_EXEC; | |
135 if (MAP_FAILED == mmap(address, bytes, protection, MAP_FIXED | MAP_PRIVATE |
MAP_ANON, -1, 0)) | |
136 CRASH(); | |
137 #elif OS(LINUX) | |
138 int protection = PROT_READ; | |
139 if (writable) | |
140 protection |= PROT_WRITE; | |
141 if (executable) | |
142 protection |= PROT_EXEC; | |
143 if (mprotect(address, bytes, protection)) | |
144 CRASH(); | |
145 madvise(address, bytes, MADV_WILLNEED); | |
146 #elif HAVE(MADV_FREE_REUSE) | |
147 UNUSED_PARAM(writable); | |
148 UNUSED_PARAM(executable); | |
149 while (madvise(address, bytes, MADV_FREE_REUSE) == -1 && errno == EAGAIN) {
} | |
150 #else | |
151 // Non-MADV_FREE_REUSE reservations automatically commit on demand. | |
152 UNUSED_PARAM(address); | |
153 UNUSED_PARAM(bytes); | |
154 UNUSED_PARAM(writable); | |
155 UNUSED_PARAM(executable); | |
156 #endif | |
157 } | |
158 | |
159 void OSAllocator::decommit(void* address, size_t bytes) | |
160 { | |
161 #if OS(QNX) | |
162 // Use PROT_NONE and MAP_LAZY to decommit the pages. | |
163 mmap(address, bytes, PROT_NONE, MAP_FIXED | MAP_LAZY | MAP_PRIVATE | MAP_ANO
N, -1, 0); | |
164 #elif OS(LINUX) | |
165 madvise(address, bytes, MADV_DONTNEED); | |
166 if (mprotect(address, bytes, PROT_NONE)) | |
167 CRASH(); | |
168 #elif HAVE(MADV_FREE_REUSE) | |
169 while (madvise(address, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN)
{ } | |
170 #elif HAVE(MADV_FREE) | |
171 while (madvise(address, bytes, MADV_FREE) == -1 && errno == EAGAIN) { } | |
172 #elif HAVE(MADV_DONTNEED) | |
173 while (madvise(address, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { } | |
174 #else | |
175 UNUSED_PARAM(address); | |
176 UNUSED_PARAM(bytes); | |
177 #endif | |
178 } | |
179 | |
180 void OSAllocator::releaseDecommitted(void* address, size_t bytes) | |
181 { | |
182 int result = munmap(address, bytes); | |
183 if (result == -1) | |
184 CRASH(); | |
185 } | |
186 | |
187 } // namespace WTF | |
188 | |
189 #endif // OS(UNIX) | |
OLD | NEW |