6819213: revive sun.boot.library.path
Summary: Support multiplex and mutable sun.boot.library.path
Reviewed-by: acorn, dcubed, xlu
--- a/hotspot/src/os/linux/vm/os_linux.cpp Sun Mar 29 18:19:05 2009 -0400
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Apr 01 16:38:01 2009 -0400
@@ -1518,21 +1518,51 @@
const char* os::get_temp_directory() { return "/tmp/"; }
-void os::dll_build_name(
- char* buffer, size_t buflen, const char* pname, const char* fname) {
- // copied from libhpi
+static bool file_exists(const char* filename) {
+ struct stat statbuf;
+ if (filename == NULL || strlen(filename) == 0) {
+ return false;
+ }
+ return os::stat(filename, &statbuf) == 0;
+}
+
+void os::dll_build_name(char* buffer, size_t buflen,
+ const char* pname, const char* fname) {
+ // Copied from libhpi
const size_t pnamelen = pname ? strlen(pname) : 0;
- /* Quietly truncate on buffer overflow. Should be an error. */
+ // Quietly truncate on buffer overflow. Should be an error.
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
*buffer = '\0';
return;
}
if (pnamelen == 0) {
- sprintf(buffer, "lib%s.so", fname);
+ snprintf(buffer, buflen, "lib%s.so", fname);
+ } else if (strchr(pname, *os::path_separator()) != NULL) {
+ int n;
+ char** pelements = split_path(pname, &n);
+ for (int i = 0 ; i < n ; i++) {
+ // Really shouldn't be NULL, but check can't hurt
+ if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
+ continue; // skip the empty path values
+ }
+ snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
+ if (file_exists(buffer)) {
+ break;
+ }
+ }
+ // release the storage
+ for (int i = 0 ; i < n ; i++) {
+ if (pelements[i] != NULL) {
+ FREE_C_HEAP_ARRAY(char, pelements[i]);
+ }
+ }
+ if (pelements != NULL) {
+ FREE_C_HEAP_ARRAY(char*, pelements);
+ }
} else {
- sprintf(buffer, "%s/lib%s.so", pname, fname);
+ snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
}
}
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Sun Mar 29 18:19:05 2009 -0400
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Apr 01 16:38:01 2009 -0400
@@ -1827,21 +1827,51 @@
const char* os::get_temp_directory() { return "/tmp/"; }
-void os::dll_build_name(
- char* buffer, size_t buflen, const char* pname, const char* fname) {
- // copied from libhpi
+static bool file_exists(const char* filename) {
+ struct stat statbuf;
+ if (filename == NULL || strlen(filename) == 0) {
+ return false;
+ }
+ return os::stat(filename, &statbuf) == 0;
+}
+
+void os::dll_build_name(char* buffer, size_t buflen,
+ const char* pname, const char* fname) {
+ // Copied from libhpi
const size_t pnamelen = pname ? strlen(pname) : 0;
- /* Quietly truncate on buffer overflow. Should be an error. */
+ // Quietly truncate on buffer overflow. Should be an error.
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
*buffer = '\0';
return;
}
if (pnamelen == 0) {
- sprintf(buffer, "lib%s.so", fname);
+ snprintf(buffer, buflen, "lib%s.so", fname);
+ } else if (strchr(pname, *os::path_separator()) != NULL) {
+ int n;
+ char** pelements = split_path(pname, &n);
+ for (int i = 0 ; i < n ; i++) {
+ // really shouldn't be NULL but what the heck, check can't hurt
+ if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
+ continue; // skip the empty path values
+ }
+ snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
+ if (file_exists(buffer)) {
+ break;
+ }
+ }
+ // release the storage
+ for (int i = 0 ; i < n ; i++) {
+ if (pelements[i] != NULL) {
+ FREE_C_HEAP_ARRAY(char, pelements[i]);
+ }
+ }
+ if (pelements != NULL) {
+ FREE_C_HEAP_ARRAY(char*, pelements);
+ }
} else {
- sprintf(buffer, "%s/lib%s.so", pname, fname);
+ snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
}
}
--- a/hotspot/src/os/windows/vm/os_windows.cpp Sun Mar 29 18:19:05 2009 -0400
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Apr 01 16:38:01 2009 -0400
@@ -1004,26 +1004,61 @@
}
}
-void os::dll_build_name(char *holder, size_t holderlen,
- const char* pname, const char* fname)
-{
- // copied from libhpi
- const size_t pnamelen = pname ? strlen(pname) : 0;
- const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
-
- /* Quietly truncates on buffer overflow. Should be an error. */
- if (pnamelen + strlen(fname) + 10 > holderlen) {
- *holder = '\0';
- return;
+static bool file_exists(const char* filename) {
+ if (filename == NULL || strlen(filename) == 0) {
+ return false;
+ }
+ return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES;
+}
+
+void os::dll_build_name(char *buffer, size_t buflen,
+ const char* pname, const char* fname) {
+ // Copied from libhpi
+ const size_t pnamelen = pname ? strlen(pname) : 0;
+ const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
+
+ // Quietly truncates on buffer overflow. Should be an error.
+ if (pnamelen + strlen(fname) + 10 > buflen) {
+ *buffer = '\0';
+ return;
+ }
+
+ if (pnamelen == 0) {
+ jio_snprintf(buffer, buflen, "%s.dll", fname);
+ } else if (c == ':' || c == '\\') {
+ jio_snprintf(buffer, buflen, "%s%s.dll", pname, fname);
+ } else if (strchr(pname, *os::path_separator()) != NULL) {
+ int n;
+ char** pelements = split_path(pname, &n);
+ for (int i = 0 ; i < n ; i++) {
+ char* path = pelements[i];
+ // Really shouldn't be NULL, but check can't hurt
+ size_t plen = (path == NULL) ? 0 : strlen(path);
+ if (plen == 0) {
+ continue; // skip the empty path values
+ }
+ const char lastchar = path[plen - 1];
+ if (lastchar == ':' || lastchar == '\\') {
+ jio_snprintf(buffer, buflen, "%s%s.dll", path, fname);
+ } else {
+ jio_snprintf(buffer, buflen, "%s\\%s.dll", path, fname);
+ }
+ if (file_exists(buffer)) {
+ break;
+ }
}
-
- if (pnamelen == 0) {
- sprintf(holder, "%s.dll", fname);
- } else if (c == ':' || c == '\\') {
- sprintf(holder, "%s%s.dll", pname, fname);
- } else {
- sprintf(holder, "%s\\%s.dll", pname, fname);
+ // release the storage
+ for (int i = 0 ; i < n ; i++) {
+ if (pelements[i] != NULL) {
+ FREE_C_HEAP_ARRAY(char, pelements[i]);
+ }
}
+ if (pelements != NULL) {
+ FREE_C_HEAP_ARRAY(char*, pelements);
+ }
+ } else {
+ jio_snprintf(buffer, buflen, "%s\\%s.dll", pname, fname);
+ }
}
// Needs to be in os specific directory because windows requires another
--- a/hotspot/src/share/vm/runtime/arguments.cpp Sun Mar 29 18:19:05 2009 -0400
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Apr 01 16:38:01 2009 -0400
@@ -852,16 +852,13 @@
FreeHeap(value);
}
return true;
- }
- else if (strcmp(key, "sun.java.command") == 0) {
-
+ } else if (strcmp(key, "sun.java.command") == 0) {
_java_command = value;
// don't add this property to the properties exposed to the java application
FreeHeap(key);
return true;
- }
- else if (strcmp(key, "sun.java.launcher.pid") == 0) {
+ } else if (strcmp(key, "sun.java.launcher.pid") == 0) {
// launcher.pid property is private and is processed
// in process_sun_java_launcher_properties();
// the sun.java.launcher property is passed on to the java application
@@ -870,13 +867,14 @@
FreeHeap(value);
}
return true;
- }
- else if (strcmp(key, "java.vendor.url.bug") == 0) {
+ } else if (strcmp(key, "java.vendor.url.bug") == 0) {
// save it in _java_vendor_url_bug, so JVM fatal error handler can access
// its value without going through the property list or making a Java call.
_java_vendor_url_bug = value;
+ } else if (strcmp(key, "sun.boot.library.path") == 0) {
+ PropertyList_unique_add(&_system_properties, key, value, true);
+ return true;
}
-
// Create new property and add at the end of the list
PropertyList_unique_add(&_system_properties, key, value);
return true;
@@ -895,7 +893,7 @@
// Ensure Agent_OnLoad has the correct initial values.
// This may not be the final mode; mode may change later in onload phase.
PropertyList_unique_add(&_system_properties, "java.vm.info",
- (char*)Abstract_VM_Version::vm_info_string());
+ (char*)Abstract_VM_Version::vm_info_string(), false);
UseInterpreter = true;
UseCompiler = true;
@@ -2767,7 +2765,7 @@
}
// This add maintains unique property key in the list.
-void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v) {
+void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append) {
if (plist == NULL)
return;
@@ -2775,7 +2773,11 @@
SystemProperty* prop;
for (prop = *plist; prop != NULL; prop = prop->next()) {
if (strcmp(k, prop->key()) == 0) {
- prop->set_value(v);
+ if (append) {
+ prop->append_value(v);
+ } else {
+ prop->set_value(v);
+ }
return;
}
}
--- a/hotspot/src/share/vm/runtime/arguments.hpp Sun Mar 29 18:19:05 2009 -0400
+++ b/hotspot/src/share/vm/runtime/arguments.hpp Wed Apr 01 16:38:01 2009 -0400
@@ -475,10 +475,13 @@
// System properties
static void init_system_properties();
- // Proptery List manipulation
+ // Property List manipulation
static void PropertyList_add(SystemProperty** plist, SystemProperty *element);
static void PropertyList_add(SystemProperty** plist, const char* k, char* v);
- static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v);
+ static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v) {
+ PropertyList_unique_add(plist, k, v, false);
+ }
+ static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append);
static const char* PropertyList_get_value(SystemProperty* plist, const char* key);
static int PropertyList_count(SystemProperty* pl);
static const char* PropertyList_get_key_at(SystemProperty* pl,int index);
--- a/hotspot/src/share/vm/runtime/hpi.hpp Sun Mar 29 18:19:05 2009 -0400
+++ b/hotspot/src/share/vm/runtime/hpi.hpp Wed Apr 01 16:38:01 2009 -0400
@@ -90,7 +90,7 @@
static inline struct protoent* get_proto_by_name(char* name);
// HPI_LibraryInterface
- static inline void dll_build_name(char *buf, int buf_len, char* path,
+ static inline void dll_build_name(char *buf, int buf_len, const char* path,
const char *name);
static inline void* dll_load(const char *name, char *ebuf, int ebuflen);
static inline void dll_unload(void *lib);
@@ -137,7 +137,15 @@
return result; \
}
-
+#define VM_HPIDECL_VOID(name, names, func, arg_type, arg_print, arg) \
+ inline void hpi::name arg_type { \
+ if (TraceHPI) { \
+ tty->print("hpi::" names "("); \
+ tty->print arg_print; \
+ tty->print(") = "); \
+ } \
+ func arg; \
+ }
#define HPIDECL_VOID(name, names, intf, func, arg_type, arg_print, arg) \
inline void hpi::name arg_type { \
@@ -197,11 +205,11 @@
(fd, size));
// HPI_LibraryInterface
-HPIDECL_VOID(dll_build_name, "dll_build_name", _library, BuildLibName,
- (char *buf, int buf_len, char *path, const char *name),
- ("buf = %p, buflen = %d, path = %s, name = %s",
- buf, buf_len, path, name),
- (buf, buf_len, path, name));
+VM_HPIDECL_VOID(dll_build_name, "dll_build_name", os::dll_build_name,
+ (char *buf, int buf_len, const char *path, const char *name),
+ ("buf = %p, buflen = %d, path = %s, name = %s",
+ buf, buf_len, path, name),
+ (buf, buf_len, path, name));
VM_HPIDECL(dll_load, "dll_load", os::dll_load,
void *, "(void *)%p",
--- a/hotspot/src/share/vm/runtime/os.cpp Sun Mar 29 18:19:05 2009 -0400
+++ b/hotspot/src/share/vm/runtime/os.cpp Wed Apr 01 16:38:01 2009 -0400
@@ -863,7 +863,6 @@
bool os::set_boot_path(char fileSep, char pathSep) {
-
const char* home = Arguments::get_java_home();
int home_len = (int)strlen(home);
@@ -893,6 +892,60 @@
return true;
}
+/*
+ * Splits a path, based on its separator, the number of
+ * elements is returned back in n.
+ * It is the callers responsibility to:
+ * a> check the value of n, and n may be 0.
+ * b> ignore any empty path elements
+ * c> free up the data.
+ */
+char** os::split_path(const char* path, int* n) {
+ *n = 0;
+ if (path == NULL || strlen(path) == 0) {
+ return NULL;
+ }
+ const char psepchar = *os::path_separator();
+ char* inpath = (char*)NEW_C_HEAP_ARRAY(char, strlen(path) + 1);
+ if (inpath == NULL) {
+ return NULL;
+ }
+ strncpy(inpath, path, strlen(path));
+ int count = 1;
+ char* p = strchr(inpath, psepchar);
+ // Get a count of elements to allocate memory
+ while (p != NULL) {
+ count++;
+ p++;
+ p = strchr(p, psepchar);
+ }
+ char** opath = (char**) NEW_C_HEAP_ARRAY(char*, count);
+ if (opath == NULL) {
+ return NULL;
+ }
+
+ // do the actual splitting
+ p = inpath;
+ for (int i = 0 ; i < count ; i++) {
+ size_t len = strcspn(p, os::path_separator());
+ if (len > JVM_MAXPATHLEN) {
+ return NULL;
+ }
+ // allocate the string and add terminator storage
+ char* s = (char*)NEW_C_HEAP_ARRAY(char, len + 1);
+ if (s == NULL) {
+ return NULL;
+ }
+ strncpy(s, p, len);
+ s[len] = '\0';
+ opath[i] = s;
+ p += len + 1;
+ }
+ FREE_C_HEAP_ARRAY(char, inpath);
+ *n = count;
+ return opath;
+}
+
void os::set_memory_serialize_page(address page) {
int count = log2_intptr(sizeof(class JavaThread)) - log2_intptr(64);
_mem_serialize_page = (volatile int32_t *)page;
--- a/hotspot/src/share/vm/runtime/os.hpp Sun Mar 29 18:19:05 2009 -0400
+++ b/hotspot/src/share/vm/runtime/os.hpp Wed Apr 01 16:38:01 2009 -0400
@@ -607,6 +607,7 @@
char fileSep,
char pathSep);
static bool set_boot_path(char fileSep, char pathSep);
+ static char** split_path(const char* path, int* n);
};
// Note that "PAUSE" is almost always used with synchronization
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/6819213/TestBootNativeLibraryPath.java Wed Apr 01 16:38:01 2009 -0400
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test TestBootNativeLibraryPath.java
+ * @bug 6819213
+ * @compile -XDignore.symbol.file TestBootNativeLibraryPath.java
+ * @summary verify sun.boot.native.library.path is expandable on 32 bit systems
+ * @run main TestBootNativeLibraryPath
+ * @author ksrini
+*/
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.tools.JavaCompiler;
+import javax.tools.ToolProvider;
+
+public class TestBootNativeLibraryPath {
+
+ private static final String TESTFILE = "Test6";
+
+ static void createTestClass() throws IOException {
+ FileOutputStream fos = new FileOutputStream(TESTFILE + ".java");
+ PrintStream ps = new PrintStream(fos);
+ ps.println("public class " + TESTFILE + "{");
+ ps.println("public static void main(String[] args) {\n");
+ ps.println("System.out.println(System.getProperty(\"sun.boot.library.path\"));\n");
+ ps.println("}}\n");
+ ps.close();
+ fos.close();
+
+ JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
+ String javacOpts[] = {TESTFILE + ".java"};
+ if (javac.run(null, null, null, javacOpts) != 0) {
+ throw new RuntimeException("compilation of " + TESTFILE + ".java Failed");
+ }
+ }
+
+ static List<String> doExec(String... args) {
+ String javaCmd = System.getProperty("java.home") + "/bin/java";
+ if (!new File(javaCmd).exists()) {
+ javaCmd = System.getProperty("java.home") + "/bin/java.exe";
+ }
+
+ ArrayList<String> cmds = new ArrayList<String>();
+ cmds.add(javaCmd);
+ for (String x : args) {
+ cmds.add(x);
+ }
+ System.out.println("cmds=" + cmds);
+ ProcessBuilder pb = new ProcessBuilder(cmds);
+
+ Map<String, String> env = pb.environment();
+ pb.directory(new File("."));
+
+ List<String> out = new ArrayList<String>();
+ try {
+ pb.redirectErrorStream(true);
+ Process p = pb.start();
+ BufferedReader rd = new BufferedReader(new InputStreamReader(p.getInputStream()),8192);
+ String in = rd.readLine();
+ while (in != null) {
+ out.add(in);
+ System.out.println(in);
+ in = rd.readLine();
+ }
+ int retval = p.waitFor();
+ p.destroy();
+ if (retval != 0) {
+ throw new RuntimeException("Error: test returned non-zero value");
+ }
+ return out;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ throw new RuntimeException(ex.getMessage());
+ }
+ }
+
+ public static void main(String[] args) {
+ try {
+ if (!System.getProperty("sun.arch.data.model").equals("32")) {
+ System.out.println("Warning: test skipped for 64-bit systems\n");
+ return;
+ }
+ String osname = System.getProperty("os.name");
+ if (osname.startsWith("Windows")) {
+ osname = "Windows";
+ }
+
+ createTestClass();
+
+ // Test a simple path
+ String libpath = File.pathSeparator + "tmp" + File.pathSeparator + "foobar";
+ List<String> processOut = null;
+ String sunbootlibrarypath = "-Dsun.boot.library.path=" + libpath;
+ processOut = doExec(sunbootlibrarypath, "-cp", ".", TESTFILE);
+ if (processOut == null || !processOut.get(0).endsWith(libpath)) {
+ throw new RuntimeException("Error: did not get expected error string");
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException("Unexpected error " + ex);
+ }
+ }
+}