You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 62 Next »

Methods should always try to return a value that allows the developer to learn about the current state of the object and/or the result of an operation. This advice is consistent with guideline EXP00-J. Do not ignore values returned by methods. The returned value should be as representative as possible of the last known state and should be chosen with the perceptions and mental model of the developer in mind.

Feedback can also be provided by throwing either standard or custom exception objects derived from the Exception class. With this approach, the developer can still get precise information about the outcome of the method and proceed to take the necessary actions. To do so, the exception should provide a detailed account of the abnormal condition at the appropriate abstraction level.

APIs should use a combination of these approaches both to help clients distinguish correct from incorrect results and to encourage careful handling of any incorrect results. At the same time, in some cases, an error value instead of an exception should be returned, and vice versa. For instance, if some method is capable of failing in a variety of ways, it is better to return failure codes than try to throw scores of different exceptions. Note that all possible failure codes should be outside the range of valid return values.

Alternatively, an object can provide a state-testing method [Bloch 2008] that checks whether the object is in a consistent state. This approach is useful only in combination with external synchronization. Lack of appropriate synchronization leads to a time-of-check, time-of-use (TOCTOU) race condition between invocation of the object's state-testing method and the call to a method that depends on the object's state. During this interval, the object's state could change unexpectedly or even maliciously.

Method return values and/or error codes must accurately specify the object's state at an appropriate level of abstraction. Clients must be able to rely on the value for performing critical decisions.

Noncompliant Code Example

As shown in this example, noncompliant methods can silently corrupt the state of the object if they fail to return a value that the developer can intuitively interpret:

public void updateNode(int id, int newValue){		
  Node current = root;
  while(current != null){
    if(current.getId() == id){
      current.setValue(newValue);
      break;
    }
    current = current.next;
  }
}

Compliant Solution

This compliant solution returns the result of the operation: true for success and false for failure:

public boolean updateNode(int id, int newValue){		
  Node current = root;
  while(current != null){
    if(current.getId() == id){
      current.setValue(newValue);
      return true; // Node successfully updated
    }
    current = current.next;
  }
  return false;
}

Compliant Solution

This compliant solution returns the updated Node so that the developer can simply check for a null value lest the operation fails. Return values for methods can vary depending on the control flow or the information that the developer finds more useful.

public Node updateNode(int id, int newValue){	
  Node current = root;
  while(current != null){
    if(current.getId() == id){
      current.setValue(newValue);
      return current;
    }
    current = current.next;
  }
  return null;
}

Compliant Solution

This solution combines the best of both worlds—exceptions and status codes. In this case, an exception is thrown if the operation is unsuccessful. The exception ensures that the client has to handle the event where the Node is not found. If the Node is found, it is updated and returned.

public Node updateNode(int id, int newValue) throws NodeNotFoundException {
  Node current = root;
  while(current != null){
    if(current.getId() == id){
      current.setValue(newValue);
      return current;
    }
    current = current.next;
  }	
  throw new NodeNotFoundException();
}

Applicability

Failure to provide appropriate feedback through a combination of return values, error codes, and exceptions can lead to inconsistent object state and unexpected program behavior.

Related Guidelines

[MITRE CWE]CWE-389, Error conditions, return values, status codes
CWE-393, Return of wrong status code

Bibliography

 


  • No labels