Skip to content

Commit

Permalink
Give MapMaker the same workaround as Cache for Android's concurrency-…
Browse files Browse the repository at this point in the history
…unsafe toArray() implementation.

The fixes the corresponding Android test for MapMaker.
Also, use that implementation for values() (for which we have no test, but it looks likely to be vulnerable, too).
Finally, include an android.com link in case the shutdown of Google Code invalidates the existing bug link.
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=100037556
  • Loading branch information
cpovirk committed Aug 6, 2015
1 parent 8ff4907 commit 9bf99b4
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 12 deletions.
32 changes: 22 additions & 10 deletions guava/src/com/google/common/cache/LocalCache.java
Expand Up @@ -4473,25 +4473,24 @@ public void clear() {
}

// super.toArray() may misbehave if size() is inaccurate, at least on old versions of Android.
// https://code.google.com/p/android/issues/detail?id=36519
// https://code.google.com/p/android/issues/detail?id=36519 / http://r.android.com/47508

@Override
public Object[] toArray() {
return toArrayList().toArray();
return toArrayList(this).toArray();
}

@Override
public <E> E[] toArray(E[] a) {
return toArrayList().toArray(a);
}

private ArrayList<T> toArrayList() {
// Avoid calling ArrayList(Collection), which may call back into toArray.
ArrayList<T> result = new ArrayList<T>(size());
Iterators.addAll(result, iterator());
return result;
return toArrayList(this).toArray(a);
}
}

private static <E> ArrayList<E> toArrayList(Collection<E> c) {
// Avoid calling ArrayList(Collection), which may call back into toArray.
ArrayList<E> result = new ArrayList<E>(c.size());
Iterators.addAll(result, c.iterator());
return result;
}

@WeakOuter
Expand Down Expand Up @@ -4546,6 +4545,19 @@ public Iterator<V> iterator() {
public boolean contains(Object o) {
return map.containsValue(o);
}

// super.toArray() may misbehave if size() is inaccurate, at least on old versions of Android.
// https://code.google.com/p/android/issues/detail?id=36519 / http://r.android.com/47508

@Override
public Object[] toArray() {
return toArrayList(this).toArray();
}

@Override
public <E> E[] toArray(E[] a) {
return toArrayList(this).toArray(a);
}
}

@WeakOuter
Expand Down
40 changes: 38 additions & 2 deletions guava/src/com/google/common/collect/MapMakerInternalMap.java
Expand Up @@ -40,6 +40,7 @@
import java.util.AbstractMap;
import java.util.AbstractQueue;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
Expand Down Expand Up @@ -3785,7 +3786,7 @@ public Entry<K, V> next() {
}

@WeakOuter
final class KeySet extends AbstractSet<K> {
final class KeySet extends SafeToArraySet<K> {

@Override
public Iterator<K> iterator() {
Expand Down Expand Up @@ -3845,10 +3846,23 @@ public boolean contains(Object o) {
public void clear() {
MapMakerInternalMap.this.clear();
}

// super.toArray() may misbehave if size() is inaccurate, at least on old versions of Android.
// https://code.google.com/p/android/issues/detail?id=36519 / http://r.android.com/47508

@Override
public Object[] toArray() {
return toArrayList(this).toArray();
}

@Override
public <E> E[] toArray(E[] a) {
return toArrayList(this).toArray(a);
}
}

@WeakOuter
final class EntrySet extends AbstractSet<Entry<K, V>> {
final class EntrySet extends SafeToArraySet<Entry<K, V>> {

@Override
public Iterator<Entry<K, V>> iterator() {
Expand Down Expand Up @@ -3896,6 +3910,28 @@ public void clear() {
}
}

private abstract static class SafeToArraySet<E> extends AbstractSet<E> {
// super.toArray() may misbehave if size() is inaccurate, at least on old versions of Android.
// https://code.google.com/p/android/issues/detail?id=36519 / http://r.android.com/47508

@Override
public Object[] toArray() {
return toArrayList(this).toArray();
}

@Override
public <E> E[] toArray(E[] a) {
return toArrayList(this).toArray(a);
}
}

private static <E> ArrayList<E> toArrayList(Collection<E> c) {
// Avoid calling ArrayList(Collection), which may call back into toArray.
ArrayList<E> result = new ArrayList<E>(c.size());
Iterators.addAll(result, c.iterator());
return result;
}

// Serialization Support

private static final long serialVersionUID = 5;
Expand Down

0 comments on commit 9bf99b4

Please sign in to comment.