[
https://issues.apache.org/jira/browse/BCEL-280?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Gary D. Gregory updated BCEL-280:
---------------------------------
Fix Version/s: 6.12.1
(was: 6.12.0)
> MethodGen.setMaxLocals() should take in account local variables defined in
> Local Variable table
> -----------------------------------------------------------------------------------------------
>
> Key: BCEL-280
> URL: https://issues.apache.org/jira/browse/BCEL-280
> Project: Commons BCEL
> Issue Type: Bug
> Components: Main
> Affects Versions: 6.0
> Environment: Ubuntu 14.04, Bcel 6.0
> Reporter: Max Kammerer
> Priority: Major
> Fix For: 6.12.1
>
> Attachments: sample-project.zip
>
>
> Kotlin compiler generates additional fake local variables that are not used
> in method code, after processing such methods with BCEL fake variables are
> kept in local variable table but maxLocals value decreased to number of
> locals used in method bytecode.
> As result "java.lang.ClassFormatError: Invalid index 6 in LocalVariableTable
> in class file test/Bug2" exception is thrown at runtime on attemt to load
> newly generated class.
> Sample code:
> {code:title=bug.kt|borderStyle=solid}
> package bug
> import org.apache.bcel.classfile.ClassParser
> import org.apache.bcel.generic.ClassGen
> import org.apache.bcel.generic.MethodGen
> class Bug {
> fun test() {
> val list = arrayListOf(1, 2, 3)
> list.forEach {
> println(it)
> }
> //here additional variable are generated - see bytecode below
> }
> }
> fun main(args: Array<String>) {
> val parser =
> ClassParser(ClassLoader.getSystemClassLoader().getResourceAsStream("bug/Bug.class"),
> "Bug.class");
> val javaClass = parser.parse();
> val classGen = ClassGen(javaClass)
> classGen.className = "test.Bug2"
> val originalMethod = classGen.methods.filter { it.name == "test"
> }.single()
> classGen.removeMethod(originalMethod)
> val newMethodGen = MethodGen(originalMethod, classGen.className,
> classGen.constantPool)
> newMethodGen.setMaxLocals()
> val newMethod = newMethodGen.method
> classGen.addMethod(newMethod)
> val bug2Class = classGen.javaClass
> // Exception in thread "main" java.lang.ClassFormatError: Invalid index 6
> in LocalVariableTable in class file test/Bug2
> // at java.lang.ClassLoader.defineClass1(Native Method)
> // at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
> // at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
> // at bug.BugKt$main$1.findClass(bug.kt:53)
> // at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
> // at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
> // at bug.BugKt.main(bug.kt:58)
> object : ClassLoader(ClassLoader.getSystemClassLoader()) {
> @Throws(ClassNotFoundException::class)
> protected override fun findClass(name: String): Class<*> {
> if (name == "test.Bug2") {
> val bytes = bug2Class.bytes
> return defineClass(name, bytes, 0, bytes.size)
> }
> return super.findClass(name)
> }
> }.loadClass("test.Bug2").newInstance()
> //8 != 6
> assert(originalMethod.code.maxLocals == newMethod.code.maxLocals)
> }
> {code}
> {code:title=Bug.test() original bytecode|borderStyle=solid}
> // access flags 0x11
> public final test()V
> L0
> LINENUMBER 9 L0
> ICONST_3
> ANEWARRAY java/lang/Integer
> DUP
> ICONST_0
> ICONST_1
> INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
> AASTORE
> DUP
> ICONST_1
> ICONST_2
> INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
> AASTORE
> DUP
> ICONST_2
> ICONST_3
> INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
> AASTORE
> INVOKESTATIC kotlin/collections/CollectionsKt.arrayListOf
> ([Ljava/lang/Object;)Ljava/util/ArrayList;
> ASTORE 1
> L1
> LINENUMBER 10 L1
> ALOAD 1
> CHECKCAST java/lang/Iterable
> ASTORE 2
> NOP
> L2
> LINENUMBER 56 L2
> ALOAD 2
> INVOKEINTERFACE java/lang/Iterable.iterator ()Ljava/util/Iterator;
> ASTORE 3
> L3
> ALOAD 3
> INVOKEINTERFACE java/util/Iterator.hasNext ()Z
> IFEQ L4
> ALOAD 3
> INVOKEINTERFACE java/util/Iterator.next ()Ljava/lang/Object;
> ASTORE 4
> L5
> ALOAD 4
> CHECKCAST java/lang/Number
> INVOKEVIRTUAL java/lang/Number.intValue ()I
> ISTORE 5
> L6
> LINENUMBER 11 L6
> NOP
> L7
> GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
> ILOAD 5
> INVOKEVIRTUAL java/io/PrintStream.println (I)V
> L8
> L9
> LINENUMBER 11 L9
> L10
> LINENUMBER 12 L10
> L11
> NOP
> L12
> GOTO L3
> L4
> LINENUMBER 57 L4
> L13
> L14
> LINENUMBER 14 L14
> RETURN
> L15
> LOCALVARIABLE it I L6 L11 5
> LOCALVARIABLE $i$a$1$forEach I L6 L11 6
> LOCALVARIABLE element$iv Ljava/lang/Object; L5 L12 4
> LOCALVARIABLE $receiver$iv Ljava/lang/Iterable; L2 L13 2
> LOCALVARIABLE $i$f$forEach I L2 L13 7
> LOCALVARIABLE list Ljava/util/ArrayList; L1 L15 1
> LOCALVARIABLE this Lbug/Bug; L0 L15 0
> MAXSTACK = 4
> MAXLOCALS = 8
> {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)