非常神秘的运行时错误:堆栈上的错误类型操作数

我得到这个非常神秘的错误:

java.lang.VerifyError: Bad type on operand stack Exception Details: Location: org/bh/tools/base/strings/TestUtils.concat(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; @28: invokevirtual Reason: Type 'java/lang/Object' (current frame, stack[1]) is not assignable to 'java/lang/String' Current Frame: bci: @28 flags: { } locals: { 'java/lang/Object', 'java/lang/CharSequence' } stack: { 'java/lang/StringBuilder', 'java/lang/Object' } Bytecode: 0x0000000: 2a12 59b8 0012 2b12 43b8 0012 2ac1 005b 0x0000010: 9900 1a2a bb00 1659 b700 1a5f b600 512b 0x0000020: b600 5eb6 0052 c000 23b0 2ac1 0016 9900 0x0000030: 152a c000 162b b600 5e59 1260 b800 63c0 0x0000040: 0023 b0bb 0016 59b7 001a 2ab6 0047 2bb6 0x0000050: 005e 5912 65b8 0063 c000 23b0 Stackmap Table: same_frame(@42) same_frame(@67) at org.bh.tools.base.math.NumberConversionKtTestKt.assertNumbersClose(NumberConversionKtTest.kt:488) at org.bh.tools.base.math.NumberConversionKtTest.Number_float32Value(NumberConversionKtTest.kt:47) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:27) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:58) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) 

在这一行: https : //github.com/BlueHuskyStudios/Blue-Base/blob/ea415b702b87b7a33d90bc13221f44205c38e9f1/JVM/test/org/bh/tools/base/math/NumberConversionKtTest.kt#L488

我觉得它涉及到这个功能: https : //github.com/BlueHuskyStudios/Blue-Base/blob/ea415b702b87b7a33d90bc13221f44205c38e9f1/JVM/src/org/bh/tools/base/strings/String%20Utils.kt#L121-L154

但我不可能明白发生了什么事情。 这似乎表明,我正在调用一个ObjectTestUtils类中的CharSequence (当我运行测试触发这个时,我不认为是触摸)的连接方法,但听起来可能接近我写的另一个函数这里没有用到。

发生了什么事情,我无法理解我的头脑。 有没有人有任何想法?


同伴JetBrains错误: KT-17210

由于我没有字节码的学习,下面的所有解释都建立在一个假设上:Kotlin巧妙地再次抛出错误。

tl; dr JVM验证整个班级,而不仅仅是使用的比例。

情况发生在以下步骤:

  1. 测试运行。 Junit发现了测试并试图调用org.bh.tools.base.math.NumberConversionKtTest::Number_float32Value反射。 这触发了NumberConversionKtTest类的加载,链接和初始化。 一切都很好。
  2. 这个方法调用了org.bh.tools.base.math.NumberConversionKtTestKt.assertNumbersClose ,它在一个尚未加载的类中(注意前一个类没有的试用Kt )。 JVM找到,加载,链接并初始化它。
  3. 现在正在执行assertNumbersClose ,即创建一个新的帧并将其推入堆栈。 在执行了一些字节码之后,程序流程移动到了第488行,并找到一个方法调用指令,要求JVM执行一个位于org.bh.tools.base.strings.TestUtils类中的org.bh.tools.base.strings.TestUtils 。 这个类还没有被加载,所以JVM开始加载一个新的类。
  4. JVM加载该类,并且在验证过程中发现方法concat ,而不是assertNumbersClose使用的那个方法不好。 它停止验证与VerifyError 。 因为differingCharacters org.bh.tools.base.math.NumberConversionKtTestKt.assertNumbersClose方法还没有被执行,即没有新的框架被创建并被压入堆栈,所以它不在堆栈org.bh.tools.base.math.NumberConversionKtTestKt.assertNumbersClose ,所以你可以看到org.bh.tools.base.math.NumberConversionKtTestKt.assertNumbersClose在顶部。

可行的解决方法

您需要以某种方式修复concat方法的字节码。 你有以下这些wrokaround。

  1. 尝试升级kotlin编译器。 我记得在kotlin 1.1中修复了一些与smartcast相关的问题。
  2. 由于此错误是kotlin编译器无法为smartcast发出CHECKCAST,因此您可以尝试添加手动投射,如下所示:

     fun concat(lhs: Any, rhs: CharSequence): CharSequence { if (lhs is String) { val s: String = lhs as String return s.plus(rhs) } else if (lhs is StringBuilder) { val sb: StringBuilder= lhs as StringBuilder return sb.append(rhs) } else { return StringBuilder().append(lhs).append(rhs) } } 

    有时适用于某些人。

  3. 如果所有这些都不起作用,请切换到普通的Java并将concat放在另一个类中。 这修复了大部分(如果不是全部的话)kotlin问题。

根据Dmitry Petrov和Alexander Chernikov的说法,这是Kotlin 1.1.1中的一个编译器错误,在即将到来的1.1.2版本中已经修复。