Inconsistent stackmap frames at branch target 147
Java class file shrinker, optimizer, obfuscator, and preverifier
Brought to you by:
guardsquare
I am attempting to trim my JAR down, but every time I run it after I use ProGuard (5.2.1) it throws the following exception:
Exception in thread "main" java.lang.VerifyError: Inconsistent stackmap frames at branch target 147 Exception Details: Location: coursier/Cache$.validateChecksum(Lcoursier/core/Artifact;Ljava/lang/String;Ljava/io/File;Ljava/util/concurrent/ExecutorService;)Lscalaz/EitherT; @147: new Reason: Type uninitialized 33 (current frame, stack[0]) is not assignable to 'scalaz/EitherT' (stack map, stack[0]) Current Frame: bci: @108 flags: { } locals: { top, top, 'java/lang/String', top, top, top, 'coursier/core/Artifact', 'scala/Option' } stack: { uninitialized 33, uninitialized 33, integer } Stackmap Frame: bci: @147 flags: { } locals: { top, top, top, top, top, top, top, 'scala/Option' } stack: { 'scalaz/EitherT', 'scalaz/EitherT' } Bytecode: 0x0000000: 1904 3a05 2a2b 2db6 00de b601 3112 24bb 0x0000010: 0033 592b b701 00b9 01b8 0300 c000 653a 0x0000020: 06bb 00a9 5919 06b6 012b 2cb9 01b7 0200 0x0000030: 3a07 1907 c100 8d99 002d 1907 c000 8d3a 0x0000040: 0819 08b6 017c c000 723a 09b2 00d8 bb00 0x0000050: 5759 2c19 0619 09b7 0124 1905 b601 a13a 0x0000060: 0aa7 002c b200 cb19 07b6 0150 9900 27b2 0x0000070: 00d8 b200 d6bb 005f 592c 1906 b601 32b7 0x0000080: 0125 b601 9db6 01a4 b601 a23a 0a19 0ab7 0x0000090: 0198 b0bb 0085 5919 07b7 0168 bf Stackmap Table: full_frame(@100,{Top,Top,Object[#114],Top,Top,Top,Object[#101],Object[#135]},{Uninitialized[#33],Uninitialized[#33]}) full_frame(@141,{Top,Top,Top,Top,Top,Top,Top,Top,Top,Top,Object[#175]},{Uninitialized[#33],Uninitialized[#33]}) full_frame(@147,{Top,Top,Top,Top,Top,Top,Top,Object[#135]},{Object[#169],Object[#169]}) at com.outr.jefe.repo.Ivy2$Local$.<init>(Ivy2.scala:11) at com.outr.jefe.repo.Ivy2$Local$.<clinit>(Ivy2.scala) at com.outr.jefe.runner.Repositories.list$lzycompute(Configuration.scala:45) at com.outr.jefe.runner.Repositories.list(Configuration.scala:43) at com.outr.jefe.runner.Runner$.start(Runner.scala:27) at com.outr.jefe.runner.Runner$.delayedEndpoint$com$outr$jefe$runner$Runner$1(Runner.scala:11) at com.outr.jefe.runner.Runner$delayedInit$body.apply(Runner.scala:9) at scala.Function0$class.apply$mcV$sp(Function0.scala:34) at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12) at scala.App$$anonfun$main$1.apply(App.scala:76) at scala.App$$anonfun$main$1.apply(App.scala:76) at scala.collection.immutable.List.foreach(List.scala:381) at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35) at scala.App$class.main(App.scala:76) at com.outr.jefe.runner.Runner$.main(Runner.scala:9) at com.outr.jefe.runner.Runner.main(Runner.scala)
This is a Scala project and I'm using the following configuration:
-injars /home/mhicks/projects/open-source/jefe/runner/target/scala-2.11/jefe-runner-assembly-1.0.0.jar -outjars /home/mhicks/projects/open-source/jefe/output/runner.jar -libraryjars <java.home>/lib/rt.jar -libraryjars <java.home>/lib/jce.jar -dontwarn scala.** -keepclasseswithmembers public class * { public static void main(java.lang.String[]); } -keep class * implements org.xml.sax.EntityResolver -keepclassmembers class * { ** MODULE$; } -keepclassmembernames class scala.concurrent.forkjoin.ForkJoinPool { long eventCount; int workerCounts; int runControl; scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode syncStack; scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode spareStack; } -keepclassmembernames class scala.concurrent.forkjoin.ForkJoinWorkerThread { int base; int sp; int runState; } -keepclassmembernames class scala.concurrent.forkjoin.ForkJoinTask { int status; } -keepclassmembernames class scala.concurrent.forkjoin.LinkedTransferQueue { scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference head; scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference tail; scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference cleanMe; } -dontoptimize -dontobfuscate -verbose
If I add "-dontshrink" and "-dontpreverify" then everything works, but I don't think ProGuard is doing anything except copying the file at that point.
Bugs: #101
Bugs: #114
Bugs: #135
Bugs: #169
Bugs: #175
Bugs: #33
Thanks for your report. The error suggests that ProGuard has computed and added incorrect preverification information for a method. Would it be possible to attach or mail me the compiled class file coursier/Cache$.class (before and after ProGuard has processed it)?
Eric, I sent you an email at the sourceforge users address. I went ahead and attached them to this ticket as well just in case.
Any updates on this?
ProGuard's preverification step fails to identify a newly created instance of scalaz.EitherT on the stack as uninitialized, after a conditional branch across the initializer (unusual bytecode). A more advanced analyzer on an internal ProGuard branch doesn't have the problem, but backporting it is non-trivial.
For the time being, you may be able to work around it by restructuring your code slightly, or maybe by using a different Scala compiler.