From ba54513f5ca9f6279b1066b320cf6ec57b271c85 Mon Sep 17 00:00:00 2001 From: Kun Zhang Date: Thu, 28 Jan 2016 11:01:22 -0800 Subject: [PATCH] Fix a concurrent modification in BlankFutureProvider. The Set from Collections.synchronizedSet() is not protected against concurrent modification during iteration. We copy an ArrayList out of it for iteration. --- .../java/io/grpc/internal/BlankFutureProvider.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/io/grpc/internal/BlankFutureProvider.java b/core/src/main/java/io/grpc/internal/BlankFutureProvider.java index 704f4d5d3b..bbb8aed20d 100644 --- a/core/src/main/java/io/grpc/internal/BlankFutureProvider.java +++ b/core/src/main/java/io/grpc/internal/BlankFutureProvider.java @@ -39,8 +39,10 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; import java.util.concurrent.CancellationException; @@ -122,7 +124,7 @@ public final class BlankFutureProvider { * they were created. */ public void link(Supplier> source) { - for (final SettableFuture future : futures) { + for (final SettableFuture future : copyFutureList()) { ListenableFuture sourceFuture = source.get(); Futures.addCallback(sourceFuture, new FutureCallback() { @Override public void onSuccess(T result) { @@ -140,10 +142,16 @@ public final class BlankFutureProvider { * Fails all futures with the given error. */ public void fail(Throwable error) { - for (SettableFuture future : futures) { + for (SettableFuture future : copyFutureList()) { future.setException(error); } } + + private List> copyFutureList() { + synchronized (futures) { + return new ArrayList>(futures); + } + } } private static Set> createSet() {