Skip to content

Commit cd2f146

Browse files
mattrjacobsbenjchristensen
authored andcommitted
Fixed issue #799 - Added break to possibly-infinite loop in CompositeException.attachCallingThreadStack
1 parent de1e0b1 commit cd2f146

File tree

2 files changed

+83
-3
lines changed

2 files changed

+83
-3
lines changed

rxjava-core/src/main/java/rx/util/CompositeException.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
import java.util.ArrayList;
1919
import java.util.Collection;
2020
import java.util.Collections;
21+
import java.util.HashSet;
2122
import java.util.List;
23+
import java.util.Set;
2224

2325
/**
2426
* Exception that is a composite of 1 or more other exceptions.
@@ -84,9 +86,16 @@ private static String getStackTraceAsString(StackTraceElement[] stack) {
8486
return s.toString();
8587
}
8688

87-
private static void attachCallingThreadStack(Throwable e, Throwable cause) {
89+
/* package-private */ static void attachCallingThreadStack(Throwable e, Throwable cause) {
90+
Set<Throwable> seenCauses = new HashSet<Throwable>();
91+
8892
while (e.getCause() != null) {
8993
e = e.getCause();
94+
if (seenCauses.contains(e.getCause())) {
95+
break;
96+
} else {
97+
seenCauses.add(e.getCause());
98+
}
9099
}
91100
// we now have 'e' as the last in the chain
92101
try {
@@ -98,12 +107,13 @@ private static void attachCallingThreadStack(Throwable e, Throwable cause) {
98107
}
99108
}
100109

101-
private final static class CompositeExceptionCausalChain extends RuntimeException {
110+
/* package-private */ final static class CompositeExceptionCausalChain extends RuntimeException {
102111
private static final long serialVersionUID = 3875212506787802066L;
112+
/* package-private */ static String MESSAGE = "Chain of Causes for CompositeException In Order Received =>";
103113

104114
@Override
105115
public String getMessage() {
106-
return "Chain of Causes for CompositeException In Order Received =>";
116+
return MESSAGE;
107117
}
108118
}
109119

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* Copyright 2013 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package rx.util;
17+
18+
import static org.junit.Assert.*;
19+
20+
import org.junit.Test;
21+
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
25+
public class CompositeExceptionTest {
26+
27+
private final Throwable ex1 = new Throwable("Ex1");
28+
private final Throwable ex2 = new Throwable("Ex2", ex1);
29+
private final Throwable ex3 = new Throwable("Ex3", ex2);
30+
31+
private final CompositeException compositeEx;
32+
33+
public CompositeExceptionTest() {
34+
List<Throwable> throwables = new ArrayList<Throwable>();
35+
throwables.add(ex1);
36+
throwables.add(ex2);
37+
throwables.add(ex3);
38+
compositeEx = new CompositeException(throwables);
39+
}
40+
41+
@Test
42+
public void testAttachCallingThreadStackParentThenChild() {
43+
CompositeException.attachCallingThreadStack(ex1, ex2);
44+
assertEquals("Ex2", ex1.getCause().getMessage());
45+
}
46+
47+
@Test
48+
public void testAttachCallingThreadStackChildThenParent() {
49+
CompositeException.attachCallingThreadStack(ex2, ex1);
50+
assertEquals("Ex1", ex2.getCause().getMessage());
51+
}
52+
53+
@Test
54+
public void testAttachCallingThreadStackAddComposite() {
55+
CompositeException.attachCallingThreadStack(ex1, compositeEx);
56+
assertEquals("Ex2", ex1.getCause().getMessage());
57+
}
58+
59+
@Test
60+
public void testAttachCallingThreadStackAddToComposite() {
61+
CompositeException.attachCallingThreadStack(compositeEx, ex1);
62+
assertEquals(CompositeException.CompositeExceptionCausalChain.MESSAGE, compositeEx.getCause().getMessage());
63+
}
64+
65+
@Test
66+
public void testAttachCallingThreadStackAddCompositeToItself() {
67+
CompositeException.attachCallingThreadStack(compositeEx, compositeEx);
68+
assertEquals(CompositeException.CompositeExceptionCausalChain.MESSAGE, compositeEx.getCause().getMessage());
69+
}
70+
}

0 commit comments

Comments
 (0)