Bug Summary

File:jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp
Warning:line 419, column 16
Value stored to 'repository_path_len' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name jfrEmergencyDump.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/libjvm/objs/precompiled -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D _GNU_SOURCE -D _REENTRANT -D LIBC=gnu -D LINUX -D VM_LITTLE_ENDIAN -D _LP64=1 -D ASSERT -D CHECK_UNHANDLED_OOPS -D TARGET_ARCH_x86 -D INCLUDE_SUFFIX_OS=_linux -D INCLUDE_SUFFIX_CPU=_x86 -D INCLUDE_SUFFIX_COMPILER=_gcc -D TARGET_COMPILER_gcc -D AMD64 -D HOTSPOT_LIB_ARCH="amd64" -D COMPILER1 -D COMPILER2 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc/adfiles -I /home/daniel/Projects/java/jdk/src/hotspot/share -I /home/daniel/Projects/java/jdk/src/hotspot/os/linux -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix -I /home/daniel/Projects/java/jdk/src/hotspot/cpu/x86 -I /home/daniel/Projects/java/jdk/src/hotspot/os_cpu/linux_x86 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc -I /home/daniel/Projects/java/jdk/src/hotspot/share/precompiled -I /home/daniel/Projects/java/jdk/src/hotspot/share/include -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix/include -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base/linux -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjimage -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc/adfiles -I /home/daniel/Projects/java/jdk/src/hotspot/share -I /home/daniel/Projects/java/jdk/src/hotspot/os/linux -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix -I /home/daniel/Projects/java/jdk/src/hotspot/cpu/x86 -I /home/daniel/Projects/java/jdk/src/hotspot/os_cpu/linux_x86 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc -D _FORTIFY_SOURCE=2 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/x86_64-linux-gnu/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/x86_64-linux-gnu/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-format-zero-length -Wno-unused-parameter -Wno-unused -Wno-parentheses -Wno-comment -Wno-unknown-pragmas -Wno-address -Wno-delete-non-virtual-dtor -Wno-char-subscripts -Wno-array-bounds -Wno-int-in-bool-context -Wno-ignored-qualifiers -Wno-missing-field-initializers -Wno-implicit-fallthrough -Wno-empty-body -Wno-strict-overflow -Wno-sequence-point -Wno-maybe-uninitialized -Wno-misleading-indentation -Wno-cast-function-type -Wno-shift-negative-value -std=c++14 -fdeprecated-macro -fdebug-compilation-dir /home/daniel/Projects/java/jdk/make/hotspot -ferror-limit 19 -fmessage-length 0 -fvisibility hidden -stack-protector 1 -fno-rtti -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /home/daniel/Projects/java/scan/2021-12-21-193737-8510-1 -x c++ /home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp
1/*
2 * Copyright (c) 2012, 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
25#include "precompiled.hpp"
26#include "jvm_io.h"
27#include "jfr/jfrEvents.hpp"
28#include "jfr/jni/jfrJavaSupport.hpp"
29#include "jfr/leakprofiler/leakProfiler.hpp"
30#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
31#include "jfr/recorder/service/jfrPostBox.hpp"
32#include "jfr/recorder/service/jfrRecorderService.hpp"
33#include "jfr/utilities/jfrTypes.hpp"
34#include "logging/log.hpp"
35#include "runtime/arguments.hpp"
36#include "runtime/atomic.hpp"
37#include "runtime/globals.hpp"
38#include "runtime/mutexLocker.hpp"
39#include "runtime/os.hpp"
40#include "runtime/thread.inline.hpp"
41#include "utilities/growableArray.hpp"
42#include "utilities/ostream.hpp"
43
44char JfrEmergencyDump::_dump_path[JVM_MAXPATHLEN4096 + 1] = { 0 };
45
46static const char vm_error_filename_fmt[] = "hs_err_pid%p.jfr";
47static const char vm_oom_filename_fmt[] = "hs_oom_pid%p.jfr";
48static const char vm_soe_filename_fmt[] = "hs_soe_pid%p.jfr";
49static const char chunk_file_jfr_ext[] = ".jfr";
50static const size_t iso8601_len = 19; // "YYYY-MM-DDTHH:MM:SS" (note: we just use a subset of the full timestamp)
51static fio_fd emergency_fd = invalid_fd;
52static const int64_t chunk_file_header_size = 68;
53static const size_t chunk_file_extension_length = sizeof chunk_file_jfr_ext - 1;
54
55/*
56 * The emergency dump logic is restrictive when it comes to
57 * using internal VM constructs such as ResourceArea / Handle / Arena.
58 * The reason being that the thread context is unknown.
59 *
60 * A single static buffer of size JVM_MAXPATHLEN is used for building paths.
61 * os::malloc / os::free are used in a few places.
62 */
63
64static char _path_buffer[JVM_MAXPATHLEN4096 + 1] = { 0 };
65
66static bool is_path_empty() {
67 return *_path_buffer == '\0';
68}
69
70// returns with an appended file separator (if successful)
71static size_t get_dump_directory() {
72 const char* dump_path = JfrEmergencyDump::get_dump_path();
73 if (*dump_path == '\0') {
74 if (os::get_current_directory(_path_buffer, sizeof(_path_buffer)) == NULL__null) {
75 return 0;
76 }
77 } else {
78 strcpy(_path_buffer, dump_path);
79 }
80 const size_t path_len = strlen(_path_buffer);
81 const int result = jio_snprintf(_path_buffer + path_len,
82 sizeof(_path_buffer),
83 "%s",
84 os::file_separator());
85 return (result == -1) ? 0 : strlen(_path_buffer);
86}
87
88static fio_fd open_exclusivly(const char* path) {
89 assert((path != NULL) && (*path != '\0'), "invariant")do { if (!((path != __null) && (*path != '\0'))) { (*
g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 89, "assert(" "(path != __null) && (*path != '\\0')"
") failed", "invariant"); ::breakpoint(); } } while (0)
;
90 return os::open(path, O_CREAT0100 | O_RDWR02, S_IREAD0400 | S_IWRITE0200);
91}
92
93static bool is_emergency_dump_file_open() {
94 return emergency_fd != invalid_fd;
95}
96
97static bool open_emergency_dump_fd(const char* path) {
98 if (path == NULL__null) {
99 return false;
100 }
101 assert(emergency_fd == invalid_fd, "invariant")do { if (!(emergency_fd == invalid_fd)) { (*g_assert_poison) =
'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 101, "assert(" "emergency_fd == invalid_fd" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
102 emergency_fd = open_exclusivly(path);
103 return emergency_fd != invalid_fd;
104}
105
106static void close_emergency_dump_file() {
107 if (is_emergency_dump_file_open()) {
108 os::close(emergency_fd);
109 }
110}
111
112static const char* create_emergency_dump_path() {
113 assert(is_path_empty(), "invariant")do { if (!(is_path_empty())) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 113, "assert(" "is_path_empty()" ") failed", "invariant"); ::
breakpoint(); } } while (0)
;
114
115 const size_t path_len = get_dump_directory();
116 if (path_len == 0) {
117 return NULL__null;
118 }
119 const char* filename_fmt = NULL__null;
120 // fetch specific error cause
121 switch (JfrJavaSupport::cause()) {
122 case JfrJavaSupport::OUT_OF_MEMORY:
123 filename_fmt = vm_oom_filename_fmt;
124 break;
125 case JfrJavaSupport::STACK_OVERFLOW:
126 filename_fmt = vm_soe_filename_fmt;
127 break;
128 default:
129 filename_fmt = vm_error_filename_fmt;
130 }
131 const bool result = Arguments::copy_expand_pid(filename_fmt, strlen(filename_fmt), _path_buffer + path_len, JVM_MAXPATHLEN4096 + 1 - path_len);
132 return result ? _path_buffer : NULL__null;
133}
134
135bool JfrEmergencyDump::open_emergency_dump_file() {
136 if (is_emergency_dump_file_open()) {
137 // opened already
138 return true;
139 }
140
141 bool result = open_emergency_dump_fd(create_emergency_dump_path());
142 if (!result && *_dump_path != '\0') {
143 log_warning(jfr)(!(LogImpl<(LogTag::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Warning))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Warning>
("Unable to create an emergency dump file at the location set by dumppath=%s", _dump_path);
144 // Fallback. Try to create it in the current directory.
145 *_dump_path = '\0';
146 *_path_buffer = '\0';
147 result = open_emergency_dump_fd(create_emergency_dump_path());
148 }
149 return result;
150}
151
152static void report(outputStream* st, bool emergency_file_opened, const char* repository_path) {
153 assert(st != NULL, "invariant")do { if (!(st != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 153, "assert(" "st != __null" ") failed", "invariant"); ::breakpoint
(); } } while (0)
;
154 if (emergency_file_opened) {
155 st->print_raw("# JFR recording file will be written. Location: ");
156 st->print_raw_cr(_path_buffer);
157 st->print_raw_cr("#");
158 } else if (repository_path != NULL__null) {
159 st->print_raw("# The JFR repository may contain useful JFR files. Location: ");
160 st->print_raw_cr(repository_path);
161 st->print_raw_cr("#");
162 } else if (!is_path_empty()) {
163 st->print_raw("# Unable to create a JFR recording file at location: ");
164 st->print_raw_cr(_path_buffer);
165 st->print_raw_cr("#");
166 }
167}
168
169void JfrEmergencyDump::set_dump_path(const char* dump_path) {
170 if (dump_path == NULL__null || *dump_path == '\0') {
171 os::get_current_directory(_dump_path, sizeof(_dump_path));
172 } else {
173 if (strlen(dump_path) < JVM_MAXPATHLEN4096 + 1) {
174 strncpy(_dump_path, dump_path, JVM_MAXPATHLEN4096 + 1);
175 _dump_path[JVM_MAXPATHLEN4096 + 1 - 1] = '\0';
176 }
177 }
178}
179
180const char* JfrEmergencyDump::get_dump_path() {
181 return _dump_path;
182}
183
184void JfrEmergencyDump::on_vm_error_report(outputStream* st, const char* repository_path) {
185 assert(st != NULL, "invariant")do { if (!(st != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 185, "assert(" "st != __null" ") failed", "invariant"); ::breakpoint
(); } } while (0)
;
186 Thread* thread = Thread::current_or_null_safe();
187 if (thread != NULL__null) {
188 report(st, open_emergency_dump_file(), repository_path);
189 } else if (repository_path != NULL__null) {
190 // a non-attached thread will not be able to write anything later
191 report(st, false, repository_path);
192 }
193}
194
195static int file_sort(const char** const file1, const char** file2) {
196 assert(NULL != *file1 && NULL != *file2, "invariant")do { if (!(__null != *file1 && __null != *file2)) { (
*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 196, "assert(" "__null != *file1 && __null != *file2"
") failed", "invariant"); ::breakpoint(); } } while (0)
;
197 int cmp = strncmp(*file1, *file2, iso8601_len);
198 if (0 == cmp) {
199 const char* const dot1 = strchr(*file1, '.');
200 assert(NULL != dot1, "invariant")do { if (!(__null != dot1)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 200, "assert(" "__null != dot1" ") failed", "invariant"); ::
breakpoint(); } } while (0)
;
201 const char* const dot2 = strchr(*file2, '.');
202 assert(NULL != dot2, "invariant")do { if (!(__null != dot2)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 202, "assert(" "__null != dot2" ") failed", "invariant"); ::
breakpoint(); } } while (0)
;
203 ptrdiff_t file1_len = dot1 - *file1;
204 ptrdiff_t file2_len = dot2 - *file2;
205 if (file1_len < file2_len) {
206 return -1;
207 }
208 if (file1_len > file2_len) {
209 return 1;
210 }
211 assert(file1_len == file2_len, "invariant")do { if (!(file1_len == file2_len)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 211, "assert(" "file1_len == file2_len" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
212 cmp = strncmp(*file1, *file2, file1_len);
213 }
214 assert(cmp != 0, "invariant")do { if (!(cmp != 0)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 214, "assert(" "cmp != 0" ") failed", "invariant"); ::breakpoint
(); } } while (0)
;
215 return cmp;
216}
217
218static void iso8601_to_date_time(char* iso8601_str) {
219 assert(iso8601_str != NULL, "invariant")do { if (!(iso8601_str != __null)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 219, "assert(" "iso8601_str != __null" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
220 assert(strlen(iso8601_str) == iso8601_len, "invariant")do { if (!(strlen(iso8601_str) == iso8601_len)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 220, "assert(" "strlen(iso8601_str) == iso8601_len" ") failed"
, "invariant"); ::breakpoint(); } } while (0)
;
221 // "YYYY-MM-DDTHH:MM:SS"
222 for (size_t i = 0; i < iso8601_len; ++i) {
223 switch (iso8601_str[i]) {
224 case 'T':
225 case '-':
226 case ':':
227 iso8601_str[i] = '_';
228 break;
229 }
230 }
231 // "YYYY_MM_DD_HH_MM_SS"
232}
233
234static void date_time(char* buffer, size_t buffer_len) {
235 assert(buffer != NULL, "invariant")do { if (!(buffer != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 235, "assert(" "buffer != __null" ") failed", "invariant");
::breakpoint(); } } while (0)
;
236 assert(buffer_len >= iso8601_len, "buffer too small")do { if (!(buffer_len >= iso8601_len)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 236, "assert(" "buffer_len >= iso8601_len" ") failed", "buffer too small"
); ::breakpoint(); } } while (0)
;
237 os::iso8601_time(buffer, buffer_len);
238 assert(strlen(buffer) >= iso8601_len + 1, "invariant")do { if (!(strlen(buffer) >= iso8601_len + 1)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 238, "assert(" "strlen(buffer) >= iso8601_len + 1" ") failed"
, "invariant"); ::breakpoint(); } } while (0)
;
239 // "YYYY-MM-DDTHH:MM:SS"
240 buffer[iso8601_len] = '\0';
241 iso8601_to_date_time(buffer);
242}
243
244static int64_t file_size(fio_fd fd) {
245 assert(fd != invalid_fd, "invariant")do { if (!(fd != invalid_fd)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 245, "assert(" "fd != invalid_fd" ") failed", "invariant");
::breakpoint(); } } while (0)
;
246 const int64_t current_offset = os::current_file_offset(fd);
247 const int64_t size = os::lseek(fd, 0, SEEK_END2);
248 os::seek_to_file_offset(fd, current_offset);
249 return size;
250}
251
252class RepositoryIterator : public StackObj {
253 private:
254 GrowableArray<const char*>* _file_names;
255 int _path_buffer_file_name_offset;
256 mutable int _iterator;
257 const char* fully_qualified(const char* file_name) const;
258 const char* filter(const char* file_name) const;
259 public:
260 RepositoryIterator(const char* repository_path);
261 ~RepositoryIterator();
262 bool has_next() const;
263 const char* next() const;
264};
265
266// append the file_name at the _path_buffer_file_name_offset position
267const char* RepositoryIterator::fully_qualified(const char* file_name) const {
268 assert(NULL != file_name, "invariant")do { if (!(__null != file_name)) { (*g_assert_poison) = 'X';;
report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 268, "assert(" "__null != file_name" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
269 assert(!is_path_empty(), "invariant")do { if (!(!is_path_empty())) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 269, "assert(" "!is_path_empty()" ") failed", "invariant");
::breakpoint(); } } while (0)
;
270 assert(_path_buffer_file_name_offset != 0, "invariant")do { if (!(_path_buffer_file_name_offset != 0)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 270, "assert(" "_path_buffer_file_name_offset != 0" ") failed"
, "invariant"); ::breakpoint(); } } while (0)
;
271
272 const int result = jio_snprintf(_path_buffer + _path_buffer_file_name_offset,
273 sizeof(_path_buffer) - _path_buffer_file_name_offset,
274 "%s",
275 file_name);
276 return result != -1 ? _path_buffer : NULL__null;
277}
278
279// caller responsible for deallocation
280const char* RepositoryIterator::filter(const char* file_name) const {
281 if (file_name == NULL__null) {
282 return NULL__null;
283 }
284 const size_t len = strlen(file_name);
285 if ((len < chunk_file_extension_length) ||
286 (strncmp(&file_name[len - chunk_file_extension_length],
287 chunk_file_jfr_ext,
288 chunk_file_extension_length) != 0)) {
289 // not a .jfr file
290 return NULL__null;
291 }
292 const char* fqn = fully_qualified(file_name);
293 if (fqn == NULL__null) {
294 return NULL__null;
295 }
296 const fio_fd fd = open_exclusivly(fqn);
297 if (invalid_fd == fd) {
298 return NULL__null;
299 }
300 const int64_t size = file_size(fd);
301 os::close(fd);
302 if (size <= chunk_file_header_size) {
303 return NULL__null;
304 }
305 char* const file_name_copy = (char*)os::malloc(len + 1, mtTracing);
306 if (file_name_copy == NULL__null) {
307 log_error(jfr, system)(!(LogImpl<(LogTag::_jfr), (LogTag::_system), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Error))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::_system), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Error>
("Unable to malloc memory during jfr emergency dump");
308 return NULL__null;
309 }
310 strncpy(file_name_copy, file_name, len + 1);
311 return file_name_copy;
312}
313
314RepositoryIterator::RepositoryIterator(const char* repository_path) :
315 _file_names(NULL__null),
316 _path_buffer_file_name_offset(0),
317 _iterator(0) {
318 DIR* dirp = os::opendir(repository_path);
319 if (dirp == NULL__null) {
320 log_error(jfr, system)(!(LogImpl<(LogTag::_jfr), (LogTag::_system), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Error))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::_system), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Error>
("Unable to open repository %s", repository_path);
321 return;
322 }
323 // store repository path in the path buffer and save that position
324 _path_buffer_file_name_offset = jio_snprintf(_path_buffer,
325 sizeof(_path_buffer),
326 "%s%s",
327 repository_path,
328 os::file_separator());
329 if (_path_buffer_file_name_offset == -1) {
330 return;
331 }
332 _file_names = new (ResourceObj::C_HEAP, mtTracing) GrowableArray<const char*>(10, mtTracing);
333 if (_file_names == NULL__null) {
334 log_error(jfr, system)(!(LogImpl<(LogTag::_jfr), (LogTag::_system), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Error))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::_system), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Error>
("Unable to malloc memory during jfr emergency dump");
335 return;
336 }
337 // iterate files in the repository and append filtered file names to the files array
338 struct dirent* dentry;
339 while ((dentry = os::readdir(dirp)) != NULL__null) {
340 const char* file_name = filter(dentry->d_name);
341 if (file_name != NULL__null) {
342 _file_names->append(file_name);
343 }
344 }
345 os::closedir(dirp);
346 if (_file_names->length() > 1) {
347 _file_names->sort(file_sort);
348 }
349}
350
351RepositoryIterator::~RepositoryIterator() {
352 if (_file_names != NULL__null) {
353 for (int i = 0; i < _file_names->length(); ++i) {
354 os::free(const_cast<char*>(_file_names->at(i)));
355 }
356 delete _file_names;
357 }
358}
359
360bool RepositoryIterator::has_next() const {
361 return _file_names != NULL__null && _iterator < _file_names->length();
362}
363
364const char* RepositoryIterator::next() const {
365 return _iterator >= _file_names->length() ? NULL__null : fully_qualified(_file_names->at(_iterator++));
366}
367
368static void write_repository_files(const RepositoryIterator& iterator, char* const copy_block, size_t block_size) {
369 assert(is_emergency_dump_file_open(), "invariant")do { if (!(is_emergency_dump_file_open())) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 369, "assert(" "is_emergency_dump_file_open()" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
370 while (iterator.has_next()) {
371 fio_fd current_fd = invalid_fd;
372 const char* const fqn = iterator.next();
373 assert(fqn != NULL, "invariant")do { if (!(fqn != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 373, "assert(" "fqn != __null" ") failed", "invariant"); ::
breakpoint(); } } while (0)
;
374 current_fd = open_exclusivly(fqn);
375 if (current_fd != invalid_fd) {
376 const int64_t size = file_size(current_fd);
377 assert(size > 0, "invariant")do { if (!(size > 0)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 377, "assert(" "size > 0" ") failed", "invariant"); ::breakpoint
(); } } while (0)
;
378 int64_t bytes_read = 0;
379 int64_t bytes_written = 0;
380 while (bytes_read < size) {
381 const ssize_t read_result = os::read_at(current_fd, copy_block, (int)block_size, bytes_read);
382 if (-1 == read_result) {
383 log_info(jfr)(!(LogImpl<(LogTag::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Info))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Info>
( // For user, should not be "jfr, system"
384 "Unable to recover JFR data");
385 break;
386 }
387 bytes_read += (int64_t)read_result;
388 assert(bytes_read - bytes_written <= (int64_t)block_size, "invariant")do { if (!(bytes_read - bytes_written <= (int64_t)block_size
)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 388, "assert(" "bytes_read - bytes_written <= (int64_t)block_size"
") failed", "invariant"); ::breakpoint(); } } while (0)
;
389 bytes_written += (int64_t)os::write(emergency_fd, copy_block, bytes_read - bytes_written);
390 assert(bytes_read == bytes_written, "invariant")do { if (!(bytes_read == bytes_written)) { (*g_assert_poison)
= 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 390, "assert(" "bytes_read == bytes_written" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
391 }
392 os::close(current_fd);
393 }
394 }
395}
396
397static void write_emergency_dump_file(const RepositoryIterator& iterator) {
398 static const size_t block_size = 1 * M; // 1 mb
399 char* const copy_block = (char*)os::malloc(block_size, mtTracing);
400 if (copy_block == NULL__null) {
401 log_error(jfr, system)(!(LogImpl<(LogTag::_jfr), (LogTag::_system), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Error))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::_system), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Error>
("Unable to malloc memory during jfr emergency dump");
402 log_error(jfr, system)(!(LogImpl<(LogTag::_jfr), (LogTag::_system), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Error))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::_system), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Error>
("Unable to write jfr emergency dump file");
403 } else {
404 write_repository_files(iterator, copy_block, block_size);
405 os::free(copy_block);
406 }
407}
408
409void JfrEmergencyDump::on_vm_error(const char* repository_path) {
410 assert(repository_path != NULL, "invariant")do { if (!(repository_path != __null)) { (*g_assert_poison) =
'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 410, "assert(" "repository_path != __null" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
411 if (open_emergency_dump_file()) {
412 RepositoryIterator iterator(repository_path);
413 write_emergency_dump_file(iterator);
414 close_emergency_dump_file();
415 }
416}
417
418static const char* create_emergency_chunk_path(const char* repository_path) {
419 const size_t repository_path_len = strlen(repository_path);
Value stored to 'repository_path_len' during its initialization is never read
420 char date_time_buffer[32] = { 0 };
421 date_time(date_time_buffer, sizeof(date_time_buffer));
422 // append the individual substrings
423 const int result = jio_snprintf(_path_buffer,
424 JVM_MAXPATHLEN4096 + 1,
425 "%s%s%s%s",
426 repository_path,
427 os::file_separator(),
428 date_time_buffer,
429 chunk_file_jfr_ext);
430 return result == -1 ? NULL__null : _path_buffer;
431}
432
433const char* JfrEmergencyDump::chunk_path(const char* repository_path) {
434 if (repository_path == NULL__null) {
435 if (!open_emergency_dump_file()) {
436 return NULL__null;
437 }
438 // We can directly use the emergency dump file name as the chunk.
439 // The chunk writer will open its own fd so we close this descriptor.
440 close_emergency_dump_file();
441 assert(!is_path_empty(), "invariant")do { if (!(!is_path_empty())) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 441, "assert(" "!is_path_empty()" ") failed", "invariant");
::breakpoint(); } } while (0)
;
442 return _path_buffer;
443 }
444 return create_emergency_chunk_path(repository_path);
445}
446
447/*
448* We are just about to exit the VM, so we will be very aggressive
449* at this point in order to increase overall success of dumping jfr data.
450*
451* If we end up deadlocking in the attempt of dumping out jfr data,
452* we rely on the WatcherThread task "is_error_reported()",
453* to exit the VM after a hard-coded timeout (disallow WatcherThread to emergency dump).
454* This "safety net" somewhat explains the aggressiveness in this attempt.
455*
456*/
457static bool prepare_for_emergency_dump(Thread* thread) {
458 assert(thread != NULL, "invariant")do { if (!(thread != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 458, "assert(" "thread != __null" ") failed", "invariant");
::breakpoint(); } } while (0)
;
459 if (thread->is_Watcher_thread()) {
460 // need WatcherThread as a safeguard against potential deadlocks
461 return false;
462 }
463
464#ifdef ASSERT1
465 Mutex* owned_lock = thread->owned_locks();
466 while (owned_lock != NULL__null) {
467 Mutex* next = owned_lock->next();
468 owned_lock->unlock();
469 owned_lock = next;
470 }
471#endif // ASSERT
472
473 if (Threads_lock->owned_by_self()) {
474 Threads_lock->unlock();
475 }
476
477 if (Module_lock->owned_by_self()) {
478 Module_lock->unlock();
479 }
480
481 if (ClassLoaderDataGraph_lock->owned_by_self()) {
482 ClassLoaderDataGraph_lock->unlock();
483 }
484
485 if (Heap_lock->owned_by_self()) {
486 Heap_lock->unlock();
487 }
488
489 if (VMOperation_lock->owned_by_self()) {
490 VMOperation_lock->unlock();
491 }
492
493 if (Service_lock->owned_by_self()) {
494 Service_lock->unlock();
495 }
496
497 if (UseNotificationThread && Notification_lock->owned_by_self()) {
498 Notification_lock->unlock();
499 }
500
501 if (CodeCache_lock->owned_by_self()) {
502 CodeCache_lock->unlock();
503 }
504
505 if (PeriodicTask_lock->owned_by_self()) {
506 PeriodicTask_lock->unlock();
507 }
508
509 if (JfrMsg_lock->owned_by_self()) {
510 JfrMsg_lock->unlock();
511 }
512
513 if (JfrBuffer_lock->owned_by_self()) {
514 JfrBuffer_lock->unlock();
515 }
516
517 if (JfrStacktrace_lock->owned_by_self()) {
518 JfrStacktrace_lock->unlock();
519 }
520 return true;
521}
522
523static volatile int jfr_shutdown_lock = 0;
524
525static bool guard_reentrancy() {
526 return Atomic::cmpxchg(&jfr_shutdown_lock, 0, 1) == 0;
527}
528
529class JavaThreadInVMAndNative : public StackObj {
530 private:
531 JavaThread* const _jt;
532 JavaThreadState _original_state;
533 public:
534
535 JavaThreadInVMAndNative(Thread* t) : _jt(t->is_Java_thread() ? JavaThread::cast(t) : NULL__null),
536 _original_state(_thread_max_state) {
537 if (_jt != NULL__null) {
538 _original_state = _jt->thread_state();
539 if (_original_state != _thread_in_vm) {
540 _jt->set_thread_state(_thread_in_vm);
541 }
542 }
543 }
544
545 ~JavaThreadInVMAndNative() {
546 if (_original_state != _thread_max_state) {
547 _jt->set_thread_state(_original_state);
548 }
549 }
550
551 void transition_to_native() {
552 if (_jt != NULL__null) {
553 assert(_jt->thread_state() == _thread_in_vm, "invariant")do { if (!(_jt->thread_state() == _thread_in_vm)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp"
, 553, "assert(" "_jt->thread_state() == _thread_in_vm" ") failed"
, "invariant"); ::breakpoint(); } } while (0)
;
554 _jt->set_thread_state(_thread_in_native);
555 }
556 }
557};
558
559static void post_events(bool exception_handler, Thread* thread) {
560 if (exception_handler) {
561 EventShutdown e;
562 e.set_reason("VM Error");
563 e.commit();
564 } else {
565 // OOM
566 LeakProfiler::emit_events(max_jlong, false, false);
567 }
568 EventDumpReason event;
569 event.set_reason(exception_handler ? "Crash" : "Out of Memory");
570 event.set_recordingId(-1);
571 event.commit();
572}
573
574void JfrEmergencyDump::on_vm_shutdown(bool exception_handler) {
575 if (!guard_reentrancy()) {
576 return;
577 }
578 Thread* thread = Thread::current_or_null_safe();
579 if (thread == NULL__null) {
580 return;
581 }
582 // Ensure a JavaThread is _thread_in_vm when we make this call
583 JavaThreadInVMAndNative jtivm(thread);
584 if (!prepare_for_emergency_dump(thread)) {
585 return;
586 }
587 post_events(exception_handler, thread);
588 // if JavaThread, transition to _thread_in_native to issue a final flushpoint
589 NoHandleMark nhm;
590 jtivm.transition_to_native();
591 const int messages = MSGBIT(MSG_VM_ERROR)(1<<(MSG_VM_ERROR));
592 JfrRecorderService service;
593 service.rotate(messages);
594}