# HG changeset patch # User dcubed # Date 1206396871 25200 # Node ID 3d51c181a2e51b2d9b7c9cc431a1c11a732ce2a4 # Parent c4e0a3afe6f27d5d305aff96dc1334c395985115 6274276: 3/2 java.lang.instrument JAR manifest processing does not remove spaces from class names Summary: Attribute values should be extracted without leading or trailing whitespace. Reviewed-by: ohair, sspitsyn diff -r c4e0a3afe6f2 -r 3d51c181a2e5 jdk/src/share/instrument/JarFacade.c --- a/jdk/src/share/instrument/JarFacade.c Mon Mar 24 15:05:09 2008 -0700 +++ b/jdk/src/share/instrument/JarFacade.c Mon Mar 24 15:14:31 2008 -0700 @@ -45,11 +45,36 @@ if (attribute->name == NULL) { free(attribute); } else { - attribute->value = strdup(value); + char *begin = value; + char *end; + + /* skip any leading white space */ + while (isspace(*begin)) { + begin++; + } + + /* skip any trailing white space */ + end = &begin[strlen(begin)]; + while (end > begin && isspace(end[-1])) { + end--; + } + + if (begin == end) { + /* no value so skip this attribute */ + free(attribute->name); + free(attribute); + return; + } + + size_t value_len = (size_t)(end - begin); + attribute->value = malloc(value_len + 1); if (attribute->value == NULL) { free(attribute->name); free(attribute); } else { + /* save the value without leading or trailing whitespace */ + strncpy(attribute->value, begin, value_len); + attribute->value[value_len] = NULL; attribute->next = NULL; if (context->head == NULL) { context->head = attribute; diff -r c4e0a3afe6f2 -r 3d51c181a2e5 jdk/test/java/lang/instrument/ManifestTest.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/instrument/ManifestTest.sh Mon Mar 24 15:14:31 2008 -0700 @@ -0,0 +1,483 @@ +# +# 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 +# @bug 6274276 +# @summary JLI JAR manifest processing should ignore leading and trailing white space. +# @author Daniel D. Daugherty +# +# @run build ManifestTestApp +# @run shell/timeout=900 ManifestTest.sh +# + +make_a_JAR() { + # version_line and premain_line are required + version_line="Manifest-Version: 1.0" + premain_line="Premain-Class: ${AGENT}" + boot_cp_line="" + expect_boot_cp_line="ExampleForBootClassPath was not loaded." + can_redef_line="" + expect_redef_line="isRedefineClassesSupported()=false" + can_retrans_line="" + expect_retrans_line="isRetransformClassesSupported()=false" + can_set_nmp_line="" + expect_set_nmp_line="isNativeMethodPrefixSupported()=false" + + while [ $# != 0 ] ; do + case "$1" in + defaults) + # just use the defaults for the test + ;; + + boot_cp_line1) + boot_cp_line="Boot-Class-Path: no_white_space" + expect_boot_cp_line="ExampleForBootClassPath was loaded." + mkdir -p no_white_space + cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class no_white_space + ;; + + boot_cp_line2) + boot_cp_line="Boot-Class-Path: has_leading_blank" + expect_boot_cp_line="ExampleForBootClassPath was loaded." + mkdir -p has_leading_blank " has_leading_blank" + # the good class is in the directory without the blank + cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class \ + has_leading_blank + # the bad class is in the directory with the blank + cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class.bad \ + " has_leading_blank"/ExampleForBootClassPath.class + ;; + + boot_cp_line3) + boot_cp_line="Boot-Class-Path: has_trailing_blank " + expect_boot_cp_line="ExampleForBootClassPath was loaded." + mkdir -p has_trailing_blank "has_trailing_blank " + # the good class is in the directory without the blank + cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class \ + has_trailing_blank + # the bad class is in the directory with the blank + cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class.bad \ + "has_trailing_blank "/ExampleForBootClassPath.class + ;; + + boot_cp_line4) + boot_cp_line="Boot-Class-Path: has_leading_and_trailing_blank " + expect_boot_cp_line="ExampleForBootClassPath was loaded." + mkdir -p has_leading_and_trailing_blank \ + " has_leading_and_trailing_blank " + # the good class is in the directory without the blanks + cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class \ + has_leading_and_trailing_blank + # the bad class is in the directory with the blanks + cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class.bad \ + " has_leading_and_trailing_blank "/ExampleForBootClassPath.class + ;; + + boot_cp_line5) + boot_cp_line="Boot-Class-Path: has_embedded blank" + expect_boot_cp_line="ExampleForBootClassPath was loaded." + mkdir -p has_embedded "has_embedded blank" + # the good class is in the first blank separated word + cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class has_embedded + # the bad class is in the directory with the blank + cp -p $OUT_OF_THE_WAY/ExampleForBootClassPath.class.bad \ + "has_embedded blank"/ExampleForBootClassPath.class + ;; + + can_redef_line1) + can_redef_line="Can-Redefine-Classes: true" + expect_redef_line="isRedefineClassesSupported()=true" + ;; + + can_redef_line2) + can_redef_line="Can-Redefine-Classes: true" + expect_redef_line="isRedefineClassesSupported()=true" + ;; + + can_redef_line3) + can_redef_line="Can-Redefine-Classes: true " + expect_redef_line="isRedefineClassesSupported()=true" + ;; + + can_redef_line4) + can_redef_line="Can-Redefine-Classes: true " + expect_redef_line="isRedefineClassesSupported()=true" + ;; + + can_redef_line5) + can_redef_line="Can-Redefine-Classes: false" + ;; + + can_redef_line6) + can_redef_line="Can-Redefine-Classes: false" + ;; + + can_redef_line7) + can_redef_line="Can-Redefine-Classes: false " + ;; + + can_redef_line8) + can_redef_line="Can-Redefine-Classes: false " + ;; + + can_redef_line9) + # this line makes the jar command unhappy and that's + # not what we're testing so skip this case + can_redef_line="Can-Redefine-Classes:" + ;; + + can_redef_line10) + can_redef_line="Can-Redefine-Classes: " + ;; + + can_redef_line11) + can_redef_line="Can-Redefine-Classes: " + ;; + + can_retrans_line1) + can_retrans_line="Can-Retransform-Classes: true" + expect_retrans_line="isRetransformClassesSupported()=true" + ;; + + can_retrans_line2) + can_retrans_line="Can-Retransform-Classes: true" + expect_retrans_line="isRetransformClassesSupported()=true" + ;; + + can_retrans_line3) + can_retrans_line="Can-Retransform-Classes: true " + expect_retrans_line="isRetransformClassesSupported()=true" + ;; + + can_retrans_line4) + can_retrans_line="Can-Retransform-Classes: true " + expect_retrans_line="isRetransformClassesSupported()=true" + ;; + + can_retrans_line5) + can_retrans_line="Can-Retransform-Classes: false" + ;; + + can_retrans_line6) + can_retrans_line="Can-Retransform-Classes: false" + ;; + + can_retrans_line7) + can_retrans_line="Can-Retransform-Classes: false " + ;; + + can_retrans_line8) + can_retrans_line="Can-Retransform-Classes: false " + ;; + + can_retrans_line9) + # this line makes the jar command unhappy and that's + # not what we're testing so skip this case + can_retrans_line="Can-Retransform-Classes:" + ;; + + can_retrans_line10) + can_retrans_line="Can-Retransform-Classes: " + ;; + + can_retrans_line11) + can_retrans_line="Can-Retransform-Classes: " + ;; + + can_set_nmp_line1) + can_set_nmp_line="Can-Set-Native-Method-Prefix: true" + expect_set_nmp_line="isNativeMethodPrefixSupported()=true" + ;; + + can_set_nmp_line2) + can_set_nmp_line="Can-Set-Native-Method-Prefix: true" + expect_set_nmp_line="isNativeMethodPrefixSupported()=true" + ;; + + can_set_nmp_line3) + can_set_nmp_line="Can-Set-Native-Method-Prefix: true " + expect_set_nmp_line="isNativeMethodPrefixSupported()=true" + ;; + + can_set_nmp_line4) + can_set_nmp_line="Can-Set-Native-Method-Prefix: true " + expect_set_nmp_line="isNativeMethodPrefixSupported()=true" + ;; + + can_set_nmp_line5) + can_set_nmp_line="Can-Set-Native-Method-Prefix: false" + ;; + + can_set_nmp_line6) + can_set_nmp_line="Can-Set-Native-Method-Prefix: false" + ;; + + can_set_nmp_line7) + can_set_nmp_line="Can-Set-Native-Method-Prefix: false " + ;; + + can_set_nmp_line8) + can_set_nmp_line="Can-Set-Native-Method-Prefix: false " + ;; + + can_set_nmp_line9) + # this line makes the jar command unhappy and that's + # not what we're testing so skip this case + can_set_nmp_line="Can-Set-Native-Method-Prefix:" + ;; + + can_set_nmp_line10) + can_set_nmp_line="Can-Set-Native-Method-Prefix: " + ;; + + can_set_nmp_line11) + can_set_nmp_line="Can-Set-Native-Method-Prefix: " + ;; + + premain_line1) + premain_line="Premain-Class: ${AGENT}" + ;; + + premain_line2) + premain_line="Premain-Class: ${AGENT} " + ;; + + premain_line3) + premain_line="Premain-Class: ${AGENT} " + ;; + + version_line1) + version_line="Manifest-Version: 1.0" + ;; + + version_line2) + version_line="Manifest-Version: 1.0 " + ;; + + version_line3) + version_line="Manifest-Version: 1.0 " + ;; + + *) + echo "ERROR: invalid test token" + exit 1 + esac + shift + done + + echo "${version_line}" > ${AGENT}.mf + echo "${premain_line}" >> ${AGENT}.mf + + if [ -n "$boot_cp_line" ]; then + echo "${boot_cp_line}" >> ${AGENT}.mf + fi + + if [ -n "$can_redef_line" ]; then + echo "${can_redef_line}" >> ${AGENT}.mf + fi + + if [ -n "$can_retrans_line" ]; then + echo "${can_retrans_line}" >> ${AGENT}.mf + fi + + if [ -n "$can_set_nmp_line" ]; then + echo "${can_set_nmp_line}" >> ${AGENT}.mf + fi + + rm -f ${AGENT}.jar + ${JAR} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}.class + + echo "$expect_boot_cp_line" > expect_boot_cp_line + echo "$expect_redef_line" > expect_redef_line + echo "$expect_retrans_line" > expect_retrans_line + echo "$expect_set_nmp_line" > expect_set_nmp_line +} + +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${TESTSRC}" = "" ] +then + echo "TESTSRC not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +JAR="${TESTJAVA}/bin/jar" +JAVAC="${TESTJAVA}"/bin/javac +JAVA="${TESTJAVA}"/bin/java + +# Now that ManifestTestApp.class is built, we move +# ExampleForBootClassPath.class so that it cannot be found +# by default +OUT_OF_THE_WAY=out_of_the_way +mkdir $OUT_OF_THE_WAY +mv "${TESTCLASSES}/ExampleForBootClassPath.class" $OUT_OF_THE_WAY + +# create a bad version of ExampleForBootClassPath.class +# so we can tell when the wrong version is run +sed 's/return 15/return 42/' "${TESTSRC}"/ExampleForBootClassPath.java \ + > ExampleForBootClassPath.java +"$JAVAC" ExampleForBootClassPath.java +mv ExampleForBootClassPath.class \ + $OUT_OF_THE_WAY/ExampleForBootClassPath.class.bad +mv ExampleForBootClassPath.java \ + $OUT_OF_THE_WAY/ExampleForBootClassPath.java.bad + +AGENT=ManifestTestAgent +# We compile the agent in the working directory instead of with +# a build task because we construct a different agent JAR file +# for each test case. +${JAVAC} -d . ${TESTSRC}/${AGENT}.java + +FAIL_MARKER=fail_marker +rm -f $FAIL_MARKER + +while read token; do + echo + echo "===== begin test case: $token =====" + make_a_JAR "$token" + + "${JAVA}" ${TESTVMOPTS} -javaagent:${AGENT}.jar \ + -classpath "${TESTCLASSES}" ManifestTestApp > output.log 2>&1 + result=$? + + cat output.log + + if [ "$result" = 0 ]; then + echo "PASS: ManifestTestApp exited with status of 0." + else + echo "FAIL: ManifestTestApp exited with status of $result" + touch $FAIL_MARKER + fi + + MESG="Hello from ${AGENT}!" + grep -s "$MESG" output.log > /dev/null + result=$? + if [ "$result" = 0 ]; then + echo "PASS: found '$MESG' in the test output" + else + echo "FAIL: did NOT find '$MESG' in the test output" + touch $FAIL_MARKER + fi + + MESG=`cat expect_boot_cp_line` + grep -s "$MESG" output.log > /dev/null + result=$? + if [ "$result" = 0 ]; then + echo "PASS: found '$MESG' in the test output" + else + echo "FAIL: did NOT find '$MESG' in the test output" + touch $FAIL_MARKER + fi + + MESG=`cat expect_redef_line` + grep -s "$MESG" output.log > /dev/null + result=$? + if [ "$result" = 0 ]; then + echo "PASS: found '$MESG' in the test output" + else + echo "FAIL: did NOT find '$MESG' in the test output" + touch $FAIL_MARKER + fi + + MESG=`cat expect_retrans_line` + grep -s "$MESG" output.log > /dev/null + result=$? + if [ "$result" = 0 ]; then + echo "PASS: found '$MESG' in the test output" + else + echo "FAIL: did NOT find '$MESG' in the test output" + touch $FAIL_MARKER + fi + + MESG=`cat expect_set_nmp_line` + grep -s "$MESG" output.log > /dev/null + result=$? + if [ "$result" = 0 ]; then + echo "PASS: found '$MESG' in the test output" + else + echo "FAIL: did NOT find '$MESG' in the test output" + touch $FAIL_MARKER + fi + + echo "===== end test case: $token =====" + echo +done << EOF +defaults +version_line1 +version_line2 +version_line3 +premain_line1 +premain_line2 +premain_line3 +boot_cp_line1 +boot_cp_line2 +boot_cp_line3 +boot_cp_line4 +boot_cp_line5 +can_redef_line1 +can_redef_line2 +can_redef_line3 +can_redef_line4 +can_redef_line5 +can_redef_line6 +can_redef_line7 +can_redef_line8 +can_redef_line10 +can_redef_line11 +can_retrans_line1 +can_retrans_line2 +can_retrans_line3 +can_retrans_line4 +can_retrans_line5 +can_retrans_line6 +can_retrans_line7 +can_retrans_line8 +can_retrans_line10 +can_retrans_line11 +can_set_nmp_line1 +can_set_nmp_line2 +can_set_nmp_line3 +can_set_nmp_line4 +can_set_nmp_line5 +can_set_nmp_line6 +can_set_nmp_line7 +can_set_nmp_line8 +can_set_nmp_line10 +can_set_nmp_line11 +EOF + +if [ -f $FAIL_MARKER ]; then + exit 1 +else + exit 0 +fi diff -r c4e0a3afe6f2 -r 3d51c181a2e5 jdk/test/java/lang/instrument/ManifestTestAgent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/instrument/ManifestTestAgent.java Mon Mar 24 15:14:31 2008 -0700 @@ -0,0 +1,41 @@ +/* + * 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. + */ + +import java.lang.instrument.Instrumentation; + +public class ManifestTestAgent { + private static Instrumentation instrumentation; + + private ManifestTestAgent() { + } + + public static void premain(String agentArgs, Instrumentation inst) { + System.out.println("Hello from ManifestTestAgent!"); + System.out.println("isNativeMethodPrefixSupported()=" + + inst.isNativeMethodPrefixSupported()); + System.out.println("isRedefineClassesSupported()=" + + inst.isRedefineClassesSupported()); + System.out.println("isRetransformClassesSupported()=" + + inst.isRetransformClassesSupported()); + } +} diff -r c4e0a3afe6f2 -r 3d51c181a2e5 jdk/test/java/lang/instrument/ManifestTestApp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/instrument/ManifestTestApp.java Mon Mar 24 15:14:31 2008 -0700 @@ -0,0 +1,69 @@ +/* + * 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. + */ + +public class ManifestTestApp { + public static void main(String args[]) { + System.out.println("Hello from ManifestTestApp!"); + + new ManifestTestApp().doTest(); + System.exit(0); + } + + private void doTest() { + try { + // load the class only found via the Boot-Class-Path attribute + Object instance = loadExampleClass(); + if (instance.getClass().getClassLoader() == null) { + System.out.println("PASS: ExampleForBootClassPath was loaded" + + " by the boot class path loader."); + } else { + System.out.println("FAIL: ExampleForBootClassPath was loaded" + + " by a non-boot class path loader."); + System.exit(1); + } + } catch (NoClassDefFoundError ncdfe) { + // This message just lets ManifestTest.sh know whether or + // not ExampleForBootClassPath was loaded. Depending on + // the current test case, that will be either a PASSing + // condition or a FAILing condition as determined by + // ManifestTest.sh. + System.out.println("ExampleForBootClassPath was not loaded."); + } + } + + Object loadExampleClass() { + ExampleForBootClassPath instance = new ExampleForBootClassPath(); + System.out.println("ExampleForBootClassPath was loaded."); + if (instance.fifteen() == 15) { + System.out.println("PASS: the correct" + + " ExampleForBootClassPath was loaded."); + } else { + System.out.println("FAIL: the wrong ExampleForBootClassPath" + + " was loaded."); + System.out.println("FAIL: instance.fifteen()=" + + instance.fifteen()); + System.exit(1); + } + return instance; + } +}