typetools / checker-framework

Pluggable type-checking for Java
http://checkerframework.org/
Other
1.01k stars 352 forks source link

Handling of non-canonical qualified types is unsound #1857

Open cushon opened 6 years ago

cushon commented 6 years ago

In the following example, the canonical type of B<Object>.I is A<@Nullable Object>.I. javac's type annotation handling appears to emit type_paths for type annotations as they appears in the source type, which don't always correspond to the canonical type that appears in bytecide. For example, below there's a @NonNull annotation on the field i at location [TYPE_ARGUMENT(0)], which is correct for the non-canonical type B<Object>.I that appears in source and incorrect for the canonical type A<Object>.I that appears in bytecode.

I'm not sure that javac's behaviour here is desirable (see JDK-8198566).

import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.nullness.qual.NonNull;

class A<@Nullable T> {
  class I {
    T f() {
      return null;
    }
  }
}

class B<@NonNull T> extends A<@Nullable Object> {
  static B<Object>.I i = new B<>().new I();

  public static void main(String[] args) {
    i.f().hashCode();
  }
}

The example compiles cleanly but results in an NPE at runtime:

./checker-framework-2.3.2/checker/bin/javac -processor Nullness T.java && java B
Exception in thread "main" java.lang.NullPointerException
        at B.main(T.java:16)
cushon commented 6 years ago

For what it's worth I did not see this is in real-world code, I just got curious how the implementation handled this case and was surprised by the result. I don't consider it particularly high priority.

I'm curious what your take is, though. Is this an oversight in the spec?