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 
}

Noncompliant Code Example

The System.runFinalizersOnExit() method has been used in this noncompliant example to simulate a garbage collection run (note that this method is deprecated due to thread-safety issues).

According to \[[API 06|AA. Java References#API 06]\] class {{System}}, {{runFinalizersOnExit()}} documentation:

Enable or disable finalization on exit; doing so specifies that the finalizers of all objects that have finalizers that have not yet been automatically invoked are to be run before the Java runtime exits. By default, finalization on exit is disabled.

The SubClass overrides the protected finalize method and performs cleanup. Subsequently, it calls super.finalize() to make sure its superclass is also finalized. The unsuspecting BaseClass calls the doLogic() method which happens to be overridden in the SubClass. This resurrects a reference to SubClass such that it is not only prevented from getting garbage collected but also cannot use its finalizer anymore in order to close new resources that may have been allocated by the called method.

class BaseClass {
  protected void finalize() throws Throwable {
    System.out.println("Superclass finalize!");
    doLogic();
  }

  public void doLogic() throws Throwable{
    System.out.println("This is super-class!");
  }
}

class SubClass extends BaseClass {
  protected void finalize() throws Throwable {
    System.out.println("Subclass finalize!");
    try {
      //  cleanup resources 				
    } finally {
      super.finalize();  // call BaseClass' finalizer
    }
  }
	
  public void doLogic() throws Throwable{
    System.out.println("This is sub-class!"); 
    // any resource allocations made here will persist
  }
}

public class BadUse {
  public static void main(String[] args) {
    try {
      BaseClass bc = new SubClass();
      System.runFinalizersOnExit(true); // artificially simulate finalization (do not do this)
    } catch (Throwable t) { /* handle error */ }  		
  }
}

A expected, this code outputs:

Subclass finalize!
Superclass finalize!
This is sub-class!

Compliant Solution

This solution eliminates the call to the overridable doLogic() method from within the finalize() method.

class BaseClass {
  protected void finalize() throws Throwable {
    System.out.println("superclass finalize!");
    // eliminate the call to the overridden doLogic().
  }
  ...
}

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()", [CWE ID 583|http://cwe.mitre.org/data/definitions/583.html] "finalize() Method Declared Public", [CWE ID 568|http://cwe.mitre.org/data/definitions/568.html] "finalize() Method Without super.finalize()"


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