8074895: os::getenv is inadequate
authorjmanson
Mon, 30 Mar 2015 17:32:18 -0400
changeset 30125 8ba6e8e367e9
parent 30124 767dff18852c
child 30128 b5e4e8a58b0b
8074895: os::getenv is inadequate Reviewed-by: dholmes, coleenp
hotspot/src/os/aix/vm/os_aix.cpp
hotspot/src/os/bsd/vm/os_bsd.cpp
hotspot/src/os/linux/vm/os_linux.cpp
hotspot/src/os/solaris/vm/os_solaris.cpp
hotspot/src/os/windows/vm/os_windows.cpp
hotspot/src/share/vm/runtime/arguments.cpp
hotspot/src/share/vm/runtime/os.cpp
hotspot/src/share/vm/runtime/os.hpp
hotspot/src/share/vm/services/memTracker.cpp
hotspot/src/share/vm/utilities/growableArray.hpp
hotspot/src/share/vm/utilities/vmError.cpp
--- a/hotspot/src/os/aix/vm/os_aix.cpp	Mon Mar 30 16:47:42 2015 +0000
+++ b/hotspot/src/os/aix/vm/os_aix.cpp	Mon Mar 30 17:32:18 2015 -0400
@@ -257,19 +257,6 @@
   return Aix::physical_memory();
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// environment support
-
-bool os::getenv(const char* name, char* buf, int len) {
-  const char* val = ::getenv(name);
-  if (val != NULL && strlen(val) < (size_t)len) {
-    strcpy(buf, val);
-    return true;
-  }
-  if (len > 0) buf[0] = 0;  // return a null string
-  return false;
-}
-
 // Return true if user is running as root.
 
 bool os::have_special_privileges() {
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp	Mon Mar 30 16:47:42 2015 +0000
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp	Mon Mar 30 17:32:18 2015 -0400
@@ -190,20 +190,6 @@
   return Bsd::physical_memory();
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// environment support
-
-bool os::getenv(const char* name, char* buf, int len) {
-  const char* val = ::getenv(name);
-  if (val != NULL && strlen(val) < (size_t)len) {
-    strcpy(buf, val);
-    return true;
-  }
-  if (len > 0) buf[0] = 0;  // return a null string
-  return false;
-}
-
-
 // Return true if user is running as root.
 
 bool os::have_special_privileges() {
--- a/hotspot/src/os/linux/vm/os_linux.cpp	Mon Mar 30 16:47:42 2015 +0000
+++ b/hotspot/src/os/linux/vm/os_linux.cpp	Mon Mar 30 17:32:18 2015 -0400
@@ -184,20 +184,6 @@
   return Linux::physical_memory();
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// environment support
-
-bool os::getenv(const char* name, char* buf, int len) {
-  const char* val = ::getenv(name);
-  if (val != NULL && strlen(val) < (size_t)len) {
-    strcpy(buf, val);
-    return true;
-  }
-  if (len > 0) buf[0] = 0;  // return a null string
-  return false;
-}
-
-
 // Return true if user is running as root.
 
 bool os::have_special_privileges() {
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp	Mon Mar 30 16:47:42 2015 +0000
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp	Mon Mar 30 17:32:18 2015 -0400
@@ -555,17 +555,6 @@
   return (bind_result == 0);
 }
 
-bool os::getenv(const char* name, char* buffer, int len) {
-  char* val = ::getenv(name);
-  if (val == NULL || strlen(val) + 1 > len) {
-    if (len > 0) buffer[0] = 0; // return a null string
-    return false;
-  }
-  strcpy(buffer, val);
-  return true;
-}
-
-
 // Return true if user is running as root.
 
 bool os::have_special_privileges() {
--- a/hotspot/src/os/windows/vm/os_windows.cpp	Mon Mar 30 16:47:42 2015 +0000
+++ b/hotspot/src/os/windows/vm/os_windows.cpp	Mon Mar 30 17:32:18 2015 -0400
@@ -153,11 +153,6 @@
 
 // Implementation of os
 
-bool os::getenv(const char* name, char* buffer, int len) {
-  int result = GetEnvironmentVariable(name, buffer, len);
-  return result > 0 && result < len;
-}
-
 bool os::unsetenv(const char* name) {
   assert(name != NULL, "Null pointer");
   return (SetEnvironmentVariable(name, NULL) == TRUE);
@@ -188,9 +183,13 @@
     char *dll_path;
     char *pslash;
     char *bin = "\\bin";
-    char home_dir[MAX_PATH];
-
-    if (!getenv("_ALT_JAVA_HOME_DIR", home_dir, MAX_PATH)) {
+    char home_dir[MAX_PATH + 1];
+    char *alt_home_dir = ::getenv("_ALT_JAVA_HOME_DIR");
+
+    if (alt_home_dir != NULL)  {
+      strncpy(home_dir, alt_home_dir, MAX_PATH + 1);
+      home_dir[MAX_PATH] = '\0';
+    } else {
       os::jvm_path(home_dir, sizeof(home_dir));
       // Found the full path to jvm.dll.
       // Now cut the path to <java_home>/jre if we can.
@@ -5930,4 +5929,3 @@
   UseNUMAInterleaving = old_use_numa_interleaving;
 }
 #endif // PRODUCT
-
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Mon Mar 30 16:47:42 2015 +0000
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Mon Mar 30 17:32:18 2015 -0400
@@ -3455,15 +3455,16 @@
   if (os::is_headless_jre()) {
     const char* headless = Arguments::get_property("java.awt.headless");
     if (headless == NULL) {
-      char envbuffer[128];
-      if (!os::getenv("JAVA_AWT_HEADLESS", envbuffer, sizeof(envbuffer))) {
+      const char *headless_env = ::getenv("JAVA_AWT_HEADLESS");
+      if (headless_env == NULL) {
         if (!add_property("java.awt.headless=true")) {
           return JNI_ENOMEM;
         }
       } else {
         char buffer[256];
-        strcpy(buffer, "java.awt.headless=");
-        strcat(buffer, envbuffer);
+        const char *key = "java.awt.headless=";
+        strcpy(buffer, key);
+        strncat(buffer, headless_env, 256 - strlen(key) - 1);
         if (!add_property(buffer)) {
           return JNI_ENOMEM;
         }
@@ -3494,75 +3495,91 @@
 }
 
 jint Arguments::parse_options_environment_variable(const char* name, SysClassPath* scp_p, bool* scp_assembly_required_p) {
-  const int N_MAX_OPTIONS = 64;
-  const int OPTION_BUFFER_SIZE = 1024;
-  char buffer[OPTION_BUFFER_SIZE];
-
-  // The variable will be ignored if it exceeds the length of the buffer.
+  char *buffer = ::getenv(name);
+
   // Don't check this variable if user has special privileges
   // (e.g. unix su command).
-  if (os::getenv(name, buffer, sizeof(buffer)) &&
-      !os::have_special_privileges()) {
-    JavaVMOption options[N_MAX_OPTIONS];      // Construct option array
-    jio_fprintf(defaultStream::error_stream(),
-                "Picked up %s: %s\n", name, buffer);
-    char* rd = buffer;                        // pointer to the input string (rd)
-    int i;
-    for (i = 0; i < N_MAX_OPTIONS;) {         // repeat for all options in the input string
-      while (isspace(*rd)) rd++;              // skip whitespace
-      if (*rd == 0) break;                    // we re done when the input string is read completely
-
-      // The output, option string, overwrites the input string.
-      // Because of quoting, the pointer to the option string (wrt) may lag the pointer to
-      // input string (rd).
-      char* wrt = rd;
-
-      options[i++].optionString = wrt;        // Fill in option
-      while (*rd != 0 && !isspace(*rd)) {     // unquoted strings terminate with a space or NULL
-        if (*rd == '\'' || *rd == '"') {      // handle a quoted string
-          int quote = *rd;                    // matching quote to look for
-          rd++;                               // don't copy open quote
-          while (*rd != quote) {              // include everything (even spaces) up until quote
-            if (*rd == 0) {                   // string termination means unmatched string
-              jio_fprintf(defaultStream::error_stream(),
-                          "Unmatched quote in %s\n", name);
-              return JNI_ERR;
-            }
-            *wrt++ = *rd++;                   // copy to option string
+  if (buffer == NULL || os::have_special_privileges()) {
+    return JNI_OK;
+  }
+
+  if ((buffer = os::strdup(buffer)) == NULL) {
+    return JNI_ENOMEM;
+  }
+
+  GrowableArray<JavaVMOption> options(2, true);    // Construct option array
+  jio_fprintf(defaultStream::error_stream(),
+              "Picked up %s: %s\n", name, buffer);
+  char* rd = buffer;                        // pointer to the input string (rd)
+  while (true) {                            // repeat for all options in the input string
+    while (isspace(*rd)) rd++;              // skip whitespace
+    if (*rd == 0) break;                    // we re done when the input string is read completely
+
+    // The output, option string, overwrites the input string.
+    // Because of quoting, the pointer to the option string (wrt) may lag the pointer to
+    // input string (rd).
+    char* wrt = rd;
+
+    JavaVMOption option;
+    option.optionString = wrt;
+    options.append(option);                 // Fill in option
+    while (*rd != 0 && !isspace(*rd)) {     // unquoted strings terminate with a space or NULL
+      if (*rd == '\'' || *rd == '"') {      // handle a quoted string
+        int quote = *rd;                    // matching quote to look for
+        rd++;                               // don't copy open quote
+        while (*rd != quote) {              // include everything (even spaces) up until quote
+          if (*rd == 0) {                   // string termination means unmatched string
+            jio_fprintf(defaultStream::error_stream(),
+                        "Unmatched quote in %s\n", name);
+            os::free(buffer);
+            return JNI_ERR;
           }
-          rd++;                               // don't copy close quote
-        } else {
-          *wrt++ = *rd++;                     // copy to option string
+          *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;
-      }
-      *wrt = 0;                               // Zero terminate option
-    }
-    // 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;
-    vm_args.nOptions = i;
-    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);
-        }
+        rd++;                               // don't copy close quote
+      } else {
+        *wrt++ = *rd++;                     // copy to option string
       }
     }
-
-    return(parse_each_vm_init_arg(&vm_args, scp_p, scp_assembly_required_p, Flag::ENVIRON_VAR));
+    // 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;
+    }
+    *wrt = 0;                               // Zero terminate option
+  }
+  JavaVMOption* options_arr =
+      NEW_C_HEAP_ARRAY_RETURN_NULL(JavaVMOption, options.length(), mtInternal);
+  if (options_arr == NULL) {
+    return JNI_ENOMEM;
+  }
+  for (int i = 0; i < options.length(); i++) {
+    options_arr[i] = options.at(i);
   }
-  return JNI_OK;
+
+  // 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);
+  os::free(buffer);
+  return result;
 }
 
 void Arguments::set_shared_spaces_flags() {
--- a/hotspot/src/share/vm/runtime/os.cpp	Mon Mar 30 16:47:42 2015 +0000
+++ b/hotspot/src/share/vm/runtime/os.cpp	Mon Mar 30 17:32:18 2015 -0400
@@ -813,16 +813,16 @@
   st->cr();
 }
 
-void os::print_environment_variables(outputStream* st, const char** env_list,
-                                     char* buffer, int len) {
+void os::print_environment_variables(outputStream* st, const char** env_list) {
   if (env_list) {
     st->print_cr("Environment Variables:");
 
     for (int i = 0; env_list[i] != NULL; i++) {
-      if (getenv(env_list[i], buffer, len)) {
+      char *envvar = ::getenv(env_list[i]);
+      if (envvar != NULL) {
         st->print("%s", env_list[i]);
         st->print("=");
-        st->print_cr("%s", buffer);
+        st->print_cr("%s", envvar);
       }
     }
   }
--- a/hotspot/src/share/vm/runtime/os.hpp	Mon Mar 30 16:47:42 2015 +0000
+++ b/hotspot/src/share/vm/runtime/os.hpp	Mon Mar 30 17:32:18 2015 -0400
@@ -164,8 +164,7 @@
   // Override me as needed
   static int    file_name_strcmp(const char* s1, const char* s2);
 
-  // get/unset environment variable
-  static bool getenv(const char* name, char* buffer, int len);
+  // unset environment variable
   static bool unsetenv(const char* name);
 
   static bool have_special_privileges();
@@ -591,7 +590,7 @@
   static void pd_print_cpu_info(outputStream* st);
   static void print_memory_info(outputStream* st);
   static void print_dll_info(outputStream* st);
-  static void print_environment_variables(outputStream* st, const char** env_list, char* buffer, int len);
+  static void print_environment_variables(outputStream* st, const char** env_list);
   static void print_context(outputStream* st, void* context);
   static void print_register_info(outputStream* st, void* context);
   static void print_siginfo(outputStream* st, void* siginfo);
--- a/hotspot/src/share/vm/services/memTracker.cpp	Mon Mar 30 16:47:42 2015 +0000
+++ b/hotspot/src/share/vm/services/memTracker.cpp	Mon Mar 30 17:32:18 2015 -0400
@@ -47,9 +47,9 @@
 NMT_TrackingLevel MemTracker::init_tracking_level() {
   NMT_TrackingLevel level = NMT_off;
   char buf[64];
-  char nmt_option[64];
   jio_snprintf(buf, sizeof(buf), "NMT_LEVEL_%d", os::current_process_id());
-  if (os::getenv(buf, nmt_option, sizeof(nmt_option))) {
+  const char *nmt_option = ::getenv(buf);
+  if (nmt_option != NULL) {
     if (strcmp(nmt_option, "summary") == 0) {
       level = NMT_summary;
     } else if (strcmp(nmt_option, "detail") == 0) {
@@ -311,4 +311,3 @@
   out->print_cr(" ");
   walker.report_statistics(out);
 }
-
--- a/hotspot/src/share/vm/utilities/growableArray.hpp	Mon Mar 30 16:47:42 2015 +0000
+++ b/hotspot/src/share/vm/utilities/growableArray.hpp	Mon Mar 30 17:32:18 2015 -0400
@@ -168,6 +168,8 @@
   GrowableArray(int initial_size, bool C_heap = false, MEMFLAGS F = mtInternal)
     : GenericGrowableArray(initial_size, 0, C_heap, F) {
     _data = (E*)raw_allocate(sizeof(E));
+// Needed for Visual Studio 2012 and older
+#pragma warning(suppress: 4345)
     for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();
   }
 
@@ -385,6 +387,8 @@
     E* newData = (E*)raw_allocate(sizeof(E));
     int i = 0;
     for (     ; i < _len; i++) ::new ((void*)&newData[i]) E(_data[i]);
+// Needed for Visual Studio 2012 and older
+#pragma warning(suppress: 4345)
     for (     ; i < _max; i++) ::new ((void*)&newData[i]) E();
     for (i = 0; i < old_max; i++) _data[i].~E();
     if (on_C_heap() && _data != NULL) {
--- a/hotspot/src/share/vm/utilities/vmError.cpp	Mon Mar 30 16:47:42 2015 +0000
+++ b/hotspot/src/share/vm/utilities/vmError.cpp	Mon Mar 30 17:32:18 2015 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -768,7 +768,7 @@
   STEP(220, "(printing environment variables)" )
 
      if (_verbose) {
-       os::print_environment_variables(st, env_list, buf, sizeof(buf));
+       os::print_environment_variables(st, env_list);
        st->cr();
      }