IllegalAccessError after obfuscating
Java class file shrinker, optimizer, obfuscator, and preverifier
Brought to you by:
guardsquare
ProGuard incorrectly renames default method of super-interface into the same name as the private method of super-class. This produces IllegalAcessError when running the obfuscated jar.
Here is an example test.java:
public class test {
public static void main(String[] a) {
foo(new D());
}
public static void foo(I i) {
System.out.println(i.getAnotherBoolean());
}
}
class C {
private boolean getBoolean() {
return false;
}
}
interface I {
default boolean getAnotherBoolean() {
return true;
}
}
class D extends C implements I {}
When the classes are packed into test.jar and given to proguard5.3.3 with the following config:
-injars test.jar
-libraryjars <java.home>/lib/rt.jar
-outjars test-o.jar
-dontoptimize
-dontshrink
-printmapping test.map
-keep class test { *** main(...); }
it renames both getBoolean and getAnotherBoolean into a:
C -> a:
void <init>() -> <init>
boolean getBoolean() -> a
D -> b:
void <init>() -> <init>
I -> c:
boolean getAnotherBoolean() -> a
test -> test:
void <init>() -> <init>
void main(java.lang.String[]) -> main
void foo(I) -> a
and because of this invokeinterface in method foo now resolves to private method of C thus producing IAE:
>java -cp test.jar test
true
>java -cp test-o.jar test
Exception in thread "main" java.lang.IllegalAccessError: b.a()Z
at test.a(Unknown Source)
at test.main(Unknown Source)
Thanks for the detailed report and sorry about the extreme delay. I can reproduce the issue. Suprisingly, I can also reproduce the issue by writing the original code with the same method name. The code still compiles fine but gives an IllegalAccessError at runtime. I'd consider it a bug in the JVM, but it seems to be undecided or even intentional (cfr. Java bugs JDK-8021581 and #8024647). I'm now working around it in the upcoming ProGuard 6.0.