JDK-8155713 : A non-type-safe subtyping relation between generics with wildcards resulting in a heap pollution
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8,9
  • Priority: P3
  • Status: Resolved
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2016-04-21
  • Updated: 2017-12-07
  • Resolved: 2017-12-07
Related Reports
Duplicate :  
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 :
Microsoft Windows 8.1 Enterprise x64, version 6.3.9600

A DESCRIPTION OF THE PROBLEM :
The following code demonstrates a problem in subtyping relation between generic types with wildcard type arguments, as implemented in the javac. The code compiles successfully without any unchecked cast warnings, but causes a heap pollution that results in a ClassCastException in a position where no explicit cast is made.

```
import java.util.ArrayList;

class Matrix<T> extends ArrayList<ArrayList<T>> {
    public static void main(String[] args) {
        Matrix<String> lorem = new Matrix<>();
        ArrayList<Matrix<String>> ipsum = new ArrayList<>();
        ipsum.add(lorem);
        ArrayList<? extends Matrix<?>> dolor = ipsum;
        ArrayList<? extends ArrayList<ArrayList<?>>> sit = dolor; // This assignment is not type-safe, but is accepted by javac
        sit.get(0).add(sit);
        String amet = lorem.get(0).get(0); // java.lang.ClassCastException: Matrix cannot be cast to java.lang.String
    }
}
```

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the following code:


```
import java.util.ArrayList;

class Matrix<T> extends ArrayList<ArrayList<T>> {
    public static void main(String[] args) {
        Matrix<String> lorem = new Matrix<>();
        ArrayList<Matrix<String>> ipsum = new ArrayList<>();
        ipsum.add(lorem);
        ArrayList<? extends Matrix<?>> dolor = ipsum;
        ArrayList<? extends ArrayList<ArrayList<?>>> sit = dolor; // This assignment is not type-safe, but is accepted by javac
        sit.get(0).add(sit);
        String amet = lorem.get(0).get(0); // java.lang.ClassCastException: Matrix cannot be cast to java.lang.String
    }
}
```

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
A compile-time error expected:

Error:(9, 60) java: incompatible types: java.util.ArrayList<capture#1 of ? extends Matrix<?>> cannot be converted to java.util.ArrayList<? extends java.util.ArrayList<java.util.ArrayList<?>>>
ACTUAL -
No compile time errors. An exception occurs when the program is run:

Exception in thread "main" java.lang.ClassCastException: Matrix cannot be cast to java.lang.String
	at Matrix.main

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.ClassCastException: Matrix cannot be cast to java.lang.String
	at Matrix.main

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.ArrayList;

class Matrix<T> extends ArrayList<ArrayList<T>> {
    public static void main(String[] args) {
        Matrix<String> lorem = new Matrix<>();
        ArrayList<Matrix<String>> ipsum = new ArrayList<>();
        ipsum.add(lorem);
        ArrayList<? extends Matrix<?>> dolor = ipsum;
        ArrayList<? extends ArrayList<ArrayList<?>>> sit = dolor; // This assignment is not type-safe, but is accepted by javac
        sit.get(0).add(sit);
        String amet = lorem.get(0).get(0); // java.lang.ClassCastException: Matrix cannot be cast to java.lang.String
    }
}
---------- END SOURCE ----------


Comments
Simplified: class JDK8155713 { static class C<T> {} static class D<T> extends C<C<T>> {} void test(C<? extends D<?>> cd) { C<? extends C<C<?>>> err = cd; } } An error should occur because: C<CAP1> where CAP1 extends D<?> <: C<? extends C<C<?>>> if D<?> <: C<C<?>> if D<CAP> <: C<C<?>> if C<C<CAP>> <: C<C<?>> if C<CAP> = C<?> which is false
07-12-2017

This is an issue, program should produce compiletime error instead throwing runtime error -sh-4.1$ /opt/java/jdk1.8.0_92/bin/javac Matrix.java -sh-4.1$ /opt/java/jdk1.8.0_92/bin/java Matrix Exception in thread "main" java.lang.ClassCastException: Matrix cannot be cast to java.lang.String at Matrix.main(Matrix.java:11) -sh-4.1$ 8uxx - Fail 9 ea b115 - Fail
29-04-2016

Eclipse gives error at compile time == Type mismatch: cannot convert from ArrayList<capture#1-of ? extends Matrix<?>> to ArrayList<? extends ArrayList<ArrayList<?>>> ==
29-04-2016