Wiki Markup |
---|
According to the Java Language Specification \[[JLS 05|AA. Java References#JLS 05]\], section 17.9 "Sleep and Yield": |
...
{quote} It is important to note that neither {{Thread.sleep}} nor {{Thread.yield}} have any synchronization semantics. In particular, the compiler does not have to flush writes cached in registers out to shared memory before a call to {{Thread.sleep}} or {{Thread.yield}}, nor does the compiler have to reload values cached in registers after a call to {{Thread.sleep}} or {{Thread.yield |
...
The assumption that thread suspension and yielding flush the cached registers and reload the values when execution resumes, is misleading and paves the way for potential coding errors.
...
}}. {quote} The assumption that thread suspension and yielding flush the cached registers and reload the values when execution resumes, is misleading and paves the way for potential coding errors. The {{Thread.getState()}} method returns the current state of a thread. Using this method for synchronization control such as checking whether a thread is blocked on a wait is inappropriate because a blocked thread is not always required to enter the {{WAITING}} or {{TIMED_WAITING}} state in cases where the JVM chooses to implement the blocking using spin-waiting \[[Goetz 06|AA. Java References#Goetz 06]\]. |
...
Noncompliant Code Example
This noncompliant code example declares a non-volatile Boolean
flag.
Code Block | ||
---|---|---|
| ||
h2. Noncompliant Code Example ({{sleep()}})
This noncompliant code example declares a non-volatile {{Boolean}} flag.
{code:bgColor=#FFCCCC}
private Boolean done;
while (!this.done) {
Thread.sleep(1000);
}
|
...
{code} "The compiler is free to read the field {{this.done}} just once, and reuse the cached value in each execution of the loop. This would mean that the loop would never terminate, even if another thread changed the value of {{this.done}}." \[[JLS 05|AA. Java References#JLS 05]\]. This occurs because {{Thread.sleep()}} does not establish a [happens-before|BB. Definitions#happens-before order] relation. |
...
h2. Compliant Solution |
...
This compliant solution declares the flag {{volatile}} to ensure that updates to it are made visible across multiple threads. |
...
Code Block | ||
---|---|---|
| ||
{code:bgColor=#ccccff}
private volatile Boolean done;
while (!this.done) {
Thread.sleep(1000);
}
|
The volatile
flag establishes a happens-before relation between this thread and any other thread that sets done
.
Risk Assessment
Relying on class Thread's sleep()
, yield()
and getState()
methods for synchronization control can cause unexpected behavior.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CON16- J | low | probable | medium | P4 | L3 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
...
{code} The {{volatile}} flag establishes a [happens-before|BB. Definitions#happens-before order] relation between this thread and any other thread that sets {{done}}. h2. Noncompliant Code Example ({{getState()}}) This noncompliant code example defines a {{doSomething()}} method that starts a thread. The thread supports interruption by checking a volatile flag and blocks waiting until notified. The {{stop()}} method notifies the thread if it is blocked on the wait and sets the flag to true so that the thread can terminate. {code:bgColor=#FFCCCC} public class Waiter { private volatile Thread thread; private volatile boolean flag; private final Object lock = new Object(); public void doSomething() { thread = new Thread(new Runnable() { public void run() { synchronized(lock) { while(!flag) { try { lock.wait(); // ... } catch (InterruptedException e) { // Forward to handler } } } } }); thread.start(); } public boolean stop() { if (thread != null) { Enum<?> e = thread.getState(); if (e.name().equals("WAITING")) { flag = true; synchronized(lock) { lock.notifyAll(); } return true; } } return false; } } {code} The {{stop()}} method incorrectly uses the {{Thread.getState()}} method to check whether the thread is still blocked and has not terminated, before delivering the notification. Because the thread may never enter the {{WAITING}} state, the {{stop()}} method may not terminate the thread. h2. Compliant Solution This compliant solution removes the check for determining whether the thread is in the {{WAITING}} state. This check is unnecessary because invoking {{notifyAll()}} on a thread that is not blocked on a {{wait()}} invocation has no effect. {code:bgColor=#ccccff} public class Waiter { // ... public boolean stop() { if (thread != null) { Enum<?> e = thread.getState(); flag = true; synchronized(lock) { lock.notifyAll(); } return true; } return false; } } {code} {mc} This does not talk about invoking getState() and comparing with TERMINATE, RUNNABLE and other states. Should we? {mc} h2. Risk Assessment Relying on class Thread's {{sleep()}}, {{yield()}} and {{getState()}} methods for synchronization control can cause unexpected behavior. || Rule || Severity || Likelihood || Remediation Cost || Priority || Level || | CON16- J | low | probable | medium | {color:green}{*}P4{*}{color} | {color:green}{*}L3{*}{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+CON44-J]. h2. References \[[JLS 05|AA. Java References#JLS 05]\] section 17.9 "Sleep and Yield" |
...
---- [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_left.png!|CON15-J. Ensure actively held locks are released on exceptional |
...
conditions] [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_up.png!|11. Concurrency (CON)] [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_right.png!|CON17-J. Avoid using ThreadGroup APIs] |