Skip to content

Commit

Permalink
Throw StackOverflowError manually instead of triggering a real stac…
Browse files Browse the repository at this point in the history
…k overflow, which sometimes hoses subsequent tests or crashes Android.

Remove existing attempted workarounds for such trouble.

Run some tests under Android now that we can.

RELNOTES=n/a
PiperOrigin-RevId: 724380185
  • Loading branch information
cpovirk authored and Google Java Core Libraries committed Feb 7, 2025
1 parent 7719744 commit 57ec95c
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 140 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -257,26 +257,17 @@ public BarChild apply(Foo unused) {
assertSame(barChild, bar);
}

@AndroidIncompatible // b/391667564: crashes from stack overflows
@J2ktIncompatible
@GwtIncompatible // StackOverflowError
public void testTransform_stackOverflow() throws Exception {
{
/*
* Initialize all relevant classes before running the test, which may otherwise poison any
* classes it is trying to load during its stack overflow.
*/
SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> unused = transform(root, identity(), directExecutor());
root.set("foo");
}

SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> output = root;
for (int i = 0; i < 10000; i++) {
output = transform(output, identity(), directExecutor());
}
assertThrows(StackOverflowError.class, () -> root.set("foo"));
SettableFuture<Object> input = SettableFuture.create();
ListenableFuture<Object> output = transform(input, identity(), directExecutor());
output.addListener(
() -> {
throw new StackOverflowError();
},
directExecutor());
assertThrows(StackOverflowError.class, () -> input.set("foo"));
}

public void testTransform_errorAfterCancellation() throws Exception {
Expand Down Expand Up @@ -469,26 +460,17 @@ public ListenableFuture<Bar> apply(Foo unused) {
assertFalse(((AbstractFuture<?>) f2).wasInterrupted());
}

@AndroidIncompatible // b/391667564: crashes from stack overflows
@J2ktIncompatible
@GwtIncompatible // StackOverflowError
public void testTransformAsync_stackOverflow() throws Exception {
{
/*
* Initialize all relevant classes before running the test, which may otherwise poison any
* classes it is trying to load during its stack overflow.
*/
SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> unused = transformAsync(root, asyncIdentity(), directExecutor());
root.set("foo");
}

SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> output = root;
for (int i = 0; i < 10000; i++) {
output = transformAsync(output, asyncIdentity(), directExecutor());
}
assertThrows(StackOverflowError.class, () -> root.set("foo"));
SettableFuture<Object> input = SettableFuture.create();
ListenableFuture<Object> output = transformAsync(input, asyncIdentity(), directExecutor());
output.addListener(
() -> {
throw new StackOverflowError();
},
directExecutor());
assertThrows(StackOverflowError.class, () -> input.set("foo"));
}

public void testTransformAsync_errorAfterCancellation() throws Exception {
Expand Down Expand Up @@ -1305,27 +1287,18 @@ public void testCatching_customTypeNoMatch() throws Exception {
assertThat(expected).hasCauseThat().isInstanceOf(RuntimeException.class);
}

@AndroidIncompatible // b/391667564: crashes from stack overflows
@J2ktIncompatible
@GwtIncompatible // StackOverflowError
public void testCatching_stackOverflow() throws Exception {
{
/*
* Initialize all relevant classes before running the test, which may otherwise poison any
* classes it is trying to load during its stack overflow.
*/
SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> unused =
catching(root, MyException.class, identity(), directExecutor());
root.setException(new MyException());
}

SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> output = root;
for (int i = 0; i < 10000; i++) {
output = catching(output, MyException.class, identity(), directExecutor());
}
assertThrows(StackOverflowError.class, () -> root.setException(new MyException()));
SettableFuture<Object> input = SettableFuture.create();
ListenableFuture<Object> output =
catching(input, MyException.class, identity(), directExecutor());
output.addListener(
() -> {
throw new StackOverflowError();
},
directExecutor());
assertThrows(StackOverflowError.class, () -> input.setException(new MyException()));
}

public void testCatching_errorAfterCancellation() throws Exception {
Expand Down Expand Up @@ -1435,27 +1408,18 @@ public void testCatchingAsync_customTypeNoMatch() throws Exception {
assertThat(expected).hasCauseThat().isInstanceOf(RuntimeException.class);
}

@AndroidIncompatible // b/391667564: crashes from stack overflows
@J2ktIncompatible
@GwtIncompatible // StackOverflowError
public void testCatchingAsync_stackOverflow() throws Exception {
{
/*
* Initialize all relevant classes before running the test, which may otherwise poison any
* classes it is trying to load during its stack overflow.
*/
SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> unused =
catchingAsync(root, MyException.class, asyncIdentity(), directExecutor());
root.setException(new MyException());
}

SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> output = root;
for (int i = 0; i < 10000; i++) {
output = catchingAsync(output, MyException.class, asyncIdentity(), directExecutor());
}
assertThrows(StackOverflowError.class, () -> root.setException(new MyException()));
SettableFuture<Object> input = SettableFuture.create();
ListenableFuture<Object> output =
catchingAsync(input, MyException.class, asyncIdentity(), directExecutor());
output.addListener(
() -> {
throw new StackOverflowError();
},
directExecutor());
assertThrows(StackOverflowError.class, () -> input.setException(new MyException()));
}

public void testCatchingAsync_errorAfterCancellation() throws Exception {
Expand Down
104 changes: 34 additions & 70 deletions guava-tests/test/com/google/common/util/concurrent/FuturesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -257,26 +257,17 @@ public BarChild apply(Foo unused) {
assertSame(barChild, bar);
}

@AndroidIncompatible // b/391667564: crashes from stack overflows
@J2ktIncompatible
@GwtIncompatible // StackOverflowError
public void testTransform_stackOverflow() throws Exception {
{
/*
* Initialize all relevant classes before running the test, which may otherwise poison any
* classes it is trying to load during its stack overflow.
*/
SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> unused = transform(root, identity(), directExecutor());
root.set("foo");
}

SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> output = root;
for (int i = 0; i < 10000; i++) {
output = transform(output, identity(), directExecutor());
}
assertThrows(StackOverflowError.class, () -> root.set("foo"));
SettableFuture<Object> input = SettableFuture.create();
ListenableFuture<Object> output = transform(input, identity(), directExecutor());
output.addListener(
() -> {
throw new StackOverflowError();
},
directExecutor());
assertThrows(StackOverflowError.class, () -> input.set("foo"));
}

public void testTransform_errorAfterCancellation() throws Exception {
Expand Down Expand Up @@ -469,26 +460,17 @@ public ListenableFuture<Bar> apply(Foo unused) {
assertFalse(((AbstractFuture<?>) f2).wasInterrupted());
}

@AndroidIncompatible // b/391667564: crashes from stack overflows
@J2ktIncompatible
@GwtIncompatible // StackOverflowError
public void testTransformAsync_stackOverflow() throws Exception {
{
/*
* Initialize all relevant classes before running the test, which may otherwise poison any
* classes it is trying to load during its stack overflow.
*/
SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> unused = transformAsync(root, asyncIdentity(), directExecutor());
root.set("foo");
}

SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> output = root;
for (int i = 0; i < 10000; i++) {
output = transformAsync(output, asyncIdentity(), directExecutor());
}
assertThrows(StackOverflowError.class, () -> root.set("foo"));
SettableFuture<Object> input = SettableFuture.create();
ListenableFuture<Object> output = transformAsync(input, asyncIdentity(), directExecutor());
output.addListener(
() -> {
throw new StackOverflowError();
},
directExecutor());
assertThrows(StackOverflowError.class, () -> input.set("foo"));
}

public void testTransformAsync_errorAfterCancellation() throws Exception {
Expand Down Expand Up @@ -1305,27 +1287,18 @@ public void testCatching_customTypeNoMatch() throws Exception {
assertThat(expected).hasCauseThat().isInstanceOf(RuntimeException.class);
}

@AndroidIncompatible // b/391667564: crashes from stack overflows
@J2ktIncompatible
@GwtIncompatible // StackOverflowError
public void testCatching_stackOverflow() throws Exception {
{
/*
* Initialize all relevant classes before running the test, which may otherwise poison any
* classes it is trying to load during its stack overflow.
*/
SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> unused =
catching(root, MyException.class, identity(), directExecutor());
root.setException(new MyException());
}

SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> output = root;
for (int i = 0; i < 10000; i++) {
output = catching(output, MyException.class, identity(), directExecutor());
}
assertThrows(StackOverflowError.class, () -> root.setException(new MyException()));
SettableFuture<Object> input = SettableFuture.create();
ListenableFuture<Object> output =
catching(input, MyException.class, identity(), directExecutor());
output.addListener(
() -> {
throw new StackOverflowError();
},
directExecutor());
assertThrows(StackOverflowError.class, () -> input.setException(new MyException()));
}

public void testCatching_errorAfterCancellation() throws Exception {
Expand Down Expand Up @@ -1435,27 +1408,18 @@ public void testCatchingAsync_customTypeNoMatch() throws Exception {
assertThat(expected).hasCauseThat().isInstanceOf(RuntimeException.class);
}

@AndroidIncompatible // b/391667564: crashes from stack overflows
@J2ktIncompatible
@GwtIncompatible // StackOverflowError
public void testCatchingAsync_stackOverflow() throws Exception {
{
/*
* Initialize all relevant classes before running the test, which may otherwise poison any
* classes it is trying to load during its stack overflow.
*/
SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> unused =
catchingAsync(root, MyException.class, asyncIdentity(), directExecutor());
root.setException(new MyException());
}

SettableFuture<Object> root = SettableFuture.create();
ListenableFuture<Object> output = root;
for (int i = 0; i < 10000; i++) {
output = catchingAsync(output, MyException.class, asyncIdentity(), directExecutor());
}
assertThrows(StackOverflowError.class, () -> root.setException(new MyException()));
SettableFuture<Object> input = SettableFuture.create();
ListenableFuture<Object> output =
catchingAsync(input, MyException.class, asyncIdentity(), directExecutor());
output.addListener(
() -> {
throw new StackOverflowError();
},
directExecutor());
assertThrows(StackOverflowError.class, () -> input.setException(new MyException()));
}

public void testCatchingAsync_errorAfterCancellation() throws Exception {
Expand Down

0 comments on commit 57ec95c

Please sign in to comment.