package tracematches; import java.util.*; public aspect FailSafeIter { pointcut collection_update(Collection c) : ( call(* java.util.Collection+.add*(..)) || call(* java.util.Collection+.remove*(..)) ) && target(c); tracematch(Collection c, Iterator i) { sym create_iter after returning(i) : call(* java.util.Collection+.iterator()) && target(c); sym call_next before: call(* java.util.Iterator+.next()) && target(i); sym update_source after : collection_update(c); create_iter call_next* update_source+ call_next { if(System.getProperty("TMTEST_ACTIVE")!=null) { throw new ConcurrentModificationException(); } } } public static void main(String[] args) { List l = new ArrayList(); //safe l.add(""); //removed //unsafe for(Iterator i = l.iterator();i.hasNext();) { i.next(); l.add(""); } //safe, not removed because points-to sets for the iterators collapse for(Iterator i = l.iterator();i.hasNext();) { i.next(); } //safe List l2 = new ArrayList(); for(Iterator i = l2.iterator();i.hasNext();) //removed { i.next(); //not removed because points-to sets for the iterators collapse l.add("");//not removed because points-to sets for the iterators collapse } } }