7200297: agent code does not handle multiple boot library path elements correctly
authordholmes
Sun, 02 Dec 2012 19:16:56 -0500
changeset 14698 9294fcf94c46
parent 14697 6ed46ffc2d33
child 14699 c3ef2c941697
7200297: agent code does not handle multiple boot library path elements correctly Summary: When bug 6819213 was fixed it enabled sun.boot.library.path property to contain multiple paths. Code in agents does not handle multiple paths when attempting to find dependent shared libs. Reviewed-by: dholmes, sspitsyn, dsamersoff Contributed-by: Bill Pittore <bill.pittore@oracle.com>
jdk/src/share/back/debugInit.c
jdk/src/share/back/error_messages.c
jdk/src/share/back/transport.c
jdk/src/share/demo/jvmti/hprof/hprof.h
jdk/src/share/demo/jvmti/hprof/hprof_init.c
jdk/src/solaris/back/linker_md.c
jdk/src/solaris/demo/jvmti/hprof/hprof_md.c
jdk/src/solaris/npt/npt_md.h
jdk/src/windows/back/linker_md.c
jdk/src/windows/demo/jvmti/hprof/hprof_md.c
jdk/src/windows/npt/npt_md.h
--- a/jdk/src/share/back/debugInit.c	Sun Dec 02 16:37:31 2012 +0000
+++ b/jdk/src/share/back/debugInit.c	Sun Dec 02 19:16:56 2012 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2012, 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
@@ -37,6 +37,7 @@
 #include "debugLoop.h"
 #include "bag.h"
 #include "invoker.h"
+#include "sys.h"
 
 /* How the options get to OnLoad: */
 #define XDEBUG "-Xdebug"
@@ -201,6 +202,8 @@
     jint              jvmtiCompileTimeMajorVersion;
     jint              jvmtiCompileTimeMinorVersion;
     jint              jvmtiCompileTimeMicroVersion;
+    char              *boot_path = NULL;
+    char              npt_lib[MAXPATHLEN];
 
     /* See if it's already loaded */
     if ( gdata!=NULL && gdata->isLoaded==JNI_TRUE ) {
@@ -227,18 +230,6 @@
     vmInitialized = JNI_FALSE;
     gdata->vmDead = JNI_FALSE;
 
-    /* Npt and Utf function init */
-    NPT_INITIALIZE(&(gdata->npt), NPT_VERSION, NULL);
-    if (gdata->npt == NULL) {
-        ERROR_MESSAGE(("JDWP: unable to initialize NPT library"));
-        return JNI_ERR;
-    }
-    gdata->npt->utf = (gdata->npt->utfInitialize)(NULL);
-    if (gdata->npt->utf == NULL) {
-        ERROR_MESSAGE(("JDWP: UTF function initialization failed"));
-        return JNI_ERR;
-    }
-
     /* Get the JVMTI Env, IMPORTANT: Do this first! For jvmtiAllocate(). */
     error = JVM_FUNC_PTR(vm,GetEnv)
                 (vm, (void **)&(gdata->jvmti), JVMTI_VERSION_1);
@@ -277,6 +268,24 @@
         forceExit(1); /* Kill entire process, no core dump wanted */
     }
 
+    JVMTI_FUNC_PTR(gdata->jvmti, GetSystemProperty)
+        (gdata->jvmti, (const char *)"sun.boot.library.path",
+         &boot_path);
+
+    dbgsysBuildLibName(npt_lib, sizeof(npt_lib), boot_path, NPT_LIBNAME);
+    /* Npt and Utf function init */
+    NPT_INITIALIZE(npt_lib, &(gdata->npt), NPT_VERSION, NULL);
+    jvmtiDeallocate(boot_path);
+    if (gdata->npt == NULL) {
+        ERROR_MESSAGE(("JDWP: unable to initialize NPT library"));
+        return JNI_ERR;
+    }
+    gdata->npt->utf = (gdata->npt->utfInitialize)(NULL);
+    if (gdata->npt->utf == NULL) {
+        ERROR_MESSAGE(("JDWP: UTF function initialization failed"));
+        return JNI_ERR;
+    }
+
     /* Parse input options */
     if (!parseOptions(options)) {
         /* No message necessary, should have been printed out already */
--- a/jdk/src/share/back/error_messages.c	Sun Dec 02 16:37:31 2012 +0000
+++ b/jdk/src/share/back/error_messages.c	Sun Dec 02 19:16:56 2012 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -70,8 +70,13 @@
     len = (int)strlen((char*)utf8buf);
 
     /* Convert to platform encoding (ignore errors, dangerous area) */
-    (void)(gdata->npt->utf8ToPlatform)(gdata->npt->utf,
-           utf8buf, len, pbuf, MAX_MESSAGE_LEN);
+    if (gdata->npt != NULL) {
+        (void)(gdata->npt->utf8ToPlatform)(gdata->npt->utf,
+               utf8buf, len, pbuf, MAX_MESSAGE_LEN);
+    } else {
+        /* May be called before NPT is initialized so don't fault */
+        strncpy(pbuf, (char*)utf8buf, len);
+    }
     (void)fprintf(fp, "%s%s%s", prefix, pbuf, suffix);
 }
 
--- a/jdk/src/share/back/transport.c	Sun Dec 02 16:37:31 2012 +0000
+++ b/jdk/src/share/back/transport.c	Sun Dec 02 19:16:56 2012 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2012, 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
@@ -144,7 +144,9 @@
     /* First, look in sun.boot.library.path. This should find the standard
      *  dt_socket and dt_shmem transport libraries, or any library
      *  that was delivered with the J2SE.
-     *  Note: Java property sun.boot.library.path contains a single directory.
+     *  Note: Since 6819213 fixed, Java property sun.boot.library.path can
+     *  contain multiple paths. Dll_dir is the first entry and
+     *  -Dsun.boot.library.path entries are appended.
      */
     libdir = gdata->property_sun_boot_library_path;
     if (libdir == NULL) {
--- a/jdk/src/share/demo/jvmti/hprof/hprof.h	Sun Dec 02 16:37:31 2012 +0000
+++ b/jdk/src/share/demo/jvmti/hprof/hprof.h	Sun Dec 02 19:16:56 2012 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -65,6 +65,7 @@
 #include "jni.h"
 #include "jvmti.h"
 #include "classfile_constants.h"
+#include "jvm_md.h"
 
 #ifndef SKIP_NPT
 #include "npt.h"   /* To get NptEnv for doing character conversions */
--- a/jdk/src/share/demo/jvmti/hprof/hprof_init.c	Sun Dec 02 16:37:31 2012 +0000
+++ b/jdk/src/share/demo/jvmti/hprof/hprof_init.c	Sun Dec 02 19:16:56 2012 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1899,6 +1899,7 @@
      */
     getSystemProperty("sun.boot.library.path", &boot_path);
     md_build_library_name(lname, FILENAME_MAX, boot_path, name);
+    jvmtiDeallocate(boot_path);
     handle = md_load_library(lname, err_buf, (int)sizeof(err_buf));
     if ( handle == NULL ) {
         /* This may be necessary on Windows. */
@@ -1941,6 +1942,9 @@
 JNIEXPORT jint JNICALL
 Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
 {
+    char *boot_path = NULL;
+    char npt_lib[JVM_MAXPATHLEN];
+
     /* See if it's already loaded */
     if ( gdata!=NULL && gdata->isLoaded==JNI_TRUE ) {
         HPROF_ERROR(JNI_TRUE, "Cannot load this JVM TI agent twice, check your java command line for duplicate hprof options.");
@@ -1957,9 +1961,15 @@
 
     gdata->jvm = vm;
 
+    /* Get the JVMTI environment */
+    getJvmti();
+
 #ifndef SKIP_NPT
+    getSystemProperty("sun.boot.library.path", &boot_path);
     /* Load in NPT library for character conversions */
-    NPT_INITIALIZE(&(gdata->npt), NPT_VERSION, NULL);
+    md_build_library_name(npt_lib, sizeof(npt_lib), boot_path, NPT_LIBNAME);
+    jvmtiDeallocate(boot_path);
+    NPT_INITIALIZE(npt_lib, &(gdata->npt), NPT_VERSION, NULL);
     if ( gdata->npt == NULL ) {
         HPROF_ERROR(JNI_TRUE, "Cannot load npt library");
     }
@@ -1969,9 +1979,6 @@
     }
 #endif
 
-    /* Get the JVMTI environment */
-    getJvmti();
-
     /* Lock needed to protect debug_malloc() code, which is not MT safe */
     #ifdef DEBUG
         gdata->debug_malloc_lock = createRawMonitor("HPROF debug_malloc lock");
--- a/jdk/src/solaris/back/linker_md.c	Sun Dec 02 16:37:31 2012 +0000
+++ b/jdk/src/solaris/back/linker_md.c	Sun Dec 02 19:16:56 2012 -0500
@@ -54,6 +54,32 @@
 #define LIB_SUFFIX "so"
 #endif
 
+static void dll_build_name(char* buffer, size_t buflen,
+                           const char* pname, const char* fname) {
+    // Based on os_solaris.cpp
+
+    char *path_sep = PATH_SEPARATOR;
+    char *pathname = (char *)pname;
+    while (strlen(pathname) > 0) {
+        char *p = strchr(pathname, *path_sep);
+        if (p == NULL) {
+            p = pathname + strlen(pathname);
+        }
+        /* check for NULL path */
+        if (p == pathname) {
+            continue;
+        }
+        (void)snprintf(buffer, buflen, "%.*s/lib%s." LIB_SUFFIX, (p - pathname),
+                       pathname, fname);
+
+        if (access(buffer, F_OK) == 0) {
+            break;
+        }
+        pathname = p + 1;
+        *buffer = '\0';
+    }
+}
+
 /*
  * create a string for the JNI native function name by adding the
  * appropriate decorations.
@@ -76,16 +102,16 @@
 {
     const int pnamelen = pname ? strlen(pname) : 0;
 
+    *holder = '\0';
     /* Quietly truncate on buffer overflow.  Should be an error. */
     if (pnamelen + (int)strlen(fname) + 10 > holderlen) {
-        *holder = '\0';
         return;
     }
 
     if (pnamelen == 0) {
         (void)snprintf(holder, holderlen, "lib%s." LIB_SUFFIX, fname);
     } else {
-        (void)snprintf(holder, holderlen, "%s/lib%s." LIB_SUFFIX, pname, fname);
+      dll_build_name(holder, holderlen, pname, fname);
     }
 }
 
--- a/jdk/src/solaris/demo/jvmti/hprof/hprof_md.c	Sun Dec 02 16:37:31 2012 +0000
+++ b/jdk/src/solaris/demo/jvmti/hprof/hprof_md.c	Sun Dec 02 19:16:56 2012 -0500
@@ -380,6 +380,31 @@
     return ntohl(l);
 }
 
+static void dll_build_name(char* buffer, size_t buflen,
+                           const char* pname, const char* fname) {
+    // Loosely based on os_solaris.cpp
+
+      char *pathname = (char *)pname;
+      while (strlen(pathname) > 0) {
+          char *p = strchr(pathname, ':');
+          if (p == NULL) {
+              p = pathname + strlen(pathname);
+          }
+          /* check for NULL path */
+          if (p == pathname) {
+              continue;
+          }
+          (void)snprintf(buffer, buflen, "%.*s/lib%s" JNI_LIB_SUFFIX,
+                         (p - pathname), pathname, fname);
+
+          if (access(buffer, F_OK) == 0) {
+            break;
+          }
+          pathname = p + 1;
+          *buffer = '\0';
+      }
+}
+
 /* Create the actual fill filename for a dynamic library.  */
 void
 md_build_library_name(char *holder, int holderlen, char *pname, char *fname)
@@ -389,9 +414,9 @@
     /* Length of options directory location. */
     pnamelen = pname ? strlen(pname) : 0;
 
+    *holder = '\0';
     /* Quietly truncate on buffer overflow.  Should be an error. */
     if (pnamelen + (int)strlen(fname) + 10 > holderlen) {
-        *holder = '\0';
         return;
     }
 
@@ -399,7 +424,7 @@
     if (pnamelen == 0) {
         (void)snprintf(holder, holderlen, "lib%s" JNI_LIB_SUFFIX, fname);
     } else {
-        (void)snprintf(holder, holderlen, "%s/lib%s" JNI_LIB_SUFFIX, pname, fname);
+      dll_build_name(holder, holderlen, pname, fname);
     }
 }
 
--- a/jdk/src/solaris/npt/npt_md.h	Sun Dec 02 16:37:31 2012 +0000
+++ b/jdk/src/solaris/npt/npt_md.h	Sun Dec 02 19:16:56 2012 -0500
@@ -36,14 +36,14 @@
 
 #define NPT_LIBNAME "npt"
 
-#define NPT_INITIALIZE(pnpt,version,options)                            \
+#define NPT_INITIALIZE(path,pnpt,version,options)                       \
     {                                                                   \
         void   *_handle;                                                \
         void   *_sym;                                                   \
                                                                         \
         if ( (pnpt) == NULL ) NPT_ERROR("NptEnv* is NULL");             \
         *(pnpt) = NULL;                                                 \
-        _handle =  dlopen(JNI_LIB_NAME(NPT_LIBNAME), RTLD_LAZY);              \
+        _handle =  dlopen(path, RTLD_LAZY);                             \
         if ( _handle == NULL ) NPT_ERROR("Cannot open library");        \
         _sym = dlsym(_handle, "nptInitialize");                         \
         if ( _sym == NULL ) NPT_ERROR("Cannot find nptInitialize");     \
--- a/jdk/src/windows/back/linker_md.c	Sun Dec 02 16:37:31 2012 +0000
+++ b/jdk/src/windows/back/linker_md.c	Sun Dec 02 19:16:56 2012 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2012, 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
@@ -32,11 +32,42 @@
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <io.h>
 
 #include "sys.h"
 
 #include "path_md.h"
 
+static void dll_build_name(char* buffer, size_t buflen,
+                           const char* pname, const char* fname) {
+    // Based on os_windows.cpp
+
+    char *path_sep = PATH_SEPARATOR;
+    char *pathname = (char *)pname;
+    while (strlen(pathname) > 0) {
+        char *p = strchr(pathname, *path_sep);
+        if (p == NULL) {
+            p = pathname + strlen(pathname);
+        }
+        /* check for NULL path */
+        if (p == pathname) {
+            continue;
+        }
+        if (*(p-1) == ':' || *(p-1) == '\\') {
+            (void)_snprintf(buffer, buflen, "%.*s%s.dll", (p - pathname),
+                            pathname, fname);
+        } else {
+            (void)_snprintf(buffer, buflen, "%.*s\\%s.dll", (p - pathname),
+                            pathname, fname);
+        }
+        if (_access(buffer, 0) == 0) {
+            break;
+        }
+        pathname = p + 1;
+        *buffer = '\0';
+    }
+}
+
 /*
  * From system_md.c v1.54
  */
@@ -80,20 +111,17 @@
 dbgsysBuildLibName(char *holder, int holderlen, char *pname, char *fname)
 {
     const int pnamelen = pname ? (int)strlen(pname) : 0;
-    const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
 
+    *holder = '\0';
     /* Quietly truncates on buffer overflow. Should be an error. */
     if (pnamelen + (int)strlen(fname) + 10 > holderlen) {
-        *holder = '\0';
         return;
     }
 
     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);
+      dll_build_name(holder, holderlen, pname, fname);
     }
 }
 
--- a/jdk/src/windows/demo/jvmti/hprof/hprof_md.c	Sun Dec 02 16:37:31 2012 +0000
+++ b/jdk/src/windows/demo/jvmti/hprof/hprof_md.c	Sun Dec 02 19:16:56 2012 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -367,28 +367,53 @@
     return 0;
 }
 
+static void dll_build_name(char* buffer, size_t buflen,
+                           const char* pname, const char* fname) {
+    // Loosley based on os_windows.cpp
+
+    char *pathname = (char *)pname;
+    while (strlen(pathname) > 0) {
+        char *p = strchr(pathname, ';');
+        if (p == NULL) {
+            p = pathname + strlen(pathname);
+        }
+        /* check for NULL path */
+        if (p == pathname) {
+            continue;
+        }
+        if (*(p-1) == ':' || *(p-1) == '\\') {
+            (void)_snprintf(buffer, buflen, "%.*s%s.dll", (p - pathname),
+                            pathname, fname);
+        } else {
+            (void)_snprintf(buffer, buflen, "%.*s\\%s.dll", (p - pathname),
+                            pathname, fname);
+        }
+        if (_access(buffer, 0) == 0) {
+            break;
+        }
+        pathname = p + 1;
+        *buffer = '\0';
+    }
+}
+
 /* Build a machine dependent library name out of a path and file name.  */
 void
 md_build_library_name(char *holder, int holderlen, char *pname, char *fname)
 {
     int   pnamelen;
-    char  c;
 
     pnamelen = pname ? (int)strlen(pname) : 0;
-    c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
 
+    *holder = '\0';
     /* Quietly truncates on buffer overflow. Should be an error. */
     if (pnamelen + strlen(fname) + 10 > (unsigned int)holderlen) {
-        *holder = '\0';
         return;
     }
 
     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);
+      dll_build_name(holder, holderlen, pname, fname);
     }
 }
 
--- a/jdk/src/windows/npt/npt_md.h	Sun Dec 02 16:37:31 2012 +0000
+++ b/jdk/src/windows/npt/npt_md.h	Sun Dec 02 19:16:56 2012 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2012, 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
@@ -33,30 +33,16 @@
 #include <string.h>
 #include <errno.h>
 
-#define NPT_LIBNAME "npt.dll"
+#define NPT_LIBNAME "npt"
 
-#define NPT_INITIALIZE(pnpt,version,options)                            \
+#define NPT_INITIALIZE(path,pnpt,version,options)                       \
     {                                                                   \
-        HINSTANCE jvm;                                                  \
         void   *_handle;                                                \
         void   *_sym;                                                   \
-        char    buf[FILENAME_MAX+32];                                   \
-        char   *lastSlash;                                              \
                                                                         \
         if ( (pnpt) == NULL ) NPT_ERROR("NptEnv* is NULL");             \
-        _handle =  NULL;                                                \
         *(pnpt) = NULL;                                                 \
-        buf[0] = 0;                                                     \
-        jvm = GetModuleHandle("jvm.dll");                               \
-        if ( jvm == NULL ) NPT_ERROR("Cannot find jvm.dll");            \
-        GetModuleFileName(jvm, buf, FILENAME_MAX);                      \
-        lastSlash = strrchr(buf, '\\');                                 \
-        if ( lastSlash != NULL ) {                                      \
-            *lastSlash = '\0';                                          \
-            (void)strcat(buf, "\\..\\");                                \
-            (void)strcat(buf, NPT_LIBNAME);                             \
-            _handle =  LoadLibrary(buf);                                \
-        }                                                               \
+        _handle =  LoadLibrary(path);                                   \
         if ( _handle == NULL ) NPT_ERROR("Cannot open library");        \
         _sym = GetProcAddress(_handle, "nptInitialize");                \
         if ( _sym == NULL ) NPT_ERROR("Cannot find nptInitialize");     \