You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 40 Next »

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 and double values atomically or in two parts. For the purposes of the Java programming language memory model, a single write to a non-volatile long or double 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. In this noncompliant code example, if one thread repeatedly calls the method one(), and another thread repeatedly calls the method two(), then method two() could occasionally print a value of i that is neither zero nor the value of the argument j.

class LongContainer {
  static long i = 0;

  static void one(long j) {
    i = j; 
  }

  static void two() {
    System.out.println("i = " + i);
  }
}

A similar problem may occur 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 LongContainer {
  static volatile long i = 0;
 
  static void one(long j) { 
    i = j; 
  }
 
  static void two() {
    System.out.println("i = " + i);
  }
}

It is important to ensure that the argument to method one() is obtained from a volatile variable or as a result of explicitly passing an integer value. Otherwise, a read of the variable argument may itself expose a vulnerability.

Semantics of volatile do not guarantee the atomicity of complex operations that involve read-modify-write sequences such as incrementing a value. See CON01-J. Ensure that compound operations on shared variables are atomic for more information.

Exceptions

CON25-EX1: If all reads and writes of 64 bit long and double values occur within a synchronized region, the atomicity of the read/write is guaranteed. This requires that no unsynchronized methods in the class expose the value and that the value is inaccessible (directly or indirectly) from other code. (CON01-J. Ensure that compound operations on shared variables are atomic)

CON25-EX2: Systems that guarantee that 64 bit long and double values are read and written as atomic operations may safely ignore this guideline.

Risk Assessment

Failure to ensure the atomicity of operations involving 64-bit values in multi-threaded applications can result in reading and writing indeterminate values. Many JVMs do handle the reading and writing of 64-bit values atomically, even though the specification does not require them to.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

CON25- J

low

unlikely

medium

P2

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/


CON07-J. Do not assume that a grouping of calls to independently atomic methods is atomic      11. Concurrency (CON)      CON03-J. Do not use background threads during class initialization

  • No labels