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:24:20 UTC

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

     [ https://issues.apache.org/jira/browse/BCEL-280?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Max Kammerer updated BCEL-280:
------------------------------
    Attachment: sample-project.zip

> 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
>         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.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)