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

Compare with Current View Page History

« Previous Version 73 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 could be performed as two separate, 32-bit operations.

According to the Java Language Specification [[JLS 2005]], 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 result in indeterminate values being read in code that is required to be thread-safe.

Noncompliant Code Example

In this noncompliant code example, if one thread repeatedly calls the assignValue() method and another thread repeatedly calls the printLong() method, the printLong() method could occasionally print a value of i that is neither zero nor the value of the j argument.

class LongContainer {
  private long i = 0;

  void assignValue(long j) {
    i = j;
  }

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

A similar problem can occur if i is declared double.

Compliant Solution (Volatile)

This compliant solution declares i volatile. Writes and reads of long and double volatile values are always atomic.

class LongContainer {
  private volatile long i = 0;

  void assignValue(long j) {
    i = j;
  }

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

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

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

Exceptions

VNA05-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. (For more information, see guideline VNA02-J. Ensure that compound operations on shared variables are atomic.)

VNA05-EX2: This guideline can be ignored for systems that guarantee that 64-bit, long and double values are read and written as atomic operations.

Risk Assessment

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

Guideline

Severity

Likelihood

Remediation Cost

Priority

Level

VNA05-J

low

unlikely

medium

P2

L3

Automated Detection

The Coverity Prevent Version 5.0 ATOMICITY checker can detect the instances of non-atomic update of a concurrently shared value. The result of the update will be determined by the interleaving of thread execution.

Related Vulnerabilities

Any vulnerabilities resulting from the violation of this guideline are listed on the CERT website.

Related Guidelines

MITRE CWE: CWE-667 "Insufficient Locking"

Bibliography

[[JLS 2005]] 17.7 Non-atomic Treatment of double and long
[[Goetz 2006]] 3.1.2. Non-Atomic 64-Bit Operations
[[Goetz 2004c]]


      11. Visibility and Atomicity (VNA)      VNA06-J. Do not assume that declaring an object reference volatile guarantees visibility of its members

  • No labels