Javaâs Java's garbage collection feature provides significant benefits from a security perspective over non-garbage-collected languages such as C and C++. The garbage collector (GC) is designed to automatically reclaim unreachable memory and avoid memory leaks. Although it is quite adept at performing this task, a malicious attacker can nevertheless launch a denial-of-service (DoS) attack, for example, by inducing abnormal heap memory allocation or abnormally prolonged object retention. For example, some versions of the GC could need to halt all executing threads to keep up with incoming allocation requests that trigger increased heap management activity. System throughput rapidly diminishes in this scenario. Real-time systems, in particular, are vulnerable to a more subtle slow-heap-exhaustion DoS attack, perpetrated by stealing CPU cycles. An attacker can perform memory allocations in a way that increases the consumption of resources (such as CPU, battery power, and memory) without triggering an OutOfMemoryError
. Writing garbage-collection-friendly code helps restrict many attack avenues.
...
This noncompliant code example uses both a short-lived local object rarelyUsedBuffer
and a long-lived heavily used object heavilyUsedBuffer
. Both are allocated in nonheap memory and are not garbage collected.
Code Block | ||
---|---|---|
| ||
ByteBuffer rarelyUsedBuffer = ByteBuffer.allocateDirect(8192);
// use rarelyUsedBuffer once
ByteBuffer heavilyUsedBuffer = ByteBuffer.allocateDirect(8192);
// use heavilyUsedBuffer many times
|
...
This compliant solution uses an indirect buffer to allocate the short-lived, infrequently used object. The heavily used buffer appropriately continues to use a nonheap, non-garbage-collected direct buffer.
Code Block | ||
---|---|---|
| ||
ByteBuffer rarelyUsedBuffer = ByteBuffer.allocate(8192);
// use rarelyUsedBuffer once
ByteBuffer heavilyUsedBuffer = ByteBuffer.allocateDirect(8192);
// use heavilyUsedBuffer many times
|
...
In this noncompliant code example, buffer
is a local variable that holds a reference to a temporary array. The programmer attempts to help the GC by assigning null
to the buffer
array when it is no longer needed.
Code Block | ||
---|---|---|
| ||
int[] buffer = new int[100];
doSomething(buffer);
buffer = null // No need to explicitly assign null
|
...
This compliant solution uses a lexical block to control the scope, and consequently the lifetime, of the buffer
object.
Code Block | ||
---|---|---|
| ||
{ // limit the scope of buffer
int[] buffer = new int[100];
doSomething(buffer);
}
|
...
In this noncompliant code example, a long-lived ArrayList
contains references to both long- and short-lived elements. The programmer marks elements that have become irrelevant by setting a âdeadâ flag in the object.
Code Block | ||
---|---|---|
| ||
class DataElement {
private boolean dead = false;
// other fields
public boolean isDead() { return dead; }
public void killMe() { dead = true; }
}
// elsewhere
ArrayList longLivedList = new ArrayList<DataElement>(...);
// processing that renders an element irrelevant
// Kill the element that is now irrelevant
longLivedList.get(someIndex).killMe();
|
...
In this compliant solution, rather than use a dead flag, the programmer assigns null
to ArrayList
elements that have become irrelevant.
Code Block | ||
---|---|---|
| ||
class DataElement {
// dead flag removed
// other fields
}
// elsewhere
ArrayList longLivedList = new ArrayList<DataElement>(...);
// processing that renders an element irrelevant
// set the reference to the irrelevant DataElement to null
longLivedList.set(someIndex, null);
|
...
This compliant solution avoids the problems associated with intentionally null references by using a singleton sentinel object. This technique is known as the Null Object pattern (also as the Sentinel pattern). When feasible, programmers should choose this design pattern over the explicit null reference values.
Code Block | ||
---|---|---|
| ||
class DataElement {
public static final DataElement NULL = createSentinel();
// dead flag removed
// other fields
private static final DataElement createSentinel() {
// allocate a sentinel object, setting all its fields
// to carefully chosen "do nothing" values
}
}
// elsewhere
ArrayList longLivedList = new ArrayList<DataElement>(...);
// processing that renders an element irrelevant
// set the reference to the irrelevant DataElement to
// the NULL object
longLivedList.set(someIndex, NULL);
|
...
[API 2006] | Class |
Item 6: âEliminate obsolete object referencesâ | |
Garbage Collection Concepts and Programming Tips | |
Java theory and practice: Garbage collection and performance | |
[Lo 2005] | Security Issues in Garbage Collection |
OBJ03-J. Do not mix generic with nongeneric raw types in new code 04. Object Orientation (OBJ) 05. Methods (MET)