Thu, 21 Aug 2014 13:57:51 -0700
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 |