8079301: Some command line options not settable via JAVA_TOOL_OPTIONS
authorjmanson
Fri, 17 Jul 2015 19:40:21 -0400
changeset 31853 c70929a2573c
parent 31850 cee76595e1bb
child 31854 49b89f076293
8079301: Some command line options not settable via JAVA_TOOL_OPTIONS Summary: Ensures special-cased command line options are settable via _JAVA_OPTIONS and JAVA_TOOL_OPTIONS. Reviewed-by: coleenp, ddmitriev
hotspot/src/share/vm/runtime/arguments.cpp
hotspot/src/share/vm/runtime/arguments.hpp
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Thu Jul 16 15:01:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Fri Jul 17 19:40:21 2015 -0400
@@ -91,7 +91,7 @@
 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 @@
 
 // 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 @@
   // 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 @@
   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 @@
         *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;
-
-  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);
+
+  // Fill out JavaVMInitArgs structure.
+  jint status = vm_args->set_args(options);
+
   delete options;
   os::free(buffer);
-  return result;
+  return status;
 }
 
 void Arguments::set_shared_spaces_flags() {
@@ -3567,32 +3599,18 @@
 }
 #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 @@
     }
 #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 @@
   }
 
   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;
   }
--- a/hotspot/src/share/vm/runtime/arguments.hpp	Thu Jul 16 15:01:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/arguments.hpp	Fri Jul 17 19:40:21 2015 -0400
@@ -220,6 +220,8 @@
   }
 };
 
+// Helper class for controlling the lifetime of JavaVMInitArgs objects.
+class ScopedVMInitArgs;
 
 class Arguments : AllStatic {
   friend class VMStructs;
@@ -374,10 +376,12 @@
   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);