diff --git a/src/os/linux/vm/os_linux.cpp b/src/os/linux/vm/os_linux.cpp index 3788eac461e7398bf5d911f70ae551c13be82b37..b4705e4a7f29805427c78f84be5741d23bee36d2 100644 --- a/src/os/linux/vm/os_linux.cpp +++ b/src/os/linux/vm/os_linux.cpp @@ -1518,21 +1518,51 @@ const char* os::dll_file_extension() { return ".so"; } 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); } } diff --git a/src/os/solaris/vm/os_solaris.cpp b/src/os/solaris/vm/os_solaris.cpp index 23b4ff2f5f20b9a321575866d66187470616ea74..ce201c3faca19a460029e89fd34bc832b5df33d6 100644 --- a/src/os/solaris/vm/os_solaris.cpp +++ b/src/os/solaris/vm/os_solaris.cpp @@ -1827,21 +1827,51 @@ const char* os::dll_file_extension() { return ".so"; } 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); } } diff --git a/src/os/windows/vm/os_windows.cpp b/src/os/windows/vm/os_windows.cpp index cc3c6202d65d41c9abbc42d7f0b127a2fd493587..0ae4c3e813157cd3a52eedf9d8884456ee77c340 100644 --- a/src/os/windows/vm/os_windows.cpp +++ b/src/os/windows/vm/os_windows.cpp @@ -1004,26 +1004,61 @@ const char * os::get_temp_directory() } } -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; +} - 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); +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; + } } + // 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 diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp index 05a84d581e9c1a8bec5b6c21cce3902dcf0d9c7c..b454864baf607813e3b5106a237e1180676bdc32 100644 --- a/src/share/vm/runtime/arguments.cpp +++ b/src/share/vm/runtime/arguments.cpp @@ -852,16 +852,13 @@ bool Arguments::add_property(const char* prop) { 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 @@ bool Arguments::add_property(const char* prop) { 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 @@ void Arguments::set_mode_flags(Mode mode) { // 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 @@ void Arguments::PropertyList_add(SystemProperty** plist, const char* k, char* v) } // 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 @@ void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, c 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; } } diff --git a/src/share/vm/runtime/arguments.hpp b/src/share/vm/runtime/arguments.hpp index b3efa55cbddfa03b3c654440a2112400b635f229..c11aef0001a50592f27cadcbe2cb19f22bee1caf 100644 --- a/src/share/vm/runtime/arguments.hpp +++ b/src/share/vm/runtime/arguments.hpp @@ -475,10 +475,13 @@ class Arguments : AllStatic { // 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); diff --git a/src/share/vm/runtime/hpi.hpp b/src/share/vm/runtime/hpi.hpp index 1e05ca7525aa61d68ace52d188a627b3881f3694..506b911ca124b8b903223be382e14f5ae7799960 100644 --- a/src/share/vm/runtime/hpi.hpp +++ b/src/share/vm/runtime/hpi.hpp @@ -90,7 +90,7 @@ public: 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 @@ public: 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 @@ HPIDECL(fsize, "fsize", _file, FileSizeFD, int, "%d", (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", diff --git a/src/share/vm/runtime/os.cpp b/src/share/vm/runtime/os.cpp index c88d91e4d99be959c33f8b66044053b7f010ebff..f23f6af42e79851deb0282b9226ce1c14b7dddc0 100644 --- a/src/share/vm/runtime/os.cpp +++ b/src/share/vm/runtime/os.cpp @@ -863,7 +863,6 @@ char* os::format_boot_path(const char* format_string, 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 @@ bool os::set_boot_path(char fileSep, char pathSep) { 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; diff --git a/src/share/vm/runtime/os.hpp b/src/share/vm/runtime/os.hpp index e655d3e34b0f94a746b8306faa38b00e32d26fde..41408583200f92ab71f8f59a8ac433d55c23901a 100644 --- a/src/share/vm/runtime/os.hpp +++ b/src/share/vm/runtime/os.hpp @@ -607,6 +607,7 @@ class os: AllStatic { 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 diff --git a/test/runtime/6819213/TestBootNativeLibraryPath.java b/test/runtime/6819213/TestBootNativeLibraryPath.java new file mode 100644 index 0000000000000000000000000000000000000000..dc49db661229a8485b9ff2a15e6b6fe2c80ba38c --- /dev/null +++ b/test/runtime/6819213/TestBootNativeLibraryPath.java @@ -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 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 cmds = new ArrayList(); + cmds.add(javaCmd); + for (String x : args) { + cmds.add(x); + } + System.out.println("cmds=" + cmds); + ProcessBuilder pb = new ProcessBuilder(cmds); + + Map env = pb.environment(); + pb.directory(new File(".")); + + List out = new ArrayList(); + 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 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); + } + } +}