混淆导致 VerifyError: Expecting a stackmap frame

Posted

技术标签:

【中文标题】混淆导致 VerifyError: Expecting a stackmap frame【英文标题】:Obfuscation causes VerifyError: Expecting a stackmap frame 【发布时间】:2013-11-24 14:05:36 【问题描述】:

我们正在使用最新的 JDK 7 (u45) 和 ProGuard 4.10 版

最近开始我们的分发失败,在混淆之后,出现以下错误:

Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at
branch target 155
Exception Details:
  Location:
    com/bla/bla/service/ioc/SpringBootstrap.c()V @0: getstatic
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0000000: b200 73b6 008b 9900 82b2 0073 b800 933b
    0000010: 1a99 0074 b200 73b6 008d 9900 6bb2 0074
    0000020: 1221 b600 cfb8 0092 4c2b b600 9c12 1db9
    ...
  Exception Handler Table:
    bci [0, 152] => handler: 155

        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
        at java.lang.Class.getMethod0(Unknown Source)
        at java.lang.Class.getMethod(Unknown Source)
        at sun.launcher.LauncherHelper.getMainMethod(Unknown Source)
        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

我在 *** 上发现了几个关于这个主题的讨论,比如

java-lang-verifyerror-expecting-a-stackmap-frame-at-branch-target-jdk-1-7 java-lang-verifyerror-expecting-a-stackmap-frame understanding-how-to-resolve-inconsistent-stackmap-frames-exception java-7-inconsistent-stackmap-frames-need-help-understanding-why-solution-wor

据我了解,java 7 使用了更严格的验证,并为类引入了堆栈映射来验证代码。所以不知何故,在我的混淆过程中,这张地图似乎被破坏了,因为只有这个异常发生,当我用 proguard 混淆我的项目时。

使用 -XX:-UseSplitVerifier 禁用验证并启动构建的 jar 会有所帮助,但我不确定这是否应该是处理此问题的方式。

所以我想知道其他人是否有类似的错误?或者是否有人甚至可能知道解决此问题的特定方法,例如通过调整混淆过程的 proguard 配置?

【问题讨论】:

【参考方案1】:

我假设您没有指定-dontpreverify?该选项几乎肯定会导致这些错误,因为它将阻止 ProGuard 更新 StackMapTable 属性。该属性在 Java 6 中是可选的,但在 Java 7 中是必需的。

您仍然可以尝试 ProGuard 4.11 的 beta 版本,但它不太可能在这里有所作为。如果您将处理后的类文件邮寄给我,我会调查一下。

(我是ProGuard的开发者)

【讨论】:

感谢您的回答埃里克。这确实是个错误。我们在配置中使用了 -dontpreverify 属性。我只是想知道,即使具有该属性,它也可以在 4.7(与 Java 7 一起)中工作。只有升级到 4.10 才发现这个错误。激活此属性修复了它,我们的服务器组件再次正常工作。 不幸的是,现在我们的客户端抛出了另一种错误:线程 AWT-EventQueue-0 上的意外问题:'''分支目标 64 处的堆栈图帧不一致'''。您是否有任何可能导致这种情况的线索?还有什么其他的,我必须考虑为 Java7 配置 ProGuard? 这听起来像同样的问题——不要为您的客户端应用程序使用 -dontpreverify。 我们确保它不用于客户端应用程序(服务器和客户端使用相同的配置进行混淆)。并且错误略有不同,因为它现在说“不一致的堆栈图”而不是“期望堆栈图”。我明白为什么地图可能会丢失(-dontpreverify),但是什么可能会导致堆栈图不一致错误? 你好,eric,很抱歉我没有回复你慷慨的检查我们的文件的提议,但我没有注意到,你又在这里回复了。只是想提一下,我们再次研究了这个主题,并在 proguard 中发现了以下 bugticket,它解决了我们的问题:sourceforge.net/p/proguard/bugs/498。再次感谢您,继续做好工作,特别是因为您很忙。我们期待未来的 Java 8 支持。【参考方案2】:

如果你们还没有找到解决方案,可以尝试检查是否有-microedition 选项。 Here's 为什么它与 StackMap 相关。删除此选项为我解决了这个问题。

【讨论】:

【参考方案3】:

在将应用程序从 1.6 迁移到 1.7 时,我也面临同样的挑战。经过巨大的努力,我们找到了解决该问题的方法。

方法一:你可以使用 -XX:-UseSplitVerifier 参数来解决这个问题,你不必担心升级库文件。

方法 2:我已按照以下步骤解决此问题。第 1 步:确定并保留应用程序使用的外部库列表。第 2 步:确定列表后,继续逐个删除外部库文件并插入升级版本的库文件,这将帮助您隔离可能导致问题的库。在我的例子中:j2ee.jar 和 openjpa-1.2.2 jar 文件创建了一个问题,然后我升级了这些解决了迁移问题的库。

因此,找出导致问题的库并将其逮捕是一个缓慢而痛苦的过程。

我希望这些信息可能有用,因为它基于我的实时经验。

【讨论】:

以上是关于混淆导致 VerifyError: Expecting a stackmap frame的主要内容,如果未能解决你的问题,请参考以下文章

java.lang.verifyerror:bad type on orerand stack

java.lang.VerifyError

java.lang.VerifyError:期望堆栈图帧

Android java.lang.VerifyError?

Android VerifyError 异常

Android:初始化新 AsyncTask 时应用程序崩溃 (VerifyError)