1 /*
   2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2020 SAP SE. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  *
  24  */
  25 
  26 #ifndef SHARE_MEMORY_METASPACE_ALLOCATION_GUARD_HPP
  27 #define SHARE_MEMORY_METASPACE_ALLOCATION_GUARD_HPP
  28 
  29 #include "memory/allocation.hpp"
  30 #include "memory/metaspace/chunkLevel.hpp"
  31 #include "utilities/debug.hpp"
  32 #include "utilities/globalDefinitions.hpp"
  33 
  34 // In Debug builds, Metadata in Metaspace can be optionally guarded - enclosed in canaries -
  35 // to detect memory overwriters.
  36 //
  37 // These canaries are periodically checked, e.g. when the Metaspace is purged in a context
  38 // of a GC.
  39 
  40 // The canaries precede any allocated block...
  41 //
  42 // +---------------+
  43 // |  'METAMETA'   |
  44 // +---------------+
  45 // |  block size   |
  46 // +---------------+
  47 // |  block...     |
  48 // .               .
  49 // .               .
  50 // .               .
  51 // |               |
  52 // +---------------+
  53 // . <padding>     .
  54 // +---------------+
  55 // |  'METAMETA'   |
  56 // +---------------+
  57 // |  block size   |
  58 // +---------------+
  59 // |  block...     |
  60 
  61 // ... and since the blocks are allocated via pointer bump and closely follow each other,
  62 // one block's prefix is its predecessor's suffix, so apart from the last block all
  63 // blocks have an overwriter canary on both ends.
  64 //
  65 
  66 // Note: this feature is only available in debug, and is activated using
  67 //  -XX:+MetaspaceGuardAllocations. When active, it disables deallocation handling - since
  68 //  freeblock handling in the freeblock lists would get too complex - so one may run leaks
  69 //  in deallocation-heavvy scenarios (e.g. lots of class redefinitions).
  70 //
  71 
  72 
  73 namespace metaspace {
  74 
  75 #ifdef ASSERT
  76 
  77 struct prefix_t {
  78   uintx mark;
  79   size_t word_size;       // raw word size including prefix
  80   // MetaWord payload [0];   // varsized (but unfortunately not all our compilers understand that)
  81 };
  82 
  83 // The prefix structure must be aligned to MetaWord size.
  84 STATIC_ASSERT((sizeof(prefix_t) & WordAlignmentMask) == 0);
  85 
  86 inline prefix_t* prefix_from_payload(MetaWord* p) {
  87   return (prefix_t*)((address)p - sizeof(prefix_t));
  88 }
  89 
  90 inline MetaWord* payload_from_prefix(prefix_t* pp) {
  91   // return pp->payload;
  92   return (MetaWord*)((address)pp + sizeof(prefix_t));
  93 }
  94 
  95 inline size_t prefix_size() {
  96   return sizeof(prefix_t);
  97 }
  98 
  99 #define EYECATCHER NOT_LP64(0x77698465) LP64_ONLY(0x7769846577698465ULL) // "META" resp "METAMETA"
 100 
 101 // Given a pointer to a memory area, establish the prefix at the start of that area and
 102 // return the starting pointer to the payload.
 103 inline MetaWord* establish_prefix(MetaWord* p_raw, size_t raw_word_size) {
 104   prefix_t* pp = (prefix_t*)p_raw;
 105   pp->mark = EYECATCHER;
 106   pp->word_size = raw_word_size;
 107   return payload_from_prefix(pp);
 108 }
 109 
 110 inline void check_prefix(const prefix_t* pp) {
 111   assert(pp->mark == EYECATCHER, "corrupt block at " PTR_FORMAT ".", p2i(pp));
 112   assert(pp->word_size > 0 && pp->word_size < chunklevel::MAX_CHUNK_WORD_SIZE,
 113          "Invalid size " SIZE_FORMAT " in block at " PTR_FORMAT ".", pp->word_size, p2i(pp));
 114 }
 115 
 116 #endif
 117 
 118 } // namespace metaspace
 119 
 120 #endif // SHARE_MEMORY_METASPACE_ALLOCATION_GUARD_HPP