JDK-8168045 : 8.3.2: Forward reference by qualified name can observe uninitialized constant variable
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 8
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2016-10-05
  • Updated: 2018-08-03
  • Resolved: 2016-10-17
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 9
9Fixed
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
not important

ADDITIONAL OS VERSION INFORMATION :
not important

EXTRA RELEVANT SYSTEM CONFIGURATION :
not important

A DESCRIPTION OF THE PROBLEM :
package net.octoplar;

/**
 * Created by Octoplar on 05.10.2016.
 */
//This program output is
    //1
    //1
    //2
class C {
    static final int i=C.j+C.k;  // "static field that are constant variable" k have default initial value here. This is JLS violation
    static final int j=1;
    static final int k=i+j;

    public static void main(String[] args) {
        System.out.println(i);  //1
        System.out.println(j);  //1
        System.out.println(k);  //2
    }
}

/*https://docs.oracle.com/javase/specs/jls/se8/html/ */



/*According point 15.28
  * expression 'C.j+C.k' is constant expression, because it composed using:
  * C.j   - Qualified names (��6.5.6.2) of the form TypeName . Identifier that refer to constant variables (��4.12.4).
  * +     - The additive operators + and - (��15.18)
  * C.k   - Qualified names (��6.5.6.2) of the form TypeName . Identifier that refer to constant variables (��4.12.4).
  *
  * expression '1' is constant expression, because it composed using:
  * 1   -  Literals of primitive type and literals of type String (��3.10.1, ��3.10.2, ��3.10.3, ��3.10.4, ��3.10.5)
  *
  * expression 'i+j' is constant expression, because it composed using:
  * i   - Simple names (��6.5.6.1) that refer to constant variables (��4.12.4).
  * +     - The additive operators + and - (��15.18)
  * j   - Simple names (��6.5.6.1) that refer to constant variables (��4.12.4).
  *
  * According point 4.12.4
  * i, j, k is constant variables
  * A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (��15.28).
  * Whether a variable is a constant variable or not may have implications with respect to class initialization (��12.4.1),
  * binary compatibility (��13.1, ��13.4.9), and definite assignment (��16 (Definite Assignment)).
  *
  *
  *
  * According point 8.3.2
  * i, j, k is static fields that are constant variables
 * Note that static fields that are constant variables (��4.12.4) are initialized before other static fields (��12.4.2).
 * This also applies in interfaces (��9.3.1).
 * Such fields will never be observed to have their default initial values (��4.12.5), even by devious programs.
 *
 * But in this example program observe k(static field that are constant variable) in two states:
 * default initial value 0 at "static final int i=C.j+C.k;"
 * and initial value 2 at "System.out.println(k);"
  * */

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run this:

class C {
    static final int i=C.j+C.k;  // "static field that are constant variable" k have default initial value here. This is JLS violation
    static final int j=1;
    static final int k=i+j;

    public static void main(String[] args) {
        System.out.println(i);  //1
        System.out.println(j);  //1
        System.out.println(k);  //2
    }
}

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect no results.
 I learn JLS now and i find this bug. 
ACTUAL -
1
1
2

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
class C {
    static final int i=C.j+C.k;  // "static field that are constant variable" k have default initial value here. This is JLS violation
    static final int j=1;
    static final int k=i+j;

    public static void main(String[] args) {
        System.out.println(i);  //1
        System.out.println(j);  //1
        System.out.println(k);  //2
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
1. remove from JLS 8.3.2 words "Such fields will never be observed to have their default initial values (��4.12.5), even by devious programs." because it is not true.

2. Forbid  all types forward references during field initialization. Now forbidden ornly direct forwadr reference. Example:

class B {
    //Instance variable forward reference example
    int iv1= iv;        // error. Illegal forward reference
    int iv2=this.iv;   //this is too forward reference, but all OK
    B selfRef=this;
    int iv3=selfRef.iv; //this is too forward reference, but all OK

    //Class variable forward reference example
    static int cv1 =cv; //error. Illegal forward reference
    static int cv2 =B.cv; //this is too forward reference, but all OK  

    int iv =11;
    static int cv=22;
}



Comments
JLS 8.3.3 prohibits forward field references, but only for references that are made by simple name (k, j). This does not catch the forward references made by the initializer of i in the Description, which are by qualified name (C.j, C.k). We do not plan to enhance 8.3.3 to catch qualified names, so the JLS 8.3.2 claim that "Such fields [i.e. static fields that are constant variables] will never be observed to have their default initial values (��4.12.5), even by devious programs." is too strong. It should claim only that "When such fields are referenced by simple name, they will never be observed to have their default initial values (��4.12.5)."
17-10-2016