Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Edited by NavBot (vkp) v1.0

Objects should not be left in an inconsistent state when exceptional conditions arise. Usual techniques for maintaining object consistency include:

  • Input validation (for example, method parameters)
  • Reordering the logic so that the code capable of resulting in the exceptional condition, executes before the code that modifies the object executes
  • Through the use of rollbacks, upon intercepting a failure notification
  • Performing required operations on a temporary copy and committing changes to the original object, after their successful completion

Noncompliant Code Example

This noncompliant code example shows a Dimensions class that contains three internal attributes, the length, width and height of a rectangular box. The getVolumePackage() method is designed to return the total volume required to hold the box, after accounting for packaging material which further adds 2 units to the dimensions of each side. Non positive values of the dimensions of the box (exclusive of packaging material) are rejected during the input validation. Also, the weight of the object is passed in as an argument and cannot be more than 20 units. Consider the case where the weight is more than 20 units (21 units, here). This causes an IllegalArgumentException which is intercepted by the custom error reporter. While the logic restores the object's original state in the absence of this exception, it omits doing the same from within the catch block. This violates the object's invariants such that when getVolumePackage() is called for the second time, it produces incorrect results.

Code Block
bgColor#FFcccc
class Dimensions {
  private int length;
  private int width;
  private int height;

  public Dimensions(int length, int width, int height) {
    this.length = length;
    this.width = width;
    this.height = height;
  }

  protected int getVolumePackage(int weight) {
    length += 2;
    width  += 2;
    height += 2;
    try {
      if(length <= 2 || width <= 2 || height <= 2 || weight <= 0 || weight > 20)
        throw new IllegalArgumentException();
	
        int volume = length * width * height; // 12 * 12 * 12 = 1728
        length -=2; width -= 2; height -= 2; // Revert back
        return volume;
      } catch(Throwable t) { 
        MyExceptionReporter mer = new MyExceptionReporter();
        mer.report(t); // Sanitize 
        return -1; // Non-positive error code
      }	
  }

  public static void main(String[] args) {
    Dimensions d = new Dimensions(10, 10, 10);
    System.out.println(d.getVolumePackage(21)); // Prints -1 (error)
    System.out.println(d.getVolumePackage(19)); // Prints 2744 instead of 1728
  }
}

Compliant Solution

To be compliant, restore prior object state on exceptional conditions.

Code Block
bgColor#ccccff
// ...
} catch(Throwable t) { 
  MyExceptionReporter mer = new MyExceptionReporter();
  mer.report(t); // Sanitize 
  length -=2; width -= 2; height -= 2; // Revert back
  return -1;
}	

Compliant Solution

A more preferable way is to perform input validation before modifying the state of the object. Also, statements that are incapable of throwing the exception should be moved outside the try block.

Code Block
bgColor#ccccff
protected int getVolumePackage(int weight) {
  try {
    if(length <= 0 || width <= 0 || height <= 0 || weight <= 0 || weight > 20)
      throw new IllegalArgumentException(); // Validate first
  } catch(Throwable t) { MyExceptionReporter mer = new MyExceptionReporter();
    mer.report(t); // Sanitize 
    return -1;
  }		

  length += 2;
  width  += 2;
  height += 2;

  int volume = length * width * height;
  length -=2; width -= 2; height -= 2;
  return volume;
}

Risk Assessment

Failing to restore prior object state on method failure can leave the object in an inconsistent state.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

EXC11- J

low

probable

high

P2

L3

Automated Detection

TODO

Related Vulnerabilities

CVE-2008-0002

References

Wiki Markup
\[[Bloch 2008|AA. Java References#Bloch 08]\] Item 64: Strive for failure atomicity


EXC10-J. Do not let code throw undeclared checked exceptions      17. Exceptional Behavior (EXC)      EXC12-J. Do not allow unsanitized user input to be logged