Before the garbage collector acts on an object to reclaim it, the object's finalizer is executed. This is required to ensure that resources such as open streams, files and network connections get freed since resource management does not happen automatically while reclaiming memory. In Java, the finalize method of java.lang.Object is used to perform this activity.

The caveats associated with the use of finalizers are discussed here:

Class MyFrame extends Jframe {
  private byte[] buffer = new byte[16 * 1024 * 1024]; // persists for at least two GC cycles 
}

Exceptions

OBJ02-EX1: Sometimes it is necessary to use finalizers especially while working with native objects/code. This is because the garbage collector cannot re-claim memory from code written in another language. Also, the lifetime of the objects is often unknown. Again, the native process must not perform any critical jobs that require immediate resource deallocation.

In such cases, finalize should be used correctly. Any subclass that overrides finalize must explicitly invoke the method for its superclass as well. There is no automatic chaining with finalize. The correct way to handle this is shown next.

protected void finalize() throws Throwable {
  try {
    //...
  }
  finally {
    super.finalize();
  }
}

Alternatively, a more expensive solution is to declare an anonymous class so that the {{finalize}} method is guaranteed to run for the superclass. This solution is applicable to public non-final classes. "The finalizer guardian object forces {{super.finalize}} to be called if a subclass overrides finalize and does not explicitly call {{super.finalize}}". \[[JLS 05|AA. Java References#JLS 05]\] Section 12.6.1: Implementing Finalization.

public class Foo {
  // The finalizeGuardian object finalizes the outer Foo object
  private final Object finalizerGuardian = new Object() {
    protected void finalize() throws Throwable {
    // Finalize outer Foo object
    }
  };
  //...
}

The ordering problem can be dangerous while dealing with native code. For example, if object A references object B (either directly or reflexively) and the latter gets finalized first, A's finalizer may end up dereferencing dangling native pointers. To impose an explicit ordering on finalizers, make sure that B is reachable before A's finalizer has concluded. This can be done by adding a reference to B in some global state variable and removing it as soon as A's finalizer gets executed. An alternative is to use the java.lang.ref references.

If a superclass defines a finalize method, make sure to decouple the objects that can be immediately garbage collected from those that depend on the finalizer. In the MyFrame example, the following code will ensure that the buffer doesn't persist longer than expected.

Class MyFrame {
  private JFrame frame; 
  private byte[] buffer = new byte[16 * 1024 * 1024]; // now decoupled
}

Risk Assessment

Finalizers can have unexpected behavior.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

OBJ02-J

medium

probable

medium

P8

L2

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

\[[JLS 05|AA. Java References#JLS 05]\] Section 12.6, Finalization of Class Instances
\[[API 06|AA. Java References#API 06]\] [finalize()|http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#finalize()]
\[[Bloch 08|AA. Java References#Bloch 08]\] Item 7, Avoid finalizers 
\[[Darwin 04|AA. Java References#Darwin 04]\] Section 9.5, The Finalize Method
\[[Flanagan 05|AA. Java References#Flanagan 05]\] Section 3.3, Destroying and Finalizing Objects
\[[Coomes 07|AA. Java References#Coomes 07]\] "Sneaky" Memory Retention
\[[Boehm 05|AA. Java References#Boehm 05]\] 
\[[MITRE 09|AA. Java References#MITRE 09]\] [CWE ID 586|http://cwe.mitre.org/data/definitions/586.html] "Explicit Call to Finalize()"


OBJ01-J. Understand how a superclass can affect a subclass      06. Object Orientation (OBJ)      OBJ03-J. Be careful about final reference