You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Max Kammerer (JIRA)" <ji...@apache.org> on 2016/09/03 10:22:20 UTC

[jira] [Created] (BCEL-280) MethodGen.setMaxLocals() should take in account local variables defined in Local Variable table

Max Kammerer created BCEL-280:
---------------------------------

             Summary: 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


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.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 = 
{code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)