Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Wiki Markup
According to the Java API documentation \[[API 062006|AA. Java References#API 06]\] for {{Iterator.remove()}} method:
{quote}
The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method. 
{quote}

Such behavior may be observed in both single and multithreaded programs. In single threaded programs, this usually happens when an element is removed when the iteration is in progress. In a multithreaded program, it is possible that one thread iterates over a collection while another concurrently modifies it. This can result in unspecified behavior. Many implementations throw a {{ConcurrentModificationException}} when such a condition is detected.  

According to the Java API documentation \[[API 062006|AA. Java References#API 06]\] for {{ConcurrentModificationException}}:
{quote}
... it is not generally permissible for one thread to modify a {{Collection}} while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some {{Iterator}} implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. {{Iterators}} that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future. 

Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw {{ConcurrentModificationException}} on a best-effort basis. Consequently, it would be wrong to write a program that depended on this exception for its correctness: {{ConcurrentModificationException}} should be used only to detect bugs.
{quote}

Do not rely on {{ConcurrentModificationException}} to stop any side effects resulting from modifying an underlying Collection while iterating over it. The fail-fast behavior may occur after processing an arbitrary number of elements. "\[Fail-fast iterators\] are implemented by associating a modification count with the collection: if the modification count changes during iteration, {{hasNext}} or {{next}} throws {{ConcurrentModificationException}}. However, this check is done without synchronization, so there is a risk of seeing a stale value of the modification count and therefore that the iterator does not realize a modification has been made. This was a deliberate design tradeoff to reduce the performance impact of the concurrent modification detection code." \[[Goetz 062006|AA. Java References#Goetz 06]\].

Notably, the enhanced {{for}} loop (for-each idiom) internally uses an {{Iterator}} {mc} consequences? {mc}.

h2. Noncompliant Code Example (single-threaded)

This noncompliant code example (based on a bug report [6687277|http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6687277]) removes an element from an {{ArrayList}} using the Collection's {{remove()}} method. This is done while iterating over the {{Collection}}. The resulting behavior is unspecified.

{code:bgColor=#FFcccc}
class BadIterate {
  public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("one");
    list.add("two");
        
    Iterator iter = list.iterator();
    while(iter.hasNext()) {
      String s = (String)iter.next();
      if(s.equals("one")) {
        list.remove(s);
      }
    }
  }    
}
{code}

h2. Compliant Solution ({{iterator.remove()}})

The {{Iterator.remove()}} method removes from the underlying {{Collection}} the last element returned by the iterator. Its behavior is fully specified.

{code:bgColor=#ccccff}
// ...
if(s.equals("one")) {
  iter.remove();
}
// ...
{code}

h2. Noncompliant Code Example (multithreaded)

This noncompliant code example is insecure in a multithreaded environment because it is possible for a thread to modify the {{widgetList}} while it is being iterated. Moreover, even the {{doSomething()}} method may modify the collection while an iteration is in progress.

{code:bgColor=#FFcccc}
List<Widget> widgetList = new ArrayList<Widget>();

pubic void widgetOperation() {
  // May throw ConcurrentModificationException
  for (Widget w : widgetList) {
    doSomething(w);
  }
}
{code}

h2. Compliant Solution (thread-safe collection)

This compliant solution wraps the {{ArrayList}} in a synchronized collection so that all modifications are subject to the locking mechanism. 

{code:bgColor=#ccccff}
List<Widget> widgetList = Collections.synchronizedList(new ArrayList<Widget>());

pubic void widgetOperation() {
  for (Widget w : widgetList) {
    doSomething(w);
  }
}
{code}

This approach needs to be implemented correctly to avoid starvation, deadlock and scalability issues \[[Goetz 062006|AA. Java References#Goetz 06]\]. 

h2. Compliant Solution (deep copying)

This compliant solution creates a deep copy of the mutable {{widgetList}} before iterating over it. 

{code:bgColor=#ccccff}
List<Widget> widgetList = new ArrayList<Widget>();

pubic void widgetOperation() {
  List<Widget> deepCopy = new ArrayList<Widget>();
  synchronized(widgetList) { // Client-side locking
    for (Object obj : widgetList) {
      deepCopy.add(obj.clone());
    }
  } 

  for (Widget w : deepCopy) {
    doSomething(w);
  }
}
{code}

Creating deep copies of the list prevents underlying changes in the original list from affecting the iteration in progress. "Since the clone is thread-confined, no other thread can modify it during iteration, eliminating the possibility of {{ConcurrentModificationException}}. (The collection still must be locked during the clone operation itself.)" \[[Goetz 062006|AA. Java References#Goetz 06]\]. However, this approach is often more expensive than other techniques. There is also a risk of operating on stale data which may affect the correctness of the code.

h2. Exceptions

*EX1:*  The {{Iterator.remove()}} method can be used to modify the underlying collection when an iteration is in progress. This is also shown in the compliant solution. 

h2. Risk Assessment

Modifying a Collection while iterating over it can lead to nondeterministic behavior.

|| Rule || Severity || Likelihood || Remediation Cost || Priority || Level ||
| MSC13- J | low | probable | medium | {color:green}{*}P4{*}{color} | {color:green}{*}L3{*}{color} |


h3. Automated Detection

The Coverity Prevent Version 5.0 *INVALIDATE_ITERATOR* checker can detect the instance where an iterator is being used after the source container of the interator is modified.


h3. Related Vulnerabilities

[HARMONY-6236|http://issues.apache.org/jira/browse/HARMONY-6236]

h2. References

\[[API 062006|AA. Java References#API 06]\] Class [ConcurrentModificationException|http://java.sun.com/j2se/1.5.0/docs/api/java/util/ConcurrentModificationException.html] 
\[[SDN 082008|AA. Java References#SDN 08]\] [Sun Bug database, Bug ID:6687277|http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6687277]
\[[Goetz 062006|AA. Java References#Goetz 06]\] 5.1.2. Iterators and Concurrentmodificationexception

----
[!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_left.png!|MSC12-J. Prefer using Iterators over Enumerations]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_up.png!|49. Miscellaneous (MSC)]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_right.png!|MSC14-J. Finish every set of statements associated with a case label with a break statement]