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]], section 17.7 "Non-atomic Treatment of double
and long
":
... this behavior is implementation specific; Java virtual machines are free to perform writes to
long
anddouble
values atomically or in two parts. For the purposes of the Java programming language memory model, a single write to a non-volatilelong
ordouble
value 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.
Noncompliant Code Example
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
.
Compliant Solution
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); } }
Compliant Solution
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.
Risk Assessment
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 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
[[JLS 05]] 17.7 Non-atomic Treatment of double and long
[[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