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 | } |