8079301: Some command line options not settable via JAVA_TOOL_OPTIONS

Ensures special-cased command line options are settable via _JAVA_OPTIONS and JAVA_TOOL_OPTIONS.

Reviewed-by: coleenp, ddmitriev
This commit is contained in:
Jeremy Manson 2015-07-17 19:40:21 -04:00
parent b02b2c4d5b
commit 8d6eb32eee
2 changed files with 161 additions and 81 deletions

View File

@ -91,7 +91,7 @@ const char* Arguments::_sun_java_launcher = DEFAULT_JAVA_LAUNCHER;
int Arguments::_sun_java_launcher_pid = -1;
bool Arguments::_sun_java_launcher_is_altjvm = false;
// These parameters are reset in method parse_vm_init_args(JavaVMInitArgs*)
// These parameters are reset in method parse_vm_init_args()
bool Arguments::_AlwaysCompileLoopMethods = AlwaysCompileLoopMethods;
bool Arguments::_UseOnStackReplacement = UseOnStackReplacement;
bool Arguments::_BackgroundCompilation = BackgroundCompilation;
@ -2251,7 +2251,9 @@ Arguments::ArgsRange Arguments::parse_memory_size(const char* s,
// Parse JavaVMInitArgs structure
jint Arguments::parse_vm_init_args(const JavaVMInitArgs* args) {
jint Arguments::parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args,
const JavaVMInitArgs *java_options_args,
const JavaVMInitArgs *cmd_line_args) {
// For components of the system classpath.
SysClassPath scp(Arguments::get_sysclasspath());
bool scp_assembly_required = false;
@ -2269,20 +2271,25 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs* args) {
// Setup flags for mixed which is the default
set_mode_flags(_mixed);
// Parse JAVA_TOOL_OPTIONS environment variable (if present)
jint result = parse_java_tool_options_environment_variable(&scp, &scp_assembly_required);
// Parse args structure generated from JAVA_TOOL_OPTIONS environment
// variable (if present).
jint result = parse_each_vm_init_arg(
java_tool_options_args, &scp, &scp_assembly_required, Flag::ENVIRON_VAR);
if (result != JNI_OK) {
return result;
}
// Parse JavaVMInitArgs structure passed in
result = parse_each_vm_init_arg(args, &scp, &scp_assembly_required, Flag::COMMAND_LINE);
// Parse args structure generated from the command line flags.
result = parse_each_vm_init_arg(cmd_line_args, &scp, &scp_assembly_required,
Flag::COMMAND_LINE);
if (result != JNI_OK) {
return result;
}
// Parse _JAVA_OPTIONS environment variable (if present) (mimics classic VM)
result = parse_java_options_environment_variable(&scp, &scp_assembly_required);
// Parse args structure generated from the _JAVA_OPTIONS environment
// variable (if present) (mimics classic VM)
result = parse_each_vm_init_arg(
java_options_args, &scp, &scp_assembly_required, Flag::ENVIRON_VAR);
if (result != JNI_OK) {
return result;
}
@ -3385,20 +3392,73 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req
return JNI_OK;
}
jint Arguments::parse_java_options_environment_variable(SysClassPath* scp_p, bool* scp_assembly_required_p) {
return parse_options_environment_variable("_JAVA_OPTIONS", scp_p,
scp_assembly_required_p);
// Helper class for controlling the lifetime of JavaVMInitArgs
// objects. The contents of the JavaVMInitArgs are guaranteed to be
// deleted on the destruction of the ScopedVMInitArgs object.
class ScopedVMInitArgs : public StackObj {
private:
JavaVMInitArgs _args;
public:
ScopedVMInitArgs() {
_args.version = JNI_VERSION_1_2;
_args.nOptions = 0;
_args.options = NULL;
_args.ignoreUnrecognized = false;
}
// Populates the JavaVMInitArgs object represented by this
// ScopedVMInitArgs object with the arguments in options. The
// allocated memory is deleted by the destructor. If this method
// returns anything other than JNI_OK, then this object is in a
// partially constructed state, and should be abandoned.
jint set_args(GrowableArray<JavaVMOption>* options) {
JavaVMOption* options_arr = NEW_C_HEAP_ARRAY_RETURN_NULL(
JavaVMOption, options->length(), mtInternal);
if (options_arr == NULL) {
return JNI_ENOMEM;
}
_args.options = options_arr;
for (int i = 0; i < options->length(); i++) {
options_arr[i] = options->at(i);
options_arr[i].optionString = os::strdup(options_arr[i].optionString);
if (options_arr[i].optionString == NULL) {
// Rely on the destructor to do cleanup.
_args.nOptions = i;
return JNI_ENOMEM;
}
}
_args.nOptions = options->length();
_args.ignoreUnrecognized = IgnoreUnrecognizedVMOptions;
return JNI_OK;
}
JavaVMInitArgs* get() { return &_args; }
~ScopedVMInitArgs() {
if (_args.options == NULL) return;
for (int i = 0; i < _args.nOptions; i++) {
os::free(_args.options[i].optionString);
}
FREE_C_HEAP_ARRAY(JavaVMOption, _args.options);
}
};
jint Arguments::parse_java_options_environment_variable(ScopedVMInitArgs* args) {
return parse_options_environment_variable("_JAVA_OPTIONS", args);
}
jint Arguments::parse_java_tool_options_environment_variable(SysClassPath* scp_p, bool* scp_assembly_required_p) {
return parse_options_environment_variable("JAVA_TOOL_OPTIONS", scp_p,
scp_assembly_required_p);
jint Arguments::parse_java_tool_options_environment_variable(ScopedVMInitArgs* args) {
return parse_options_environment_variable("JAVA_TOOL_OPTIONS", args);
}
jint Arguments::parse_options_environment_variable(const char* name, SysClassPath* scp_p, bool* scp_assembly_required_p) {
jint Arguments::parse_options_environment_variable(const char* name,
ScopedVMInitArgs* vm_args) {
char *buffer = ::getenv(name);
// Don't check this variable if user has special privileges
// Don't check this environment variable if user has special privileges
// (e.g. unix su command).
if (buffer == NULL || os::have_special_privileges()) {
return JNI_OK;
@ -3443,48 +3503,20 @@ jint Arguments::parse_options_environment_variable(const char* name, SysClassPat
*wrt++ = *rd++; // copy to option string
}
}
// Need to check if we're done before writing a NULL,
// because the write could be to the byte that rd is pointing to.
if (*rd++ == 0) {
*wrt = 0;
break;
if (*rd != 0) {
// In this case, the assignment to wrt below will make *rd nul,
// which will interfere with the next loop iteration.
rd++;
}
*wrt = 0; // Zero terminate option
}
JavaVMOption* options_arr =
NEW_C_HEAP_ARRAY_RETURN_NULL(JavaVMOption, options->length(), mtInternal);
if (options_arr == NULL) {
delete options;
os::free(buffer);
return JNI_ENOMEM;
}
for (int i = 0; i < options->length(); i++) {
options_arr[i] = options->at(i);
}
// Construct JavaVMInitArgs structure and parse as if it was part of the command line
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options_arr;
vm_args.nOptions = options->length();
vm_args.ignoreUnrecognized = IgnoreUnrecognizedVMOptions;
// Fill out JavaVMInitArgs structure.
jint status = vm_args->set_args(options);
if (PrintVMOptions) {
const char* tail;
for (int i = 0; i < vm_args.nOptions; i++) {
const JavaVMOption *option = vm_args.options + i;
if (match_option(option, "-XX:", &tail)) {
logOption(tail);
}
}
}
jint result = parse_each_vm_init_arg(&vm_args, scp_p, scp_assembly_required_p,
Flag::ENVIRON_VAR);
FREE_C_HEAP_ARRAY(JavaVMOption, options_arr);
delete options;
os::free(buffer);
return result;
return status;
}
void Arguments::set_shared_spaces_flags() {
@ -3567,32 +3599,18 @@ static bool use_vm_log() {
}
#endif // PRODUCT
// Parse entry point called from JNI_CreateJavaVM
jint Arguments::parse(const JavaVMInitArgs* args) {
// Initialize ranges and constraints
CommandLineFlagRangeList::init();
CommandLineFlagConstraintList::init();
static jint match_special_option_and_act(const JavaVMInitArgs* args,
char** flags_file) {
// 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;
for (int 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;
settings_file_specified = true;
*flags_file = (char *) tail;
continue;
}
if (match_option(option, "-XX:+PrintVMOptions")) {
@ -3646,10 +3664,69 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
}
#endif
}
return JNI_OK;
}
static void print_options(const JavaVMInitArgs *args) {
const char* tail;
for (int index = 0; index < args->nOptions; index++) {
const JavaVMOption *option = args->options + index;
if (match_option(option, "-XX:", &tail)) {
logOption(tail);
}
}
}
// Parse entry point called from JNI_CreateJavaVM
jint Arguments::parse(const JavaVMInitArgs* args) {
// Initialize ranges and constraints
CommandLineFlagRangeList::init();
CommandLineFlagConstraintList::init();
// If flag "-XX:Flags=flags-file" is used it will be the first option to be processed.
const char* hotspotrc = ".hotspotrc";
char* flags_file = NULL;
bool settings_file_specified = false;
bool needs_hotspotrc_warning = false;
ScopedVMInitArgs java_tool_options_args;
ScopedVMInitArgs java_options_args;
jint code =
parse_java_tool_options_environment_variable(&java_tool_options_args);
if (code != JNI_OK) {
return code;
}
code = parse_java_options_environment_variable(&java_options_args);
if (code != JNI_OK) {
return code;
}
code =
match_special_option_and_act(java_tool_options_args.get(), &flags_file);
if (code != JNI_OK) {
return code;
}
code = match_special_option_and_act(args, &flags_file);
if (code != JNI_OK) {
return code;
}
code = match_special_option_and_act(java_options_args.get(), &flags_file);
if (code != JNI_OK) {
return code;
}
settings_file_specified = (flags_file != NULL);
if (IgnoreUnrecognizedVMOptions) {
// uncast const to modify the flag args->ignoreUnrecognized
*(jboolean*)(&args->ignoreUnrecognized) = true;
java_tool_options_args.get()->ignoreUnrecognized = true;
java_options_args.get()->ignoreUnrecognized = true;
}
// Parse specified settings file
@ -3672,16 +3749,15 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
}
if (PrintVMOptions) {
for (index = 0; index < args->nOptions; index++) {
const JavaVMOption *option = args->options + index;
if (match_option(option, "-XX:", &tail)) {
logOption(tail);
}
}
print_options(java_tool_options_args.get());
print_options(args);
print_options(java_options_args.get());
}
// Parse JavaVMInitArgs structure passed in, as well as JAVA_TOOL_OPTIONS and _JAVA_OPTIONS
jint result = parse_vm_init_args(args);
jint result = parse_vm_init_args(java_tool_options_args.get(),
java_options_args.get(), args);
if (result != JNI_OK) {
return result;
}

View File

@ -220,6 +220,8 @@ class AgentLibraryList VALUE_OBJ_CLASS_SPEC {
}
};
// Helper class for controlling the lifetime of JavaVMInitArgs objects.
class ScopedVMInitArgs;
class Arguments : AllStatic {
friend class VMStructs;
@ -374,10 +376,12 @@ class Arguments : AllStatic {
static bool process_argument(const char* arg, jboolean ignore_unrecognized, Flag::Flags origin);
static void process_java_launcher_argument(const char*, void*);
static void process_java_compiler_argument(char* arg);
static jint parse_options_environment_variable(const char* name, SysClassPath* scp_p, bool* scp_assembly_required_p);
static jint parse_java_tool_options_environment_variable(SysClassPath* scp_p, bool* scp_assembly_required_p);
static jint parse_java_options_environment_variable(SysClassPath* scp_p, bool* scp_assembly_required_p);
static jint parse_vm_init_args(const JavaVMInitArgs* args);
static jint parse_options_environment_variable(const char* name, ScopedVMInitArgs* vm_args);
static jint parse_java_tool_options_environment_variable(ScopedVMInitArgs* vm_args);
static jint parse_java_options_environment_variable(ScopedVMInitArgs* vm_args);
static jint parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args,
const JavaVMInitArgs *java_options_args,
const JavaVMInitArgs *cmd_line_args);
static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, SysClassPath* scp_p, bool* scp_assembly_required_p, Flag::Flags origin);
static jint finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_required);
static bool is_bad_option(const JavaVMOption* option, jboolean ignore, const char* option_type);