Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8340443

javac bad access when calling protected method with visibility expanded by interface implementation

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 11, 17, 21, 23
    • tools
    • Linux yrodiere-thinkpadp1gen4i.remote.csb 6.10.9-200.fc40.x86_64 #1 SMP PREEMPT_DYNAMIC Sun Sep 8 17:23:55 UTC 2024 x86_64 GNU/Linux

    • x86_64
    • linux

      Credit for bug discovery, investigation and reproducer: Christian Beikov, https://github.com/beikov/

      Quoting:

      > [With the following code,] Javac gets confused when compiling `b.a()` in the constructor `pkg2.Impl(pkg2.AbstractBase)`.
      > It emits `invokevirtual pkg2/AbstractBase.a:()Ljava/lang/String` instead of `invokeinterface pkg2/BaseInterface.a:()Ljava/lang/String`.
      >
      > This leads to a verifier error:
      >
      > ```
      > java.lang.VerifyError: Bad access to protected data in invokevirtual
      > Exception Details:
      > Location:
      > pkg2/Impl.<init>(Lpkg2/AbstractBase;)V @5: invokevirtual
      > Reason:
      > Type 'pkg2/AbstractBase' (current frame, stack[0]) is not assignable to > 'pkg2/Impl'
      > Current Frame:
      > bci: @5
      > flags: { }
      > locals: { 'pkg2/Impl', 'pkg2/AbstractBase' }
      > stack: { 'pkg2/AbstractBase' }
      > Bytecode:
      > 0000000: 2ab7 0001 2bb6 0007 57b1
      > ```

      The problem can be reproduced at least with OpenJDK 11 through 23 GA (build 23+37-2369).

      A reproducer is available at https://github.com/beikov/javac-visibility-verifier
      Since the reproducer uses Maven, I believe it technically compiles using javax.tools, but using javac directly (passing `-Dmaven.compiler.forceJavacCompilerUse=true`) gives the same result.

      To run the reproducer:

      ```
      git clone https://github.com/beikov/javac-visibility-verifier.git
      ./mvnw clean package
      java -jar target/javac-visibility-bug-1.0-SNAPSHOT.jar
      ```

      Relevant code:

      ```
      package pkg1;

      public abstract class AbstractRootBase {
      protected abstract String a();
      }
      ```

      ```
      package pkg2;

      import pkg1.AbstractRootBase;

      public abstract class AbstractBase extends AbstractRootBase implements BaseInterface {
      }
      ```

      ```
      package pkg2;

      public interface BaseInterface {
      String a();
      }
      ```

      ```
      package pkg2;

      public class Impl extends AbstractBase {
      Impl() {
      }
      Impl(AbstractBase b) {
      b.a(); // This leads to bad access
      }

      @Override
      public String a() {
      return null;
      }

      public static void main(String[] args) {
      Impl impl = new Impl();
      new Impl(impl);
      }
      }
      ```

            tongwan Andrew Wang
            yrodiere Yoann Rodiere
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: