JDK-8333854 : IllegalAccessError with proxies after JDK-8332457
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 23
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2024-06-09
  • Updated: 2024-10-18
  • Resolved: 2024-06-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 23 JDK 24
23Fixed 24 b03Fixed
Related Reports
Relates :  
Relates :  
Description
After JDK-8332457 (Examine startup overheads from JDK-8294961), the following example fails at runtime with a IllegalAccessError. It succeeds with earlier JDK versions.

I noticed this because it breaks test coverage for https://github.com/google/guice.

In this example the proxied interface I is public, so the proxy is generated into a separate package (jdk.proxy1), but the interface declares a method with a package access interface J. I think that after the changes in JDK-8332457 the type in the method signature is getting accessed from the jdk.proxy package, resulting in the IllegalAccessError.

import java.lang.reflect.Proxy;

public class Z {

  public interface I {
    void f(J j);
  }

  interface J {
    void g();
  }

  public static void main(String[] args) {
    I proxy =
        (I)
            Proxy.newProxyInstance(
                I.class.getClassLoader(), new Class<?>[] {I.class}, (p, m, a) -> null);
    proxy.f(() -> {});
  }
}

$ java Z
Exception in thread "main" java.lang.IllegalAccessError: failed to access class Z$J from class jdk.proxy1.$Proxy0 (Z$J is in unnamed module of loader 'app'; jdk.proxy1.$Proxy0 is in module jdk.proxy1 of loader 'app')
        at jdk.proxy1/jdk.proxy1.$Proxy0.f(Unknown Source)
        at Z.main(Z.java:18)
Comments
A pull request was submitted for review. Branch: jdk23 URL: https://git.openjdk.org/jdk/pull/19815 Date: 2024-06-20 20:11:06 +0000
11-07-2024

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/19615 Date: 2024-06-10 01:32:09 +0000
11-07-2024

Mach5 tier1-3 for JDK23: https://mach5.us.oracle.com/mdash/jobs/Chen_Liang-jdk23-20240620-1934-12645457
20-06-2024

Changeset: 91bd85d6 Author: Chen Liang <liach@openjdk.org> Date: 2024-06-18 13:51:50 +0000 URL: https://git.openjdk.org/jdk/commit/91bd85d65dff9cea91b88da7ef241be5c7b85f94
18-06-2024

The patch has been redone to emulate the old behavior before the problematic patch, given a backout was impossible.
12-06-2024

Indeed, we cannot just encode classes or method types in the constant pool. That must be the reason these classes were obtained by Class.forName back then, but interestingly no regression tests were in place... A solution may be to pass the descriptor string and use MethodType.fromDescriptorString, which uses Class.forName(xx, false, loader) which will not fail of the package-private access check. FYI Adam Sotona is on vacation this week, so I think I can take over.
10-06-2024