A common misconception is to assume that shared references to immutable objects are made visible across multiple threads as soon as they are updated. For instance, a developer can misconceive that a class containing fields referring to only immutable objects, is immutable, and consequently, thread-safe.
The Java⢠Programming Language, Fourth Edition [[JPL 06]], "Section 14.10.2. Final Fields and Security" states:
... you can use
final
fields to define immutable objects. There is a common misconception that shared access to immutable objects does not require any synchronization because the state of the object never changes. This is a misconception in general because it relies on the assumption that a thread will be guaranteed to see the initialized state of the immutable object, and that need not be the case. The problem is that, while the shared object is immutable, the reference used to access the shared object is itself shared and often mutable. Consequently, a correctly synchronized program must synchronize access to that shared reference, but often programs do not do this, because programmers do not recognize the need to do it. For example, suppose one thread creates aString
object and stores a reference to it in astatic
field. A second thread then uses that reference to access the string. There is no guarantee, based on what we've discussed so far, that the values written by the first thread when constructing the string will be seen by the second thread when it accesses the string.
References to both immutable and mutable objects must be made visible to all the threads. Immutable objects can be safely shared amongst multiple threads, however, mutable objects may not be fully constructed when their references are made visible. The guideline [CON26-J. Do not publish partially initialized objects] focuses on object construction and visibility issues specific to mutable objects.
Noncompliant Code Example
This noncompliant code example consists of an immutable class Helper
:
// Immutable Helper public final class Helper { private final int n; public Helper(int n) { this.n = n; } // ... }
and a mutable class Foo
:
final class Foo { private Helper helper; public Helper getHelper() { return helper; } public void setHelper(int num) { helper = new Helper(num); } }
The getHelper()
method publishes the mutable helper
field. Because the Helper
class is [immutable], it cannot be changed after it is initialized
do not replace with "after initialization"
. Furthermore, it is always properly constructed before its reference is made visible, in compliance with [CON26-J. Do not publish partially initialized objects]. However, a thread can observe the helper
field of class Foo
to contain a stale reference.
Compliant Solution (synchronization)
This compliant solution synchronizes the methods of class Foo
to ensure that no thread sees a stale Helper
reference.
final class Foo { private Helper helper; public synchronized Helper getHelper() { return helper; } public synchronized void setHelper(int num) { helper = new Helper(num); } }
The immutable Helper
class remains unchanged.
Compliant Solution (volatile
)
References to immutable member objects can be made visible by declaring them volatile
.
final class Foo { private volatile Helper helper; public Helper getHelper() { return helper; } public void setHelper(int num) { helper = new Helper(num); } }
The immutable Helper
class remains unchanged.
Compliant Solution (java.util.concurrent
utilities)
This compliant solution uses an AtomicReference
wrapper around the immutable Helper
object.
final class Foo { private final AtomicReference<Helper> helperRef = new AtomicReference<Helper>(); public Helper getHelper() { return helperRef.get(); } public void setHelper(int num) { helperRef.set(new Helper(num)); } }
The immutable Helper
class remains unchanged.
It is also possible to declare the helper
field as final, and consequently render class Foo
immutable, however, this may not be in agreement with the class's functional specification.
Risk Assessment
The assumption that classes containing immutable objects are immutable is misleading and can cause serious thread-safety issues.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
CON28-J |
low |
probable |
medium |
P4 |
L2 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
[[API 06]]
[[JPL 06]], 14.10.2. Final Fields and Security:
[!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_left.png!] [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_up.png!] [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_right.png!]