NoAbortForBadClassFile.java revision 4254:d601b22360fa
19313Ssos/* 29313Ssos * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 39313Ssos * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 49313Ssos * 59313Ssos * This code is free software; you can redistribute it and/or modify it 69313Ssos * under the terms of the GNU General Public License version 2 only, as 79313Ssos * published by the Free Software Foundation. 89313Ssos * 9111798Sdes * This code is distributed in the hope that it will be useful, but WITHOUT 109313Ssos * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 119313Ssos * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 129313Ssos * version 2 for more details (a copy is included in the LICENSE file that 139313Ssos * accompanied this code). 149313Ssos * 1597748Sschweikh * You should have received a copy of the GNU General Public License version 169313Ssos * 2 along with this work; if not, write to the Free Software Foundation, 179313Ssos * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 189313Ssos * 199313Ssos * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 209313Ssos * or visit www.oracle.com if you need additional information or have any 219313Ssos * questions. 229313Ssos */ 239313Ssos 249313Ssos/** 259313Ssos * @test 269313Ssos * @bug 8182450 279313Ssos * @summary Bad classfiles should not abort compilations 289313Ssos * @library /tools/lib 29116173Sobrien * @modules 30116173Sobrien * jdk.compiler/com.sun.tools.javac.api 31116173Sobrien * jdk.compiler/com.sun.tools.javac.code 32156874Sru * jdk.compiler/com.sun.tools.javac.comp 33101189Srwatson * jdk.compiler/com.sun.tools.javac.jvm 3431784Seivind * jdk.compiler/com.sun.tools.javac.main 359313Ssos * jdk.compiler/com.sun.tools.javac.processing 369313Ssos * jdk.compiler/com.sun.tools.javac.util 3776166Smarkm * @build toolbox.ToolBox toolbox.JavacTask 3876166Smarkm * @run main NoAbortForBadClassFile 399313Ssos */ 409313Ssos 419313Ssosimport java.nio.file.Files; 4231561Sbdeimport java.nio.file.Path; 43101189Srwatsonimport java.nio.file.Paths; 449313Ssosimport java.util.ArrayList; 4572538Sjlemonimport java.util.Arrays; 4676166Smarkmimport java.util.Collections; 4776166Smarkmimport java.util.List; 48102814Siedowseimport java.util.stream.Collectors; 4976166Smarkmimport java.util.stream.Stream; 5014331Speter 5176166Smarkmimport com.sun.tools.javac.api.JavacTaskImpl; 5212458Sbdeimport com.sun.tools.javac.api.JavacTool; 5372538Sjlemonimport com.sun.tools.javac.code.Flags; 5472538Sjlemonimport com.sun.tools.javac.code.Symbol.ClassSymbol; 5572538Sjlemonimport com.sun.tools.javac.code.Symbol.CompletionFailure; 5672538Sjlemonimport com.sun.tools.javac.code.Symtab; 57140214Sobrienimport com.sun.tools.javac.jvm.ClassReader; 58140214Sobrienimport com.sun.tools.javac.util.Context; 59140214Sobrienimport com.sun.tools.javac.util.Context.Factory; 60140214Sobrienimport com.sun.tools.javac.util.Names; 6164905Smarcelimport com.sun.tools.javac.util.Options; 6268583Smarcelimport toolbox.Task; 63133816Stjrimport toolbox.Task.Expect; 6464905Smarcel 659313Ssosimport toolbox.TestRunner; 669313Ssosimport toolbox.ToolBox; 6783366Sjulian 689313Ssospublic class NoAbortForBadClassFile extends TestRunner { 69102814Siedowse 70102814Siedowse private ToolBox tb = new ToolBox(); 719313Ssos 72102814Siedowse public NoAbortForBadClassFile() { 7314331Speter super(System.out); 749313Ssos } 7572543Sjlemon 76102814Siedowse public static void main(String... args) throws Exception { 779313Ssos new NoAbortForBadClassFile().runTests(m -> new Object[] { Paths.get(m.getName()) }); 78102814Siedowse } 79102814Siedowse 80102814Siedowse @Test 81102814Siedowse public void testBrokenClassFile(Path base) throws Exception { 829313Ssos Path classes = base.resolve("classes"); 839313Ssos Path brokenClassFile = classes.resolve("test").resolve("Broken.class"); 849313Ssos 8583366Sjulian Files.createDirectories(brokenClassFile.getParent()); 869313Ssos Files.newOutputStream(brokenClassFile).close(); 8783382Sjhb 88102814Siedowse Path src = base.resolve("src"); 89102814Siedowse tb.writeJavaFiles(src, 9014331Speter "package test; public class Test { private void test() { Broken b; String.unknown(); } }"); 9114331Speter Path out = base.resolve("out"); 92102814Siedowse tb.createDirectories(out); 9314331Speter 94102814Siedowse List<String> log = new toolbox.JavacTask(tb) 9514331Speter .options("-classpath", classes.toString(), 969313Ssos "-XDrawDiagnostics") 9772543Sjlemon .outdir(out) 9872543Sjlemon .files(tb.findJavaFiles(src)) 99102814Siedowse .run(Expect.FAIL) 1009313Ssos .writeAll() 101102814Siedowse .getOutputLines(Task.OutputKind.DIRECT); 1029313Ssos 103102814Siedowse List<String> expectedOut = Arrays.asList( 104111798Sdes "Test.java:1:57: compiler.err.cant.access: test.Broken, (compiler.misc.bad.class.file.header: Broken.class, (compiler.misc.class.file.wrong.class: java.lang.AutoCloseable))", 105102814Siedowse "Test.java:1:73: compiler.err.cant.resolve.location.args: kindname.method, unknown, , , (compiler.misc.location: kindname.class, java.lang.String, null)", 1069313Ssos "2 errors" 107102814Siedowse ); 1089313Ssos 109102814Siedowse if (!expectedOut.equals(log)) 1109313Ssos throw new Exception("expected output not found: " + log); 111102814Siedowse } 1129313Ssos 113102814Siedowse @Test 1149313Ssos public void testLoading(Path base) throws Exception { 115102814Siedowse Path src = base.resolve("src"); 1169313Ssos tb.writeJavaFiles(src, 117102814Siedowse "public class Test { static { new Object() {}; } public static class I { public static class II { } } }"); 1189313Ssos Path out = base.resolve("out"); 119102814Siedowse tb.createDirectories(out); 1209313Ssos 121102814Siedowse new toolbox.JavacTask(tb) 1229313Ssos .outdir(out) 123102814Siedowse .files(tb.findJavaFiles(src)) 1249313Ssos .run(Expect.SUCCESS) 125102814Siedowse .writeAll() 1269313Ssos .getOutputLines(Task.OutputKind.DIRECT); 127102814Siedowse 12870061Sjhb List<Path> files; 129102814Siedowse try (Stream<Path> dir = Files.list(out)) { 1309313Ssos files = dir.collect(Collectors.toList()); 13189306Salfred } 1329313Ssos 133113917Sjhb List<List<Path>> result = new ArrayList<>(); 13489319Salfred 13589319Salfred permutations(files, Collections.emptyList(), result); 13689319Salfred 137102003Srwatson for (List<Path> order : result) { 138102003Srwatson for (Path missing : order) { 13989319Salfred Path test = base.resolve("test"); 14089319Salfred 14191140Stanimura if (Files.exists(test)) { 14270061Sjhb tb.cleanDirectory(test); 14314331Speter } else { 14472543Sjlemon tb.createDirectories(test); 14572543Sjlemon } 14614331Speter 14791140Stanimura for (Path p : order) { 148102814Siedowse Files.copy(p, test.resolve(p.getFileName())); 1499313Ssos } 1509313Ssos 1519313Ssos List<String> actual = complete(test, order, missing, true); 1529313Ssos 15383366Sjulian Files.delete(test.resolve(missing.getFileName())); 1549313Ssos 1559313Ssos List<String> expected = complete(test, order, missing, false); 15612858Speter 15712858Speter if (!actual.equals(expected)) { 1589313Ssos throw new AssertionError("Unexpected state, actual=\n" + actual + "\nexpected=\n" + expected + "\norder=" + order + "\nmissing=" + missing); 15912858Speter } 1609313Ssos } 16112858Speter } 1629313Ssos } 1639313Ssos 1649313Ssos private static void permutations(List<Path> todo, List<Path> currentList, List<List<Path>> result) { 16572543Sjlemon if (todo.isEmpty()) { 16672543Sjlemon result.add(currentList); 16783221Smarcel return ; 1689313Ssos } 16912858Speter 17012858Speter for (Path p : todo) { 1719313Ssos List<Path> nextTODO = new ArrayList<>(todo); 17283366Sjulian 1739313Ssos nextTODO.remove(p); 1749313Ssos 1759313Ssos List<Path> nextList = new ArrayList<>(currentList); 17614331Speter 17783366Sjulian nextList.add(p); 17814331Speter 17914331Speter permutations(nextTODO, nextList, result); 18014331Speter } 18114331Speter } 18214331Speter 18314331Speter private List<String> complete(Path test, List<Path> order, Path missing, boolean badClassFile) { 18472543Sjlemon Context context = new Context(); 18572543Sjlemon if (badClassFile) { 18672543Sjlemon TestClassReader.preRegister(context); 18714331Speter } 18814331Speter JavacTool tool = JavacTool.create(); 18914331Speter JavacTaskImpl task = (JavacTaskImpl) tool.getTask(null, null, null, List.of("-classpath", test.toString(), "-XDblockClass=" + flatName(missing)), null, null, context); 19014331Speter Symtab syms = Symtab.instance(context); 19114331Speter Names names = Names.instance(context); 19214331Speter 19314331Speter task.getElements().getTypeElement("java.lang.Object"); 19483366Sjulian 19514331Speter if (!badClassFile) { 19614331Speter //to ensure the same paths taken in ClassFinder.completeEnclosing in case the file is missing: 197111797Sdes syms.enterClass(syms.unnamedModule, names.fromString(flatName(missing))); 19814331Speter } 19914331Speter 20083366Sjulian List<String> result = new ArrayList<>(); 20114331Speter 20214331Speter for (Path toCheck : order) { 20314331Speter ClassSymbol sym = syms.enterClass(syms.unnamedModule, names.fromString(flatName(toCheck))); 2049313Ssos 20583366Sjulian try { 2069313Ssos sym.complete(); 20714331Speter } catch (CompletionFailure ignore) { 20814331Speter } 20914331Speter 21014331Speter long flags = sym.flags_field; 21114331Speter 21283366Sjulian flags &= ~(Flags.CLASS_SEEN | Flags.SOURCE_SEEN); 21314331Speter 21414331Speter result.add("sym: " + sym.flatname + ", " + sym.owner.flatName() + 21583221Smarcel ", " + sym.type + ", " + sym.members_field + ", " + flags); 21683221Smarcel } 21783221Smarcel 21883221Smarcel return result; 21983221Smarcel } 22083221Smarcel 22183221Smarcel private String flatName(Path p) { 22283221Smarcel return p.getFileName().toString().replace(".class", ""); 22383221Smarcel } 22483221Smarcel 22583221Smarcel private static class TestClassReader extends ClassReader { 22683221Smarcel public static void preRegister(Context ctx) { 22783221Smarcel ctx.put(classReaderKey, (Factory<ClassReader>) c -> new TestClassReader(ctx)); 22883221Smarcel } 22983221Smarcel 23083221Smarcel private final String block; 23183221Smarcel 23283221Smarcel public TestClassReader(Context context) { 23383221Smarcel super(context); 23483221Smarcel block = Options.instance(context).get("blockClass"); 23583221Smarcel } 23683221Smarcel 23783221Smarcel @Override 23883221Smarcel public void readClassFile(ClassSymbol c) { 23983221Smarcel super.readClassFile(c); 24083221Smarcel 24183221Smarcel if (c.flatname.contentEquals(block)) { 24283221Smarcel throw badClassFile("blocked"); 24383221Smarcel } 24483221Smarcel } 24583366Sjulian 24683221Smarcel } 24714331Speter 248111798Sdes} 24983221Smarcel