diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 9b0c263a2..c6338ef7c 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -251,6 +251,7 @@ Mario Frasca
Mariusz Nowostawski
Mark A. Ziesemer
Mark DeLaFranier
+Mark Harmer
Mark Hecker
Mark Niggemann
Mark R. Diggory
diff --git a/WHATSNEW b/WHATSNEW
index a74856e45..9229d4825 100644
--- a/WHATSNEW
+++ b/WHATSNEW
@@ -33,6 +33,10 @@ Fixed bugs:
of the destination directory.
Bugzilla Report 62890
+ * Fixes a potential java.util.ConcurrentModificationException in
+ org.apache.tools.ant.Project#getCopyOfReferences.
+ Github Pull Request #81
+
Other changes:
--------------
diff --git a/contributors.xml b/contributors.xml
index ebf03ee77..c56bd2454 100644
--- a/contributors.xml
+++ b/contributors.xml
@@ -1045,6 +1045,10 @@
Mark
DeLaFranier
+
+ Mark
+ Harmer
+
Mark
Hecker
diff --git a/src/main/org/apache/tools/ant/Project.java b/src/main/org/apache/tools/ant/Project.java
index 62aafbc4c..39a83a476 100644
--- a/src/main/org/apache/tools/ant/Project.java
+++ b/src/main/org/apache/tools/ant/Project.java
@@ -140,6 +140,9 @@ public class Project implements ResourceFactory {
private String description;
+ /** lock object used when adding/removing references */
+ private final Object referencesLock = new Object();
+
/** Map of references within the project (paths etc) (String to Object). */
private final Hashtable references = new AntRefTable();
@@ -1971,17 +1974,19 @@ public class Project implements ResourceFactory {
* @param value The value of the reference.
*/
public void addReference(final String referenceName, final Object value) {
- final Object old = ((AntRefTable) references).getReal(referenceName);
- if (old == value) {
- // no warning, this is not changing anything
- return;
- }
- if (old != null && !(old instanceof UnknownElement)) {
- log("Overriding previous definition of reference to " + referenceName,
- MSG_VERBOSE);
+ synchronized (referencesLock) {
+ final Object old = ((AntRefTable) references).getReal(referenceName);
+ if (old == value) {
+ // no warning, this is not changing anything
+ return;
+ }
+ if (old != null && !(old instanceof UnknownElement)) {
+ log("Overriding previous definition of reference to " + referenceName,
+ MSG_VERBOSE);
+ }
+ log("Adding reference: " + referenceName, MSG_DEBUG);
+ references.put(referenceName, value);
}
- log("Adding reference: " + referenceName, MSG_DEBUG);
- references.put(referenceName, value);
}
/**
@@ -2002,7 +2007,9 @@ public class Project implements ResourceFactory {
* @since Ant 1.8.0
*/
public boolean hasReference(final String key) {
- return references.containsKey(key);
+ synchronized (referencesLock) {
+ return references.containsKey(key);
+ }
}
/**
@@ -2015,7 +2022,9 @@ public class Project implements ResourceFactory {
* @since Ant 1.8.1
*/
public Map getCopyOfReferences() {
- return new HashMap<>(references);
+ synchronized (referencesLock) {
+ return new HashMap<>(references);
+ }
}
/**
@@ -2029,11 +2038,14 @@ public class Project implements ResourceFactory {
* there is no such reference in the project, with type inference.
*/
public T getReference(final String key) {
- @SuppressWarnings("unchecked")
- final T ret = (T) references.get(key);
- if (ret != null) {
- return ret;
+ synchronized (referencesLock) {
+ @SuppressWarnings("unchecked")
+ final T ret = (T) references.get(key);
+ if (ret != null) {
+ return ret;
+ }
}
+
if (!key.equals(MagicNames.REFID_PROPERTY_HELPER)) {
try {
if (PropertyHelper.getPropertyHelper(this).containsProperties(key)) {