Skip to content

Commit 9aaeaa5

Browse files
committed
[GR-23226] Reraise StackOverflowError as RecursionError
PullRequest: graalpython/1010
2 parents ee60ed5 + 1937b4a commit 9aaeaa5

File tree

8 files changed

+135
-45
lines changed

8 files changed

+135
-45
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/control/TopLevelExceptionHandler.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
*/
4141
package com.oracle.graal.python.nodes.control;
4242

43+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RecursionError;
4344
import static com.oracle.graal.python.nodes.SpecialMethodNames.__STR__;
4445
import static com.oracle.graal.python.runtime.exception.PythonErrorType.SystemExit;
4546

@@ -61,13 +62,15 @@
6162
import com.oracle.graal.python.nodes.call.CallNode;
6263
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
6364
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
65+
import com.oracle.graal.python.nodes.statement.ExceptionHandlingStatementNode;
6466
import com.oracle.graal.python.runtime.ExecutionContext.IndirectCalleeContext;
6567
import com.oracle.graal.python.runtime.PythonContext;
6668
import com.oracle.graal.python.runtime.PythonCore;
6769
import com.oracle.graal.python.runtime.PythonOptions;
6870
import com.oracle.graal.python.runtime.exception.ExceptionUtils;
6971
import com.oracle.graal.python.runtime.exception.PException;
7072
import com.oracle.graal.python.runtime.exception.PythonExitException;
73+
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
7174
import com.oracle.truffle.api.CompilerDirectives;
7275
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
7376
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -88,6 +91,7 @@ public class TopLevelExceptionHandler extends RootNode {
8891
@Child private LookupAndCallUnaryNode callStrNode = LookupAndCallUnaryNode.create(__STR__);
8992
@Child private CallNode exceptionHookCallNode = CallNode.create();
9093
@Child private GetExceptionTracebackNode getExceptionTracebackNode;
94+
@Child private PythonObjectFactory pythonObjectFactory;
9195

9296
public TopLevelExceptionHandler(PythonLanguage language, RootNode child) {
9397
super(language);
@@ -111,6 +115,14 @@ private PythonContext getContext() {
111115
return context.get();
112116
}
113117

118+
private PythonObjectFactory factory() {
119+
if (pythonObjectFactory == null) {
120+
CompilerDirectives.transferToInterpreterAndInvalidate();
121+
pythonObjectFactory = insert(PythonObjectFactory.create());
122+
}
123+
return pythonObjectFactory;
124+
}
125+
114126
@Override
115127
public Object execute(VirtualFrame frame) {
116128
if (exception != null) {
@@ -128,7 +140,15 @@ public Object execute(VirtualFrame frame) {
128140
printStackTrace(e);
129141
}
130142
return null;
131-
} catch (Exception | StackOverflowError e) {
143+
} catch (StackOverflowError e) {
144+
PException pe = ExceptionHandlingStatementNode.wrapJavaException(e, this, factory().createBaseException(RecursionError, "maximum recursion depth exceeded", new Object[]{}));
145+
PBaseException pythonException = pe.getExceptionObject();
146+
printExc(frame, pythonException);
147+
if (getContext().getOption(PythonOptions.WithJavaStacktrace)) {
148+
printStackTrace(e);
149+
}
150+
return null;
151+
} catch (Exception e) {
132152
boolean exitException = e instanceof TruffleException && ((TruffleException) e).isExit();
133153
if (!exitException) {
134154
ExceptionUtils.printPythonLikeStackTrace(e);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/generator/GeneratorTryExceptNode.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,11 @@ public void executeVoid(VirtualFrame frame) {
9393
return;
9494
} catch (ControlFlowException e) {
9595
throw e;
96-
} catch (Exception | StackOverflowError | AssertionError e) {
97-
if (shouldCatchAllExceptions()) {
96+
} catch (Throwable e) {
97+
PException pe = wrapJavaExceptionIfApplicable(e);
98+
if (pe != null) {
9899
gen.setActive(frame, exceptFlag, true);
99-
catchExceptionInGeneratorFirstTime(frame, wrapJavaException(e));
100+
catchExceptionInGeneratorFirstTime(frame, pe);
100101
reset(frame);
101102
return;
102103
} else {
@@ -165,6 +166,13 @@ private void runExceptionHandler(VirtualFrame frame, PException exception, Excep
165166
} catch (PException handlerException) {
166167
tryChainExceptionFromHandler(handlerException, exception);
167168
throw handlerException;
169+
} catch (Throwable e) {
170+
PException handlerException = wrapJavaExceptionIfApplicable(e);
171+
if (handlerException == null) {
172+
throw e;
173+
}
174+
tryChainExceptionFromHandler(handlerException, exception);
175+
throw handlerException;
168176
} finally {
169177
restoreExceptionState(frame, savedExceptionState);
170178
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/generator/GeneratorTryFinallyNode.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ public void executeVoid(VirtualFrame frame) {
7878
e.markFrameEscaped();
7979
tryChainPreexistingException(frame, e);
8080
gen.setActiveException(frame, activeExceptionIndex, e);
81+
} catch (Throwable e) {
82+
exceptionProfile.enter();
83+
PException pe = wrapJavaExceptionIfApplicable(e);
84+
if (pe == null) {
85+
throw e;
86+
}
87+
activeException = pe;
88+
pe.setCatchingFrameReference(frame);
89+
pe.markFrameEscaped();
90+
tryChainPreexistingException(frame, pe);
91+
gen.setActiveException(frame, activeExceptionIndex, pe);
8192
}
8293
gen.setActive(frame, finallyFlag, true);
8394
}
@@ -92,6 +103,15 @@ public void executeVoid(VirtualFrame frame) {
92103
tryChainExceptionFromHandler(handlerException, activeException);
93104
}
94105
throw handlerException;
106+
} catch (Throwable e) {
107+
PException handlerException = wrapJavaExceptionIfApplicable(e);
108+
if (handlerException == null) {
109+
throw e;
110+
}
111+
if (activeException != null) {
112+
tryChainExceptionFromHandler(handlerException, activeException);
113+
}
114+
throw handlerException;
95115
} finally {
96116
if (activeException != null) {
97117
restoreExceptionState(frame, savedExceptionState);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/generator/GeneratorWithNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,12 @@ protected void handleException(VirtualFrame frame, Object withObject, Object exi
9696
}
9797

9898
@Override
99-
protected void doLeave(VirtualFrame frame, Object withObject, boolean gotException, Object exitCallable) {
99+
protected void doLeave(VirtualFrame frame, Object withObject, Object exitCallable) {
100100
if (gen.isActive(frame, yieldSlot)) {
101101
gen.setActive(frame, yieldSlot, false);
102102
} else {
103103
reset(frame);
104-
super.doLeave(frame, withObject, gotException, exitCallable);
104+
super.doLeave(frame, withObject, exitCallable);
105105
}
106106
}
107107

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/ExceptionHandlingStatementNode.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,25 @@
4040
*/
4141
package com.oracle.graal.python.nodes.statement;
4242

43+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RecursionError;
44+
import static com.oracle.graal.python.runtime.exception.PythonErrorType.SystemError;
45+
4346
import com.oracle.graal.python.PythonLanguage;
4447
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
4548
import com.oracle.graal.python.nodes.util.ExceptionStateNodes;
4649
import com.oracle.graal.python.nodes.util.ExceptionStateNodes.ExceptionState;
4750
import com.oracle.graal.python.runtime.PythonContext;
4851
import com.oracle.graal.python.runtime.PythonOptions;
4952
import com.oracle.graal.python.runtime.exception.PException;
50-
import com.oracle.graal.python.runtime.exception.PythonErrorType;
5153
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
5254
import com.oracle.truffle.api.CompilerDirectives;
5355
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
5456
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5557
import com.oracle.truffle.api.TruffleException;
5658
import com.oracle.truffle.api.TruffleLanguage;
5759
import com.oracle.truffle.api.frame.VirtualFrame;
60+
import com.oracle.truffle.api.nodes.ControlFlowException;
61+
import com.oracle.truffle.api.nodes.Node;
5862
import com.oracle.truffle.api.profiles.ConditionProfile;
5963
import com.oracle.truffle.api.profiles.LoopConditionProfile;
6064

@@ -184,11 +188,26 @@ protected boolean shouldCatchAllExceptions() {
184188
return shouldCatchAllExceptions;
185189
}
186190

187-
protected PException wrapJavaException(Throwable e) {
188-
PException pe = PException.fromObject(getBaseException(e), this);
191+
public static PException wrapJavaException(Throwable e, Node node, PBaseException pythonException) {
192+
PException pe = PException.fromObject(pythonException, node);
193+
pe.setHideLocation(true);
189194
// Re-attach truffle stacktrace
190195
moveTruffleStackTrace(e, pe);
191-
return pe;
196+
// Create a new traceback chain, because the current one has been finalized by Truffle
197+
return pe.getExceptionForReraise();
198+
}
199+
200+
protected PException wrapJavaExceptionIfApplicable(Throwable e) {
201+
if (e instanceof ControlFlowException) {
202+
return null;
203+
}
204+
if (shouldCatchAllExceptions() && (e instanceof Exception || e instanceof AssertionError)) {
205+
return wrapJavaException(e, this, factory().createBaseException(SystemError, "%m", new Object[]{e}));
206+
}
207+
if (e instanceof StackOverflowError) {
208+
return wrapJavaException(e, this, factory().createBaseException(RecursionError, "maximum recursion depth exceeded", new Object[]{}));
209+
}
210+
return null;
192211
}
193212

194213
@TruffleBoundary
@@ -198,9 +217,4 @@ private static void moveTruffleStackTrace(Throwable e, PException pe) {
198217
// the cutoff point to the catch site
199218
pe.getTruffleStackTrace();
200219
}
201-
202-
@TruffleBoundary
203-
private PBaseException getBaseException(Throwable e) {
204-
return factory().createBaseException(PythonErrorType.SystemError, "%m", new Object[]{e});
205-
}
206220
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/TryExceptNode.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ public void executeVoid(VirtualFrame frame) {
107107
return;
108108
}
109109
}
110-
if (shouldCatchAllExceptions()) {
111-
PException pe = wrapJavaException(e);
110+
PException pe = wrapJavaExceptionIfApplicable(e);
111+
if (pe != null) {
112112
boolean handled = catchException(frame, pe);
113113
if (handled) {
114114
return;
@@ -145,6 +145,13 @@ private boolean catchException(VirtualFrame frame, TruffleException exception) {
145145
} catch (PException handlerException) {
146146
tryChainExceptionFromHandler(handlerException, exception);
147147
throw handlerException;
148+
} catch (Exception | StackOverflowError | AssertionError e) {
149+
PException handlerException = wrapJavaExceptionIfApplicable(e);
150+
if (handlerException == null) {
151+
throw e;
152+
}
153+
tryChainExceptionFromHandler(handlerException, exception);
154+
throw handlerException;
148155
}
149156
return false;
150157
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/TryFinallyNode.java

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,29 +51,46 @@ public void executeVoid(VirtualFrame frame) {
5151
try {
5252
body.executeVoid(frame);
5353
} catch (PException handledException) {
54-
exceptionProfile.enter();
55-
// any thrown Python exception is visible in the finally block
56-
handledException.setCatchingFrameReference(frame);
57-
tryChainPreexistingException(frame, handledException);
58-
ExceptionState exceptionState = saveExceptionState(frame);
59-
SetCaughtExceptionNode.execute(frame, handledException);
60-
try {
61-
finalbody.executeVoid(frame);
62-
} catch (PException handlerException) {
63-
tryChainExceptionFromHandler(handlerException, handledException);
64-
throw handlerException;
65-
} finally {
66-
restoreExceptionState(frame, exceptionState);
67-
}
68-
throw handledException.getExceptionForReraise();
54+
handleException(frame, handledException);
6955
} catch (ControlFlowException e) {
7056
finalbody.executeVoid(frame);
7157
throw e;
58+
} catch (Throwable e) {
59+
PException pe = wrapJavaExceptionIfApplicable(e);
60+
if (pe == null) {
61+
throw e;
62+
}
63+
handleException(frame, pe);
7264
}
7365
finalbody.executeVoid(frame);
7466
}
7567
}
7668

69+
private void handleException(VirtualFrame frame, PException handledException) {
70+
exceptionProfile.enter();
71+
// any thrown Python exception is visible in the finally block
72+
handledException.setCatchingFrameReference(frame);
73+
tryChainPreexistingException(frame, handledException);
74+
ExceptionState exceptionState = saveExceptionState(frame);
75+
SetCaughtExceptionNode.execute(frame, handledException);
76+
try {
77+
finalbody.executeVoid(frame);
78+
} catch (PException handlerException) {
79+
tryChainExceptionFromHandler(handlerException, handledException);
80+
throw handlerException;
81+
} catch (Throwable e) {
82+
PException handlerException = wrapJavaExceptionIfApplicable(e);
83+
if (handlerException == null) {
84+
throw e;
85+
}
86+
tryChainExceptionFromHandler(handlerException, handledException);
87+
throw handlerException;
88+
} finally {
89+
restoreExceptionState(frame, exceptionState);
90+
}
91+
throw handledException.getExceptionForReraise();
92+
}
93+
7794
public StatementNode getBody() {
7895
return body;
7996
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/WithNode.java

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ private PRaiseNode getRaiseNode() {
104104

105105
@Override
106106
public void executeVoid(VirtualFrame frame) {
107-
boolean gotException = false;
108107
Object withObject = getWithObject(frame);
109108
Object enterCallable = enterGetter.execute(withObject);
110109
if (enterCallable == PNone.NO_VALUE) {
@@ -120,20 +119,20 @@ public void executeVoid(VirtualFrame frame) {
120119
try {
121120
doBody(frame);
122121
} catch (PException exception) {
123-
gotException = true;
124122
handleException(frame, withObject, exitCallable, exception);
123+
return;
125124
} catch (ControlFlowException e) {
125+
doLeave(frame, withObject, exitCallable);
126126
throw e;
127-
} catch (Exception | StackOverflowError | AssertionError e) {
128-
if (shouldCatchAllExceptions()) {
129-
gotException = true;
130-
handleException(frame, withObject, exitCallable, wrapJavaException(e));
131-
} else {
127+
} catch (Throwable e) {
128+
PException pe = wrapJavaExceptionIfApplicable(e);
129+
if (pe == null) {
132130
throw e;
133131
}
134-
} finally {
135-
doLeave(frame, withObject, gotException, exitCallable);
132+
handleException(frame, withObject, exitCallable, pe);
133+
return;
136134
}
135+
doLeave(frame, withObject, exitCallable);
137136
}
138137

139138
/**
@@ -154,10 +153,8 @@ protected void doBody(VirtualFrame frame) {
154153
* Leave the with-body. Call __exit__ if it hasn't already happened because of an exception, and
155154
* reset the exception state.
156155
*/
157-
protected void doLeave(VirtualFrame frame, Object withObject, boolean gotException, Object exitCallable) {
158-
if (!gotException) {
159-
exitDispatch.execute(frame, exitCallable, new Object[]{withObject, PNone.NONE, PNone.NONE, PNone.NONE}, PKeyword.EMPTY_KEYWORDS);
160-
}
156+
protected void doLeave(VirtualFrame frame, Object withObject, Object exitCallable) {
157+
exitDispatch.execute(frame, exitCallable, new Object[]{withObject, PNone.NONE, PNone.NONE, PNone.NONE}, PKeyword.EMPTY_KEYWORDS);
161158
}
162159

163160
/**
@@ -187,6 +184,13 @@ protected void handleException(VirtualFrame frame, Object withObject, Object exi
187184
} catch (PException handlerException) {
188185
tryChainExceptionFromHandler(handlerException, pException);
189186
throw handlerException;
187+
} catch (Throwable e) {
188+
PException handlerException = wrapJavaExceptionIfApplicable(e);
189+
if (handlerException == null) {
190+
throw e;
191+
}
192+
tryChainExceptionFromHandler(handlerException, pException);
193+
throw handlerException;
190194
} finally {
191195
restoreExceptionState(frame, savedExceptionState);
192196
}

0 commit comments

Comments
 (0)