src/share/vm/memory/guardedMemory.hpp

Thu, 21 Aug 2014 13:57:51 -0700

author
iklam
date
Thu, 21 Aug 2014 13:57:51 -0700
changeset 7089
6e0cb14ce59b
parent 7032
fa62fb12cdca
child 7627
d68158e12cea
permissions
-rw-r--r--

8046070: Class Data Sharing clean up and refactoring
Summary: Cleaned up CDS to be more configurable, maintainable and extensible
Reviewed-by: dholmes, coleenp, acorn, mchung

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

mercurial