使用 Proguard 编译会给出 SimException: “局部变量类型不匹配”

发布于 2024-11-02 01:13:02 字数 3212 浏览 0 评论 0原文

当我在启用 Proguard 的情况下编译 Android 应用程序时,出现以下错误:

-dex:
 [echo] Converting compiled files and external libraries into /home/ka/dev/workspace/ImPress/build/classes.dex...
[apply] 
[apply] UNEXPECTED TOP-LEVEL EXCEPTION:
[apply] com.android.dx.cf.code.SimException: local variable type mismatch: attempt to set or access a value of type java.io.File using a local variable of type java.lang.Object[]. This is symptomatic of .class transformation tools that ignore local variable information.
[apply]     at com.android.dx.cf.code.BaseMachine.throwLocalMismatch(BaseMachine.java:550)
[apply]     at com.android.dx.cf.code.BaseMachine.getLocalTarget(BaseMachine.java:405)
[apply]     at com.android.dx.cf.code.BaseMachine.storeResults(BaseMachine.java:532)
[apply]     at com.android.dx.cf.code.ValueAwareMachine.run(ValueAwareMachine.java:197)
[apply]     at com.android.dx.cf.code.RopperMachine.run(RopperMachine.java:291)
[apply]     at com.android.dx.cf.code.Simulator$SimVisitor.visitLocal(Simulator.java:608)
[apply]     at com.android.dx.cf.code.BytecodeArray.parseInstruction(BytecodeArray.java:526)
[apply]     at com.android.dx.cf.code.Simulator.simulate(Simulator.java:99)
[apply]     at com.android.dx.cf.code.Ropper.processBlock(Ropper.java:684)
[apply]     at com.android.dx.cf.code.Ropper.doit(Ropper.java:639)
[apply]     at com.android.dx.cf.code.Ropper.convert(Ropper.java:252)
[apply]     at com.android.dx.dex.cf.CfTranslator.processMethods(CfTranslator.java:252)
[apply]     at com.android.dx.dex.cf.CfTranslator.translate0(CfTranslator.java:131)
[apply]     at com.android.dx.dex.cf.CfTranslator.translate(CfTranslator.java:85)
[apply]     at com.android.dx.command.dexer.Main.processClass(Main.java:369)
[apply]     at com.android.dx.command.dexer.Main.processFileBytes(Main.java:346)
[apply]     at com.android.dx.command.dexer.Main.access$400(Main.java:59)
[apply]     at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:294)
[apply]     at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:244)
[apply]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:130)
[apply]     at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:108)
[apply]     at com.android.dx.command.dexer.Main.processOne(Main.java:313)
[apply]     at com.android.dx.command.dexer.Main.processAllFiles(Main.java:233)
[apply]     at com.android.dx.command.dexer.Main.run(Main.java:185)
[apply]     at com.android.dx.command.dexer.Main.main(Main.java:166)
[apply]     at com.android.dx.command.Main.main(Main.java:90)
[apply] ...at bytecode offset 00000006
[apply] locals[0000]: Lcom/officemax/impress/ui/library/task/DocumentBrowserTask;
[apply] locals[0001]: [Ljava/lang/Object;
[apply] locals[0002]: <invalid>
[apply] ...while working on block 0006
[apply] ...while working on method doTaskJob:([Ljava/lang/Object;)Lcom/kaciula/utils/ui/BasicTaskResponse;
[apply] ...while processing doTaskJob ([Ljava/lang/Object;)Lcom/kaciula/utils/ui/BasicTaskResponse;
[apply] ...while processing com/officemax/impress/ui/library/task/DocumentBrowserTask.class
[apply] 
[apply] 1 error; aborting

如何解决此问题?

When I compile my Android Application with Proguard enabled I get the following error:

-dex:
 [echo] Converting compiled files and external libraries into /home/ka/dev/workspace/ImPress/build/classes.dex...
[apply] 
[apply] UNEXPECTED TOP-LEVEL EXCEPTION:
[apply] com.android.dx.cf.code.SimException: local variable type mismatch: attempt to set or access a value of type java.io.File using a local variable of type java.lang.Object[]. This is symptomatic of .class transformation tools that ignore local variable information.
[apply]     at com.android.dx.cf.code.BaseMachine.throwLocalMismatch(BaseMachine.java:550)
[apply]     at com.android.dx.cf.code.BaseMachine.getLocalTarget(BaseMachine.java:405)
[apply]     at com.android.dx.cf.code.BaseMachine.storeResults(BaseMachine.java:532)
[apply]     at com.android.dx.cf.code.ValueAwareMachine.run(ValueAwareMachine.java:197)
[apply]     at com.android.dx.cf.code.RopperMachine.run(RopperMachine.java:291)
[apply]     at com.android.dx.cf.code.Simulator$SimVisitor.visitLocal(Simulator.java:608)
[apply]     at com.android.dx.cf.code.BytecodeArray.parseInstruction(BytecodeArray.java:526)
[apply]     at com.android.dx.cf.code.Simulator.simulate(Simulator.java:99)
[apply]     at com.android.dx.cf.code.Ropper.processBlock(Ropper.java:684)
[apply]     at com.android.dx.cf.code.Ropper.doit(Ropper.java:639)
[apply]     at com.android.dx.cf.code.Ropper.convert(Ropper.java:252)
[apply]     at com.android.dx.dex.cf.CfTranslator.processMethods(CfTranslator.java:252)
[apply]     at com.android.dx.dex.cf.CfTranslator.translate0(CfTranslator.java:131)
[apply]     at com.android.dx.dex.cf.CfTranslator.translate(CfTranslator.java:85)
[apply]     at com.android.dx.command.dexer.Main.processClass(Main.java:369)
[apply]     at com.android.dx.command.dexer.Main.processFileBytes(Main.java:346)
[apply]     at com.android.dx.command.dexer.Main.access$400(Main.java:59)
[apply]     at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:294)
[apply]     at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:244)
[apply]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:130)
[apply]     at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:108)
[apply]     at com.android.dx.command.dexer.Main.processOne(Main.java:313)
[apply]     at com.android.dx.command.dexer.Main.processAllFiles(Main.java:233)
[apply]     at com.android.dx.command.dexer.Main.run(Main.java:185)
[apply]     at com.android.dx.command.dexer.Main.main(Main.java:166)
[apply]     at com.android.dx.command.Main.main(Main.java:90)
[apply] ...at bytecode offset 00000006
[apply] locals[0000]: Lcom/officemax/impress/ui/library/task/DocumentBrowserTask;
[apply] locals[0001]: [Ljava/lang/Object;
[apply] locals[0002]: <invalid>
[apply] ...while working on block 0006
[apply] ...while working on method doTaskJob:([Ljava/lang/Object;)Lcom/kaciula/utils/ui/BasicTaskResponse;
[apply] ...while processing doTaskJob ([Ljava/lang/Object;)Lcom/kaciula/utils/ui/BasicTaskResponse;
[apply] ...while processing com/officemax/impress/ui/library/task/DocumentBrowserTask.class
[apply] 
[apply] 1 error; aborting

How can I fix this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

往日情怀 2024-11-09 01:13:03

这是 ProGuard 中的一个错误。它的优化步骤有时不会完全正确地更新类文件内的可选“LocalVariableTable”和“LocalVariableTypeTable”调试属性。 Dalvik VM 显式检查调试属性,如果不一致则拒绝类文件。

您应该检查最新版本的 ProGuard 是否修复了该问题。否则,您应该从类文件中删除局部变量名称和类型。您可以要求 java 编译器不要生成它们(例如“javac -g:none”)。您还可以要求 ProGuard 不要保留它们(不要指定“-keepattributes LocalVariableTable,LocalVariableTypeTable”)。

This is a bug in ProGuard. Its optimization step sometimes doesn't update the optional "LocalVariableTable" and "LocalVariableTypeTable" debug attributes inside class files entirely correctly. The Dalvik VM explicitly checks the debug attributes and rejects the class files if they are inconsistent.

You should check if the latest version of ProGuard fixes the problem. Otherwise, you should remove local variable names and types from the class files. You can ask the java compiler not to generate them (e.g. "javac -g:none"). You can also ask ProGuard not to keep them (don't specify "-keepattributes LocalVariableTable,LocalVariableTypeTable").

拍不死你 2024-11-09 01:13:03

实际的 Proguard 部分完成,但 dex 无法再转换生成的字节码。 Dex 认为 LocalVariableTable 不正确。埃里克·拉福图恩(Eric Lafortune)是解释原因的更好来源(请参阅他的回答)。

如果您不仅不进行混淆,而且跳过优化步骤(-dontoptimize),那么问题就会消失。但你想用它来缩小尺寸。解决此问题的另一种方法是删除 javacdex 中的调试标志。唯一的问题是,你也不会有正确的堆栈跟踪。您将获得没有源文件信息或行号的堆栈跟踪行,例如:

net.lp.collectionista.domain.items.book.BookItem.getCoverImageForFormField(Unkno‌​wn Source)

您可以通过在 ant javac 标记中添加 debug="false" 来实现此目的main-rules.xml(您可能需要先将该部分复制到 build.xml)。这将设置一个标志javac -g:none。您还必须配置 dex,这在提供的 ant 模板中很难做到。我复制了 dex-helper 宏,确保它正在被使用,并在 dex 调用周围添加了一个条件标记:

        <echo>Converting compiled files and external libraries into ${intermediate.dex.file}...</echo>
        <if condition="debug">
            <then>
                <apply executable="${dx}" failonerror="true" parallel="true">
                    <arg value="--dex" />
                    <arg value="--output=${intermediate.dex.file}" />
                    <extra-parameters />
                    <arg line="${verbose.option}" />
                    <arg path="${out.dex.input.absolute.dir}" />
                    <path refid="out.dex.jar.input.ref" />
                    <external-libs />
                </apply>
            </then>
            <else>
                <apply executable="${dx}" failonerror="true" parallel="true">
                    <arg value="--dex" />
                    <arg value="--output=${intermediate.dex.file}" />
                    <arg value="--no-locals" /><!-- otherwise dex fails on the proguard bytecode -->
                    <extra-parameters />
                    <arg line="${verbose.option}" />
                    <arg path="${out.dex.input.absolute.dir}" />
                    <path refid="out.dex.jar.input.ref" />
                    <external-libs />
                </apply>
            </else>
        </if>

--no-locals 执行此操作。

为了减少堆栈跟踪信息的丢失,您可以分别使用行号信息以及类和方法名称信息:

-keepattributes SourceFile, LineNumberTable
-keep,allowshrinking,allowoptimization class * { <methods>; }

这样您可以进行部分混淆,并且仍然具有等效的良好堆栈跟踪。不过,我仍然建议您在发布时创建并保留映射文件。

最重要的是,您不应该指定 -keepattributes LocalVariableTable,LocalVariableTypeTable 以及同样的 -keepparameternames (如果您进行混淆,这本身也可能会给您带来麻烦) 。请注意,第二个隐含第一个,尽管从其名称中可能无法清楚地看出它影响属性。

就个人而言,考虑到 Proguard 的其他问题,我选择进行混淆,但减少堆栈跟踪信息的丢失。我还没有尝试过@plowman 的建议。

有关更多详细信息,您可以在此处找到我的版本控制项目文件:

The actual Proguard part finishes, but then dex cannot convert the resulting bytecode anymore. Dex considers the LocalVariableTable incorrect. Eric Lafortune is the better source to explain why (see his answer).

The problem goes away if you not only don't obfuscate, but also skip the optimization step (-dontoptimize). But you want to have this for the size reduction. Another way to solve it is to drop the debug flags in javac and in dex. Only problem is that then you wouldn't have proper stacktraces either. You will get stacktrace lines without source file info or line numbers such as:

net.lp.collectionista.domain.items.book.BookItem.getCoverImageForFormField(Unkno‌​wn Source)

You can do this by adding debug="false" in the javac tag in the ant main-rules.xml (you may want to copy the part to a build.xml first). This will set a flag javac -g:none. You also have to configure dex and this is harder to do in the provided ant template. I copied the dex-helper macro, made sure it was being used, and added a condition tag surrounding the dex calls:

        <echo>Converting compiled files and external libraries into ${intermediate.dex.file}...</echo>
        <if condition="debug">
            <then>
                <apply executable="${dx}" failonerror="true" parallel="true">
                    <arg value="--dex" />
                    <arg value="--output=${intermediate.dex.file}" />
                    <extra-parameters />
                    <arg line="${verbose.option}" />
                    <arg path="${out.dex.input.absolute.dir}" />
                    <path refid="out.dex.jar.input.ref" />
                    <external-libs />
                </apply>
            </then>
            <else>
                <apply executable="${dx}" failonerror="true" parallel="true">
                    <arg value="--dex" />
                    <arg value="--output=${intermediate.dex.file}" />
                    <arg value="--no-locals" /><!-- otherwise dex fails on the proguard bytecode -->
                    <extra-parameters />
                    <arg line="${verbose.option}" />
                    <arg path="${out.dex.input.absolute.dir}" />
                    <path refid="out.dex.jar.input.ref" />
                    <external-libs />
                </apply>
            </else>
        </if>

It's the --no-locals that does it.

To mitigate the loss of stacktrace information you can use, respectively for line number information and class and method names information:

-keepattributes SourceFile, LineNumberTable
-keep,allowshrinking,allowoptimization class * { <methods>; }

This way you can do partial obfuscation, and still have equivalent good stacktraces. I still suggest you create and keep the mapping files upon release though.

On top of all this you shouldn't specify -keepattributes LocalVariableTable,LocalVariableTypeTable and equally -keepparameternames (if you do obfuscate, this by itself might get you into troubles as well). Note that the second implies the first, even though it may not be clear from its name that it affects attributes.

Personally, and in view of other problems with Proguard, I chose to do the obfuscation but mitigate the loss of stacktrace information. I haven't tried @plowman's proposal yet.

For more details you can find my version controlled project files here:

故人如初 2024-11-09 01:13:03

我刚刚在 Windows 的 Android Studio 上重新出现了这个问题,禁用 Instant Run 使一切再次正常运行。

I just had this resurface on Windows' Android Studio, and disabling Instant Run made things work again.

一萌ing 2024-11-09 01:13:02

在将 -dontobfuscate 标志添加到我的 proguard.cfg 文件后,我遇到了同样的问题。

最终的解决方案是我需要将其添加到我的优化中:

!code/allocation/variable

这使我的完整优化字符串如下所示:

-optimizations !field/removal/writeonly,!field/marking/private,!class/merging/*,!code/allocation/variable

I ran into the same problem after adding the -dontobfuscate flag to my proguard.cfg file.

The solution ended up being that I needed to add this to my optimizations:

!code/allocation/variable

This makes my complete optimization string look like this:

-optimizations !field/removal/writeonly,!field/marking/private,!class/merging/*,!code/allocation/variable
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文