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
--- 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;
--- /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
--- /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());
+ }
+}
--- /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;
+ }
+}