JDK-8078241 : Regression: Interface field becomes null if implementation field has same name
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 8u31
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_7
  • CPU: x86_64
  • Submitted: 2015-03-27
  • Updated: 2015-04-21
  • Resolved: 2015-04-21
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)


FULL OS VERSION :
Windows 7 64-bit
Linux 2.6 (RHEL 6) x86_64


A DESCRIPTION OF THE PROBLEM :
Often a public static final field such as a singleton "INSTANCE" or "EMPTY" is instantiated in a concrete implementation class, and then an identically-named field is exposed in an interface.

This has always worked fine ever since interface constants were introduced in Java 5, up through Java 7.

It works in Java 8 as well, however if the interface happens to extend Iterable, AND if you happen to reference the implementation BEFORE referencing the interface field, then the interface field gets clobbered, and has a null value for the rest of the program's execution.

THIS HAS BEEN FIXED IN 1.8.0_40. However I couldn't find any exact fix referenced in the Release Notes, though it seems related to Bug ID 8043275 "interface initialization for default methods".


THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: Yes

THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes

REGRESSION.  Last worked in version 7u72

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Define an interface that extends Iterable, and provide an implementation class.

Declare an interface field (constant) that references a static final field with the same name in the implementation class.

Create an instance of the implementation class BEFORE referencing the interface field.

From now on, all references of the interface field will return null.

EXPECTED VERSUS ACTUAL BEHAVIOR :
References of the interface field should not return null.
REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.*;
import junit.framework.TestCase;
import junit.textui.TestRunner;

public class IterableInterfaceBugTest extends TestCase
{
  public static void main(String[] args)
  {
    System.out.println("JRE " + System.getProperty("java.runtime.version"));
    TestRunner.run(IterableInterfaceBugTest.class);
  }

  public interface MyIterable extends Iterable<String>
  {
    MyIterable INSTANCE = MyIterableImpl.INSTANCE;
  }

  public static class MyIterableImpl implements MyIterable
  {
    public static final MyIterableImpl INSTANCE = new MyIterableImpl();

    public Iterator<String> iterator()
    {
      return Arrays.asList("Hello", "World.").iterator();
    }
  }

  public interface NotIterable
  {
    NotIterable INSTANCE = NotIterableImpl.INSTANCE;
  }

  public static class NotIterableImpl implements NotIterable
  {
    public static final NotIterableImpl INSTANCE = new NotIterableImpl();

    public Iterator<String> iterator()
    {
      return Arrays.asList("Hello", "World.").iterator();
    }
  }

  public void testNotIterable()
  {
    // succeeds on all JREs (problem only seen if the interface extends Iterable)
    assertNotNull(NotIterableImpl.INSTANCE);
    assertNotNull(NotIterable.INSTANCE);
  }

  public void testMyIterable()
  {
    assertNotNull(MyIterableImpl.INSTANCE);
    // fails for JRE 1.8.0_25 and 1.8.0_31
    // succeeds on JRE 1.7.x and 1.8.0_40.
    assertNotNull(MyIterable.INSTANCE);
  }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Workaround is to redesign the interface constant so that you don't have to have a field with the same name in the implementation, for example:

  MyIterable.EMPTY = new MyIterableImpl();

If you do not have ability to change the code, then upgrade to 1.8.0_40 which does not exhibit the bug, or downgrade to 1.7.0_72.


Comments
According to the test result, I didn't find any issue with 8u40. Moving across JDK for further investigation by dev team.
21-04-2015