The Java Language Specification allows 64 bit long and double values to be treated as two 32 bit values. For example, a 64-bit write operation may be performed as two separate 32-bit operations.
According to the Java Language Specification \[[JLS 05|AA. Java References#JLS 05]\], section 17.7 "Non-atomic Treatment of {{double}} and {{long}}": |
... this behavior is implementation specific; Java virtual machines are free to perform writes to
longanddoublevalues atomically or in two parts. For the purposes of the Java programming language memory model, a single write to a non-volatilelongordoublevalue is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64 bit value from one write, and the second 32 bits from another write.
This behavior can be result in reading indeterminate values in code that is required to be thread-safe.
The Java programming language allows threads to access shared variables. If, in this noncompliant code example, one thread repeatedly calls the method one() (but no more than Integer.MAX_VALUE times in all), and another thread repeatedly calls the method two():
class Test {
static long i = 0;
static void one() { i++; }
static void two() {
System.out.println("i =" + i);
}
}
|
then method two() could occasionally print a value for i that is not one more than the previous value printed by two(). A similar problem occurs if i is declared as a double.
This compliant solution declares the variables as volatile. Writes and reads of volatile long and double values are always atomic.
class Test {
static long i = 0;
static void one() { i++; }
static void two() {
System.out.println("i =" + i);
}
}
|
This compliant solution synchronizes calls to methods one() and two()}}. This guarantees these two method calls are treated as atomic operation, including reading and writing to the variable i.
class Test {
static long i = 0;
static void synchronized one() { i++; }
static synchronized void two() {
System.out.println("i =" + i);
}
}
|
Consequently, there is no need to qualify i as a volatile type.
Failure to ensure the atomicity of operations involving 64-bit values in multithreaded applications can result in reading and writing indeterminate values.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
|---|---|---|---|---|---|
CON39- J |
low |
probable |
medium |
P4 |
L3 |
TODO
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
\[[JLS 05|AA. Java References#JLS 05]\] 17.7 Non-atomic Treatment of double and long \[[Goetz 06|AA. Java References#Goetz 06]\] 3.1.2. Nonatomic 64-bit Operations |
CON06-J. Ensure atomicity of thread-safe code 11. Concurrency (CON) CON02-J. Do not use background threads during class initialization