A common misconception is that shared references to immutable objects are visible across multiple threads as soon as they are updated. For example, a developer can mistakenly believe that a class containing fields referring to only immutable objects, is immutable, and consequently, thread-safe.
The Java⢠Programming Language, Fourth Edition, "Section 14.10.2. Final Fields and Security" states \[[JPL 06|AA. Java References#JPL 06]\]:
{quote}
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.
{quote}
{mc} The String example might be good for the intro...if the long quote was not a good idea, perhaps a "For example, ..." line will help {mc}
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] discusses object construction and visibility issues specific to mutable objects.
h2. Noncompliant Code Example
This noncompliant code example consists of an immutable class {{Helper}}:
{code}
// Immutable Helper
public final class Helper {
private final int n;
public Helper(int n) {
this.n = n;
}
// ...
}
{code}
and a mutable class {{Foo}}:
{code:bgColor=#FFCCCC}
final class Foo {
private Helper helper;
public Helper getHelper() {
return helper;
}
public void setHelper(int num) {
helper = new Helper(num);
}
}
{code}
The {{getHelper()}} method publishes the mutable {{helper}} field. Because the {{Helper}} class is [immutable|BB. Definitions#immutable], it cannot be changed after it is initialized{mc} do not replace with "after initialization" {mc}. Furthermore, because {{Helper}} is immutable, it is always properly constructed before its reference is made visible, in compliance with [CON26-J. Do not publish partially initialized objects]. Unfortunately, a separate thread might observe a stale reference in the {{helper}} field of class {{Foo}}.
h2. Compliant Solution (synchronization)
This compliant solution synchronizes the methods of class {{Foo}} to ensure that no thread sees a stale {{Helper}} reference.
{code:bgColor=#CCCCFF}
final class Foo {
private Helper helper;
public synchronized Helper getHelper() {
return helper;
}
public synchronized void setHelper(int num) {
helper = new Helper(num);
}
}
{code}
The immutable {{Helper}} class remains unchanged.
h2. Compliant Solution ({{volatile}})
References to immutable member objects can be made visible by declaring them {{volatile}}.
{code:bgColor=#CCCCFF}
final class Foo {
private volatile Helper helper;
public Helper getHelper() {
return helper;
}
public void setHelper(int num) {
helper = new Helper(num);
}
}
{code}
The immutable {{Helper}} class remains unchanged.
h2. Compliant Solution ({{java.util.concurrent}} utilities)
This compliant solution wraps the immutable {{Helper}} object within an {{AtomicReference}} wrapper that may be updated atomically.
{code:bgColor=#CCCCFF}
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));
}
}
{code}
The immutable {{Helper}} class remains unchanged.
{mc} Sometimes I use the area before the risk assessment as a summary area for other CSs that can simply be mentioned to avoid redundancy, or CSs that are worth considering but have limitations which preclude us from recommending them. Basically general advice so that the implementer is not left wondering with a "what if I use ..." question. You deleted the line about making Helper immutable so where could such advice go? {mc}
h2. 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 | {color:green}{*}P4{*}{color} | {color:green}{*}L2{*}{color} |
h3. Automated Detection
TODO
h3. Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the [CERT website|https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+CON28-J].
h2. References
\[[API 06|AA. Java References#API 06]\]
\[[JPL 06|AA. Java References#JPL 06]\] Section 14.10.2. Final Fields and Security
----
[!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_left.png!|FIO36-J. Do not create multiple buffered wrappers on an InputStream] [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_up.png!|09. Input Output (FIO)] [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_right.png!|09. Input Output (FIO)]
|