Mercurial > hg > truffle
comparison src/share/vm/memory/guardedMemory.hpp @ 20318:fa62fb12cdca
6311046: -Xcheck:jni should support checking of GetPrimitiveArrayCritical.
Summary: Wrapped memory with standard bounds checking "GuardedMemory".
Reviewed-by: zgu, fparain, dcubed
author | dsimms |
---|---|
date | Thu, 14 Aug 2014 15:16:07 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
20317:ee019285a52c | 20318:fa62fb12cdca |
---|---|
1 /* | |
2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 * | |
23 */ | |
24 | |
25 #ifndef SHARE_VM_MEMORY_GUARDED_MEMORY_HPP | |
26 #define SHARE_VM_MEMORY_GUARDED_MEMORY_HPP | |
27 | |
28 #include "memory/allocation.hpp" | |
29 #include "utilities/globalDefinitions.hpp" | |
30 | |
31 /** | |
32 * Guarded memory for detecting buffer overrun. | |
33 * | |
34 * Allows allocations to be wrapped with padded bytes of a known byte pattern, | |
35 * that is a "guard". Guard patterns may be verified to detect buffer overruns. | |
36 * | |
37 * Primarily used by "debug malloc" and "checked JNI". | |
38 * | |
39 * Memory layout: | |
40 * | |
41 * |Offset | Content | Description | | |
42 * |------------------------------------------------------------ | |
43 * |base_addr | 0xABABABABABABABAB | Head guard | | |
44 * |+16 | <size_t:user_size> | User data size | | |
45 * |+sizeof(uintptr_t) | <tag> | Tag word | | |
46 * |+sizeof(void*) | 0xF1 <user_data> ( | User data | | |
47 * |+user_size | 0xABABABABABABABAB | Tail guard | | |
48 * ------------------------------------------------------------- | |
49 * | |
50 * Where: | |
51 * - guard padding uses "badResourceValue" (0xAB) | |
52 * - tag word is general purpose | |
53 * - user data | |
54 * -- initially padded with "uninitBlockPad" (0xF1), | |
55 * -- to "freeBlockPad" (0xBA), when freed | |
56 * | |
57 * Usage: | |
58 * | |
59 * * Allocations: one may wrap allocations with guard memory: | |
60 * <code> | |
61 * Thing* alloc_thing() { | |
62 * void* mem = user_alloc_fn(GuardedMemory::get_total_size(sizeof(thing))); | |
63 * GuardedMemory guarded(mem, sizeof(thing)); | |
64 * return (Thing*) guarded.get_user_ptr(); | |
65 * } | |
66 * </code> | |
67 * * Verify: memory guards are still in tact | |
68 * <code> | |
69 * bool verify_thing(Thing* thing) { | |
70 * GuardedMemory guarded((void*)thing); | |
71 * return guarded.verify_guards(); | |
72 * } | |
73 * </code> | |
74 * * Free: one may mark bytes as freed (further debugging support) | |
75 * <code> | |
76 * void free_thing(Thing* thing) { | |
77 * GuardedMemory guarded((void*)thing); | |
78 * assert(guarded.verify_guards(), "Corrupt thing"); | |
79 * user_free_fn(guards.release_for_freeing(); | |
80 * } | |
81 * </code> | |
82 */ | |
83 class GuardedMemory : StackObj { // Wrapper on stack | |
84 | |
85 // Private inner classes for memory layout... | |
86 | |
87 protected: | |
88 | |
89 /** | |
90 * Guard class for header and trailer known pattern to test for overwrites. | |
91 */ | |
92 class Guard { // Class for raw memory (no vtbl allowed) | |
93 friend class GuardedMemory; | |
94 protected: | |
95 enum { | |
96 GUARD_SIZE = 16 | |
97 }; | |
98 | |
99 u_char _guard[GUARD_SIZE]; | |
100 | |
101 public: | |
102 | |
103 void build() { | |
104 u_char* c = _guard; // Possibly unaligned if tail guard | |
105 u_char* end = c + GUARD_SIZE; | |
106 while (c < end) { | |
107 *c = badResourceValue; | |
108 c++; | |
109 } | |
110 } | |
111 | |
112 bool verify() const { | |
113 u_char* c = (u_char*) _guard; | |
114 u_char* end = c + GUARD_SIZE; | |
115 while (c < end) { | |
116 if (*c != badResourceValue) { | |
117 return false; | |
118 } | |
119 c++; | |
120 } | |
121 return true; | |
122 } | |
123 | |
124 }; // GuardedMemory::Guard | |
125 | |
126 /** | |
127 * Header guard and size | |
128 */ | |
129 class GuardHeader : Guard { | |
130 friend class GuardedMemory; | |
131 protected: | |
132 // Take care in modifying fields here, will effect alignment | |
133 // e.g. x86 ABI 16 byte stack alignment | |
134 union { | |
135 uintptr_t __unused_full_word1; | |
136 size_t _user_size; | |
137 }; | |
138 void* _tag; | |
139 public: | |
140 void set_user_size(const size_t usz) { _user_size = usz; } | |
141 size_t get_user_size() const { return _user_size; } | |
142 | |
143 void set_tag(const void* tag) { _tag = (void*) tag; } | |
144 void* get_tag() const { return _tag; } | |
145 | |
146 }; // GuardedMemory::GuardHeader | |
147 | |
148 // Guarded Memory... | |
149 | |
150 protected: | |
151 u_char* _base_addr; | |
152 | |
153 public: | |
154 | |
155 /** | |
156 * Create new guarded memory. | |
157 * | |
158 * Wraps, starting at the given "base_ptr" with guards. Use "get_user_ptr()" | |
159 * to return a pointer suitable for user data. | |
160 * | |
161 * @param base_ptr allocation wishing to be wrapped, must be at least "GuardedMemory::get_total_size()" bytes. | |
162 * @param user_size the size of the user data to be wrapped. | |
163 * @param tag optional general purpose tag. | |
164 */ | |
165 GuardedMemory(void* base_ptr, const size_t user_size, const void* tag = NULL) { | |
166 wrap_with_guards(base_ptr, user_size, tag); | |
167 } | |
168 | |
169 /** | |
170 * Wrap existing guarded memory. | |
171 * | |
172 * To use this constructor, one must have created guarded memory with | |
173 * "GuardedMemory(void*, size_t, void*)" (or indirectly via helper, e.g. "wrap_copy()"). | |
174 * | |
175 * @param user_p existing wrapped memory. | |
176 */ | |
177 GuardedMemory(void* userp) { | |
178 u_char* user_ptr = (u_char*) userp; | |
179 assert((uintptr_t)user_ptr > (sizeof(GuardHeader) + 0x1000), "Invalid pointer"); | |
180 _base_addr = (user_ptr - sizeof(GuardHeader)); | |
181 } | |
182 | |
183 /** | |
184 * Create new guarded memory. | |
185 * | |
186 * Wraps, starting at the given "base_ptr" with guards. Allows reuse of stack allocated helper. | |
187 * | |
188 * @param base_ptr allocation wishing to be wrapped, must be at least "GuardedMemory::get_total_size()" bytes. | |
189 * @param user_size the size of the user data to be wrapped. | |
190 * @param tag optional general purpose tag. | |
191 * | |
192 * @return user data pointer (inner pointer to supplied "base_ptr"). | |
193 */ | |
194 void* wrap_with_guards(void* base_ptr, size_t user_size, const void* tag = NULL) { | |
195 assert(base_ptr != NULL, "Attempt to wrap NULL with memory guard"); | |
196 _base_addr = (u_char*)base_ptr; | |
197 get_head_guard()->build(); | |
198 get_head_guard()->set_user_size(user_size); | |
199 get_tail_guard()->build(); | |
200 set_tag(tag); | |
201 set_user_bytes(uninitBlockPad); | |
202 assert(verify_guards(), "Expected valid memory guards"); | |
203 return get_user_ptr(); | |
204 } | |
205 | |
206 /** | |
207 * Verify head and tail guards. | |
208 * | |
209 * @return true if guards are intact, false would indicate a buffer overrun. | |
210 */ | |
211 bool verify_guards() const { | |
212 if (_base_addr != NULL) { | |
213 return (get_head_guard()->verify() && get_tail_guard()->verify()); | |
214 } | |
215 return false; | |
216 } | |
217 | |
218 /** | |
219 * Set the general purpose tag. | |
220 * | |
221 * @param tag general purpose tag. | |
222 */ | |
223 void set_tag(const void* tag) { get_head_guard()->set_tag(tag); } | |
224 | |
225 /** | |
226 * Return the general purpose tag. | |
227 * | |
228 * @return the general purpose tag, defaults to NULL. | |
229 */ | |
230 void* get_tag() const { return get_head_guard()->get_tag(); } | |
231 | |
232 /** | |
233 * Return the size of the user data. | |
234 * | |
235 * @return the size of the user data. | |
236 */ | |
237 size_t get_user_size() const { | |
238 assert(_base_addr, "Not wrapping any memory"); | |
239 return get_head_guard()->get_user_size(); | |
240 } | |
241 | |
242 /** | |
243 * Return the user data pointer. | |
244 * | |
245 * @return the user data pointer. | |
246 */ | |
247 u_char* get_user_ptr() const { | |
248 assert(_base_addr, "Not wrapping any memory"); | |
249 return _base_addr + sizeof(GuardHeader); | |
250 } | |
251 | |
252 /** | |
253 * Release the wrapped pointer for resource freeing. | |
254 * | |
255 * Pads the user data with "freeBlockPad", and dis-associates the helper. | |
256 * | |
257 * @return the original base pointer used to wrap the data. | |
258 */ | |
259 void* release_for_freeing() { | |
260 set_user_bytes(freeBlockPad); | |
261 return release(); | |
262 } | |
263 | |
264 /** | |
265 * Dis-associate the help from the original base address. | |
266 * | |
267 * @return the original base pointer used to wrap the data. | |
268 */ | |
269 void* release() { | |
270 void* p = (void*) _base_addr; | |
271 _base_addr = NULL; | |
272 return p; | |
273 } | |
274 | |
275 virtual void print_on(outputStream* st) const; | |
276 | |
277 protected: | |
278 GuardHeader* get_head_guard() const { return (GuardHeader*) _base_addr; } | |
279 Guard* get_tail_guard() const { return (Guard*) (get_user_ptr() + get_user_size()); }; | |
280 void set_user_bytes(u_char ch) { | |
281 memset(get_user_ptr(), ch, get_user_size()); | |
282 } | |
283 | |
284 public: | |
285 /** | |
286 * Return the total size required for wrapping the given user size. | |
287 * | |
288 * @return the total size required for wrapping the given user size. | |
289 */ | |
290 static size_t get_total_size(size_t user_size) { | |
291 size_t total_size = sizeof(GuardHeader) + user_size + sizeof(Guard); | |
292 assert(total_size > user_size, "Unexpected wrap-around"); | |
293 return total_size; | |
294 } | |
295 | |
296 // Helper functions... | |
297 | |
298 /** | |
299 * Wrap a copy of size "len" of "ptr". | |
300 * | |
301 * @param ptr the memory to be copied | |
302 * @param len the length of the copy | |
303 * @param tag optional general purpose tag (see GuardedMemory::get_tag()) | |
304 * | |
305 * @return guarded wrapped memory pointer to the user area, or NULL if OOM. | |
306 */ | |
307 static void* wrap_copy(const void* p, const size_t len, const void* tag = NULL); | |
308 | |
309 /** | |
310 * Free wrapped copy. | |
311 * | |
312 * Frees memory copied with "wrap_copy()". | |
313 * | |
314 * @param p memory returned by "wrap_copy()". | |
315 * | |
316 * @return true if guards were verified as intact. false indicates a buffer overrun. | |
317 */ | |
318 static bool free_copy(void* p); | |
319 | |
320 // Testing... | |
321 #ifndef PRODUCT | |
322 static void test_guarded_memory(void); | |
323 #endif | |
324 }; // GuardedMemory | |
325 | |
326 #endif // SHARE_VM_MEMORY_GUARDED_MEMORY_HPP |