8230776: Javac throws AssertionError in jvm.Gen.visitExec

8231311: javac throws NPE in TransTypes.retype
8230964: Javac throws AssertionError in PoolReader.resolve
8230963: javac throws j.l.CCE in PoolReader.getName
8230919: javac throws j.l.CCE in ClassReader.readClass

Reviewed-by: jlahoda
This commit is contained in:
Vicente Romero 2020-09-01 14:31:18 -04:00
parent 9924c45fae
commit e19022e515
10 changed files with 477 additions and 11 deletions

View File

@ -2214,6 +2214,7 @@ public class ClassReader {
Integer.toString(minorVersion));
}
}
validateMethodType(name, type);
if (name == names.init && currentOwner.hasOuterInstance()) {
// Sometimes anonymous classes don't have an outer
// instance, however, there is no reliable way to tell so
@ -2241,6 +2242,7 @@ public class ClassReader {
} finally {
currentOwner = prevOwner;
}
validateMethodType(name, m.type);
setParameters(m, type);
if ((flags & VARARGS) != 0) {
@ -2254,6 +2256,13 @@ public class ClassReader {
return m;
}
void validateMethodType(Name name, Type t) {
if ((!t.hasTag(TypeTag.METHOD) && !t.hasTag(TypeTag.FORALL)) ||
(name == names.init && !t.getReturnType().hasTag(TypeTag.VOID))) {
throw badClassFile("method.descriptor.invalid", name);
}
}
private List<Type> adjustMethodParams(long flags, List<Type> args) {
if (args.isEmpty()) {
return args;
@ -2478,6 +2487,9 @@ public class ClassReader {
Integer.toString(minorVersion));
}
c.flags_field = flags;
if (c.owner.kind != MDL) {
throw badClassFile("module.info.definition.expected");
}
currentModule = (ModuleSymbol) c.owner;
int this_class = nextChar();
// temp, no check on this_class

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, 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
@ -36,6 +36,9 @@ import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Name.NameMapper;
import com.sun.tools.javac.util.Names;
import java.util.Arrays;
import java.util.BitSet;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Dynamic;
@ -88,11 +91,27 @@ public class PoolReader {
this.syms = syms;
}
private static final BitSet classCP = new BitSet();
private static final BitSet constantCP = new BitSet();
private static final BitSet moduleCP = new BitSet();
private static final BitSet packageCP = new BitSet();
private static final BitSet utf8CP = new BitSet();
private static final BitSet nameAndTypeCP = new BitSet();
static {
classCP.set(CONSTANT_Class);
constantCP.set(CONSTANT_Integer, CONSTANT_String + 1); // the toIndex is exclusive
moduleCP.set(CONSTANT_Module);
packageCP.set(CONSTANT_Package);
utf8CP.set(CONSTANT_Utf8);
nameAndTypeCP.set(CONSTANT_NameandType);
}
/**
* Get a class symbol from the pool at given index.
*/
ClassSymbol getClass(int index) {
return pool.readIfNeeded(index);
return pool.readIfNeeded(index, classCP);
}
/**
@ -120,14 +139,14 @@ public class PoolReader {
* Get a module symbol from the pool at given index.
*/
ModuleSymbol getModule(int index) {
return pool.readIfNeeded(index);
return pool.readIfNeeded(index, moduleCP);
}
/**
* Get a module symbol from the pool at given index.
*/
PackageSymbol getPackage(int index) {
return pool.readIfNeeded(index);
return pool.readIfNeeded(index, packageCP);
}
/**
@ -141,7 +160,7 @@ public class PoolReader {
* Get a name from the pool at given index.
*/
Name getName(int index) {
return pool.readIfNeeded(index);
return pool.readIfNeeded(index, utf8CP);
}
/**
@ -155,14 +174,14 @@ public class PoolReader {
* Get a name and type pair from the pool at given index.
*/
NameAndType getNameAndType(int index) {
return pool.readIfNeeded(index);
return pool.readIfNeeded(index, nameAndTypeCP);
}
/**
* Get a class symbol from the pool at given index.
*/
Object getConstant(int index) {
return pool.readIfNeeded(index);
return pool.readIfNeeded(index, constantCP);
}
boolean hasTag(int index, int tag) {
@ -171,12 +190,14 @@ public class PoolReader {
private <Z> Z getUtf8(int index, NameMapper<Z> mapper) {
int tag = pool.tag(index);
int offset = pool.offset(index);
if (tag == CONSTANT_Utf8) {
int offset = pool.offset(index);
int len = pool.poolbuf.getChar(offset);
return mapper.map(pool.poolbuf.elems, offset + 2, len);
} else {
throw new AssertionError("Unexpected constant tag: " + tag);
throw reader.badClassFile("unexpected.const.pool.tag.at",
Integer.toString(tag),
Integer.toString(offset - 1));
}
}
@ -215,7 +236,9 @@ public class PoolReader {
return syms.enterModule(name);
}
default:
throw new AssertionError("Unexpected constant tag: " + tag);
throw reader.badClassFile("unexpected.const.pool.tag.at",
Integer.toString(tag),
Integer.toString(offset - 1));
}
}
@ -311,11 +334,15 @@ public class PoolReader {
}
@SuppressWarnings("unchecked")
<P> P readIfNeeded(int index) {
<P> P readIfNeeded(int index, BitSet expectedTags) {
Object v = values[checkIndex(index)];
if (v != null) {
return (P)v;
} else {
int currentTag = tag(index);
if (!expectedTags.get(currentTag)) {
throw reader.badClassFile("unexpected.const.pool.tag.at", tag(index), offset(index));
}
P p = (P)resolve(poolbuf, tag(index), offset(index));
values[index] = p;
return p;

View File

@ -2279,6 +2279,9 @@ compiler.misc.bad.const.pool.tag=\
compiler.misc.bad.const.pool.tag.at=\
bad constant pool tag: {0} at {1}
compiler.misc.unexpected.const.pool.tag.at=\
unexpected constant pool tag: {0} at {1}
compiler.misc.bad.signature=\
bad signature: {0}
@ -2322,6 +2325,9 @@ compiler.misc.invalid.static.interface=\
compiler.misc.anachronistic.module.info=\
module declaration found in version {0}.{1} classfile
compiler.misc.module.info.definition.expected=\
module-info definition expected
# 0: name
compiler.misc.file.doesnt.contain.class=\
file does not contain class {0}
@ -2336,6 +2342,10 @@ compiler.misc.file.does.not.contain.module=\
compiler.misc.illegal.start.of.class.file=\
illegal start of class file
# 0: name
compiler.misc.method.descriptor.invalid=\
method descriptor invalid for {0}
compiler.misc.unable.to.access.file=\
unable to access file: {0}

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2020, 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 8230776 8231311 8230964 8230919 8230963
* @summary Javac throws AssertionError on fussed class files
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.javac.util
* @library /tools/lib
* @build toolbox.ToolBox toolbox.JavacTask toolbox.TestRunner
* @compile Test1.jcod
* @compile Test2.jcod
* @compile Test3.jcod
* @compile Test4.jcod
* @compile Test5.jcod
* @run main AssertionsReadingClassfilesTest
*/
import toolbox.JavacTask;
import toolbox.Task;
import toolbox.ToolBox;
import toolbox.TestRunner;
public class AssertionsReadingClassfilesTest extends TestRunner {
static final String SubSrc = "class Sub extends Test#ID {}";
static final String expectedOuputBadDescriptor = "Sub.java:1:19: compiler.err.cant.access: Test#ID, " +
"(compiler.misc.bad.class.file.header: Test#ID.class, (compiler.misc.method.descriptor.invalid: <init>))";
private final ToolBox tb = new ToolBox();
public AssertionsReadingClassfilesTest() {
super(System.err);
}
public static void main(String... args) throws Exception {
new AssertionsReadingClassfilesTest().runTests();
}
@Test
public void testBadDescriptor() {
testHelper(SubSrc.replaceAll("#ID", "1"), expectedOuputBadDescriptor.replaceAll("#ID", "1"));
testHelper(SubSrc.replaceAll("#ID", "2"), expectedOuputBadDescriptor.replaceAll("#ID", "2"));
}
private void testHelper(String src, String expectedMsg) {
String javacOut = new JavacTask(tb)
.sources(src)
.classpath(System.getProperty("test.classes"))
.options("-XDrawDiagnostics")
.run(Task.Expect.FAIL)
.writeAll()
.getOutput(Task.OutputKind.DIRECT);
if (!javacOut.contains(expectedMsg)) {
throw new AssertionError("test failed, unexpected output");
}
}
@Test
public void testBadSuperClass() {
String expectedOutput =
"Sub.java:1:19: compiler.err.cant.access: Test3, (compiler.misc.bad.class.file.header: Test3.class, " +
"(compiler.misc.unexpected.const.pool.tag.at: 10, 11))";
testHelper(SubSrc.replaceAll("#ID", "3"), expectedOutput);
}
@Test
public void testModuleInfoExpected() {
String expectedOutput =
"Sub.java:1:19: compiler.err.cant.access: Test4, (compiler.misc.bad.class.file.header: Test4.class, " +
"(compiler.misc.module.info.definition.expected))";
testHelper(SubSrc.replaceAll("#ID", "4"), expectedOutput);
}
@Test
public void testUnexpectedCPEntry() {
String expectedOutput =
"Sub.java:1:19: compiler.err.cant.access: Test5, (compiler.misc.bad.class.file.header: Test5.class, " +
"(compiler.misc.unexpected.const.pool.tag.at: 12, 88))";
testHelper(SubSrc.replaceAll("#ID", "5"), expectedOutput);
}
}

View File

@ -0,0 +1,62 @@
class Test1 {
0xCAFEBABE;
0; // minor version
60; // version
[13] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "java/lang/Object"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2A
Utf8 "()F"; // #6 at 0x33
class #8; // #7 at 0x39
Utf8 "Test1"; // #8 at 0x3C
Utf8 "Code"; // #9 at 0x43
Utf8 "LineNumberTable"; // #10 at 0x4A
Utf8 "SourceFile"; // #11 at 0x5C
Utf8 "Test1.java"; // #12 at 0x69
} // Constant Pool
0x0021; // access [ ACC_PUBLIC ACC_SUPER ]
#7;// this_cpx
#2;// super_cpx
[0] { // Interfaces
} // Interfaces
[0] { // Fields
} // Fields
[1] { // Methods
{ // method at 0x81
0x0001; // access
#5; // name_index : <init>
#6; // descriptor_index : ()F
[1] { // Attributes
Attr(#9, 29) { // Code at 0x89
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB70001B1;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#10, 6) { // LineNumberTable at 0xA0
[1] { // line_number_table
0 2; // at 0xAC
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
}
} // Methods
[1] { // Attributes
Attr(#11, 2) { // SourceFile at 0xAE
#12;
} // end SourceFile
} // Attributes
} // end class Test1

View File

@ -0,0 +1,62 @@
class Test2 {
0xCAFEBABE;
0; // minor version
60; // version
[] { // Constant Pool
; // first element is empty
Method #2 #3; // #1
class #4; // #2
NameAndType #5 #6; // #3
Utf8 "java/lang/Object"; // #4
Utf8 "<init>"; // #5
Utf8 "*)V"; // #6
class #8; // #7
Utf8 "Test2"; // #8
Utf8 "Code"; // #9
Utf8 "LineNumberTable"; // #10
Utf8 "SourceFile"; // #11
Utf8 "Test2.java"; // #12
} // Constant Pool
0x0021; // access
#7;// this_cpx
#2;// super_cpx
[] { // Interfaces
} // Interfaces
[] { // Fields
} // Fields
[] { // Methods
{ // method
0x0001; // access
#5; // name_index
#6; // descriptor_index
[] { // Attributes
Attr(#9) { // Code
1; // max_stack
1; // max_locals
Bytes[]{
0x2AB70001B1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#10) { // LineNumberTable
[] { // line_number_table
0 1;
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
}
} // Methods
[] { // Attributes
Attr(#11) { // SourceFile
#12;
} // end SourceFile
} // Attributes
} // end class Test2

View File

@ -0,0 +1,62 @@
class Test3 {
0xCAFEBABE;
0; // minor version
56; // version
[] { // Constant Pool
; // first element is empty
Method #3 #10; // #1
class #11; // #2
class #12; // #3
Utf8 "<init>"; // #4
Utf8 "()V"; // #5
Utf8 "Code"; // #6
Utf8 "LineNumberTable"; // #7
Utf8 "SourceFile"; // #8
Utf8 "Test3.java"; // #9
NameAndType #4 #5; // #10
Utf8 "Test3"; // #11
Utf8 "java/lang/Object"; // #12
} // Constant Pool
0x0021; // access
#2;// this_cpx
#1;// super_cpx
[] { // Interfaces
} // Interfaces
[] { // Fields
} // Fields
[] { // Methods
{ // method
0x0001; // access
#4; // name_index
#5; // descriptor_index
[] { // Attributes
Attr(#6) { // Code
1; // max_stack
1; // max_locals
Bytes[]{
0x2AB70001B1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#7) { // LineNumberTable
[] { // line_number_table
0 1;
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
}
} // Methods
[] { // Attributes
Attr(#8) { // SourceFile
#9;
} // end SourceFile
} // Attributes
} // end class Test3

View File

@ -0,0 +1,62 @@
class Test4 {
0xCAFEBABE;
0; // minor version
60; // version
[] { // Constant Pool
; // first element is empty
Method #2 #3; // #1
class #4; // #2
NameAndType #5 #6; // #3
Utf8 "java/lang/Object"; // #4
Utf8 "<init>"; // #5
Utf8 "()V"; // #6
class #8; // #7
Utf8 "Test4"; // #8
Utf8 "Code"; // #9
Utf8 "LineNumberTable"; // #10
Utf8 "SourceFile"; // #11
Utf8 "Test4.java"; // #12
} // Constant Pool
0x8021; // access
#7;// this_cpx
#2;// super_cpx
[] { // Interfaces
} // Interfaces
[] { // Fields
} // Fields
[] { // Methods
{ // method
0x0001; // access
#5; // name_index
#6; // descriptor_index
[] { // Attributes
Attr(#9) { // Code
1; // max_stack
1; // max_locals
Bytes[]{
0x2AB70001B1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#10) { // LineNumberTable
[] { // line_number_table
0 1;
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
}
} // Methods
[] { // Attributes
Attr(#11) { // SourceFile
#12;
} // end SourceFile
} // Attributes
} // end class Test4

View File

@ -0,0 +1,62 @@
class Test5 {
0xCAFEBABE;
0; // minor version
56; // version
[] { // Constant Pool
; // first element is empty
Method #3 #10; // #1
class #10; // #2
class #12; // #3
Utf8 "<init>"; // #4
Utf8 "()V"; // #5
Utf8 "Code"; // #6
Utf8 "LineNumberTable"; // #7
Utf8 "SourceFile"; // #8
Utf8 "Test5.java"; // #9
NameAndType #4 #5; // #10
Utf8 "Test5"; // #11
Utf8 "java/lang/Object"; // #12
} // Constant Pool
0x0021; // access
#2;// this_cpx
#3;// super_cpx
[] { // Interfaces
} // Interfaces
[] { // Fields
} // Fields
[] { // Methods
{ // method
0x0001; // access
#4; // name_index
#5; // descriptor_index
[] { // Attributes
Attr(#6) { // Code
8193; // max_stack
1; // max_locals
Bytes[]{
0x2AB70001B1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#7) { // LineNumberTable
[] { // line_number_table
0 1;
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
}
} // Methods
[] { // Attributes
Attr(#8) { // SourceFile
#9;
} // end SourceFile
} // Attributes
} // end class #4 #5

View File

@ -48,6 +48,7 @@ compiler.err.unsupported.cross.fp.lit # Scanner: host system d
compiler.misc.bad.class.signature # bad class file
compiler.misc.bad.const.pool.tag # bad class file
compiler.misc.bad.const.pool.tag.at # bad class file
compiler.misc.unexpected.const.pool.tag.at # bad class file
compiler.misc.bad.const.pool.index # bad class file
compiler.misc.bad.constant.range # bad class file
compiler.misc.bad.constant.value # bad class file
@ -76,6 +77,8 @@ compiler.misc.kindname.static
compiler.misc.kindname.type.variable
compiler.misc.kindname.type.variable.bound
compiler.misc.kindname.value
compiler.misc.method.descriptor.invalid # bad class file
compiler.misc.module.info.definition.expected # bad class file
compiler.misc.module.name.mismatch
compiler.misc.module.non.zero.opens # bad class file
compiler.misc.no.unique.minimal.instance.exists