From ecdf296456ae0b7368bbbf8db45b54215e8f125c Mon Sep 17 00:00:00 2001 From: Bill Pittore Date: Sun, 2 Dec 2012 19:16:56 -0500 Subject: [PATCH] 7200297: agent code does not handle multiple boot library path elements correctly 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 --- jdk/src/share/back/debugInit.c | 35 +++++++++++------- jdk/src/share/back/error_messages.c | 11 ++++-- jdk/src/share/back/transport.c | 6 ++-- jdk/src/share/demo/jvmti/hprof/hprof.h | 3 +- jdk/src/share/demo/jvmti/hprof/hprof_init.c | 17 ++++++--- jdk/src/solaris/back/linker_md.c | 30 ++++++++++++++-- jdk/src/solaris/demo/jvmti/hprof/hprof_md.c | 29 +++++++++++++-- jdk/src/solaris/npt/npt_md.h | 4 +-- jdk/src/windows/back/linker_md.c | 40 +++++++++++++++++---- jdk/src/windows/demo/jvmti/hprof/hprof_md.c | 39 ++++++++++++++++---- jdk/src/windows/npt/npt_md.h | 22 +++--------- 11 files changed, 175 insertions(+), 61 deletions(-) diff --git a/jdk/src/share/back/debugInit.c b/jdk/src/share/back/debugInit.c index 490099b06c5..25ffbffc91a 100644 --- a/jdk/src/share/back/debugInit.c +++ b/jdk/src/share/back/debugInit.c @@ -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 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved) 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 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved) 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 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved) 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 */ diff --git a/jdk/src/share/back/error_messages.c b/jdk/src/share/back/error_messages.c index 13a04b5173a..2ec5bbfa2e5 100644 --- a/jdk/src/share/back/error_messages.c +++ b/jdk/src/share/back/error_messages.c @@ -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 @@ vprint_message(FILE *fp, const char *prefix, const char *suffix, 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); } diff --git a/jdk/src/share/back/transport.c b/jdk/src/share/back/transport.c index b3154941729..40608b31239 100644 --- a/jdk/src/share/back/transport.c +++ b/jdk/src/share/back/transport.c @@ -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 @@ loadTransport(char *name, jdwpTransportEnv **transportPtr) /* 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) { diff --git a/jdk/src/share/demo/jvmti/hprof/hprof.h b/jdk/src/share/demo/jvmti/hprof/hprof.h index 6e61affce11..ec9fbf01870 100644 --- a/jdk/src/share/demo/jvmti/hprof/hprof.h +++ b/jdk/src/share/demo/jvmti/hprof/hprof.h @@ -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 */ diff --git a/jdk/src/share/demo/jvmti/hprof/hprof_init.c b/jdk/src/share/demo/jvmti/hprof/hprof_init.c index 9183800c428..328c474d410 100644 --- a/jdk/src/share/demo/jvmti/hprof/hprof_init.c +++ b/jdk/src/share/demo/jvmti/hprof/hprof_init.c @@ -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 @@ load_library(char *name) */ 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 @@ lookup_library_symbol(void *library, char **symbols, int nsymbols) 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 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved) 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 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved) } #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"); diff --git a/jdk/src/solaris/back/linker_md.c b/jdk/src/solaris/back/linker_md.c index 5cc83f3df89..a1cbcce3fcf 100644 --- a/jdk/src/solaris/back/linker_md.c +++ b/jdk/src/solaris/back/linker_md.c @@ -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 @@ dbgsysBuildLibName(char *holder, int holderlen, char *pname, char *fname) { 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); } } diff --git a/jdk/src/solaris/demo/jvmti/hprof/hprof_md.c b/jdk/src/solaris/demo/jvmti/hprof/hprof_md.c index 284a2e6fee7..1df2271ce4e 100644 --- a/jdk/src/solaris/demo/jvmti/hprof/hprof_md.c +++ b/jdk/src/solaris/demo/jvmti/hprof/hprof_md.c @@ -380,6 +380,31 @@ md_ntohl(unsigned l) 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 @@ md_build_library_name(char *holder, int holderlen, char *pname, char *fname) /* 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 @@ md_build_library_name(char *holder, int holderlen, char *pname, char *fname) 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); } } diff --git a/jdk/src/solaris/npt/npt_md.h b/jdk/src/solaris/npt/npt_md.h index 9b0c33655a3..76d5b663c04 100644 --- a/jdk/src/solaris/npt/npt_md.h +++ b/jdk/src/solaris/npt/npt_md.h @@ -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"); \ diff --git a/jdk/src/windows/back/linker_md.c b/jdk/src/windows/back/linker_md.c index a651eee4b87..e3ca2584cef 100644 --- a/jdk/src/windows/back/linker_md.c +++ b/jdk/src/windows/back/linker_md.c @@ -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 #include #include +#include #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 @@ void 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); } } diff --git a/jdk/src/windows/demo/jvmti/hprof/hprof_md.c b/jdk/src/windows/demo/jvmti/hprof/hprof_md.c index 2f3ba24fc9a..e5cbeda0f69 100644 --- a/jdk/src/windows/demo/jvmti/hprof/hprof_md.c +++ b/jdk/src/windows/demo/jvmti/hprof/hprof_md.c @@ -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 @@ get_last_error_string(char *buf, int len) 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); } } diff --git a/jdk/src/windows/npt/npt_md.h b/jdk/src/windows/npt/npt_md.h index 50747ddd7fd..e4e5dc3ffe3 100644 --- a/jdk/src/windows/npt/npt_md.h +++ b/jdk/src/windows/npt/npt_md.h @@ -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 #include -#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"); \