From 2a19cd56258884e25f26565d7b865cc2ec931b23 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 6 Jun 2013 19:01:48 +0200 Subject: SI-2464 Resiliance against missing InnerClass attributes A classfile in the wild related to Vaadin lacked the InnerClasses attribute. As such, our class file parser treated a nested enum class as top-level, which led to a crash when trying to find its linked module. More details of the investigation are available in the JIRA comments. The test introduces a new facility to rewrite classfiles. This commit turns this situation into a logged warning, rather than crashing. Code by @paulp, test by yours truly. --- .../nsc/symtab/classfile/ClassfileParser.scala | 12 +++++--- src/partest/scala/tools/partest/BytecodeTest.scala | 35 +++++++++++++++++++--- 2 files changed, 39 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index fb927d15d3..1e84c73633 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -588,10 +588,14 @@ abstract class ClassfileParser { // sealed java enums if (jflags.isEnum) { val enumClass = sym.owner.linkedClassOfClass - if (!enumClass.isSealed) - enumClass setFlag (SEALED | ABSTRACT) - - enumClass addChild sym + enumClass match { + case NoSymbol => + devWarning(s"no linked class for java enum $sym in ${sym.owner}. A referencing class file might be missing an InnerClasses entry.") + case linked => + if (!linked.isSealed) + linked setFlag (SEALED | ABSTRACT) + linked addChild sym + } } } } diff --git a/src/partest/scala/tools/partest/BytecodeTest.scala b/src/partest/scala/tools/partest/BytecodeTest.scala index 2699083069..172fa29189 100644 --- a/src/partest/scala/tools/partest/BytecodeTest.scala +++ b/src/partest/scala/tools/partest/BytecodeTest.scala @@ -2,10 +2,9 @@ package scala.tools.partest import scala.tools.nsc.util.JavaClassPath import scala.collection.JavaConverters._ -import scala.tools.asm -import asm.{ ClassReader } -import asm.tree.{ClassNode, MethodNode, InsnList} -import java.io.InputStream +import scala.tools.asm.{ClassWriter, ClassReader} +import scala.tools.asm.tree.{ClassNode, MethodNode, InsnList} +import java.io.{FileOutputStream, FileInputStream, File => JFile, InputStream} import AsmNode._ /** @@ -127,3 +126,31 @@ abstract class BytecodeTest extends ASMConverters { new JavaClassPath(containers, DefaultJavaContext) } } + +object BytecodeTest { + /** Parse `file` as a class file, transforms the ASM representation with `f`, + * and overwrites the orginal file. + */ + def modifyClassFile(file: JFile)(f: ClassNode => ClassNode) { + val rfile = new reflect.io.File(file) + def readClass: ClassNode = { + val cr = new ClassReader(rfile.toByteArray()) + val cn = new ClassNode() + cr.accept(cn, 0) + cn + } + + def writeClass(cn: ClassNode) { + val writer = new ClassWriter(0) + cn.accept(writer) + val os = rfile.bufferedOutput() + try { + os.write(writer.toByteArray) + } finally { + os.close() + } + } + + writeClass(f(readClass)) + } +} -- cgit v1.2.3