Question Compiler avec Proguard donne SimException: "incompatibilité de type variable locale"


Lorsque je compile mon application Android avec Proguard activé, j'obtiens l'erreur suivante:

-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

Comment puis-je résoudre ce problème?


46
2018-04-18 09:50


origine


Réponses:


La partie Proguard actuelle se termine, mais dex ne peut plus convertir le bytecode résultant. Dex considère le LocalVariableTable Incorrect. Eric Lafortune est la meilleure source pour expliquer pourquoi (voir sa réponse).

Le problème disparaît si vous ne brouillez pas seulement, mais ignorez également l’étape d’optimisation (-dontoptimize). Mais vous voulez avoir ceci pour la réduction de taille. Une autre façon de le résoudre est de déposer les indicateurs de débogage dans javac et en dex. Le seul problème est que vous ne disposeriez pas non plus de stacktraces. Vous obtiendrez des lignes de stacktrace sans informations sur le fichier source ni numéros de ligne tels que:

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

Vous pouvez le faire en ajoutant debug="false" dans le javac tag dans la fourmi main-rules.xml (vous voudrez peut-être copier la pièce dans un build.xml premier). Cela mettra un drapeau javac -g:none. Vous devez également configurer dex et cela est plus difficile à faire dans le gabarit fourni. J'ai copié le dex-helper macro, s’est assuré qu’elle était utilisée et a ajouté une balise de condition entourant les appels de 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>

C'est le --no-locals ça le fait.

Pour limiter la perte d'informations de stacktrace, vous pouvez utiliser, respectivement, les informations de numéro de ligne et les informations sur les noms de classe et de méthode:

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

De cette façon, vous pouvez effectuer un masquage partiel et avoir toujours de bons empilements. Je vous suggère néanmoins de créer et de conserver les fichiers de mappage dès leur sortie.

En plus de tout cela, vous ne devez pas spécifier -keepattributes LocalVariableTable,LocalVariableTypeTable et également -keepparameternames (Si vous obscurcissez, cela peut vous causer des problèmes). Notez que le second implique le premier, même si son nom n'indique pas clairement qu'il affecte les attributs.

Personnellement, et compte tenu des autres problèmes rencontrés avec Proguard, j'ai choisi de faire l'obscurcissement, mais d'atténuer la perte d'informations de stacktrace. Je n'ai pas encore essayé la proposition de @ plowman.

Pour plus de détails, vous pouvez trouver mes fichiers de projet contrôlés par version ici:


15
2017-11-02 18:52



J'ai rencontré le même problème après avoir ajouté l'indicateur -dontobfuscate à mon fichier proguard.cfg.

La solution a fini par être que je devais ajouter ceci à mes optimisations:

!code/allocation/variable

Cela fait que ma chaîne d'optimisation complète ressemble à ceci:

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

95
2017-09-28 18:20



Ceci est un bogue dans ProGuard. Son étape d'optimisation ne met parfois pas à jour correctement les attributs de débogage facultatifs "LocalVariableTable" et "LocalVariableTypeTable" à l'intérieur des fichiers de classe. La machine virtuelle Dalvik vérifie explicitement les attributs de débogage et rejette les fichiers de classe s’ils sont incohérents.

Vous devez vérifier si la dernière version de ProGuard résout le problème. Sinon, vous devez supprimer les noms de variables locales et les types des fichiers de classe. Vous pouvez demander au compilateur Java de ne pas les générer (par exemple, "javac -g: none"). Vous pouvez également demander à ProGuard de ne pas les conserver (ne spécifiez pas "-keepattributes LocalVariableTable, LocalVariableTypeTable").


22
2018-04-19 20:00



J'ai simplement refait surface sur Android Studio de Windows, et la désactivation d'Instant Run a permis de faire fonctionner les choses à nouveau.


6
2018-05-12 06:38