diff --git a/WHATSNEW b/WHATSNEW index b25e43ac5..1cdbd444a 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -77,6 +77,10 @@ Fixed bugs: * complete-ant-cmd.pl now also completes tasks without a description. Bugzilla Report 57542 + * LocalPropertyStack could run into ConcurrentModificationException + when tasks spawned new child threads that accessed the properties. + Bugzilla Report 55074 + Other changes: -------------- diff --git a/src/main/org/apache/tools/ant/property/LocalPropertyStack.java b/src/main/org/apache/tools/ant/property/LocalPropertyStack.java index cced57919..482f28cde 100644 --- a/src/main/org/apache/tools/ant/property/LocalPropertyStack.java +++ b/src/main/org/apache/tools/ant/property/LocalPropertyStack.java @@ -17,10 +17,9 @@ */ package org.apache.tools.ant.property; - -import java.util.HashMap; import java.util.LinkedList; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.apache.tools.ant.PropertyHelper; @@ -31,6 +30,7 @@ import org.apache.tools.ant.PropertyHelper; */ public class LocalPropertyStack { private final LinkedList> stack = new LinkedList>(); + private final Object LOCK = new Object(); // -------------------------------------------------- // @@ -43,8 +43,11 @@ public class LocalPropertyStack { * @param property the name of the local property. */ public void addLocal(String property) { - if (!stack.isEmpty()) { - stack.getFirst().put(property, NullReturn.NULL); + synchronized (LOCK) { + Map map = stack.peek(); + if (map != null) { + map.put(property, NullReturn.NULL); + } } } @@ -52,14 +55,18 @@ public class LocalPropertyStack { * Enter the local scope. */ public void enterScope() { - stack.addFirst(new HashMap()); + synchronized (LOCK) { + stack.addFirst(new ConcurrentHashMap()); + } } /** * Exit the local scope. */ public void exitScope() { - stack.removeFirst().clear(); + synchronized (LOCK) { + stack.removeFirst().clear(); + } } // -------------------------------------------------- @@ -73,9 +80,11 @@ public class LocalPropertyStack { * @return a copy. */ public LocalPropertyStack copy() { - LocalPropertyStack ret = new LocalPropertyStack(); - ret.stack.addAll(stack); - return ret; + synchronized (LOCK) { + LocalPropertyStack ret = new LocalPropertyStack(); + ret.stack.addAll(stack); + return ret; + } } // -------------------------------------------------- @@ -91,10 +100,12 @@ public class LocalPropertyStack { * @return Object value. */ public Object evaluate(String property, PropertyHelper helper) { - for (Map map : stack) { - Object ret = map.get(property); - if (ret != null) { - return ret; + synchronized (LOCK) { + for (Map map : stack) { + Object ret = map.get(property); + if (ret != null) { + return ret; + } } } return null; @@ -137,9 +148,11 @@ public class LocalPropertyStack { } private Map getMapForProperty(String property) { - for (Map map : stack) { - if (map.get(property) != null) { - return map; + synchronized (LOCK) { + for (Map map : stack) { + if (map.get(property) != null) { + return map; + } } } return null;