src/share/vm/runtime/arguments.cpp

Print this page

        

*** 54,63 **** --- 54,65 ---- #endif // INCLUDE_ALL_GCS // Note: This is a special bug reporting site for the JVM #define DEFAULT_VENDOR_URL_BUG "http://bugreport.java.com/bugreport/crash.jsp" #define DEFAULT_JAVA_LAUNCHER "generic" + #define N_MAX_OPTIONS 64 + #define OPTION_BUFFER_SIZE 1024 #define UNSUPPORTED_GC_OPTION(gc) \ do { \ if (gc) { \ if (FLAG_IS_CMDLINE(gc)) { \
*** 110,120 **** --- 112,188 ---- SystemProperty *Arguments::_java_home = NULL; SystemProperty *Arguments::_java_class_path = NULL; SystemProperty *Arguments::_sun_boot_class_path = NULL; char* Arguments::_ext_dirs = NULL; + // change the 0 on next line to 1 to enable argument tracing + #if 0 + #define JVM_ARGS_ETRACE(x) x + #else + #define JVM_ARGS_ETRACE(x) + #endif + // Dump VM Option with a tag + void DumpOption(const JavaVMOption *option_p, + const int index, const char *tag) { + if (PrintVMOptions && Verbose) { + if (index >= 0) { + jio_fprintf(defaultStream::output_stream(), + "%s:[%d]='%s'\n", tag, index, option_p->optionString); + } + } + } + + // Dump VM Option with a tag + void DumpVMOption(const JavaVMInitArgs* args_p, + const int index, const char *tag) { + if (PrintVMOptions && Verbose) { + if (args_p->options != NULL) { + if ((index >= 0) && (index < args_p->nOptions)) { + JavaVMOption *option_p = args_p->options + index; + jio_fprintf(defaultStream::output_stream(), + "%s:[%d]='%s'\n", tag, index, option_p->optionString); + } + } + } + } + + // Dump VM Options with a tag + void DumpVMOptions(const JavaVMInitArgs* args_p, const char *tag) { + if (PrintVMOptions && Verbose) { + if (args_p->options != NULL) { + for (int index = 0; index < args_p->nOptions; index++) { + JavaVMOption *option_p = args_p->options + index; + jio_fprintf(defaultStream::output_stream(), + "%s:[%d]='%s'\n", tag, index, option_p->optionString); + } + } + } + } + + // Free memory associated with an options list + void FreeVMOptions(JavaVMInitArgs **args_pp, const JavaVMInitArgs *args_base_p) { + assert(args_pp != NULL, "args_pp must not be NULL"); + assert(*args_pp != NULL, "*args_pp must not be NULL"); + if (args_base_p == (*args_pp)) { + // Do not free memory we did not allocate + return; + } + assert((*args_pp)->options != NULL, "(*args_pp)->options must not be NULL"); + for (int index = 0; index < (*args_pp)->nOptions; index++) { + JavaVMOption *option_p = (*args_pp)->options + index; + if (option_p->optionString != NULL) { + os::free(option_p->optionString); + option_p->optionString = NULL; + } + } + os::free((void *)(*args_pp)->options); + (*args_pp)->options = NULL; + os::free((void *)(*args_pp)); + (*args_pp) = NULL; + } + // Check if head of 'option' matches 'name', and sets 'tail' to the remaining // part of the option string. static bool match_option(const JavaVMOption *option, const char* name, const char** tail) { int len = (int)strlen(name);
*** 2642,2651 **** --- 2710,2720 ---- Flag::Flags origin) { // Remaining part of option string const char* tail; // iterate over arguments + DumpVMOptions(args, "Parse each"); for (int index = 0; index < args->nOptions; index++) { bool is_absolute_path = false; // for -agentpath vs -agentlib const JavaVMOption* option = args->options + index;
*** 3275,3286 **** } else if (match_option(option, "-XX:-CreateMinidumpOnCrash")) { FLAG_SET_CMDLINE(bool, CreateCoredumpOnCrash, false); jio_fprintf(defaultStream::output_stream(), "CreateMinidumpOnCrash is replaced by CreateCoredumpOnCrash: CreateCoredumpOnCrash is off\n"); } else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx ! // Skip -XX:Flags= since that case has already been handled ! if (strncmp(tail, "Flags=", strlen("Flags=")) != 0) { if (!process_argument(tail, args->ignoreUnrecognized, origin)) { return JNI_EINVAL; } } // Unknown option --- 3344,3357 ---- } else if (match_option(option, "-XX:-CreateMinidumpOnCrash")) { FLAG_SET_CMDLINE(bool, CreateCoredumpOnCrash, false); jio_fprintf(defaultStream::output_stream(), "CreateMinidumpOnCrash is replaced by CreateCoredumpOnCrash: CreateCoredumpOnCrash is off\n"); } else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx ! // Skip -XX:Flags= and -XX:VMOptionsFile= since those cases have ! // already been handled ! if ((strncmp(tail, "Flags=", strlen("Flags=")) != 0) && ! (strncmp(tail, "VMOptionsFile=", strlen("VMOptionsFile=")) != 0)) { if (!process_argument(tail, args->ignoreUnrecognized, origin)) { return JNI_EINVAL; } } // Unknown option
*** 3696,3721 **** return false; } #endif // PRODUCT ! // Parse entry point called from JNI_CreateJavaVM ! jint Arguments::parse(const JavaVMInitArgs* args) { ! // Remaining part of option string ! const char* tail; ! // If flag "-XX:Flags=flags-file" is used it will be the first option to be processed. const char* hotspotrc = ".hotspotrc"; bool settings_file_specified = false; bool needs_hotspotrc_warning = false; const char* flags_file; int index; for (index = 0; index < args->nOptions; index++) { const JavaVMOption *option = args->options + index; if (ArgumentsExt::process_options(option)) { continue; } if (match_option(option, "-XX:Flags=", &tail)) { flags_file = tail; --- 3767,4331 ---- return false; } #endif // PRODUCT ! jint Arguments::alloc_JVM_options_list(const int needed_slots, ! const int version, ! struct JavaVMInitArgs **ret_args_head) { ! assert(needed_slots > 0, "needed_slots must greater than zero"); ! assert(ret_args_head != NULL, "ret_args_head must not be NULL"); ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Allocating %d option slots\n", needed_slots)); ! JavaVMInitArgs *new_args_head = ! (JavaVMInitArgs *) os::malloc(sizeof (JavaVMInitArgs), mtInternal); ! if (new_args_head == NULL) { ! jio_fprintf(defaultStream::error_stream(), ! "Could not allocate arguments list head\n"); ! return JNI_ENOMEM; ! } ! memset(new_args_head, 0, sizeof (struct JavaVMInitArgs)); ! int bytes_needed = needed_slots * (sizeof (struct JavaVMOption)); ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "to allocate options list %d %d\n", ! needed_slots, bytes_needed)); ! ! JavaVMOption *new_options_head = ! (struct JavaVMOption *) os::malloc(bytes_needed, mtInternal); ! ! if (new_options_head == NULL) { ! jio_fprintf(defaultStream::error_stream(), ! "Could not allocate options list with %d entries" ! " and %d bytes\n", ! needed_slots, bytes_needed); ! ! os::free(new_args_head); ! new_args_head = NULL; ! ! return JNI_ENOMEM; ! } ! ! memset(new_options_head, 0, bytes_needed); ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "allocation need for options list %d %d\n", ! needed_slots, bytes_needed)); ! ! // Assemble the args object ! new_args_head->options = new_options_head; ! new_args_head->nOptions = 0; ! new_args_head->version = version; ! ! // Return newly allocated but not populated options list ! *ret_args_head = new_args_head; ! ! return JNI_OK; ! } ! ! // Copy num_slots NULL separated JVM options from buffer to ! // new_options[0] through new_options[num_slots - 1]. ! // The byte_cnt includes null termination. ! jint Arguments::copy_JVM_options_from_buf(const char *buffer, ! const size_t byte_cnt, ! const int num_slots, ! int *cur_slot_p, ! struct JavaVMOption *new_options) { ! ! assert(buffer != NULL, "buffer must not be NULL"); ! assert(byte_cnt > 1, "byte_cnt must be greater than one"); ! assert(num_slots > 0, "num_slots must be greater than zero"); ! assert(cur_slot_p != NULL, "cur_slot_p must not be NULL"); ! assert(new_options != NULL, "new_options must not be NULL"); ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Copying %d options from buffer\n", ! num_slots)); ! (*cur_slot_p) = 0; ! const char *head = buffer; ! const char *tail = buffer + byte_cnt - 1; ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Copying option %d %d %d\n", ! byte_cnt, *cur_slot_p, num_slots)); ! ! while ((head < tail) && (*cur_slot_p < num_slots)) { ! // Skip null character separator(s) ! while ((head < tail) && (*head == '\0')) { ! head++; ! } ! ! if (head >= tail) { ! break; ! } ! ! // save a copy of the string in the options list ! new_options[(*cur_slot_p)].optionString = ! os::strdup_check_oom(head, mtInternal); ! ! if (new_options[(*cur_slot_p)].optionString == NULL) { ! jio_fprintf(defaultStream::error_stream(), ! "Could not copy file option string '%s'\n", head); ! return JNI_ENOMEM; ! } ! ! DumpOption(new_options, *cur_slot_p, "copy"); ! const char *dummy; ! if (match_option(&new_options[(*cur_slot_p)], ! "-XX:VMOptionsFile=", &dummy)) { ! jio_fprintf(defaultStream::error_stream(), ! "VM options file is only supported on the command line\n"); ! ! (*cur_slot_p)++; // We do not need this slot, but count it on the ! // list so the error handling can clean this up ! return JNI_EINVAL; ! } ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Copying option %d %d %s\n", ! *cur_slot_p, ! num_slots, ! new_options[(*cur_slot_p)].optionString)); ! (*cur_slot_p)++; // Done with current slot ! ! while ((head < tail) && (*head != '\0')) { ! head++; ! } ! } ! ! return JNI_OK; ! } ! ! // Parse the JVM options from file_name into ret_buff. The ! // options in ret_buff are NULL separated in order to preserve ! // any embedded white space that was quoted in file_name. ! jint Arguments::parse_JVM_options_file(const char *file_name, ! char **ret_buff, ! size_t *ret_bytes, ! int *ret_opt_cnt) { ! ! assert(file_name != NULL, "file_name must not be NULL."); ! assert(ret_buff != NULL, "ret_buff must not be NULL."); ! assert(ret_bytes != NULL, "ret_bytes must not be NULL."); ! assert(ret_opt_cnt != NULL, "ret_opt_cnt must not be NULL."); ! ! // Default all return params to not return data ! *ret_buff = NULL; ! *ret_bytes = 0; ! *ret_opt_cnt = 0; ! ! int fd = ::open(file_name, O_RDONLY); ! if (fd < 0) { ! jio_fprintf(defaultStream::error_stream(), ! "Could not open options file '%s'\n", ! file_name); ! return JNI_ERR; ! } ! ! // '+ 1' for NULL termination even with max bytes ! int bytes_alloc = OPTION_BUFFER_SIZE + 1; ! ! char *buf = (char *)os::malloc(bytes_alloc, mtInternal); ! ! if (buf == NULL) { ! jio_fprintf(defaultStream::error_stream(), ! "Could not allocate read buffer for options file parse\n"); ! os::close(fd); ! return JNI_ENOMEM; ! } ! ! memset(buf, 0, (unsigned)bytes_alloc); ! ! // Fill buffer ! // Use ::read() instead of os::read because os::read() ! // might do a thead state transition ! // and it is too early for that here ! ! int bytes_read = ::read(fd, (void *)buf, ! (unsigned)bytes_alloc); ! if (bytes_read < 0) { ! os::free(buf); ! buf = NULL; ! os::close(fd); ! jio_fprintf(defaultStream::error_stream(), ! "Could not read options file '%s'\n", file_name); ! return JNI_ERR; ! } ! ! if (bytes_read == 0) { ! // tell caller there is no option data and that is ok ! os::free(buf); ! buf = NULL; ! os::close(fd); ! return JNI_OK; ! } ! ! // file is larger than OPTION_BUFFER_SIZE ! if (bytes_read > bytes_alloc - 1) { ! os::free(buf); ! buf = NULL; ! os::close(fd); ! jio_fprintf(defaultStream::error_stream(), ! "Options file '%s' is larger than %d bytes.\n", ! file_name, bytes_alloc - 1); ! return JNI_EINVAL; ! } ! ! os::close(fd); ! ! // some pointers to help with parsing ! char *buf_end = buf + bytes_read; ! char *cur_token_head = buf; ! char *wrt = buf; ! char *rd = buf; ! ! // count tokens ! int token_cnt = 0; ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Parse buf loop > '%s'\n", ! buf)); ! // parse all options ! while (rd < buf_end) { ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Parse buf loop white > >%s<\n", rd)); ! // skip leading white space from the input string ! while (rd < buf_end && iswhite(*rd)) { ! rd++; ! } ! ! if (rd >= buf_end) { ! break; ! } ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Parse next token > %s\n", rd)); ! // Remember this is where we found the head of the token. ! cur_token_head = wrt; ! ! // Tokens are strings of non white space characters separated ! // by one or more white spaces. ! while (rd < buf_end && !iswhite(*rd)) { ! if (*rd == '\'' || *rd == '"') { // handle a quoted string ! int quote = *rd; // matching quote to look for ! rd++; // don't copy open quote ! while (rd < buf_end && *rd != quote) { ! // include everything (even spaces) ! // up until the close quote ! *wrt++ = *rd++; // copy to option string ! } ! ! if (rd < buf_end) { ! rd++; // don't copy close quote ! } else { ! // did not see closing quote ! jio_fprintf(defaultStream::error_stream(), ! "Unmatched quote in '%s'\n", file_name); ! os::free(buf); ! buf = NULL; ! return JNI_EINVAL; ! } ! } else { ! *wrt++ = *rd++; // copy to option string ! } ! } ! ! // steal a white space character and set it to NULL ! *wrt++ = '\0'; ! token_cnt++; ! // We now have a complete token ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Current parsed token > %s\n", ! cur_token_head)); ! ! rd++; // Advance to next character ! } ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Done parsing tokens > %d\n", ! token_cnt)); ! ! if (token_cnt > N_MAX_OPTIONS) { ! jio_fprintf(defaultStream::error_stream(), ! "Options file has more than %d options.\n", ! N_MAX_OPTIONS); ! os::free(buf); ! buf = NULL; ! return JNI_EINVAL; ! } ! ! // Pass the data the back to the caller ! *ret_buff = buf; ! *ret_opt_cnt = token_cnt; ! *ret_bytes = (size_t)(wrt - buf); ! ! return JNI_OK; ! } ! ! // Merge options from a JVM options file with the options provided ! // by argsin and return the merge results via *argsout. If the ! // '-XX:VMOptionsFile=...' option is not specified on the command ! // line, then there is nothing to merge and *argsout is set to NULL. ! jint Arguments::merge_JVM_options_file(const JavaVMInitArgs *argsin, ! JavaVMInitArgs **argsout) { ! ! assert(argsin != NULL, "argsin should not be NULL"); ! assert(argsout != NULL, "argsout should not be NULL"); ! ! JavaVMInitArgs *new_args_head = NULL; ! char *options_file = NULL; ! bool options_file_found = false; ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Found %d existing option(s)\n", ! argsin->nOptions)); ! ! // Take a peak at options passed in, looking for an options file ! int old_index = 0; ! const char *tail = NULL; ! while (old_index < argsin->nOptions) { ! JavaVMOption *option = argsin->options + old_index; ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Found existing option %s\n", ! option->optionString)); ! ! if (match_option(option, "-XX:VMOptionsFile=", &tail)) { ! // Only one options file allowed on the command line. ! if (options_file_found) { ! jio_fprintf(defaultStream::error_stream(), ! "Only one VM Options file is supported " ! "on the command line\n"); ! ! *argsout = NULL; ! os::free(options_file); ! options_file = NULL; ! return JNI_EINVAL; ! } else { ! options_file_found = true; ! } ! options_file = os::strdup_check_oom(tail, mtInternal); ! if (options_file == NULL) { ! jio_fprintf(defaultStream::error_stream(), ! "Could not copy options file path\n"); ! ! return JNI_ENOMEM; ! } ! } ! old_index++; ! } ! ! // No option file specified so nothing more to do ! if (options_file == NULL) { ! *argsout = NULL; ! return JNI_OK; ! } ! ! DumpVMOptions(argsin, "Premerge"); ! ! char *buff; // Contents of the options file ! size_t byte_cnt = 0; // bytes in buffer ! int file_slots = 0; // # options found in file ! ! // We have requested an options file, so we need to read it ! // and do a simple white space parse on it. ! jint result = parse_JVM_options_file(options_file, ! &buff, ! &byte_cnt, ! &file_slots); ! if (result != JNI_OK) { ! // the option file processing failed ! jio_fprintf(defaultStream::error_stream(), ! "Options file '%s', parsing error\n", ! options_file); ! ! os::free(options_file); ! options_file = NULL; ! *argsout = NULL; ! return result; ! } ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Found %d bytes and %d options\n", ! byte_cnt, file_slots)); ! // no options but that is ok ! if (file_slots == 0) { ! os::free(options_file); ! options_file = NULL; ! *argsout = NULL; ! return JNI_OK; ! } ! ! // Combine cmd line slot count and the options file slots passed to us ! // We need one less because the "-XX:VMOptionsFile" is not included ! // in the new list. ! int num_slots = argsin->nOptions + file_slots - 1; ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Allocate option list with %d slots, %d file," ! " %d exist\n", ! num_slots, file_slots, argsin->nOptions)); ! ! // Allocate a new option list ! result = Arguments::alloc_JVM_options_list(num_slots, argsin->version, ! &new_args_head); ! if (result != JNI_OK) { ! // the option file processing failed ! jio_fprintf(defaultStream::error_stream(), ! "Memory error in options processing\n"); ! os::free(buff); ! buff = NULL; ! os::free(options_file); ! options_file = NULL; ! *argsout = NULL; ! return result; ! } ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "merge option list > %d %d\n", ! argsin->nOptions, num_slots)); ! ! old_index = 0; ! while ((old_index < argsin->nOptions) && ! (new_args_head->nOptions < num_slots)) { ! ! JavaVMOption *old_option_p = argsin->options + old_index; ! JavaVMOption *new_option_p = new_args_head->options + ! new_args_head->nOptions; ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "Merge option %s old %d new %d\n", ! old_option_p->optionString, ! old_index, new_args_head->nOptions)); ! ! // Allow the VM option tracing to come on early. ! if (match_option(old_option_p, "-XX:+PrintVMOptions")) { ! PrintVMOptions = true; ! } ! ! if (match_option(old_option_p, "-XX:VMOptionsFile=", &tail)) { ! int file_slots_used = 0; ! result = Arguments::copy_JVM_options_from_buf(buff, ! byte_cnt, ! file_slots, ! &file_slots_used, ! new_option_p); ! // Update option count for success and failure. ! // The initialized count is required to free the new args object ! new_args_head->nOptions += file_slots_used; ! ! if (result != JNI_OK) { ! // the option file processing failed ! jio_fprintf(defaultStream::error_stream(), ! "Options copy error '%s'\n", ! options_file); ! ! os::free(buff); ! buff = NULL; ! os::free(options_file); ! options_file = NULL; ! FreeVMOptions(&new_args_head, argsin); ! *argsout = NULL; ! return result; ! } ! ! old_index++; // Next slot in the input list ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "old %d new %d file %d\n", ! old_index, ! new_args_head->nOptions, ! file_slots)); ! } else { ! // We only increment the index if the option preexisted. ! // The options file copying increments the index too ! new_option_p->optionString = ! os::strdup_check_oom(old_option_p->optionString, mtInternal); ! ! if (new_option_p->optionString == NULL) { ! jio_fprintf(defaultStream::error_stream(), ! "Could not allocate command option string '%s'\n", ! old_option_p->optionString); ! ! FreeVMOptions(&new_args_head, argsin); ! *argsout = NULL; ! os::free(buff); ! buff = NULL; ! os::free(options_file); ! options_file = NULL; ! return JNI_ENOMEM; ! } ! ! new_option_p->extraInfo = NULL; ! ! DumpOption(old_option_p, old_index, "old"); ! DumpOption(new_option_p, new_args_head->nOptions, "new"); ! ! DumpVMOption(new_args_head, new_args_head->nOptions, "new"); ! DumpVMOption(argsin, old_index, "old"); ! old_index++; // Next slot in the input list ! new_args_head->nOptions++; // Next slot in the new args list ! } ! ! } ! ! os::free(buff); ! buff = NULL; ! os::free(options_file); ! options_file = NULL; ! ! JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), ! "trace final num ops %d\n", ! new_args_head->nOptions)); ! ! // We have a list of options that is ready to be returned to the caller. ! *argsout = new_args_head; ! DumpVMOptions(*argsout, "Postmerge"); ! return JNI_OK; ! } ! ! // Parse entry point called from JNI_CreateJavaVM ! ! jint Arguments::parse(const struct JavaVMInitArgs *argsin) { const char* hotspotrc = ".hotspotrc"; bool settings_file_specified = false; bool needs_hotspotrc_warning = false; + // If flag "-XX:Flags=flags-file" is used it will be the + // first option to be processed. const char* flags_file; int index; + struct JavaVMInitArgs *args = NULL; + + jint result = Arguments::merge_JVM_options_file(argsin, &args); + if (result != JNI_OK) { + // A more specific error message has been printed to the error stream + jio_fprintf(defaultStream::error_stream(), + "Options merge error, VM will exit\n"); + vm_exit(1); + } + + if (args == NULL) { + args = (JavaVMInitArgs *)argsin; + JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), + "no file options merged\n")); + } else { + JVM_ARGS_ETRACE(jio_fprintf(defaultStream::error_stream(), + "file options merged\n")); + } + + DumpVMOptions(args, "Final Command Line"); + const char* tail = NULL; for (index = 0; index < args->nOptions; index++) { const JavaVMOption *option = args->options + index; + if (match_option(option, "-XX:VMOptionsFile=", &tail)) { + // -XX:VMOptionsFile= can only appear here if the option file + // is empty or if there are no options to process, ignore it. + continue; + } if (ArgumentsExt::process_options(option)) { continue; } if (match_option(option, "-XX:Flags=", &tail)) { flags_file = tail;
*** 3780,3795 **** --- 4390,4407 ---- } // Parse specified settings file if (settings_file_specified) { if (!process_settings_file(flags_file, true, args->ignoreUnrecognized)) { + FreeVMOptions(&args, argsin); return JNI_EINVAL; } } else { #ifdef ASSERT // Parse default .hotspotrc settings file if (!process_settings_file(".hotspotrc", false, args->ignoreUnrecognized)) { + FreeVMOptions(&args, argsin); return JNI_EINVAL; } #else struct stat buf; if (os::stat(hotspotrc, &buf) == 0) {
*** 3806,3820 **** } } } // Parse JavaVMInitArgs structure passed in, as well as JAVA_TOOL_OPTIONS and _JAVA_OPTIONS ! jint result = parse_vm_init_args(args); if (result != JNI_OK) { return result; } // Call get_shared_archive_path() here, after possible SharedArchiveFile option got parsed. SharedArchivePath = get_shared_archive_path(); if (SharedArchivePath == NULL) { return JNI_ENOMEM; } --- 4418,4435 ---- } } } // Parse JavaVMInitArgs structure passed in, as well as JAVA_TOOL_OPTIONS and _JAVA_OPTIONS ! result = parse_vm_init_args(args); if (result != JNI_OK) { + FreeVMOptions(&args, argsin); return result; } + FreeVMOptions(&args, argsin); + // Call get_shared_archive_path() here, after possible SharedArchiveFile option got parsed. SharedArchivePath = get_shared_archive_path(); if (SharedArchivePath == NULL) { return JNI_ENOMEM; }