From 671d12ce6b3aed7a63fd734e484bd63f6dca588c Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Sun, 20 Nov 2016 07:57:57 -0800 Subject: [PATCH] 8169909: java agent fails to add to class path when the initial module is a named module Reviewed-by: alanb --- .../jdk/internal/loader/ClassLoaders.java | 4 +- .../modules/AppendToClassPathModuleTest.java | 59 ++++++++++ .../modules/AppendToClassPathModuleTest.sh | 67 ++++++++++++ .../modules/src/test/jdk/test/Main.java | 43 ++++++++ .../modules/src/test/module-info.java | 25 +++++ .../modules/classpath/JavaClassPathTest.java | 101 +++++++++++++++--- .../classpath/src/m/jdk/test/Main.java | 9 +- 7 files changed, 290 insertions(+), 18 deletions(-) create mode 100644 jdk/test/java/lang/instrument/modules/AppendToClassPathModuleTest.java create mode 100644 jdk/test/java/lang/instrument/modules/AppendToClassPathModuleTest.sh create mode 100644 jdk/test/java/lang/instrument/modules/src/test/jdk/test/Main.java create mode 100644 jdk/test/java/lang/instrument/modules/src/test/module-info.java diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java b/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java index 7ed01991bb1..64492508dc0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java @@ -72,13 +72,13 @@ public class ClassLoaders { // If neither is specified then default to -cp // If -cp is not specified and -m is specified, the value of // java.class.path is an empty string, then no class path. - URLClassPath ucp = null; + URLClassPath ucp = new URLClassPath(new URL[0]); String mainMid = System.getProperty("jdk.module.main"); String cp = System.getProperty("java.class.path"); if (cp == null) cp = ""; if (mainMid == null || cp.length() > 0) - ucp = toURLClassPath(cp); + addClassPathToUCP(cp, ucp); // create the class loaders BOOT_LOADER = new BootClassLoader(bcp); diff --git a/jdk/test/java/lang/instrument/modules/AppendToClassPathModuleTest.java b/jdk/test/java/lang/instrument/modules/AppendToClassPathModuleTest.java new file mode 100644 index 00000000000..78c5e615330 --- /dev/null +++ b/jdk/test/java/lang/instrument/modules/AppendToClassPathModuleTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016, 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 + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8169909 + * @library src /lib/testlibrary + * @build test/* + * @run shell AppendToClassPathModuleTest.sh + * @run main AppendToClassPathModuleTest + */ + +import java.util.Map; +import static jdk.testlibrary.ProcessTools.*; + +/** + * Launch a modular test with no class path and no CLASSPATH set. + * The java agent appends to the "hidden" directory to the class path + * at runtime. + */ +public class AppendToClassPathModuleTest { + public static void main(String... args) throws Throwable { + String modulepath = System.getProperty("test.module.path"); + ProcessBuilder pb = + createJavaProcessBuilder("-javaagent:Agent.jar", + "--module-path", modulepath, + "-m", "test/jdk.test.Main"); + + // remove CLASSPATH environment variable + Map env = pb.environment(); + String value = env.remove("CLASSPATH"); + + int exitCode = executeCommand(pb).getExitValue(); + if (exitCode != 0) { + throw new RuntimeException("Test failed: " + exitCode); + } + } + +} diff --git a/jdk/test/java/lang/instrument/modules/AppendToClassPathModuleTest.sh b/jdk/test/java/lang/instrument/modules/AppendToClassPathModuleTest.sh new file mode 100644 index 00000000000..5937acba058 --- /dev/null +++ b/jdk/test/java/lang/instrument/modules/AppendToClassPathModuleTest.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +# +# Copyright (c) 2016, 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 +# 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +if [ "${TESTSRC}" = "" ] +then + echo "TESTSRC not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTSRC=${TESTSRC}" + +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTJAVA=${TESTJAVA}" + +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +echo "TESTCLASSES=${TESTCLASSES}" + +mkdir -p hidden +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ + -d hidden ${TESTSRC}/../ExampleForClassPath.java + +mkdir -p classes +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ + -d classes ${TESTSRC}/../InstrumentationHandoff.java + +echo "Manifest-Version: 1.0" > Agent.mf +echo "Class-Path: hidden/" >> Agent.mf +echo "Premain-Class: InstrumentationHandoff" >> Agent.mf + +${TESTJAVA}/bin/jar ${TESTTOOLVMOPTS} cvfm Agent.jar \ + Agent.mf -C classes InstrumentationHandoff.class diff --git a/jdk/test/java/lang/instrument/modules/src/test/jdk/test/Main.java b/jdk/test/java/lang/instrument/modules/src/test/jdk/test/Main.java new file mode 100644 index 00000000000..94b05e41712 --- /dev/null +++ b/jdk/test/java/lang/instrument/modules/src/test/jdk/test/Main.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, 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 + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test; + +/** + * Launched by AppendToClassPathModuleTest. + */ +public class Main { + public static void main(String... args) throws Exception { + // "java.class.path" system property is expected to be empty. + String value = System.getProperty("java.class.path"); + if (!value.isEmpty()) { + throw new RuntimeException("Non-empty java.class.path=" + value); + } + + // load the "hidden" class that should be loaded by the system loader + Class c = Class.forName("ExampleForClassPath"); + if (c.getClassLoader() != ClassLoader.getSystemClassLoader()) { + throw new RuntimeException(c + " loaderd by " + c.getClassLoader()); + } + } +} diff --git a/jdk/test/java/lang/instrument/modules/src/test/module-info.java b/jdk/test/java/lang/instrument/modules/src/test/module-info.java new file mode 100644 index 00000000000..92ea019a3eb --- /dev/null +++ b/jdk/test/java/lang/instrument/modules/src/test/module-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016, 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 + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module test { +} diff --git a/jdk/test/tools/launcher/modules/classpath/JavaClassPathTest.java b/jdk/test/tools/launcher/modules/classpath/JavaClassPathTest.java index 72afcb06fc0..634a27fa95c 100644 --- a/jdk/test/tools/launcher/modules/classpath/JavaClassPathTest.java +++ b/jdk/test/tools/launcher/modules/classpath/JavaClassPathTest.java @@ -21,12 +21,14 @@ * questions. */ +import java.io.BufferedWriter; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.spi.ToolProvider; import jdk.testlibrary.OutputAnalyzer; import org.testng.annotations.BeforeTest; @@ -42,6 +44,7 @@ import static jdk.testlibrary.ProcessTools.*; * @summary Test the default class path if -Djava.class.path is set * @library /lib/testlibrary * @modules jdk.compiler + * jdk.jartool * @build CompilerUtils jdk.testlibrary.* * @run testng JavaClassPathTest */ @@ -50,6 +53,7 @@ public class JavaClassPathTest { private static final Path SRC_DIR = Paths.get(System.getProperty("test.src"), "src"); private static final Path MODS_DIR = Paths.get("mods"); + private static final Path LIB_DIR = Paths.get("lib"); private static final String TEST_MODULE = "m"; private static final String TEST_MAIN = "jdk.test.Main"; @@ -66,27 +70,47 @@ public class JavaClassPathTest { Path res = Paths.get("jdk/test/res.properties"); Files.createFile(res); + + ToolProvider jartool = ToolProvider.findFirst("jar").orElseThrow( + () -> new RuntimeException("jar tool not found") + ); + + Path jarfile = LIB_DIR.resolve("m.jar"); + Files.createDirectories(LIB_DIR); + assertTrue(jartool.run(System.out, System.err, "cfe", + jarfile.toString(), TEST_MAIN, + file.toString()) == 0); + + Path manifest = LIB_DIR.resolve("manifest"); + try (BufferedWriter writer = Files.newBufferedWriter(manifest)) { + writer.write("CLASS-PATH: lib/m.jar"); + } + jarfile = LIB_DIR.resolve("m1.jar"); + assertTrue(jartool.run(System.out, System.err, "cfme", + jarfile.toString(), manifest.toString(), TEST_MAIN, + file.toString()) == 0); } @DataProvider(name = "classpath") public Object[][] classpath() { return new Object[][]{ // true indicates that class path default to current working directory - { "", true }, - { "-Djava.class.path", true }, - { "-Djava.class.path=", true }, - { "-Djava.class.path=.", true }, + { "", "." }, + { "-Djava.class.path", "." }, + { "-Djava.class.path=", "" }, + { "-Djava.class.path=.", "." }, }; } @Test(dataProvider = "classpath") - public void testUnnamedModule(String option, boolean expected) throws Throwable { + public void testUnnamedModule(String option, String expected) throws Throwable { List args = new ArrayList<>(); if (!option.isEmpty()) { args.add(option); } args.add(TEST_MAIN); - args.add(Boolean.toString(expected)); + args.add(Boolean.toString(true)); + args.add(expected); assertTrue(execute(args).getExitValue() == 0); } @@ -95,15 +119,14 @@ public class JavaClassPathTest { public Object[][] moduleAndClassPath() { return new Object[][]{ // true indicates that class path default to current working directory - { "", false }, - { "-Djava.class.path", false }, - { "-Djava.class.path=", false }, - { "-Djava.class.path=.", true }, + { "", "" }, + { "-Djava.class.path", "" }, + { "-Djava.class.path=", "" }, }; } @Test(dataProvider = "moduleAndClassPath") - public void testNamedModule(String option, boolean expected) throws Throwable { + public void testNamedModule(String option, String expected) throws Throwable { List args = new ArrayList<>(); if (!option.isEmpty()) { args.add(option); @@ -112,7 +135,61 @@ public class JavaClassPathTest { args.add(MODS_DIR.toString()); args.add("-m"); args.add(TEST_MODULE + "/" + TEST_MAIN); - args.add(Boolean.toString(expected)); + // not default to CWD + args.add(Boolean.toString(false)); + args.add(expected); + + + assertTrue(execute(args).getExitValue() == 0); + } + + @Test + public void testClassPath() throws Throwable { + List args = new ArrayList<>(); + args.add("-Djava.class.path=."); + args.add("--module-path"); + args.add(MODS_DIR.toString()); + args.add("-m"); + args.add(TEST_MODULE + "/" + TEST_MAIN); + args.add(Boolean.toString(true)); + args.add("."); + + assertTrue(execute(args).getExitValue() == 0); + } + + @Test + public void testJAR() throws Throwable { + String jarfile = LIB_DIR.resolve("m.jar").toString(); + List args = new ArrayList<>(); + args.add("-jar"); + args.add(jarfile); + args.add(Boolean.toString(false)); + args.add(jarfile); + + assertTrue(execute(args).getExitValue() == 0); + } + + /* + * Test CLASS-PATH attribute in manifest + */ + @Test + public void testClassPathAttribute() throws Throwable { + String jarfile = LIB_DIR.resolve("m1.jar").toString(); + + List args = new ArrayList<>(); + args.add("-jar"); + args.add(jarfile); + args.add(Boolean.toString(false)); + args.add(jarfile); + + assertTrue(execute(args).getExitValue() == 0); + + args.clear(); + args.add("-cp"); + args.add(jarfile); + args.add(TEST_MAIN); + args.add(Boolean.toString(false)); + args.add(jarfile); assertTrue(execute(args).getExitValue() == 0); } diff --git a/jdk/test/tools/launcher/modules/classpath/src/m/jdk/test/Main.java b/jdk/test/tools/launcher/modules/classpath/src/m/jdk/test/Main.java index 41e7cd8717d..8a6c671ae89 100644 --- a/jdk/test/tools/launcher/modules/classpath/src/m/jdk/test/Main.java +++ b/jdk/test/tools/launcher/modules/classpath/src/m/jdk/test/Main.java @@ -29,13 +29,14 @@ public class Main { static final String JAVA_CLASS_PATH = "java.class.path"; public static void main(String[] args) throws Exception { + boolean expected = args[0].equals("true"); + String cpath = args.length > 1 ? args[1] : ""; String value = System.getProperty(JAVA_CLASS_PATH); - if (value == null) { - throw new RuntimeException(JAVA_CLASS_PATH + " is expected non-null" + - " for compatibility"); + if (!value.equals(cpath)) { + throw new RuntimeException(JAVA_CLASS_PATH + "=" + value + + " expected=" + cpath); } - boolean expected = args[0].equals("true"); ClassLoader loader = ClassLoader.getSystemClassLoader(); URL url = loader.getResource("jdk/test/res.properties"); if ((expected && url == null) || (!expected && url != null)) {