...
Synchronizing both methods guarantees that they cannot execute concurrently. If one thread were to call initialize()
just before another thread calls called getHelper()
, the synchronized initialize()
method will would always finish first. The synchronized
keywords establish a happens-before relationship between the two threads. Consequently, the thread calling getHelper()
would see either the fully initialized Helper
object or an absent Helper
object (that is, helper
would contain a null
reference). This approach guarantees proper publication both for immutable and for mutable members.
...
The Java Memory Model guarantees that the fully-initialized values of fields that are declared final will be fully constructed before any reference to the containing object is made visibleare safely published to every thread that reads those values at some point no later than the end of the object's constructor.
Code Block | ||
---|---|---|
| ||
class Foo { private final Helper helper; public Helper getHelper() { return helper; } public Foo() { // Point 1 helper = new Helper(42); // Point 2 } } |
...
Consequently, the reference to the helper
instance should not be published before remain unpublished until the Foo
class's constructor has finished its initializationcompleted. ( See rule TSM01-J. Do not let the (this) reference escape during object construction for additional information.)
Compliant Solution (Final Field and Thread-safe Composition)
...
The helper
field is declared final to guarantee that the vector is always created before any accesses take place. It can be initialized safely by invoking the synchronized initialize()
method, which ensures that only one Helper
object is ever added to the vector. If getHelper()
is is invoked before initialize()
, it calls initializeThe getHelper()
to avoid avoids the possibility of a null-pointer de-reference by the client. The getHelper()
method does not require synchronization to simply return Helper
, and, because the conditionally invoking initialize()
. Although the isEmpty()
call in getHelper()
is made from an unsynchronized context (which permits multiple threads to decide that they must invoke initialize
, race conditions that could result in addition of a second object to the vector are nevertheless impossible. The synchronized initialize()
method also checks to make sure whether helper
is empty before adding a new Helper
object, there is no possibility of exploiting a race condition to add a second object to the vectorand at most one thread can execute initialize()
at any time; consequently, only the first thread to execute initialize can ever see an empty vector. Consequently, the getHelper()
method can safely omit any synchronization of its own.
Compliant Solution (Static Initialization)
In this compliant solution, the helper
field is initialized statically initialized, ensuring that the object referenced by the field is fully initialized before its reference is becomes visible.
Code Block | ||
---|---|---|
| ||
// Immutable Foo final class Foo { private static final Helper helper = new Helper(42); public static Helper getHelper() { return helper; } } |
Although not a requirement, the The helper
field should be declared final to document the class's immutability.
...
This compliant solution requires that helper
be declared volatile and that class Helper
be immutable. If it were not immutablemutable, the code would violate rule VNA06-J. Do not assume that declaring a reference volatile guarantees visibility of the members of the referenced object, and additional synchronization would be necessary. (See ; see the next compliant solution for details. ) AndAdditionally, if the helper
field were non-volatile, it would violate rule VNA01-J. Ensure visibility of shared references to immutable objects.
Similarly, Providing a public static factory method that returns a new instance of Helper
can be provided in the Helper
class Helper
is both permitted and encouraged. This approach allows the Helper
instance to be created in a private
constructor.
Compliant Solution (Mutable Thread-safe Object, Volatile Reference)
If When Helper
is mutable but thread-safe, it can be published safely by declaring the helper
field in the Foo
class volatile.
Code Block | ||
---|---|---|
| ||
class Foo { private volatile Helper helper; public Helper getHelper() { return helper; } public void initialize() { helper = new Helper(42); } } // Mutable but thread-safe Helper public class Helper { private volatile int n; private final Object lock = new Object(); public Helper(int n) { this.n = n; } public void setN(int value) { synchronized (lock) { n = value; } } } |
Because the Helper
object can change state after its construction, synchronization is necessary Synchronization is required to ensure the visibility of mutable members after initial publication . Consequently, because the Helper
object can change state after its construction. This compliant solution synchronizes the setN()
method is synchronized to provide guarantee the visibility of the n
field in this compliant solution. ( See rule VNA06-J. Do not assume that declaring a reference volatile guarantees visibility of the members of the referenced object for additional information.)
If the Helper
class is not was synchronized properlyincorrectly, declaring helper
volatile in the Foo
class class would guarantee only guarantees the visibility of the initial publication of Helper
and not ; the visibility guarantee would exclude visibility of subsequent state changes. Consequently, volatile references alone are inadequate for publishing objects that are not thread-safe.
If the helper
field in the Foo
class is not declared volatile, the n
field should be declared volatile so that to establish a happens-before relationship is established between the initialization of n
and the write of Helper
to the helper
field. This is in compliance would comply with rule VNA06-J. Do not assume that declaring a reference volatile guarantees visibility of the members of the referenced object. This is required only when the caller (class Foo
) cannot be trusted to declare helper
volatile.
...
TSM03-EX1: Classes that prevent partially initialized objects from being used may publish partially initialized objects. This may could be implemented, for example, by setting a volatile boolean flag in the last statement of the initializing code and ensuring checking whether this flag is set before allowing class methods to execute.
...
This technique ensures that, even if in the event that a reference to the Helper
object instance is were published before its initialization is overwas complete, the instance is unusable. The instance is would be unusable because every each method within Helper
must check checks the flag to determine whether the initialization has finished.
Risk Assessment
Failing Failure to synchronize access to shared mutable data can cause different threads to observe different states of the object or to observe a partially-initialized object.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
TSM03-J | medium | probable | medium | P8 | L2 |
Automated Detection
...
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
...
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="6e68f386b4c70f76-0cece812-4fcd4af1-8c8490db-70a6682731d65e6891e434d5"><ac:plain-text-body><![CDATA[ | [[API 2006 | AA. Bibliography#API 06]] |
| ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="5cbb1c632dfc6fd0-8ec56f17-458d4edc-ad3ab337-067577ee5cb769cd77e7ab70"><ac:plain-text-body><![CDATA[ | [[Bloch 2001 | AA. Bibliography#Bloch 01]] | Item 48: "Synchronize access to shared mutable data" | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="ab11487805f43808-7212562d-40864f75-ab71b418-fd2422fb6fb40d6cbec92a93"><ac:plain-text-body><![CDATA[ | [[Goetz 2006 | AA. Bibliography#Goetz 06]] | Section 3.5.3 "Safe Publication Idioms" | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="732c72b310871737-835b527b-467849ca-845ca15b-251e5962c368dc1ec75110df"><ac:plain-text-body><![CDATA[ | [[Goetz 2007 | AA. Bibliography#Goetz 07]] | Pattern #2: "one-time safe publication" | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="c4c19e61c81b7b51-0a5cce05-453c4e3a-81c1bf8f-3c1be9dc13d12c59f4bdfaf4"><ac:plain-text-body><![CDATA[ | [[JPL 2006 | AA. Bibliography#JPL 06]] | 14.10.2. "Final Fields and Security" | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="e96f562e44ef6738-5d2f14ce-46874659-b31d88e9-03171fb936764f577238427b"><ac:plain-text-body><![CDATA[ | [[Pugh 2004 | AA. Bibliography#Pugh 04]] |
| ]]></ac:plain-text-body></ac:structured-macro> |
...