| File: | jdk/src/hotspot/share/services/mallocTracker.cpp |
| Warning: | line 255, column 3 Value stored to 'header' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* |
| 2 | * Copyright (c) 2014, 2021, 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 | #include "precompiled.hpp" |
| 25 | |
| 26 | #include "runtime/os.hpp" |
| 27 | #include "services/mallocSiteTable.hpp" |
| 28 | #include "services/mallocTracker.hpp" |
| 29 | #include "services/mallocTracker.inline.hpp" |
| 30 | #include "services/memTracker.hpp" |
| 31 | #include "utilities/debug.hpp" |
| 32 | #include "utilities/ostream.hpp" |
| 33 | |
| 34 | size_t MallocMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)(align_up(sizeof(MallocMemorySnapshot), sizeof(size_t))/sizeof (size_t))]; |
| 35 | |
| 36 | #ifdef ASSERT1 |
| 37 | void MemoryCounter::update_peak_count(size_t count) { |
| 38 | size_t peak_cnt = peak_count(); |
| 39 | while (peak_cnt < count) { |
| 40 | size_t old_cnt = Atomic::cmpxchg(&_peak_count, peak_cnt, count, memory_order_relaxed); |
| 41 | if (old_cnt != peak_cnt) { |
| 42 | peak_cnt = old_cnt; |
| 43 | } |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | void MemoryCounter::update_peak_size(size_t sz) { |
| 48 | size_t peak_sz = peak_size(); |
| 49 | while (peak_sz < sz) { |
| 50 | size_t old_sz = Atomic::cmpxchg(&_peak_size, peak_sz, sz, memory_order_relaxed); |
| 51 | if (old_sz != peak_sz) { |
| 52 | peak_sz = old_sz; |
| 53 | } |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | size_t MemoryCounter::peak_count() const { |
| 58 | return Atomic::load(&_peak_count); |
| 59 | } |
| 60 | |
| 61 | size_t MemoryCounter::peak_size() const { |
| 62 | return Atomic::load(&_peak_size); |
| 63 | } |
| 64 | #endif |
| 65 | |
| 66 | // Total malloc invocation count |
| 67 | size_t MallocMemorySnapshot::total_count() const { |
| 68 | size_t amount = 0; |
| 69 | for (int index = 0; index < mt_number_of_types; index ++) { |
| 70 | amount += _malloc[index].malloc_count(); |
| 71 | } |
| 72 | return amount; |
| 73 | } |
| 74 | |
| 75 | // Total malloc'd memory amount |
| 76 | size_t MallocMemorySnapshot::total() const { |
| 77 | size_t amount = 0; |
| 78 | for (int index = 0; index < mt_number_of_types; index ++) { |
| 79 | amount += _malloc[index].malloc_size(); |
| 80 | } |
| 81 | amount += _tracking_header.size() + total_arena(); |
| 82 | return amount; |
| 83 | } |
| 84 | |
| 85 | // Total malloc'd memory used by arenas |
| 86 | size_t MallocMemorySnapshot::total_arena() const { |
| 87 | size_t amount = 0; |
| 88 | for (int index = 0; index < mt_number_of_types; index ++) { |
| 89 | amount += _malloc[index].arena_size(); |
| 90 | } |
| 91 | return amount; |
| 92 | } |
| 93 | |
| 94 | // Make adjustment by subtracting chunks used by arenas |
| 95 | // from total chunks to get total free chunk size |
| 96 | void MallocMemorySnapshot::make_adjustment() { |
| 97 | size_t arena_size = total_arena(); |
| 98 | int chunk_idx = NMTUtil::flag_to_index(mtChunk); |
| 99 | _malloc[chunk_idx].record_free(arena_size); |
| 100 | } |
| 101 | |
| 102 | |
| 103 | void MallocMemorySummary::initialize() { |
| 104 | assert(sizeof(_snapshot) >= sizeof(MallocMemorySnapshot), "Sanity Check")do { if (!(sizeof(_snapshot) >= sizeof(MallocMemorySnapshot ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 104, "assert(" "sizeof(_snapshot) >= sizeof(MallocMemorySnapshot)" ") failed", "Sanity Check"); ::breakpoint(); } } while (0); |
| 105 | // Uses placement new operator to initialize static area. |
| 106 | ::new ((void*)_snapshot)MallocMemorySnapshot(); |
| 107 | } |
| 108 | |
| 109 | void MallocHeader::mark_block_as_dead() { |
| 110 | _canary = _header_canary_dead_mark; |
| 111 | NOT_LP64(_alt_canary = _header_alt_canary_dead_mark); |
| 112 | set_footer(_footer_canary_dead_mark); |
| 113 | } |
| 114 | |
| 115 | void MallocHeader::release() { |
| 116 | assert(MemTracker::enabled(), "Sanity")do { if (!(MemTracker::enabled())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 116, "assert(" "MemTracker::enabled()" ") failed", "Sanity" ); ::breakpoint(); } } while (0); |
| 117 | |
| 118 | check_block_integrity(); |
| 119 | |
| 120 | MallocMemorySummary::record_free(size(), flags()); |
| 121 | MallocMemorySummary::record_free_malloc_header(sizeof(MallocHeader)); |
| 122 | if (MemTracker::tracking_level() == NMT_detail) { |
| 123 | MallocSiteTable::deallocation_at(size(), _bucket_idx, _pos_idx); |
| 124 | } |
| 125 | |
| 126 | mark_block_as_dead(); |
| 127 | } |
| 128 | |
| 129 | void MallocHeader::print_block_on_error(outputStream* st, address bad_address) const { |
| 130 | assert(bad_address >= (address)this, "sanity")do { if (!(bad_address >= (address)this)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 130, "assert(" "bad_address >= (address)this" ") failed" , "sanity"); ::breakpoint(); } } while (0); |
| 131 | |
| 132 | // This function prints block information, including hex dump, in case of a detected |
| 133 | // corruption. The hex dump should show both block header and corruption site |
| 134 | // (which may or may not be close together or identical). Plus some surrounding area. |
| 135 | // |
| 136 | // Note that we use os::print_hex_dump(), which is able to cope with unmapped |
| 137 | // memory (it uses SafeFetch). |
| 138 | |
| 139 | st->print_cr("NMT Block at " PTR_FORMAT"0x%016" "l" "x" ", corruption at: " PTR_FORMAT"0x%016" "l" "x" ": ", |
| 140 | p2i(this), p2i(bad_address)); |
| 141 | static const size_t min_dump_length = 256; |
| 142 | address from1 = align_down((address)this, sizeof(void*)) - (min_dump_length / 2); |
| 143 | address to1 = from1 + min_dump_length; |
| 144 | address from2 = align_down(bad_address, sizeof(void*)) - (min_dump_length / 2); |
| 145 | address to2 = from2 + min_dump_length; |
| 146 | if (from2 > to1) { |
| 147 | // Dump gets too large, split up in two sections. |
| 148 | os::print_hex_dump(st, from1, to1, 1); |
| 149 | st->print_cr("..."); |
| 150 | os::print_hex_dump(st, from2, to2, 1); |
| 151 | } else { |
| 152 | // print one hex dump |
| 153 | os::print_hex_dump(st, from1, to2, 1); |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | // Check block integrity. If block is broken, print out a report |
| 158 | // to tty (optionally with hex dump surrounding the broken block), |
| 159 | // then trigger a fatal error. |
| 160 | void MallocHeader::check_block_integrity() const { |
| 161 | |
| 162 | #define PREFIX "NMT corruption: " |
| 163 | // Note: if you modify the error messages here, make sure you |
| 164 | // adapt the associated gtests too. |
| 165 | |
| 166 | // Weed out obviously wrong block addresses of NULL or very low |
| 167 | // values. Note that we should not call this for ::free(NULL), |
| 168 | // which should be handled by os::free() above us. |
| 169 | if (((size_t)p2i(this)) < K) { |
| 170 | fatal(PREFIX "Block at " PTR_FORMAT ": invalid block address", p2i(this))do { (*g_assert_poison) = 'X';; report_fatal(INTERNAL_ERROR, "/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 170, PREFIX "Block at " "0x%016" "l" "x" ": invalid block address" , p2i(this)); ::breakpoint(); } while (0); |
| 171 | } |
| 172 | |
| 173 | // From here on we assume the block pointer to be valid. We could |
| 174 | // use SafeFetch but since this is a hot path we don't. If we are |
| 175 | // wrong, we will crash when accessing the canary, which hopefully |
| 176 | // generates distinct crash report. |
| 177 | |
| 178 | // Weed out obviously unaligned addresses. NMT blocks, being the result of |
| 179 | // malloc calls, should adhere to malloc() alignment. Malloc alignment is |
| 180 | // specified by the standard by this requirement: |
| 181 | // "malloc returns a pointer which is suitably aligned for any built-in type" |
| 182 | // For us it means that it is *at least* 64-bit on all of our 32-bit and |
| 183 | // 64-bit platforms since we have native 64-bit types. It very probably is |
| 184 | // larger than that, since there exist scalar types larger than 64bit. Here, |
| 185 | // we test the smallest alignment we know. |
| 186 | // Should we ever start using std::max_align_t, this would be one place to |
| 187 | // fix up. |
| 188 | if (!is_aligned(this, sizeof(uint64_t))) { |
| 189 | print_block_on_error(tty, (address)this); |
| 190 | fatal(PREFIX "Block at " PTR_FORMAT ": block address is unaligned", p2i(this))do { (*g_assert_poison) = 'X';; report_fatal(INTERNAL_ERROR, "/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 190, PREFIX "Block at " "0x%016" "l" "x" ": block address is unaligned" , p2i(this)); ::breakpoint(); } while (0); |
| 191 | } |
| 192 | |
| 193 | // Check header canary |
| 194 | if (_canary != _header_canary_life_mark) { |
| 195 | print_block_on_error(tty, (address)this); |
| 196 | fatal(PREFIX "Block at " PTR_FORMAT ": header canary broken.", p2i(this))do { (*g_assert_poison) = 'X';; report_fatal(INTERNAL_ERROR, "/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 196, PREFIX "Block at " "0x%016" "l" "x" ": header canary broken." , p2i(this)); ::breakpoint(); } while (0); |
| 197 | } |
| 198 | |
| 199 | #ifndef _LP641 |
| 200 | // On 32-bit we have a second canary, check that one too. |
| 201 | if (_alt_canary != _header_alt_canary_life_mark) { |
| 202 | print_block_on_error(tty, (address)this); |
| 203 | fatal(PREFIX "Block at " PTR_FORMAT ": header alternate canary broken.", p2i(this))do { (*g_assert_poison) = 'X';; report_fatal(INTERNAL_ERROR, "/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 203, PREFIX "Block at " "0x%016" "l" "x" ": header alternate canary broken." , p2i(this)); ::breakpoint(); } while (0); |
| 204 | } |
| 205 | #endif |
| 206 | |
| 207 | // Does block size seems reasonable? |
| 208 | if (_size >= max_reasonable_malloc_size) { |
| 209 | print_block_on_error(tty, (address)this); |
| 210 | fatal(PREFIX "Block at " PTR_FORMAT ": header looks invalid (weirdly large block size)", p2i(this))do { (*g_assert_poison) = 'X';; report_fatal(INTERNAL_ERROR, "/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 210, PREFIX "Block at " "0x%016" "l" "x" ": header looks invalid (weirdly large block size)" , p2i(this)); ::breakpoint(); } while (0); |
| 211 | } |
| 212 | |
| 213 | // Check footer canary |
| 214 | if (get_footer() != _footer_canary_life_mark) { |
| 215 | print_block_on_error(tty, footer_address()); |
| 216 | fatal(PREFIX "Block at " PTR_FORMAT ": footer canary broken at " PTR_FORMAT " (buffer overflow?)",do { (*g_assert_poison) = 'X';; report_fatal(INTERNAL_ERROR, "/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 217, PREFIX "Block at " "0x%016" "l" "x" ": footer canary broken at " "0x%016" "l" "x" " (buffer overflow?)", p2i(this), p2i(footer_address ())); ::breakpoint(); } while (0) |
| 217 | p2i(this), p2i(footer_address()))do { (*g_assert_poison) = 'X';; report_fatal(INTERNAL_ERROR, "/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 217, PREFIX "Block at " "0x%016" "l" "x" ": footer canary broken at " "0x%016" "l" "x" " (buffer overflow?)", p2i(this), p2i(footer_address ())); ::breakpoint(); } while (0); |
| 218 | } |
| 219 | #undef PREFIX |
| 220 | } |
| 221 | |
| 222 | bool MallocHeader::record_malloc_site(const NativeCallStack& stack, size_t size, |
| 223 | size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) const { |
| 224 | return MallocSiteTable::allocation_at(stack, size, bucket_idx, pos_idx, flags); |
| 225 | } |
| 226 | |
| 227 | bool MallocHeader::get_stack(NativeCallStack& stack) const { |
| 228 | return MallocSiteTable::access_stack(stack, _bucket_idx, _pos_idx); |
| 229 | } |
| 230 | |
| 231 | bool MallocTracker::initialize(NMT_TrackingLevel level) { |
| 232 | if (level >= NMT_summary) { |
| 233 | MallocMemorySummary::initialize(); |
| 234 | } |
| 235 | |
| 236 | if (level == NMT_detail) { |
| 237 | return MallocSiteTable::initialize(); |
| 238 | } |
| 239 | return true; |
| 240 | } |
| 241 | |
| 242 | // Record a malloc memory allocation |
| 243 | void* MallocTracker::record_malloc(void* malloc_base, size_t size, MEMFLAGS flags, |
| 244 | const NativeCallStack& stack, NMT_TrackingLevel level) { |
| 245 | assert(level != NMT_off, "precondition")do { if (!(level != NMT_off)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 245, "assert(" "level != NMT_off" ") failed", "precondition" ); ::breakpoint(); } } while (0); |
| 246 | void* memblock; // the address for user data |
| 247 | MallocHeader* header = NULL__null; |
| 248 | |
| 249 | if (malloc_base == NULL__null) { |
| 250 | return NULL__null; |
| 251 | } |
| 252 | |
| 253 | // Uses placement global new operator to initialize malloc header |
| 254 | |
| 255 | header = ::new (malloc_base)MallocHeader(size, flags, stack, level); |
Value stored to 'header' is never read | |
| 256 | memblock = (void*)((char*)malloc_base + sizeof(MallocHeader)); |
| 257 | |
| 258 | // The alignment check: 8 bytes alignment for 32 bit systems. |
| 259 | // 16 bytes alignment for 64-bit systems. |
| 260 | assert(((size_t)memblock & (sizeof(size_t) * 2 - 1)) == 0, "Alignment check")do { if (!(((size_t)memblock & (sizeof(size_t) * 2 - 1)) == 0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 260, "assert(" "((size_t)memblock & (sizeof(size_t) * 2 - 1)) == 0" ") failed", "Alignment check"); ::breakpoint(); } } while (0 ); |
| 261 | |
| 262 | #ifdef ASSERT1 |
| 263 | if (level > NMT_off) { |
| 264 | // Read back |
| 265 | assert(get_size(memblock) == size, "Wrong size")do { if (!(get_size(memblock) == size)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 265, "assert(" "get_size(memblock) == size" ") failed", "Wrong size" ); ::breakpoint(); } } while (0); |
| 266 | assert(get_flags(memblock) == flags, "Wrong flags")do { if (!(get_flags(memblock) == flags)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 266, "assert(" "get_flags(memblock) == flags" ") failed", "Wrong flags" ); ::breakpoint(); } } while (0); |
| 267 | } |
| 268 | #endif |
| 269 | |
| 270 | return memblock; |
| 271 | } |
| 272 | |
| 273 | void* MallocTracker::record_free(void* memblock) { |
| 274 | assert(MemTracker::tracking_level() != NMT_off && memblock != NULL, "precondition")do { if (!(MemTracker::tracking_level() != NMT_off && memblock != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/services/mallocTracker.cpp" , 274, "assert(" "MemTracker::tracking_level() != NMT_off && memblock != __null" ") failed", "precondition"); ::breakpoint(); } } while (0); |
| 275 | MallocHeader* header = malloc_header(memblock); |
| 276 | header->release(); |
| 277 | return (void*)header; |
| 278 | } |