-
Notifications
You must be signed in to change notification settings - Fork 6.2k
8353727: HeapDumpPath doesn't expand %p #24482
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ab82116
4ec2b03
c32e4ca
40c67a0
09f6654
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,6 +43,7 @@ | |
| #include "oops/objArrayOop.inline.hpp" | ||
| #include "oops/oop.inline.hpp" | ||
| #include "oops/typeArrayOop.inline.hpp" | ||
| #include "runtime/arguments.hpp" | ||
| #include "runtime/continuationWrapper.inline.hpp" | ||
| #include "runtime/frame.inline.hpp" | ||
| #include "runtime/handles.inline.hpp" | ||
|
|
@@ -2747,77 +2748,50 @@ void HeapDumper::dump_heap() { | |
| void HeapDumper::dump_heap(bool oome) { | ||
| static char base_path[JVM_MAXPATHLEN] = {'\0'}; | ||
| static uint dump_file_seq = 0; | ||
| char* my_path; | ||
| char my_path[JVM_MAXPATHLEN]; | ||
| const int max_digit_chars = 20; | ||
|
|
||
| const char* dump_file_name = "java_pid"; | ||
| const char* dump_file_ext = HeapDumpGzipLevel > 0 ? ".hprof.gz" : ".hprof"; | ||
| const char* dump_file_name = HeapDumpGzipLevel > 0 ? "java_pid%p.hprof.gz" : "java_pid%p.hprof"; | ||
|
|
||
| // The dump file defaults to java_pid<pid>.hprof in the current working | ||
| // directory. HeapDumpPath=<file> can be used to specify an alternative | ||
| // dump file name or a directory where dump file is created. | ||
| if (dump_file_seq == 0) { // first time in, we initialize base_path | ||
| // Calculate potentially longest base path and check if we have enough | ||
| // allocated statically. | ||
| const size_t total_length = | ||
| (HeapDumpPath == nullptr ? 0 : strlen(HeapDumpPath)) + | ||
| strlen(os::file_separator()) + max_digit_chars + | ||
| strlen(dump_file_name) + strlen(dump_file_ext) + 1; | ||
| if (total_length > sizeof(base_path)) { | ||
| // Set base path (name or directory, default or custom, without seq no), doing %p substitution. | ||
| const char *path_src = (HeapDumpPath != nullptr && HeapDumpPath[0] != '\0') ? HeapDumpPath : dump_file_name; | ||
| if (!Arguments::copy_expand_pid(path_src, strlen(path_src), base_path, JVM_MAXPATHLEN - max_digit_chars)) { | ||
| warning("Cannot create heap dump file. HeapDumpPath is too long."); | ||
| return; | ||
| } | ||
|
|
||
| bool use_default_filename = true; | ||
| if (HeapDumpPath == nullptr || HeapDumpPath[0] == '\0') { | ||
| // HeapDumpPath=<file> not specified | ||
| } else { | ||
| strcpy(base_path, HeapDumpPath); | ||
| // check if the path is a directory (must exist) | ||
| DIR* dir = os::opendir(base_path); | ||
| if (dir == nullptr) { | ||
| use_default_filename = false; | ||
| } else { | ||
| // HeapDumpPath specified a directory. We append a file separator | ||
| // (if needed). | ||
| os::closedir(dir); | ||
| size_t fs_len = strlen(os::file_separator()); | ||
| if (strlen(base_path) >= fs_len) { | ||
| char* end = base_path; | ||
| end += (strlen(base_path) - fs_len); | ||
| if (strcmp(end, os::file_separator()) != 0) { | ||
| strcat(base_path, os::file_separator()); | ||
| } | ||
| // Check if the path is an existing directory | ||
| DIR* dir = os::opendir(base_path); | ||
| if (dir != nullptr) { | ||
| os::closedir(dir); | ||
| // Path is a directory. Append a file separator (if needed). | ||
| size_t fs_len = strlen(os::file_separator()); | ||
| if (strlen(base_path) >= fs_len) { | ||
| char* end = base_path; | ||
| end += (strlen(base_path) - fs_len); | ||
| if (strcmp(end, os::file_separator()) != 0) { | ||
| strcat(base_path, os::file_separator()); | ||
| } | ||
| } | ||
| // Then add the default name, with %p substitution. Use my_path temporarily. | ||
| if (!Arguments::copy_expand_pid(dump_file_name, strlen(dump_file_name), my_path, JVM_MAXPATHLEN - max_digit_chars)) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC there is a pre-existing bug, and if I am right one you should fix: this calculation assumes that there is only a single %p. There may be multiple. Many. E.g. as a malicious attempt to cause a buffer overflow. This is what I meant with stringStream. stringStream offers protection against stuff like that without the manual buffer counting headaches. I would give Arguments a method like this: and in there print to sink, with print or putc. This would never truncate. Then use it like this: Just a rough sketch. And fine for followup PRs, though I think it may make your life easier if you do it now.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thankfully copy_expand_pid does handle multiple %p replacements. It seems good to use that to check the buffer length, partly for that reason, as just knowing a max number of digits wasn't so flexible if many %p were present. Thanks for the other ideas!
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah okay, it checks for overflow. Okay, please disregard half of what I have written :) |
||
| warning("Cannot create heap dump file. HeapDumpPath is too long."); | ||
kevinjwalls marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return; | ||
| } | ||
| const size_t dlen = strlen(base_path); | ||
| jio_snprintf(&base_path[dlen], sizeof(base_path) - dlen, "%s", my_path); | ||
| } | ||
| // If HeapDumpPath wasn't a file name then we append the default name | ||
| if (use_default_filename) { | ||
| const size_t dlen = strlen(base_path); // if heap dump dir specified | ||
| jio_snprintf(&base_path[dlen], sizeof(base_path)-dlen, "%s%d%s", | ||
| dump_file_name, os::current_process_id(), dump_file_ext); | ||
| } | ||
| const size_t len = strlen(base_path) + 1; | ||
| my_path = (char*)os::malloc(len, mtInternal); | ||
| if (my_path == nullptr) { | ||
| warning("Cannot create heap dump file. Out of system memory."); | ||
| return; | ||
| } | ||
| strncpy(my_path, base_path, len); | ||
| strncpy(my_path, base_path, JVM_MAXPATHLEN); | ||
| } else { | ||
| // Append a sequence number id for dumps following the first | ||
| const size_t len = strlen(base_path) + max_digit_chars + 2; // for '.' and \0 | ||
| my_path = (char*)os::malloc(len, mtInternal); | ||
| if (my_path == nullptr) { | ||
| warning("Cannot create heap dump file. Out of system memory."); | ||
| return; | ||
| } | ||
| jio_snprintf(my_path, len, "%s.%d", base_path, dump_file_seq); | ||
| } | ||
| dump_file_seq++; // increment seq number for next time we dump | ||
|
|
||
| HeapDumper dumper(false /* no GC before heap dump */, | ||
| oome /* pass along out-of-memory-error flag */); | ||
| dumper.dump(my_path, tty, HeapDumpGzipLevel); | ||
| os::free(my_path); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.