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

A non-type-safe subtyping relation between generics with wildcards resulting in a heap pollution

XMLWordPrintable

    • generic
    • generic

      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 ----------

            dlsmith Dan Smith
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: