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

Method reference can emit bytecode pointing at non-visible base types

    XMLWordPrintable

Details

    • generic
    • generic

    Description

      FULL PRODUCT VERSION :
      java version "1.8.0_92"
      Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
      Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Darwin 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05 PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64

      A DESCRIPTION OF THE PROBLEM :
      When a method reference is created to a public type where the referenced public method is inherited from a non-visible class, the Java compiler incorrectly points the invokevirtual/invokeinterface bytecode at that non-visible base type instead of the visible subclass.

      If the base type is swapped for a package-private interface which defines the public method (with a default impl), the generated bytecode will not only point at the non-visible interface type but will also be an invokeinterface.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Create a package-private class (e.g., 'Base') which defines a public method (e.g., 'method'). In the same package, create public class (e.g., 'Subclass') which extends the package-private class and defines no additional methods.

      In another package, specify a method reference to the public class from the first package and the public method inherited from its base class.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The generated synthetic method for the method reference contains an invokevirtual which points at the public subclass and the method name. This allows the method to be called on subclass instances like a normal method call.
      ACTUAL -
      An IllegalAccessError is thrown because the invokevirtual instruction points at the non-visible base class which is package-private in a different package.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Exception in thread "main" java.lang.IllegalAccessError: tried to access class com.example.sub.Base from class com.example.Main
      at com.example.Main.lambda$main$0(Main.java:10)

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      // Subclass.java
      package com.example.sub;

      abstract class Base {
        public String method() {
          return "Hello!";
        }
      }

      public class Subclass extends Base {
      }

      // Main.java
      package com.example;

      import com.example.sub.Subclass;
      import java.util.Collections;

      public final class Main {
        public static void main(String... args) {
          Collections.singleton(new Subclass())
              .stream()
              .map(Subclass::method)
              .forEach(System.out::println);
        }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Switch the method reference to a lambda.

        .map(Subclass::method)

      becomes

        .map(o -> o.method())

      Attachments

        Issue Links

          Activity

            People

              vromero Vicente Arturo Romero Zaldivar
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: