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