Skip to content

Commit 5e09ebb

Browse files
authored
Do not catch and ignore fatal exceptions (#3827)
1 parent 42a9c1a commit 5e09ebb

File tree

6 files changed

+105
-2
lines changed

6 files changed

+105
-2
lines changed

src/main/java/com/fasterxml/jackson/databind/ext/Java7Support.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.fasterxml.jackson.databind.introspect.Annotated;
55
import com.fasterxml.jackson.databind.introspect.AnnotatedParameter;
66
import com.fasterxml.jackson.databind.util.ClassUtil;
7+
import com.fasterxml.jackson.databind.util.ExceptionUtil;
78

89
/**
910
* To support Java7-incomplete platforms, we will offer support for JDK 7
@@ -25,6 +26,7 @@ public abstract class Java7Support
2526
// 09-Sep-2019, tatu: Used to log earlier, but with 2.10.0 let's not log
2627
// java.util.logging.Logger.getLogger(Java7Support.class.getName())
2728
// .warning("Unable to load JDK7 annotations (@ConstructorProperties, @Transient): no Java7 annotation support added");
29+
ExceptionUtil.rethrowIfFatal(t);
2830
}
2931
IMPL = impl;
3032
}

src/main/java/com/fasterxml/jackson/databind/ext/OptionalHandlerFactory.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.fasterxml.jackson.databind.ser.Serializers;
99
import com.fasterxml.jackson.databind.ser.std.DateSerializer;
1010
import com.fasterxml.jackson.databind.util.ClassUtil;
11+
import com.fasterxml.jackson.databind.util.ExceptionUtil;
1112

1213
/**
1314
* Helper class used for isolating details of handling optional+external types
@@ -55,6 +56,7 @@ public class OptionalHandlerFactory implements java.io.Serializable
5556
node = org.w3c.dom.Node.class;
5657
doc = org.w3c.dom.Document.class;
5758
} catch (Throwable e) {
59+
ExceptionUtil.rethrowIfFatal(e);
5860
// not optimal but will do
5961
// 02-Nov-2020, Xakep_SDK: Remove java.logging module dependency
6062
// Logger.getLogger(OptionalHandlerFactory.class.getName())
@@ -73,7 +75,9 @@ public class OptionalHandlerFactory implements java.io.Serializable
7375
Java7Handlers x = null;
7476
try {
7577
x = Java7Handlers.instance();
76-
} catch (Throwable t) { }
78+
} catch (Throwable t) {
79+
ExceptionUtil.rethrowIfFatal(t);
80+
}
7781
_jdk7Helper = x;
7882
}
7983

@@ -232,6 +236,7 @@ private Object instantiate(String className, JavaType valueType)
232236
try {
233237
return instantiate(Class.forName(className), valueType);
234238
} catch (Throwable e) {
239+
ExceptionUtil.rethrowIfFatal(e);
235240
throw new IllegalStateException("Failed to find class `"
236241
+className+"` for handling values of type "+ClassUtil.getTypeDescription(valueType)
237242
+", problem: ("+e.getClass().getName()+") "+e.getMessage());
@@ -243,6 +248,7 @@ private Object instantiate(Class<?> handlerClass, JavaType valueType)
243248
try {
244249
return ClassUtil.createInstance(handlerClass, false);
245250
} catch (Throwable e) {
251+
ExceptionUtil.rethrowIfFatal(e);
246252
throw new IllegalStateException("Failed to create instance of `"
247253
+handlerClass.getName()+"` for handling values of type "+ClassUtil.getTypeDescription(valueType)
248254
+", problem: ("+e.getClass().getName()+") "+e.getMessage());

src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ public class JacksonAnnotationIntrospector
6666
Java7Support x = null;
6767
try {
6868
x = Java7Support.instance();
69-
} catch (Throwable t) { }
69+
} catch (Throwable t) {
70+
ExceptionUtil.rethrowIfFatal(t);
71+
}
7072
_java7Helper = x;
7173
}
7274

src/main/java/com/fasterxml/jackson/databind/util/ClassUtil.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,7 @@ public static boolean isJDK17OrAbove() {
11801180
try {
11811181
return getJDKMajorVersion() >= 17;
11821182
} catch (Throwable t) {
1183+
ExceptionUtil.rethrowIfFatal(t);
11831184
System.err.println("Failed to determine JDK major version, assuming pre-JDK-17; problem: "+t);
11841185
return false;
11851186
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.fasterxml.jackson.databind.util;
2+
3+
/**
4+
* Utility methods for dealing with exceptions/throwables
5+
*
6+
* @since 2.15
7+
*/
8+
public class ExceptionUtil {
9+
private ExceptionUtil() {}
10+
11+
/**
12+
* It is important never to catch all <code>Throwable</code>s. Some like
13+
* {@link InterruptedException} should be rethrown. Based on
14+
* <a href="https://www.scala-lang.org/api/2.13.10/scala/util/control/NonFatal$.html">scala.util.control.NonFatal</a>.
15+
*
16+
* This method should be used with care.
17+
* <p>
18+
* If the <code>Throwable</code> is fatal, it is rethrown, otherwise, this method just returns.
19+
* The input throwable is thrown if it is an <code>Error</code> or a <code>RuntimeException</code>.
20+
* Otherwise, the method wraps the throwable in a RuntimeException and throws that.
21+
* </p>
22+
*
23+
* @param throwable to check
24+
* @throws Error the input throwable if it is fatal
25+
* @throws RuntimeException the input throwable if it is fatal - throws the original throwable
26+
* if is a <code>RuntimeException</code>. Otherwise, wraps the throwable in a RuntimeException.
27+
*/
28+
public static void rethrowIfFatal(Throwable throwable) throws Error, RuntimeException {
29+
if (isFatal(throwable)) {
30+
if (throwable instanceof Error) {
31+
throw (Error) throwable;
32+
}
33+
if (throwable instanceof RuntimeException) {
34+
throw (RuntimeException) throwable;
35+
}
36+
throw new RuntimeException(throwable);
37+
}
38+
}
39+
40+
/**
41+
* It is important never to catch all <code>Throwable</code>s. Some like
42+
* {@link InterruptedException} should be rethrown. Based on
43+
* <a href="https://www.scala-lang.org/api/2.13.10/scala/util/control/NonFatal$.html">scala.util.control.NonFatal</a>.
44+
*
45+
* @param throwable to check
46+
* @return whether the <code>Throwable</code> is a fatal error
47+
*/
48+
private static boolean isFatal(Throwable throwable) {
49+
return (throwable instanceof VirtualMachineError
50+
|| throwable instanceof ThreadDeath
51+
|| throwable instanceof InterruptedException
52+
|| throwable instanceof ClassCircularityError
53+
|| throwable instanceof ClassFormatError
54+
|| throwable instanceof IncompatibleClassChangeError
55+
|| throwable instanceof BootstrapMethodError
56+
|| throwable instanceof VerifyError
57+
);
58+
}
59+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.fasterxml.jackson.databind.util;
2+
3+
import com.fasterxml.jackson.databind.BaseTest;
4+
5+
public class ExceptionUtilTest extends BaseTest {
6+
public void testNoClassDefError() {
7+
//next line should be a no-op
8+
ExceptionUtil.rethrowIfFatal(new NoClassDefFoundError("fake"));
9+
}
10+
11+
public void testExceptionInInitializerError() {
12+
//next line should be a no-op
13+
ExceptionUtil.rethrowIfFatal(new ExceptionInInitializerError("fake"));
14+
}
15+
16+
public void testOutOfMemoryError() {
17+
try {
18+
ExceptionUtil.rethrowIfFatal(new OutOfMemoryError("fake"));
19+
fail("expected OutOfMemoryError");
20+
} catch (OutOfMemoryError err) {
21+
assertEquals("fake", err.getMessage());
22+
}
23+
}
24+
25+
public void testVerifyError() {
26+
try {
27+
ExceptionUtil.rethrowIfFatal(new VerifyError("fake"));
28+
fail("expected VerifyError");
29+
} catch (VerifyError err) {
30+
assertEquals("fake", err.getMessage());
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)