[ 
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.8.3
                       (was: 6.8.2)

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

Reply via email to