Finalizer inconsistency¶
ID: java/missing-super-finalize
Kind: problem
Security severity:
Severity: error
Precision: medium
Tags:
- reliability
- maintainability
- external/cwe/cwe-568
Query suites:
- java-security-and-quality.qls
Click to see the query in the CodeQL repository
A finalize
method that overrides the finalizer of a superclass but does not call super.finalize
may leave system resources undisposed of or cause other cleanup actions to be left undone.
Recommendation¶
Make sure that all finalize
methods call super.finalize
to ensure that the finalizer of its superclass is executed. Finalizer chaining is not automatic in Java.
It is also possible to defend against subclasses that do not call super.finalize
by putting the cleanup code into a finalizer guardian instead of the finalize
method. A finalizer guardian is an anonymous object instance that contains the cleanup code for the enclosing object in its finalize
method. The only reference to the finalizer guardian is stored in a private field of the enclosing instance, which means that both the guardian and the enclosing instance can be finalized at the same time. This way, a subclass cannot block the execution of the cleanup code by not calling super.finalize
.
Example¶
In the following example, WrongCache.finalize
does not call super.finalize
, which means that native resources are not disposed of. However, RightCache.finalize
does call super.finalize
, which means that native resources are disposed of.
class LocalCache {
private Collection<NativeResource> localResources;
//...
protected void finalize() throws Throwable {
for (NativeResource r : localResources) {
r.dispose();
}
};
}
class WrongCache extends LocalCache {
//...
@Override
protected void finalize() throws Throwable {
// BAD: Empty 'finalize', which does not call 'super.finalize'.
// Native resources in LocalCache are not disposed of.
}
}
class RightCache extends LocalCache {
//...
@Override
protected void finalize() throws Throwable {
// GOOD: 'finalize' calls 'super.finalize'.
// Native resources in LocalCache are disposed of.
super.finalize();
}
}
The following example shows a finalizer guardian.
class GuardedLocalCache {
private Collection<NativeResource> localResources;
// A finalizer guardian, which performs the finalize actions for 'GuardedLocalCache'
// even if a subclass does not call 'super.finalize' in its 'finalize' method
private Object finalizerGuardian = new Object() {
protected void finalize() throws Throwable {
for (NativeResource r : localResources) {
r.dispose();
}
};
};
}
References¶
Java API Specification: Object.finalize().
J. Bloch, Effective Java (second edition), Item 7. Addison-Wesley, 2008.
Common Weakness Enumeration: CWE-568.