dsimms@7032: /* poonam@7627: * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. dsimms@7032: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. dsimms@7032: * dsimms@7032: * This code is free software; you can redistribute it and/or modify it dsimms@7032: * under the terms of the GNU General Public License version 2 only, as dsimms@7032: * published by the Free Software Foundation. dsimms@7032: * dsimms@7032: * This code is distributed in the hope that it will be useful, but WITHOUT dsimms@7032: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or dsimms@7032: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License dsimms@7032: * version 2 for more details (a copy is included in the LICENSE file that dsimms@7032: * accompanied this code). dsimms@7032: * dsimms@7032: * You should have received a copy of the GNU General Public License version dsimms@7032: * 2 along with this work; if not, write to the Free Software Foundation, dsimms@7032: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. dsimms@7032: * dsimms@7032: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA dsimms@7032: * or visit www.oracle.com if you need additional information or have any dsimms@7032: * questions. dsimms@7032: * dsimms@7032: */ dsimms@7032: dsimms@7032: #ifndef SHARE_VM_MEMORY_GUARDED_MEMORY_HPP dsimms@7032: #define SHARE_VM_MEMORY_GUARDED_MEMORY_HPP dsimms@7032: dsimms@7032: #include "memory/allocation.hpp" dsimms@7032: #include "utilities/globalDefinitions.hpp" dsimms@7032: dsimms@7032: /** dsimms@7032: * Guarded memory for detecting buffer overrun. dsimms@7032: * dsimms@7032: * Allows allocations to be wrapped with padded bytes of a known byte pattern, dsimms@7032: * that is a "guard". Guard patterns may be verified to detect buffer overruns. dsimms@7032: * dsimms@7032: * Primarily used by "debug malloc" and "checked JNI". dsimms@7032: * dsimms@7032: * Memory layout: dsimms@7032: * dsimms@7032: * |Offset | Content | Description | dsimms@7032: * |------------------------------------------------------------ dsimms@7032: * |base_addr | 0xABABABABABABABAB | Head guard | dsimms@7032: * |+16 | | User data size | dsimms@7032: * |+sizeof(uintptr_t) | | Tag word | dsimms@7032: * |+sizeof(void*) | 0xF1 ( | User data | dsimms@7032: * |+user_size | 0xABABABABABABABAB | Tail guard | dsimms@7032: * ------------------------------------------------------------- dsimms@7032: * dsimms@7032: * Where: dsimms@7032: * - guard padding uses "badResourceValue" (0xAB) dsimms@7032: * - tag word is general purpose dsimms@7032: * - user data dsimms@7032: * -- initially padded with "uninitBlockPad" (0xF1), dsimms@7032: * -- to "freeBlockPad" (0xBA), when freed dsimms@7032: * dsimms@7032: * Usage: dsimms@7032: * dsimms@7032: * * Allocations: one may wrap allocations with guard memory: dsimms@7032: * dsimms@7032: * Thing* alloc_thing() { dsimms@7032: * void* mem = user_alloc_fn(GuardedMemory::get_total_size(sizeof(thing))); dsimms@7032: * GuardedMemory guarded(mem, sizeof(thing)); dsimms@7032: * return (Thing*) guarded.get_user_ptr(); dsimms@7032: * } dsimms@7032: * dsimms@7032: * * Verify: memory guards are still in tact dsimms@7032: * dsimms@7032: * bool verify_thing(Thing* thing) { dsimms@7032: * GuardedMemory guarded((void*)thing); dsimms@7032: * return guarded.verify_guards(); dsimms@7032: * } dsimms@7032: * dsimms@7032: * * Free: one may mark bytes as freed (further debugging support) dsimms@7032: * dsimms@7032: * void free_thing(Thing* thing) { dsimms@7032: * GuardedMemory guarded((void*)thing); dsimms@7032: * assert(guarded.verify_guards(), "Corrupt thing"); dsimms@7032: * user_free_fn(guards.release_for_freeing(); dsimms@7032: * } dsimms@7032: * dsimms@7032: */ dsimms@7032: class GuardedMemory : StackObj { // Wrapper on stack dsimms@7032: dsimms@7032: // Private inner classes for memory layout... dsimms@7032: dsimms@7032: protected: dsimms@7032: dsimms@7032: /** dsimms@7032: * Guard class for header and trailer known pattern to test for overwrites. dsimms@7032: */ dsimms@7032: class Guard { // Class for raw memory (no vtbl allowed) dsimms@7032: friend class GuardedMemory; dsimms@7032: protected: dsimms@7032: enum { dsimms@7032: GUARD_SIZE = 16 dsimms@7032: }; dsimms@7032: dsimms@7032: u_char _guard[GUARD_SIZE]; dsimms@7032: dsimms@7032: public: dsimms@7032: dsimms@7032: void build() { dsimms@7032: u_char* c = _guard; // Possibly unaligned if tail guard dsimms@7032: u_char* end = c + GUARD_SIZE; dsimms@7032: while (c < end) { dsimms@7032: *c = badResourceValue; dsimms@7032: c++; dsimms@7032: } dsimms@7032: } dsimms@7032: dsimms@7032: bool verify() const { dsimms@7032: u_char* c = (u_char*) _guard; dsimms@7032: u_char* end = c + GUARD_SIZE; dsimms@7032: while (c < end) { dsimms@7032: if (*c != badResourceValue) { dsimms@7032: return false; dsimms@7032: } dsimms@7032: c++; dsimms@7032: } dsimms@7032: return true; dsimms@7032: } dsimms@7032: dsimms@7032: }; // GuardedMemory::Guard dsimms@7032: dsimms@7032: /** dsimms@7032: * Header guard and size dsimms@7032: */ dsimms@7032: class GuardHeader : Guard { dsimms@7032: friend class GuardedMemory; dsimms@7032: protected: dsimms@7032: // Take care in modifying fields here, will effect alignment dsimms@7032: // e.g. x86 ABI 16 byte stack alignment dsimms@7032: union { dsimms@7032: uintptr_t __unused_full_word1; dsimms@7032: size_t _user_size; dsimms@7032: }; dsimms@7032: void* _tag; dsimms@7032: public: dsimms@7032: void set_user_size(const size_t usz) { _user_size = usz; } dsimms@7032: size_t get_user_size() const { return _user_size; } dsimms@7032: dsimms@7032: void set_tag(const void* tag) { _tag = (void*) tag; } dsimms@7032: void* get_tag() const { return _tag; } dsimms@7032: dsimms@7032: }; // GuardedMemory::GuardHeader dsimms@7032: dsimms@7032: // Guarded Memory... dsimms@7032: dsimms@7032: protected: dsimms@7032: u_char* _base_addr; dsimms@7032: dsimms@7032: public: dsimms@7032: dsimms@7032: /** dsimms@7032: * Create new guarded memory. dsimms@7032: * dsimms@7032: * Wraps, starting at the given "base_ptr" with guards. Use "get_user_ptr()" dsimms@7032: * to return a pointer suitable for user data. dsimms@7032: * dsimms@7032: * @param base_ptr allocation wishing to be wrapped, must be at least "GuardedMemory::get_total_size()" bytes. dsimms@7032: * @param user_size the size of the user data to be wrapped. dsimms@7032: * @param tag optional general purpose tag. dsimms@7032: */ dsimms@7032: GuardedMemory(void* base_ptr, const size_t user_size, const void* tag = NULL) { dsimms@7032: wrap_with_guards(base_ptr, user_size, tag); dsimms@7032: } dsimms@7032: dsimms@7032: /** dsimms@7032: * Wrap existing guarded memory. dsimms@7032: * dsimms@7032: * To use this constructor, one must have created guarded memory with dsimms@7032: * "GuardedMemory(void*, size_t, void*)" (or indirectly via helper, e.g. "wrap_copy()"). dsimms@7032: * dsimms@7032: * @param user_p existing wrapped memory. dsimms@7032: */ dsimms@7032: GuardedMemory(void* userp) { dsimms@7032: u_char* user_ptr = (u_char*) userp; dsimms@7032: assert((uintptr_t)user_ptr > (sizeof(GuardHeader) + 0x1000), "Invalid pointer"); dsimms@7032: _base_addr = (user_ptr - sizeof(GuardHeader)); dsimms@7032: } dsimms@7032: dsimms@7032: /** dsimms@7032: * Create new guarded memory. dsimms@7032: * dsimms@7032: * Wraps, starting at the given "base_ptr" with guards. Allows reuse of stack allocated helper. dsimms@7032: * dsimms@7032: * @param base_ptr allocation wishing to be wrapped, must be at least "GuardedMemory::get_total_size()" bytes. dsimms@7032: * @param user_size the size of the user data to be wrapped. dsimms@7032: * @param tag optional general purpose tag. dsimms@7032: * dsimms@7032: * @return user data pointer (inner pointer to supplied "base_ptr"). dsimms@7032: */ dsimms@7032: void* wrap_with_guards(void* base_ptr, size_t user_size, const void* tag = NULL) { dsimms@7032: assert(base_ptr != NULL, "Attempt to wrap NULL with memory guard"); dsimms@7032: _base_addr = (u_char*)base_ptr; dsimms@7032: get_head_guard()->build(); dsimms@7032: get_head_guard()->set_user_size(user_size); dsimms@7032: get_tail_guard()->build(); dsimms@7032: set_tag(tag); dsimms@7032: set_user_bytes(uninitBlockPad); dsimms@7032: assert(verify_guards(), "Expected valid memory guards"); dsimms@7032: return get_user_ptr(); dsimms@7032: } dsimms@7032: dsimms@7032: /** dsimms@7032: * Verify head and tail guards. dsimms@7032: * dsimms@7032: * @return true if guards are intact, false would indicate a buffer overrun. dsimms@7032: */ dsimms@7032: bool verify_guards() const { dsimms@7032: if (_base_addr != NULL) { dsimms@7032: return (get_head_guard()->verify() && get_tail_guard()->verify()); dsimms@7032: } dsimms@7032: return false; dsimms@7032: } dsimms@7032: dsimms@7032: /** dsimms@7032: * Set the general purpose tag. dsimms@7032: * dsimms@7032: * @param tag general purpose tag. dsimms@7032: */ dsimms@7032: void set_tag(const void* tag) { get_head_guard()->set_tag(tag); } dsimms@7032: dsimms@7032: /** dsimms@7032: * Return the general purpose tag. dsimms@7032: * dsimms@7032: * @return the general purpose tag, defaults to NULL. dsimms@7032: */ dsimms@7032: void* get_tag() const { return get_head_guard()->get_tag(); } dsimms@7032: dsimms@7032: /** dsimms@7032: * Return the size of the user data. dsimms@7032: * dsimms@7032: * @return the size of the user data. dsimms@7032: */ dsimms@7032: size_t get_user_size() const { poonam@7627: assert(_base_addr != NULL, "Not wrapping any memory"); dsimms@7032: return get_head_guard()->get_user_size(); dsimms@7032: } dsimms@7032: dsimms@7032: /** dsimms@7032: * Return the user data pointer. dsimms@7032: * dsimms@7032: * @return the user data pointer. dsimms@7032: */ dsimms@7032: u_char* get_user_ptr() const { poonam@7627: assert(_base_addr != NULL, "Not wrapping any memory"); dsimms@7032: return _base_addr + sizeof(GuardHeader); dsimms@7032: } dsimms@7032: dsimms@7032: /** dsimms@7032: * Release the wrapped pointer for resource freeing. dsimms@7032: * dsimms@7032: * Pads the user data with "freeBlockPad", and dis-associates the helper. dsimms@7032: * dsimms@7032: * @return the original base pointer used to wrap the data. dsimms@7032: */ dsimms@7032: void* release_for_freeing() { dsimms@7032: set_user_bytes(freeBlockPad); dsimms@7032: return release(); dsimms@7032: } dsimms@7032: dsimms@7032: /** dsimms@7032: * Dis-associate the help from the original base address. dsimms@7032: * dsimms@7032: * @return the original base pointer used to wrap the data. dsimms@7032: */ dsimms@7032: void* release() { dsimms@7032: void* p = (void*) _base_addr; dsimms@7032: _base_addr = NULL; dsimms@7032: return p; dsimms@7032: } dsimms@7032: dsimms@7032: virtual void print_on(outputStream* st) const; dsimms@7032: dsimms@7032: protected: dsimms@7032: GuardHeader* get_head_guard() const { return (GuardHeader*) _base_addr; } dsimms@7032: Guard* get_tail_guard() const { return (Guard*) (get_user_ptr() + get_user_size()); }; dsimms@7032: void set_user_bytes(u_char ch) { dsimms@7032: memset(get_user_ptr(), ch, get_user_size()); dsimms@7032: } dsimms@7032: poonam@7627: public: dsimms@7032: /** dsimms@7032: * Return the total size required for wrapping the given user size. dsimms@7032: * dsimms@7032: * @return the total size required for wrapping the given user size. dsimms@7032: */ dsimms@7032: static size_t get_total_size(size_t user_size) { dsimms@7032: size_t total_size = sizeof(GuardHeader) + user_size + sizeof(Guard); dsimms@7032: assert(total_size > user_size, "Unexpected wrap-around"); dsimms@7032: return total_size; dsimms@7032: } dsimms@7032: dsimms@7032: // Helper functions... dsimms@7032: dsimms@7032: /** dsimms@7032: * Wrap a copy of size "len" of "ptr". dsimms@7032: * dsimms@7032: * @param ptr the memory to be copied dsimms@7032: * @param len the length of the copy dsimms@7032: * @param tag optional general purpose tag (see GuardedMemory::get_tag()) dsimms@7032: * dsimms@7032: * @return guarded wrapped memory pointer to the user area, or NULL if OOM. dsimms@7032: */ dsimms@7032: static void* wrap_copy(const void* p, const size_t len, const void* tag = NULL); dsimms@7032: dsimms@7032: /** dsimms@7032: * Free wrapped copy. dsimms@7032: * dsimms@7032: * Frees memory copied with "wrap_copy()". dsimms@7032: * dsimms@7032: * @param p memory returned by "wrap_copy()". dsimms@7032: * dsimms@7032: * @return true if guards were verified as intact. false indicates a buffer overrun. dsimms@7032: */ dsimms@7032: static bool free_copy(void* p); dsimms@7032: dsimms@7032: // Testing... dsimms@7032: #ifndef PRODUCT dsimms@7032: static void test_guarded_memory(void); dsimms@7032: #endif dsimms@7032: }; // GuardedMemory dsimms@7032: dsimms@7032: #endif // SHARE_VM_MEMORY_GUARDED_MEMORY_HPP