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