Skip to content

Commit a0e70c4

Browse files
committed
8370175: State engine terminates when throwing self-caused exception
Reviewed-by: jlahoda, fandreuzzi
1 parent 8b536b5 commit a0e70c4

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

src/jdk.jshell/share/classes/jdk/jshell/execution/DirectExecutionControl.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,9 @@
2929
import java.lang.reflect.Field;
3030
import java.lang.reflect.InvocationTargetException;
3131
import java.lang.reflect.Method;
32+
import java.util.Collections;
33+
import java.util.IdentityHashMap;
34+
import java.util.Set;
3235
import java.util.stream.IntStream;
3336
import jdk.jshell.spi.ExecutionControl;
3437
import jdk.jshell.spi.SPIResolutionException;
@@ -335,10 +338,15 @@ private static boolean needsEscape(int idx, int cp) {
335338
* @throws ExecutionControl.InternalException for internal problems
336339
*/
337340
protected String throwConvertedInvocationException(Throwable cause) throws RunException, InternalException {
338-
throw asRunException(cause);
341+
// Guard against recursive cause chains by
342+
// using a Set with identity equality semantics.
343+
Set<Throwable> dejaVu = Collections.newSetFromMap(new IdentityHashMap<>());
344+
dejaVu.add(cause);
345+
346+
throw asRunException(cause, dejaVu);
339347
}
340348

341-
private RunException asRunException(Throwable ex) {
349+
private RunException asRunException(Throwable ex, Set<Throwable> dejaVu) {
342350
if (ex instanceof SPIResolutionException) {
343351
SPIResolutionException spire = (SPIResolutionException) ex;
344352
return new ResolutionException(spire.id(), spire.getStackTrace());
@@ -347,7 +355,14 @@ private RunException asRunException(Throwable ex) {
347355
ex.getClass().getName(),
348356
ex.getStackTrace());
349357
Throwable cause = ex.getCause();
350-
ue.initCause(cause == null ? null : asRunException(cause));
358+
if (cause != null) {
359+
Throwable throwable = dejaVu.add(cause)
360+
? asRunException(cause, dejaVu)
361+
: new UserException("CIRCULAR REFERENCE!",
362+
cause.getClass().getName(),
363+
cause.getStackTrace());
364+
ue.initCause(throwable);
365+
}
351366
return ue;
352367
}
353368
}

test/langtools/jdk/jshell/ExceptionsTest.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
/*
2525
* @test
2626
* @summary Tests for exceptions
27-
* @bug 8198801 8212167 8210527
27+
* @bug 8198801 8212167 8210527 8370175
2828
* @modules jdk.compiler/com.sun.tools.javac.api
2929
* jdk.compiler/com.sun.tools.javac.main
3030
* jdk.jdeps/com.sun.tools.javap
@@ -320,6 +320,16 @@ public void stackOverflow() {
320320
assertExecuteException("f();", StackOverflowError.class);
321321
}
322322

323+
@Test
324+
public void recursiveCauses() {
325+
assertEval("var one = new Throwable();");
326+
assertEval("var two = new Error();");
327+
assertEval("one.initCause(two);");
328+
assertEval("two.initCause(one);");
329+
assertExecuteException("throw one;", Throwable.class);
330+
assertExecuteException("throw two;", Error.class);
331+
}
332+
323333
private StackTraceElement newStackTraceElement(String className, String methodName, Snippet key, int lineNumber) {
324334
return new StackTraceElement(className, methodName, "#" + key.id(), lineNumber);
325335
}

0 commit comments

Comments
 (0)