Checker Classcast   as of Julia version 2.6.0 (built on 6 Sep 2018)

belongs to group Basic

Identify possibly incorrect classcasts


Java checks explicit type downcasts at runtime. If they do not hold, a runtime exception is thrown. This checker verifies that casts will be satisfied at runtime, so that they will never throw an exception.

Action: For each classcast warning, verify that all types that will ever reach that program point are assignable to the type used for the cast.

Examples


Consider the following code:

public class TestCasts {
  public Object f;
  public Object g = "hi";

  public void m1(Object o) {
    if (((String) o).startsWith("hello"))
      System.out.println("nice to meet you");
  }

  public void m2(String s, Object o) {
    if (((String) o).startsWith("hello"))
      System.out.println("nice to meet you");
  }

  public void m3(String s, Object o) {
    if (((String) wrap(o)).startsWith("hello"))
      System.out.println("nice to meet you");
  }

  public void m4() {
    if (((String) f).startsWith("hello"))
      System.out.println("nice to meet you");
  }

  public void m5() {
    if (((String) g).startsWith("hello"))
      System.out.println("nice to meet you");
  }

  private Object wrap(Object o) {
    return o;
  }

  public void caller1() {
    m1("hi");
    m1(this);
  }

  public void caller2() {
    m2("ciao", "hello");
    m2("come stai", "how are you?");
  }

  public void caller3() {
    m3("ciao", "hello");
    m3("come stai", f = new Object());
  }
}

This checker, with an analysis run from every public entry, issues the following warnings:

TestCasts.java:6: [Classcast: ClasscastOfFormalWarning] Are you sure that formal parameter "o" can be cast from java.lang.Object into java.lang.String? An inconsistent value seems passed at line 36
TestCasts.java:11: [Classcast: ClasscastOfFormalWarning] Are you sure that formal parameter "o" can be cast from java.lang.Object into java.lang.String?

since a TestCasts instance is actually passed at line 36 and reaches line 6, where a classcast exception will be raised at runtime. At line 11, there is no program point where something which is not a string is passed for o at line 10; nevertheless, Julia issues a warning there since method m2() is public and might be called with every possible value for o, hence not necessarily with a string.

By default, this checker only checks for casts on the formal parameters of entry methods. By using the fullCheck option, this checker will apply a complete check of the code, covering all possible casts in the program. This makes the analysis sound but, in general, might lead to a large number of false alarms. In the previous example, that option will make this checker issue two more warnings:

TestCasts.java:16: [Classcast: ClasscastOfMethodReturnWarning] Are you sure that the return value of wrap can be cast from java.lang.Object into java.lang.String? An inconsistent value seems passed at line 46
TestCasts.java:21: [Classcast: ClasscastOfFieldWarning] Are you sure that field f can be cast from java.lang.Object into java.lang.String? An inconsistent value seems passed at line 46

since a java.lang.Object is passed at line 46 for o and is then returned by wrap() at line 16; moreover, that same object is written at line 46 into field f and the cast at line 21 will fail.

Checking stores into arrays

Store operations into arrays might fail at runtime if the type of the elements of the array cannot hold the value written into the array. For instance, the following code:

public class CheckArrays {
  private final Object[] arr;
  private int next;

  public CheckArrays(Object[] arr) {
    this.arr = arr;
  }

  public void add(Object o) {
    if (next < arr.length)
      arr[next++] = o;
  }

  public static void main(String[] args) {
    CheckArrays ca = new CheckArrays(new String[5]);
    ca.add(new Object());
  }
}

will run into an ArrayStoreException at line 11 at runtime, since an array of strings cannot hold a java.lang.Object. This is acknowledged by Julia as well, since this checker issues the following warning:

CheckArrays.java:11: [Classcast: ArrayStoreWarning] Are you sure that you are writing into an array that can always contain the rightvalue?

Note that this erroneous situation is often the consequence of a very permissive API, that provides public methods for both setting the array and the elements of the array, with a permissive type signature, as in the example above. Such a practice is hence discouraged.