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

Use of HYPOTHETICAL flag in bridge generation logic leads to missing bridges in some cases

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: P4
    • Resolution: Duplicate
    • Affects Version/s: 7u85, 8, 9
    • Fix Version/s: 11
    • Component/s: tools
    • Labels:
      None
    • Subcomponent:
    • Resolved In Build:
      b16

      Description

       think I found a bug in the interaction between 'hypothetical' bridge methods and the workaround for JDK-6342411.

      A hypothetical bridge method "is not strictly necessary in the binary, but is represented in the symbol table to detect erasure clashes." [1]

      Bridges are required to work around JDK-6342411 when a non-public super class declares a public method that's inherited into a public derived class. Without the bridge, reflectively invoking the method on the derived class fails with `IllegalAccessException: can not access a member with modifiers "public"`. [2][3]

      The issue I found occurs when a bridge method candidate qualifies as a hypothetical bridge *and* is necessary to work around JDK-6342411. The path for hypothetical bridges wins, so the bridge is entered in the symbol table but not generated in the binary, and attempts to invoke it reflectively fail.

      Attached is a patch with a regression test and a possible fix.

      Here's the repro:

      === ./p/I.java ===
      package p;

      public interface I<T> {
        void f(T t);
      }
      === ./p/B.java ===
      package p;

      public class B extends A<String> {}
      === ./p/A.java ===
      package p;

      class A<T> implements I<T> {
        public void f(T t) {}
      }
      === ./Test.java ===
      import java.lang.reflect.Method;

      public class Test {
        public static void main(String[] args) throws Exception {
          Method m = Class.forName("p.B").getMethod("f", Object.class);
          m.invoke(new p.B(), new Object[]{null});
        }
      }
      ===

      $ javac p/I.java p/A.java p/B.java Test.java
      $ java Test
      Exception in thread "main" java.lang.IllegalAccessException: Class Test can not access a member of class p.A with modifiers "public"
              at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:101)
              at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:295)
              at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:287)
              at java.lang.reflect.Method.invoke(Method.java:476)
              at Test.main(Test.java:6)

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              mcimadamore Maurizio Cimadamore
              Reporter:
              mcimadamore Maurizio Cimadamore
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: