Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: re-wrote

Declaring an immutable or thread-safe object as volatile ensures that a thread will not observe the object in an inconsistent state prior to its initialization. However, declaring mutable or thread-unsafe objects volatile does not offer any such advantages. object volatile to ensure visibility of the most up-to-date object state does not work without the use of explicit synchronization in cases where the object is not thread-safe.

Wiki Markup
In the absence of synchronization, the effect of declaring an object {{volatile}} is that multiple threads which see the new object reference never see a partially initialized object. However, this holds only when the object is "effectively immutable" \[[Goetz 07|AA. Java References#Goetz 07]\], that is, its state cannot be directly or indirectly changed after the object is initialized or published. 

Noncompliant Code Example

This noncompliant code example declares an instance field of type Date Map as volatile. The problem is that the field can be changed mutated using a setter method setDateputData(). Even if one thread sees the new reference, the object state that it observes may change in the meantime.

Code Block
bgColor#FFCCCC#FFcccc
public class FooContainer<K,V> {
  public volatile DateMap<K,V> dmap;
    
  public FooContainer() {
    dmap = new DateHashMap<K,V>();  	
  }
  
  public voidV setDateget(DateObject datek) {
    d = datereturn map.get(k);
  }
  
  public Datevoid getDate(putData(K key, V value) {
    //  return dPerform validation of value
    map.put(key, value);
  }  
}

public class Client {
  public void doSomething() {
    FooContainer fcon = new FooContainer();
    // This needs to see the fully constructed object not just the reference
    if (fcon.dmap != null) { 
      // ...            	
    }             
  }
}

The client code depends on the publication of the Date object to carry out its operations. There is a race condition between setting the date and checking in the client code, whether it is null. During the race window interval, the state of the Date object could change.

Compliant Solution

Even if the client thread sees the new reference, the object state that it observes may change in the meantime. Because the object is not effectively immutable, it is unsafe for use in a multi-threaded environment.

Compliant Solution (final)

This compliant solution declares the Map instance as final because the semantics of final dictate that the object will be immediately visible after initializationThe object can only be safely published if it is immutable or thread-safe. Otherwise, explicit synchronization is required to ensure thread safety. This compliant solution uses volatile to guard retrievals that use the getter method. A synchronized setter method is used to set the value of the Date object to ensure thread-safety. Defensive copies of the setter argument must be made to make the class Foo effectively immutable.

Code Block
bgColor#ccccff
public class FooContainer<K,V> {
  publicfinal volatile Date dMap<K,V> map;
    
  public FooContainer() {
    dmap = new DateHashMap<K,V>();	
  }

  public V }
  get(Object k) {
  public synchronized voidreturn setDate(Date date) {    
    // Defensive copyingmap.get(k);
  }
}

The obvious drawback of this solution is that the setter method cannot be accommodated if the goal is to ensure immutability. The Container and Map class are both effectively immutable in this case because the Map instance can only be manipulated via one of the setters whilst there is none here. The words effectively immutable are used instead of immutable because the Map instance is technically mutable but restricted here so that it has all the immutability properties. The Map class does not have any static methods that can be used to change its state, so the effective immutability property is enforced.

Compliant Solution (volatile)

It follows from the previous compliant solution that it is safe to declare the object volatile because it is effectively immutable.

Code Block
bgColor#ccccff

public class Container<K,V> {
  volatile Map<K,V> map;

  public Container() {
    dmap = date.clonenew HashMap<K,V>();	
  }
  
  public DateV getDateget(Object k) {
    return dmap.cloneget(k);
  }  
}

Compliant Solution (synchronization)

This compliant solution ensures that the Foo object is immutable by removing the setter method and declaring the Date field as final. The Date object can be safely published as a resultuses explicit synchronization to ensure thread safety. It declares the object volatile to guard retrievals that use the getter method. A synchronized setter method is used to set the value of the Map object.

Code Block
bgColor#ccccff
public class FooContainer<K,V> {
  publicvolatile final Date dMap<K,V> map;
    
  public FooContainer() {
    dmap = new DateHashMap<K,V>();	
  }

  }
    public V get(Object k) {
    return map.get(k);
  }

  public synchronized Datevoid getDate(putData(K key, V value) {
    // Perform  return d.clone(validation of value
    map.put(key, value);
  }  
}

This compliant solution has the advantage that it can accommodate the setter method. Declaring the object as volatile for safe publication using getter methods is cheaper in terms of performance, than declaring the getters as synchronized. However, it is mandatory to synchronize the setter methods.

Risk Assessment

Failing to synchronize access to shared mutable data can cause different threads to observe different states of the object.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

CON26- J

medium

probable

medium

P12 P8

L1 L2

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

Wiki Markup
\[[Goetz 07|AA. Java References#Goetz 07]\] Pattern #2: "one-time safe publication"

...