Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/memory/guardedMemory.hpp
32285 views
/*1* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#ifndef SHARE_VM_MEMORY_GUARDED_MEMORY_HPP25#define SHARE_VM_MEMORY_GUARDED_MEMORY_HPP2627#include "memory/allocation.hpp"28#include "utilities/globalDefinitions.hpp"2930/**31* Guarded memory for detecting buffer overrun.32*33* Allows allocations to be wrapped with padded bytes of a known byte pattern,34* that is a "guard". Guard patterns may be verified to detect buffer overruns.35*36* Primarily used by "debug malloc" and "checked JNI".37*38* Memory layout:39*40* |Offset | Content | Description |41* |------------------------------------------------------------42* |base_addr | 0xABABABABABABABAB | Head guard |43* |+16 | <size_t:user_size> | User data size |44* |+sizeof(uintptr_t) | <tag> | Tag word |45* |+sizeof(void*) | 0xF1 <user_data> ( | User data |46* |+user_size | 0xABABABABABABABAB | Tail guard |47* -------------------------------------------------------------48*49* Where:50* - guard padding uses "badResourceValue" (0xAB)51* - tag word is general purpose52* - user data53* -- initially padded with "uninitBlockPad" (0xF1),54* -- to "freeBlockPad" (0xBA), when freed55*56* Usage:57*58* * Allocations: one may wrap allocations with guard memory:59* <code>60* Thing* alloc_thing() {61* void* mem = user_alloc_fn(GuardedMemory::get_total_size(sizeof(thing)));62* GuardedMemory guarded(mem, sizeof(thing));63* return (Thing*) guarded.get_user_ptr();64* }65* </code>66* * Verify: memory guards are still in tact67* <code>68* bool verify_thing(Thing* thing) {69* GuardedMemory guarded((void*)thing);70* return guarded.verify_guards();71* }72* </code>73* * Free: one may mark bytes as freed (further debugging support)74* <code>75* void free_thing(Thing* thing) {76* GuardedMemory guarded((void*)thing);77* assert(guarded.verify_guards(), "Corrupt thing");78* user_free_fn(guards.release_for_freeing();79* }80* </code>81*/82class GuardedMemory : StackObj { // Wrapper on stack8384// Private inner classes for memory layout...8586protected:8788/**89* Guard class for header and trailer known pattern to test for overwrites.90*/91class Guard { // Class for raw memory (no vtbl allowed)92friend class GuardedMemory;93protected:94enum {95GUARD_SIZE = 1696};9798u_char _guard[GUARD_SIZE];99100public:101102void build() {103u_char* c = _guard; // Possibly unaligned if tail guard104u_char* end = c + GUARD_SIZE;105while (c < end) {106*c = badResourceValue;107c++;108}109}110111bool verify() const {112u_char* c = (u_char*) _guard;113u_char* end = c + GUARD_SIZE;114while (c < end) {115if (*c != badResourceValue) {116return false;117}118c++;119}120return true;121}122123}; // GuardedMemory::Guard124125/**126* Header guard and size127*/128class GuardHeader : Guard {129friend class GuardedMemory;130protected:131// Take care in modifying fields here, will effect alignment132// e.g. x86 ABI 16 byte stack alignment133union {134uintptr_t __unused_full_word1;135size_t _user_size;136};137void* _tag;138public:139void set_user_size(const size_t usz) { _user_size = usz; }140size_t get_user_size() const { return _user_size; }141142void set_tag(const void* tag) { _tag = (void*) tag; }143void* get_tag() const { return _tag; }144145}; // GuardedMemory::GuardHeader146147// Guarded Memory...148149protected:150u_char* _base_addr;151152public:153154/**155* Create new guarded memory.156*157* Wraps, starting at the given "base_ptr" with guards. Use "get_user_ptr()"158* to return a pointer suitable for user data.159*160* @param base_ptr allocation wishing to be wrapped, must be at least "GuardedMemory::get_total_size()" bytes.161* @param user_size the size of the user data to be wrapped.162* @param tag optional general purpose tag.163*/164GuardedMemory(void* base_ptr, const size_t user_size, const void* tag = NULL) {165wrap_with_guards(base_ptr, user_size, tag);166}167168/**169* Wrap existing guarded memory.170*171* To use this constructor, one must have created guarded memory with172* "GuardedMemory(void*, size_t, void*)" (or indirectly via helper, e.g. "wrap_copy()").173*174* @param user_p existing wrapped memory.175*/176GuardedMemory(void* userp) {177u_char* user_ptr = (u_char*) userp;178assert((uintptr_t)user_ptr > (sizeof(GuardHeader) + 0x1000), "Invalid pointer");179_base_addr = (user_ptr - sizeof(GuardHeader));180}181182/**183* Create new guarded memory.184*185* Wraps, starting at the given "base_ptr" with guards. Allows reuse of stack allocated helper.186*187* @param base_ptr allocation wishing to be wrapped, must be at least "GuardedMemory::get_total_size()" bytes.188* @param user_size the size of the user data to be wrapped.189* @param tag optional general purpose tag.190*191* @return user data pointer (inner pointer to supplied "base_ptr").192*/193void* wrap_with_guards(void* base_ptr, size_t user_size, const void* tag = NULL) {194assert(base_ptr != NULL, "Attempt to wrap NULL with memory guard");195_base_addr = (u_char*)base_ptr;196get_head_guard()->build();197get_head_guard()->set_user_size(user_size);198get_tail_guard()->build();199set_tag(tag);200set_user_bytes(uninitBlockPad);201assert(verify_guards(), "Expected valid memory guards");202return get_user_ptr();203}204205/**206* Verify head and tail guards.207*208* @return true if guards are intact, false would indicate a buffer overrun.209*/210bool verify_guards() const {211if (_base_addr != NULL) {212return (get_head_guard()->verify() && get_tail_guard()->verify());213}214return false;215}216217/**218* Set the general purpose tag.219*220* @param tag general purpose tag.221*/222void set_tag(const void* tag) { get_head_guard()->set_tag(tag); }223224/**225* Return the general purpose tag.226*227* @return the general purpose tag, defaults to NULL.228*/229void* get_tag() const { return get_head_guard()->get_tag(); }230231/**232* Return the size of the user data.233*234* @return the size of the user data.235*/236size_t get_user_size() const {237assert(_base_addr != NULL, "Not wrapping any memory");238return get_head_guard()->get_user_size();239}240241/**242* Return the user data pointer.243*244* @return the user data pointer.245*/246u_char* get_user_ptr() const {247assert(_base_addr != NULL, "Not wrapping any memory");248return _base_addr + sizeof(GuardHeader);249}250251/**252* Release the wrapped pointer for resource freeing.253*254* Pads the user data with "freeBlockPad", and dis-associates the helper.255*256* @return the original base pointer used to wrap the data.257*/258void* release_for_freeing() {259set_user_bytes(freeBlockPad);260return release();261}262263/**264* Dis-associate the help from the original base address.265*266* @return the original base pointer used to wrap the data.267*/268void* release() {269void* p = (void*) _base_addr;270_base_addr = NULL;271return p;272}273274virtual void print_on(outputStream* st) const;275276protected:277GuardHeader* get_head_guard() const { return (GuardHeader*) _base_addr; }278Guard* get_tail_guard() const { return (Guard*) (get_user_ptr() + get_user_size()); };279void set_user_bytes(u_char ch) {280memset(get_user_ptr(), ch, get_user_size());281}282283public:284/**285* Return the total size required for wrapping the given user size.286*287* @return the total size required for wrapping the given user size.288*/289static size_t get_total_size(size_t user_size) {290size_t total_size = sizeof(GuardHeader) + user_size + sizeof(Guard);291assert(total_size > user_size, "Unexpected wrap-around");292return total_size;293}294295// Helper functions...296297/**298* Wrap a copy of size "len" of "ptr".299*300* @param ptr the memory to be copied301* @param len the length of the copy302* @param tag optional general purpose tag (see GuardedMemory::get_tag())303*304* @return guarded wrapped memory pointer to the user area, or NULL if OOM.305*/306static void* wrap_copy(const void* p, const size_t len, const void* tag = NULL);307308/**309* Free wrapped copy.310*311* Frees memory copied with "wrap_copy()".312*313* @param p memory returned by "wrap_copy()".314*315* @return true if guards were verified as intact. false indicates a buffer overrun.316*/317static bool free_copy(void* p);318319// Testing...320#ifndef PRODUCT321static void test_guarded_memory(void);322#endif323}; // GuardedMemory324325#endif // SHARE_VM_MEMORY_GUARDED_MEMORY_HPP326327328