Concurrency related vulnerabilities can manifest themselves when assumptions are made about the multithreaded behavior of derived classes. An overridden synchronized method's contract may be violated if a subclass defines an implementation that is not safe for concurrent access. Furthermore, if an overridden method makes concurrency guarantees, even if it is not itself synchronized, the subclass must adhere to those guarantees.
The rule CON04-J. Synchronize using an internal private lock object places stringent documentation requirements on any class that can be subclassed and makes concurrency guarantees.
Noncompliant Code Example (
...
synchronized method
...
)
This noncompliant code example defines a synchronized doSomething() method in a class called SynchronizedBase.
| Code Block | ||
|---|---|---|
| ||
class SynchronizedBaseThreadSafeBase { public synchronized void doSomething() { // ... } } class UnsynchronizedSubclassThreadUnsafeSubclass extends SynchronizedBaseThreadSafeBase { public void doSomething() { // ... } } |
The base method can be safely used by many threads. However, if a subclass UnsynchronizedSubclass ThreadUnsafeSubclass overrides the method but leaves it unsynchronized, its instance cannot be safely passed to multiple threads.
This problem is hard to notice because threads that accept instances of SynchronizedBase ThreadSafeBase also accept instances of its subclasses. Consequently, the threads may incorrectly assume that the subclasses are thread-safe.
Compliant Solution (synchronized method
...
)
This compliant solution synchronizes the doSomething() method of the subclass.
| Code Block | ||
|---|---|---|
| ||
class SynchronizedBaseThreadSafeBase { public synchronized void doSomething() { // ... } } class SynchronizedSubclassThreadSafeSubclass extends SynchronizedBaseThreadSafeBase { public synchronized void doSomething() { // ... } } |
This compliant solution does not violate CON04-J. Synchronize using an internal private lock object because the accessibility of the class is package-private which is allowable when untrusted code cannot infiltrate the package.
Compliant Solution (block synchronization in subclass)
Noncompliant Code Example (private lock)
This noncompliant code example defines a doSomething() method in a class called ThreadSafeBase. This method utilizes an internal private lock, in accordance with CON04-J. Synchronize using an internal private lock object.
| Code Block | ||
|---|---|---|
| ||
class ThreadSafeBase {
private final Object lock = new Object();
public void doSomething() {
synchronized (lock) {
// ...
}
}
}
class ThreadUnsafeSubclass extends ThreadSafeBase {
public void doSomething() {
// ...
}
}
|
The base method can be safely used by many threads. However, if a subclass ThreadUnsafeSubclass overrides the method but provides no concurrency guarantees, its instance cannot be safely passed to multiple threads.
Compliant Solution (private lock)
This compliant solution synchronizes the doSomething() method of the subclassAn alternative is to use block synchronization by defining an internal private final lock object in the extending class.
| Code Block | ||
|---|---|---|
| ||
class ThreadSafeBase { private final Object lock = new Object(); public void doSomething() { synchronized (lock) { // ... } } } class SynchronizedSubclassThreadSafeSubclass extends SynchronizedBaseThreadSafeBase { private final Object lock = new Object(); public void doSomething() { synchronized (lock) { // ... } } } |
This is the preferred choice when untrusted code can obtain the intrinsic lock of the class object (CON04-J. Synchronize using an internal private lock object).
Exceptions
EX1: If the subclass implements block synchronization instead of method synchronization, it is likely that thread-safety has been accounted for. This condition should be sufficiently documentedNote that the ThreadSafeBase.lock and ThreadSafeSubclass.lock objects are distinct and mutually invisible. Consequently ThreadSafeSubclass can provide some thread-safety guarantees similar to ThreadSafeBase.
Risk Assessment
Failure to provide synchronization in overriding methods can result in unexpected behavior.
...