Skip to content

Commit

Permalink
Internal change.
Browse files Browse the repository at this point in the history
RELNOTES=n/a
PiperOrigin-RevId: 587705182
  • Loading branch information
cpovirk authored and Google Java Core Libraries committed Dec 4, 2023
1 parent f4c1264 commit fedb419
Show file tree
Hide file tree
Showing 20 changed files with 116 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static com.google.common.base.StandardSystemProperty.OS_NAME;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.junit.Assert.assertThrows;

import com.google.common.annotations.GwtIncompatible;
Expand Down Expand Up @@ -1056,6 +1057,25 @@ public void run() {
t.join();
}

public void testCatchesUndeclaredThrowableFromListener() {
AbstractFuture<String> f = new AbstractFuture<String>() {};
f.set("foo");
f.addListener(() -> sneakyThrow(new SomeCheckedException()), directExecutor());
}

private static final class SomeCheckedException extends Exception {}

/** Throws an undeclared checked exception. */
private static void sneakyThrow(Throwable t) {
class SneakyThrower<T extends Throwable> {
@SuppressWarnings("unchecked") // intentionally unsafe for test
void throwIt(Throwable t) throws T {
throw (T) t;
}
}
new SneakyThrower<Error>().throwIt(t);
}

public void testTrustedGetFailure_Completed() {
SettableFuture<String> future = SettableFuture.create();
future.set("261");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,9 @@ protected boolean setFuture(ListenableFuture<? extends V> future) {
// since all we are doing is unpacking a completed future which should be fast.
try {
future.addListener(valueToSet, DirectExecutor.INSTANCE);
} catch (RuntimeException | Error t) {
} catch (Throwable t) {
// Any Exception is either a RuntimeException or sneaky checked exception.
//
// addListener has thrown an exception! SetFuture.run can't throw any exceptions so this
// must have been caused by addListener itself. The most likely explanation is a
// misconfigured mock. Try to switch to Failure.
Expand Down Expand Up @@ -1193,6 +1195,7 @@ protected String pendingToString() {
return null;
}

@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private void addPendingString(StringBuilder builder) {
// Capture current builder length so it can be truncated if this future ends up completing while
// the toString is being calculated
Expand All @@ -1209,7 +1212,9 @@ private void addPendingString(StringBuilder builder) {
String pendingDescription;
try {
pendingDescription = Strings.emptyToNull(pendingToString());
} catch (RuntimeException | StackOverflowError e) {
} catch (Exception | StackOverflowError e) {
// Any Exception is either a RuntimeException or sneaky checked exception.
//
// Don't call getMessage or toString() on the exception, in case the exception thrown by the
// subclass is implemented with bugs similar to the subclass.
pendingDescription = "Exception thrown from implementation: " + e.getClass();
Expand All @@ -1228,6 +1233,7 @@ private void addPendingString(StringBuilder builder) {
}
}

@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private void addDoneString(StringBuilder builder) {
try {
V value = getUninterruptibly(this);
Expand All @@ -1238,7 +1244,7 @@ private void addDoneString(StringBuilder builder) {
builder.append("FAILURE, cause=[").append(e.getCause()).append("]");
} catch (CancellationException e) {
builder.append("CANCELLED"); // shouldn't be reachable
} catch (RuntimeException e) {
} catch (Exception e) { // sneaky checked exception
builder.append("UNKNOWN, cause=[").append(e.getClass()).append(" thrown from get()]");
}
}
Expand All @@ -1262,6 +1268,7 @@ private void appendResultObject(StringBuilder builder, @CheckForNull Object o) {
}

/** Helper for printing user supplied objects into our toString method. */
@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private void appendUserObject(StringBuilder builder, @CheckForNull Object o) {
// This is some basic recursion detection for when people create cycles via set/setFuture or
// when deep chains of futures exist resulting in a StackOverflowException. We could detect
Expand All @@ -1273,7 +1280,9 @@ private void appendUserObject(StringBuilder builder, @CheckForNull Object o) {
} else {
builder.append(o);
}
} catch (RuntimeException | StackOverflowError e) {
} catch (Exception | StackOverflowError e) {
// Any Exception is either a RuntimeException or sneaky checked exception.
//
// Don't call getMessage or toString() on the exception, in case the exception thrown by the
// user object is implemented with bugs similar to the user object.
builder.append("Exception thrown from implementation: ").append(e.getClass());
Expand All @@ -1284,10 +1293,11 @@ private void appendUserObject(StringBuilder builder, @CheckForNull Object o) {
* Submits the given runnable to the given {@link Executor} catching and logging all {@linkplain
* RuntimeException runtime exceptions} thrown by the executor.
*/
@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private static void executeListener(Runnable runnable, Executor executor) {
try {
executor.execute(runnable);
} catch (RuntimeException e) {
} catch (Exception e) { // sneaky checked exception
// Log it and keep going -- bad runnable and/or executor. Don't punish the other runnables if
// we're given a bad one. We only catch RuntimeException because we want Errors to propagate
// up.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,9 @@ public Cancellable reschedule() {
lock.lock();
try {
toReturn = initializeOrUpdateCancellationDelegate(schedule);
} catch (RuntimeException | Error e) {
} catch (Throwable e) {
// Any Exception is either a RuntimeException or sneaky checked exception.
//
// If an exception is thrown by the subclass then we need to make sure that the service
// notices and transitions to the FAILED state. We do it by calling notifyFailed directly
// because the service does not monitor the state of the future so if the exception is not
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,11 @@ public void execute() {
* Submits the given runnable to the given {@link Executor} catching and logging all {@linkplain
* RuntimeException runtime exceptions} thrown by the executor.
*/
@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private static void executeListener(Runnable runnable, Executor executor) {
try {
executor.execute(runnable);
} catch (RuntimeException e) {
} catch (Exception e) { // sneaky checked exception
// Log it and keep going -- bad runnable and/or executor. Don't punish the other runnables if
// we're given a bad one. We only catch RuntimeException because we want Errors to propagate
// up.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,8 @@ public O get(long timeout, TimeUnit unit)
private O applyTransformation(I input) throws ExecutionException {
try {
return function.apply(input);
} catch (RuntimeException | Error t) {
} catch (Throwable t) {
// Any Exception is either a RuntimeException or sneaky checked exception.
throw new ExecutionException(t);
}
}
Expand Down Expand Up @@ -1091,7 +1092,8 @@ public void run() {
} catch (ExecutionException e) {
callback.onFailure(e.getCause());
return;
} catch (RuntimeException | Error e) {
} catch (Throwable e) {
// Any Exception is either a RuntimeException or sneaky checked exception.
callback.onFailure(e);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,13 @@ class ImmediateFuture<V extends @Nullable Object> implements ListenableFuture<V>
}

@Override
@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
public void addListener(Runnable listener, Executor executor) {
checkNotNull(listener, "Runnable was null.");
checkNotNull(executor, "Executor was null.");
try {
executor.execute(listener);
} catch (RuntimeException e) {
} catch (Exception e) { // sneaky checked exception
// ListenableFuture's contract is that it will not throw unchecked exceptions, so log the bad
// runnable and/or executor and swallow it.
log.log(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ synchronized void add(ListenerCallQueue.Event<L> event, Object label) {
* Dispatches all listeners {@linkplain #enqueue enqueued} prior to this call, serially and in
* order.
*/
@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
void dispatch() {
boolean scheduleEventRunner = false;
synchronized (this) {
Expand All @@ -170,7 +171,7 @@ void dispatch() {
if (scheduleEventRunner) {
try {
executor.execute(this);
} catch (RuntimeException e) {
} catch (Exception e) { // sneaky checked exception
// reset state in case of an error so that later dispatch calls will actually do something
synchronized (this) {
isThreadScheduled = false;
Expand All @@ -186,6 +187,7 @@ void dispatch() {
}

@Override
@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
public void run() {
boolean stillRunning = true;
try {
Expand All @@ -206,7 +208,7 @@ public void run() {
// Always run while _not_ holding the lock, to avoid deadlocks.
try {
nextToRun.call(listener);
} catch (RuntimeException e) {
} catch (Exception e) { // sneaky checked exception
// Log it and keep going.
logger.log(
Level.SEVERE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,8 @@ private void signalNextWaiter() {
private boolean isSatisfied(Guard guard) {
try {
return guard.isSatisfied();
} catch (RuntimeException | Error throwable) {
} catch (Throwable throwable) {
// Any Exception is either a RuntimeException or sneaky checked exception.
signalAllWaiters();
throw throwable;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,8 @@ public NeverSuccessfulListenableFutureTask(Runnable delegate) {
public void run() {
try {
delegate.run();
} catch (RuntimeException | Error t) {
} catch (Throwable t) {
// Any Exception is either a RuntimeException or sneaky checked exception.
setException(t);
throw t;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ public String toString() {

try {
executor.execute(worker);
} catch (RuntimeException | Error t) {
} catch (Throwable t) {
// Any Exception is either a RuntimeException or sneaky checked exception.
synchronized (queue) {
boolean removed =
(workerRunningState == IDLE || workerRunningState == QUEUING)
Expand Down Expand Up @@ -202,6 +203,7 @@ public void run() {
* will still be present. If the composed Executor is an ExecutorService, it can respond to
* shutdown() by returning tasks queued on that Thread after {@link #worker} drains the queue.
*/
@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private void workOnQueue() {
boolean interruptedDuringTask = false;
boolean hasSetRunning = false;
Expand Down Expand Up @@ -235,7 +237,7 @@ private void workOnQueue() {
interruptedDuringTask |= Thread.interrupted();
try {
task.run();
} catch (RuntimeException e) {
} catch (Exception e) { // sneaky checked exception
log.log(Level.SEVERE, "Exception while executing runnable " + task, e);
} finally {
task = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static com.google.common.base.StandardSystemProperty.OS_NAME;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.junit.Assert.assertThrows;

import com.google.common.annotations.GwtIncompatible;
Expand Down Expand Up @@ -1056,6 +1057,25 @@ public void run() {
t.join();
}

public void testCatchesUndeclaredThrowableFromListener() {
AbstractFuture<String> f = new AbstractFuture<String>() {};
f.set("foo");
f.addListener(() -> sneakyThrow(new SomeCheckedException()), directExecutor());
}

private static final class SomeCheckedException extends Exception {}

/** Throws an undeclared checked exception. */
private static void sneakyThrow(Throwable t) {
class SneakyThrower<T extends Throwable> {
@SuppressWarnings("unchecked") // intentionally unsafe for test
void throwIt(Throwable t) throws T {
throw (T) t;
}
}
new SneakyThrower<Error>().throwIt(t);
}

public void testTrustedGetFailure_Completed() {
SettableFuture<String> future = SettableFuture.create();
future.set("261");
Expand Down
20 changes: 15 additions & 5 deletions guava/src/com/google/common/util/concurrent/AbstractFuture.java
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,9 @@ protected boolean setFuture(ListenableFuture<? extends V> future) {
// since all we are doing is unpacking a completed future which should be fast.
try {
future.addListener(valueToSet, DirectExecutor.INSTANCE);
} catch (RuntimeException | Error t) {
} catch (Throwable t) {
// Any Exception is either a RuntimeException or sneaky checked exception.
//
// addListener has thrown an exception! SetFuture.run can't throw any exceptions so this
// must have been caused by addListener itself. The most likely explanation is a
// misconfigured mock. Try to switch to Failure.
Expand Down Expand Up @@ -1193,6 +1195,7 @@ protected String pendingToString() {
return null;
}

@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private void addPendingString(StringBuilder builder) {
// Capture current builder length so it can be truncated if this future ends up completing while
// the toString is being calculated
Expand All @@ -1209,7 +1212,9 @@ private void addPendingString(StringBuilder builder) {
String pendingDescription;
try {
pendingDescription = Strings.emptyToNull(pendingToString());
} catch (RuntimeException | StackOverflowError e) {
} catch (Exception | StackOverflowError e) {
// Any Exception is either a RuntimeException or sneaky checked exception.
//
// Don't call getMessage or toString() on the exception, in case the exception thrown by the
// subclass is implemented with bugs similar to the subclass.
pendingDescription = "Exception thrown from implementation: " + e.getClass();
Expand All @@ -1228,6 +1233,7 @@ private void addPendingString(StringBuilder builder) {
}
}

@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private void addDoneString(StringBuilder builder) {
try {
V value = getUninterruptibly(this);
Expand All @@ -1238,7 +1244,7 @@ private void addDoneString(StringBuilder builder) {
builder.append("FAILURE, cause=[").append(e.getCause()).append("]");
} catch (CancellationException e) {
builder.append("CANCELLED"); // shouldn't be reachable
} catch (RuntimeException e) {
} catch (Exception e) { // sneaky checked exception
builder.append("UNKNOWN, cause=[").append(e.getClass()).append(" thrown from get()]");
}
}
Expand All @@ -1262,6 +1268,7 @@ private void appendResultObject(StringBuilder builder, @CheckForNull Object o) {
}

/** Helper for printing user supplied objects into our toString method. */
@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private void appendUserObject(StringBuilder builder, @CheckForNull Object o) {
// This is some basic recursion detection for when people create cycles via set/setFuture or
// when deep chains of futures exist resulting in a StackOverflowException. We could detect
Expand All @@ -1273,7 +1280,9 @@ private void appendUserObject(StringBuilder builder, @CheckForNull Object o) {
} else {
builder.append(o);
}
} catch (RuntimeException | StackOverflowError e) {
} catch (Exception | StackOverflowError e) {
// Any Exception is either a RuntimeException or sneaky checked exception.
//
// Don't call getMessage or toString() on the exception, in case the exception thrown by the
// user object is implemented with bugs similar to the user object.
builder.append("Exception thrown from implementation: ").append(e.getClass());
Expand All @@ -1284,10 +1293,11 @@ private void appendUserObject(StringBuilder builder, @CheckForNull Object o) {
* Submits the given runnable to the given {@link Executor} catching and logging all {@linkplain
* RuntimeException runtime exceptions} thrown by the executor.
*/
@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private static void executeListener(Runnable runnable, Executor executor) {
try {
executor.execute(runnable);
} catch (RuntimeException e) {
} catch (Exception e) { // sneaky checked exception
// Log it and keep going -- bad runnable and/or executor. Don't punish the other runnables if
// we're given a bad one. We only catch RuntimeException because we want Errors to propagate
// up.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,9 @@ public Cancellable reschedule() {
lock.lock();
try {
toReturn = initializeOrUpdateCancellationDelegate(schedule);
} catch (RuntimeException | Error e) {
} catch (Throwable e) {
// Any Exception is either a RuntimeException or sneaky checked exception.
//
// If an exception is thrown by the subclass then we need to make sure that the service
// notices and transitions to the FAILED state. We do it by calling notifyFailed directly
// because the service does not monitor the state of the future so if the exception is not
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,11 @@ public void execute() {
* Submits the given runnable to the given {@link Executor} catching and logging all {@linkplain
* RuntimeException runtime exceptions} thrown by the executor.
*/
@SuppressWarnings("CatchingUnchecked") // sneaky checked exception
private static void executeListener(Runnable runnable, Executor executor) {
try {
executor.execute(runnable);
} catch (RuntimeException e) {
} catch (Exception e) { // sneaky checked exception
// Log it and keep going -- bad runnable and/or executor. Don't punish the other runnables if
// we're given a bad one. We only catch RuntimeException because we want Errors to propagate
// up.
Expand Down

0 comments on commit fedb419

Please sign in to comment.