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_FENCED_MEMORY_HPP 26 #define SHARE_VM_MEMORY_FENCED_MEMORY_HPP 27 28 #include "memory/allocation.hpp" 29 #include "utilities/globalDefinitions.hpp" 30 31 /** 32 * Fenced memory for detecting buffer overrun. 33 * 34 * Allows allocations to be wrapped with padded bytes of a known byte pattern, 35 * that is a "fence". Fence 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 fence | 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 fence | 48 * ------------------------------------------------------------- 49 * 50 * Where: 51 * - fence 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 fence memory: 60 * <code> 61 * Thing* alloc_thing() { 62 * void* mem = alloc_fn(sizeof(thing) + FencedMemory::get_total_size()); 63 * FencedMemory fenced(mem, sizeof(thing)); 64 * return (Thing*) fenced.get_user_ptr(); 65 * } 66 * </code> 67 * * Verify: memory fences are still in tact 68 * <code> 69 * bool verify_thing(Thing* thing) { 70 * FencedMemory fenced((void*)thing); 71 * return fenced.verify_fences(); 72 * } 73 * </code> 74 * * Free: one may mark bytes as freed (further debugging support) 75 * <code> 76 * void free_thing(Thing* thing) { 77 * FencedMemory fenced((void*)thing); 78 * assert(fenced.verify_fences(), "Corrupt thing"); 79 * free_fn(fenced.release_for_freeing(); 80 * } 81 * </code> 82 */ 83 class FencedMemory : StackObj { // Wrapper on stack 84 85 // Private inner classes for memory layout... 86 87 protected: 88 89 /** 90 * Fence class for header and trailer known pattern to test for overwrites. 91 */ 92 class Fence { // Class for raw memory (no vtbl allowed) 93 friend class FencedMemory; 94 protected: 95 static const int FENCE_SIZE = 16; 96 97 u_char _fence[FENCE_SIZE]; 98 99 public: 100 101 void build() { 102 u_char* c = _fence; // Possibly unaligned if tail fence 103 u_char* end = c + FENCE_SIZE; 104 while (c < end) { 105 *c = badResourceValue; 106 c++; 107 } 108 } 109 110 bool verify() const { 111 u_char* c = (u_char*) _fence; 112 u_char* end = c + FENCE_SIZE; 113 while (c < end) { 114 if (*c != badResourceValue) { 115 return false; 116 } 117 c++; 118 } 119 return true; 120 } 121 122 }; // FencedMemory::Fence 123 124 /** 125 * Header fence and size 126 */ 127 class FenceHeader : Fence { 128 friend class FencedMemory; 129 protected: 130 union { 131 uintptr_t __unused_full_word1; 132 size_t _user_size; 133 }; 134 void* _tag; 135 public: 136 void set_user_size(const size_t usz) { _user_size = usz; } 137 size_t get_user_size() const { return _user_size; } 138 139 void set_tag(const void* tag) { _tag = (void*) tag; } 140 void* get_tag() const { return _tag; } 141 142 }; // FencedMemory::FenceHeader 143 144 // Fenced Memory... 145 146 protected: 147 u_char* _base_addr; 148 149 public: 150 151 /** 152 * Create new fenced memory. 153 * 154 * Wraps, starting at the given "base_ptr" with fences. Use "get_user_ptr()" 155 * to return a pointer suitable for user data. 156 * 157 * @param base_ptr allocation wishing to be wrapped, must be at least "FencedMemory::get_total_size()" bytes. 158 * @param user_size the size of the user data to be wrapped. 159 * @param tag optional general purpose tag. 160 */ 161 FencedMemory(void* base_ptr, const size_t user_size, const void* tag = NULL) { 162 wrap_with_fences(base_ptr, user_size, tag); 163 } 164 165 /** 166 * Wrap existing fenced memory. 167 * 168 * To use this constructor, one must have created fenced memory with 169 * "FencedMemory(void*, size_t, void*)" (or indirectly via helper, e.g. "wrap_copy()"). 170 * 171 * @param user_p existing wrapped memory. 172 */ 173 FencedMemory(void* userp) { 174 u_char* user_ptr = (u_char*) userp; 175 assert((uintptr_t)user_ptr > (sizeof(FenceHeader) + 0x1000), "Invalid pointer"); 176 _base_addr = (user_ptr - sizeof(FenceHeader)); 177 } 178 179 /** 180 * Create new fenced memory. 181 * 182 * Wraps, starting at the given "base_ptr" with fences. Allows reuse of stack allocated helper. 183 * 184 * @param base_ptr allocation wishing to be wrapped, must be at least "FencedMemory::get_total_size()" bytes. 185 * @param user_size the size of the user data to be wrapped. 186 * @param tag optional general purpose tag. 187 * 188 * @return user data pointer (inner pointer to supplied "base_ptr"). 189 */ 190 void* wrap_with_fences(void* base_ptr, size_t user_size, const void* tag = 0) { 191 assert(base_ptr, "Attempt to wrap NULL with fence"); 192 _base_addr = (u_char*)base_ptr; 193 get_head_fence()->build(); 194 get_head_fence()->set_user_size(user_size); 195 get_tail_fence()->build(); 196 set_tag(tag); 197 set_user_bytes(uninitBlockPad); 198 assert(verify_fences(), "Expected valid fences"); 199 return get_user_ptr(); 200 } 201 202 /** 203 * Verify head and tail fences. 204 * 205 * @return true if fences are intact, false would indicate a buffer overrun. 206 */ 207 bool verify_fences() const { 208 if (_base_addr) { 209 return (get_head_fence()->verify() && get_tail_fence()->verify()); 210 } 211 return false; 212 } 213 214 /** 215 * Set the general purpose tag. 216 * 217 * @param tag general purpose tag. 218 */ 219 void set_tag(const void* tag) { get_head_fence()->set_tag(tag); } 220 221 /** 222 * Return the general purpose tag. 223 * 224 * @return the general purpose tag, defaults to NULL. 225 */ 226 void* get_tag() const { return get_head_fence()->get_tag(); } 227 228 /** 229 * Return the size of the user data. 230 * 231 * @return the size of the user data. 232 */ 233 size_t get_user_size() const { 234 assert(_base_addr, "Not wrapping any memory"); 235 return get_head_fence()->get_user_size(); 236 } 237 238 /** 239 * Return the user data. 240 * 241 * @return the user data. 242 */ 243 u_char* get_user_ptr() const { 244 assert(_base_addr, "Not wrapping any memory"); 245 return _base_addr + sizeof(FenceHeader); 246 } 247 248 /** 249 * Release the wrapped pointer for resource freeing. 250 * 251 * Pads the user data with "freeBlockPad", and dis-associates the helper. 252 * 253 * @return the original base pointer used to wrap the data. 254 */ 255 void* release_for_freeing() { 256 set_user_bytes(freeBlockPad); 257 return release(); 258 } 259 260 /** 261 * Dis-associate the help from the original base address. 262 * 263 * @return the original base pointer used to wrap the data. 264 */ 265 void* release() { 266 void* p = (void*) _base_addr; 267 _base_addr = NULL; 268 return p; 269 } 270 271 virtual void print_on(outputStream* st) const; 272 273 protected: 274 FenceHeader* get_head_fence() const { return (FenceHeader*) _base_addr; } 275 Fence* get_tail_fence() const { return (Fence*) (get_user_ptr() + get_user_size()); }; 276 void set_user_bytes(u_char ch) { 277 memset(get_user_ptr(), ch, get_user_size()); 278 } 279 public: 280 /** 281 * Return the total size required for wrapping the given user size. 282 * 283 * @return the total size required for wrapping the given user size. 284 */ 285 static size_t get_total_size(size_t user_size) { 286 size_t total_size = sizeof(FenceHeader) + user_size + sizeof(Fence); 287 assert(total_size > user_size, "Unexpected wrap-around"); 288 return total_size; 289 } 290 291 // Helper functions... 292 293 /** 294 * Wrap a copy of size "len" of "ptr". 295 * 296 * @param ptr the memory to be copied 297 * @param len the length of the copy 298 * @param tag optional general purpose tag (see FencedMemory::get_tag()) 299 * 300 * @return fenced wrapped memory pointer to the user area, or NULL if OOM. 301 */ 302 static void* wrap_copy(const void* p, const size_t len, const void* tag = NULL); 303 304 /** 305 * Free wrapped copy. 306 * 307 * Frees memory copied with "wrap_copy()". 308 * 309 * @param p memory returned by "wrap_copy()". 310 * 311 * @return true if fences were verified as intact. false indicates a buffer overrun. 312 */ 313 static bool free_copy(void* p); 314 315 // Testing... 316 #ifndef PRODUCT 317 static void test_fenced_memory(void); 318 #endif 319 }; // FencedMemory 320 321 #endif // SHARE_VM_MEMORY_FENCED_MEMORY_HPP