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()
, and another thread repeatedly calls the method two()
:
class Test { static long i = 0; static void one(long j) { i = j; } static void two() { System.out.println("i =" + i); } }
then method two()
could occasionally print a value for i
that is neither zero nor a previous value of j
two()
. A similar problem occurs if i
is declared as a double
.
Compliant Solution (volatile)
This compliant solution declares i
as volatile
. Writes and reads of volatile long
and double
values are always atomic.
class Test { static volatile long i = 0; static void one(long j) { i = j; } static void two() { System.out.println("i =" + i); } }
Compliant Solution (atomic variable classes)
This compliant solution uses atomic variable classes from the java.util.concurrent.atomic
package. These classes provide lock-free thread-safe programming on single variables.
class Test { static AtomicLong i = 0; static void one(long j) { i = j; } static void two() { System.out.println("i =" + i); } }
It is also possible to hold doubles using the Double.doubleToLongBits
and Double.longBitsToDouble
conversions.
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
[[Goetz 04]] Brian Goetz. Java theory and practice: Going atomic. November 2004. http://www.ibm.com/developerworks/java/library/j-jtp11234/
CON06-J. Ensure atomicity of thread-safe code 11. Concurrency (CON) CON02-J. Do not use background threads during class initialization