Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: added NCE/CS based on concurrency utilities

Wiki Markup
The methods {{java.lang.Object.notify()}} and {{java.lang.Object.notifyAll()}} are used to waken waiting thread(s). These methods must be called from code that holds the same object lock as the waiting thread(s). The method {{notify()}} is deceptive in most cases unless all of the following conditions hold: \[[Goetz 06|AA. Java References#Goetz 06]\]

...

These requirements are typically true when only one thread is waiting. Otherwise, if either condition does not hold, incorrect program behavior may result.

The java.util.concurrent utilities (interface Condition) provide the signal() and signalAll() methods to awaken waiting threads that are blocked on an await() call. Like the notify() method, the signal() method wakes up any one of the threads that is waiting on the condition and consequently, may be insecure.

Noncompliant Code Example

This noncompliant code example violates the liveness property. A lock is obtained using a raw Object lock and three threads are started. Two condition predicates are used. One checks whether the buffer has zero elements and the other checks if the buffer is full with ten elements (buffer is not shown for brevity, only the count of the number of elements in the buffer at any time is shown). Initially the buffer is neither full nor empty. Conditions are created so that the buffer becomes empty and thread 1 goes into wait state, followed by thread 2, when the buffer becomes full.

...

Note that when thread 2 goes into the wait state, the condition predicate of thread 1 becomes false. When notify() is invoked by thread 3, it can be delivered to either thread 1 or thread 2 depending on the particular Java Virtual Machine (JVM). If thread 1 is chosen to be notified, its condition turns out to be false, which terminates it. This is the required functionality, that is, any thread whose condition predicate is false must be terminated. However, if the notification is delivered to thread 2, it has no effect because its condition predicate is still true, and consequently, it goes into the wait state once again. Thread 1 continues to wait despite its condition predicate being false and is not terminated in this case.

Compliant Solution

This compliant solution uses the notifyAll() method which sends notifications to all threads that wait on the same lock object. As a result, liveness is not affected unlike the noncompliant code example. The condition predicate controls which threads can resume their operations. Ensure that the lock is released promptly after the call to notifyAll().

Code Block
bgColor#ccccff
else if(number == 3) {
  list.notifyAll();      	   		  
} 	    	  

Noncompliant Code Example

This noncompliant code example derives from the previous noncompliant code example but uses the Condition interface. Field cond is used to let threads wait on different condition predicates.

Code Block
bgColor#FFcccc

final Condition cond = lock.newCondition();
// ...

public void run (){
  lock.lock();  
  try {    	  
    if(number == 1) {	  
      while(buffer_count == 0) { 
        cond.await();		  
      }  
    } else if(number == 2) {  	    		  
      while(buffer_count == 10) {	
        cond.await();   	    		    	        	    
      }      
    } else if(number == 3) {
      cond.signal();	
    } 	   
  } catch (InterruptedException ie) {
      // Handle the exception
  } finally {
    lock.unlock();
  }
}	  

Similar to Object.notify(), the cond.signal() method may choose either of the threads and awaken it.

Compliant Solution (signalAll())

This compliant solution uses the signalAll() method to resume all the waiting threads whose condition predicate allows doing so.

Code Block
bgColor#ccccff

} else if(number == 3) {
  cond.signalAll();
} 

Compliant Solution (create more Condition variables)

This compliant solution uses two different condition variables full and empty to indicate whether the the buffer is full or empty, respectively.

Code Block
bgColor#ccccff

final Lock lock = new ReentrantLock();
final Condition full = lock.newCondition();
final Condition empty = lock.newCondition();
// ...

public void run (){
  lock.lock();  
  try {    	  
    if(number == 1) {	  
      while(buffer_count == 0) { 
        empty.await();		  
      }  
    } else if(number == 2) {  	    		  
      while(buffer_count == 10) {	
        full.await();   	    		    	        	    
      }
    } else if(number == 3) {
      empty.signal();	
      full.signal();      	   		  
    } 	   
  } catch (InterruptedException ie) {
    // Handle the exception
  } finally {
    lock.unlock();
  }
}	  

Even though signal() is used, it is guaranteed that only one thread will awaken because each condition predicate corresponds to a unique Condition variable.

Exceptions

EX1: If there are several similar threads waiting for a notification, and it is permissible to invoke any of them, notify() may be used. The criteria for liveness is relaxed in this case.

Risk Assessment

Invoking the notify() method instead of notifyAll() can be a threat to the liveness property of the system.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

CON19- 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

Wiki Markup
\[[JLS 05|AA. Java References#JLS 05]\] [Chapter 17, Threads and Locks|http://java.sun.com/docs/books/jls/third_edition/html/memory.html]
\[[Goetz 06|AA. Java References#Goetz 06]\] Section 14.2.4, Notification
\[[Bloch 01|AA. Java References#Bloch 01]\] Item 50: Never invoke wait outside a loop

...