Hidden Truths in Dead Software Path

Why is there code in software products that actually never will be executed?

The reasons for this can be technical. Your compiler may introduce dead code to the compiled product as part of its compilation scheme.  But also this dead code can show you where you as a programmer actually did something wrong.

We developed a method using the OPAL framework based on abstract interpretation that successfully detects dead software paths, filters out all the technical issues that you couldn’t take care of and shows you just the issues that you might want to fix depending on their severity.

How do we do that?

Let’s look at the following code block. A method gets an array and checks if it is not null or its length is greater than zero. If either is the case code block (a) is executed. It is followed  by code block (b) in any case. The method might throw an exception.

public static X doStuff(SomeType[] array) {
   if(array != null || array.length > 0) {// (a)}
   // (b)
} // (ex)

So now let’s build something that we already know: a control-flow graph (CFG) of the compiled byte code instructions of this piece of code:

deadpath-cfg

That didn’t hurt so much now, did it? Well now to something more daring: An Abstract Interpretation Flow Graph (AIFG). We do that by performing an abstract interpretation of the byte code block and constructing a graph while interpreting. If there are certain constraints we annotate the edges. Thus we only collect edges that can be taken.

deadpath-aifg

Here we see something interesting. The arraylength instruction actually cannot ever evaluate to a value. It will always throw an exception as its predecessor only forwards control if the array is null. So by comparing the CFG with the AIFG we immediately see infeasible paths and can point towards the first edge of an infeasible path. This effectively shows the programmer were her problems are.

What do we find?

Let’s do this one as a quiz: I show you some code snippets we found and you try to figure out whats wrong.

boolean isInitValueValid(int v) {
  if ((v < Integer.MIN_VALUE) || (v > Integer.MAX_VALUE)) {
    return false;
  }
  return true;
}
if (maxBits > 4 || maxBits < 8) {
  maxBits = 8;
}
if (maxBits > 8) 
  maxBits = 16;
}
public boolean containsValue(Attribute attribute) {
  return
    attribute != null &&
    attribute instanceof Attribute &&
    attribute.equals(...(Attribute)attribute...));
}
doc = new CachedDocument(uri);
if (doc==null) return null; // better error handling needed
// For now we set owner to null. In the future, it may be 
// passed as an argument.
Window owner = null;
if (owner instanceof Frame) { ... }
int bands = bandOffsets.length;
... // [bandOffsets is not used by the next 6 lines of code]
if (bandOffsets == null) 
   throw new ArrayIndexOutOfBoundsException("...");

Where can I find out more or get the software?

You can visit my talk at ESEC/FSE 2015 in Bergamo, Italy on Thursday, September 3rd 2015 in room Alabastro B  in the 14:30 Session R5.c. I will also make the slides available later this week.

You can read our paper, which we provide as a preprint here.

And you can download our software here.