Skip to content

Commit 371a922

Browse files
committed
[GR-59095] Fix handling internal and interop exceptions on top level
PullRequest: graalpython/3521
2 parents 66530d3 + 5b7f1e5 commit 371a922

File tree

4 files changed

+39
-67
lines changed

4 files changed

+39
-67
lines changed

Diff for: graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java

+8-50
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import java.util.HashMap;
4444
import java.util.Iterator;
4545
import java.util.List;
46-
import java.util.ListIterator;
4746
import java.util.Map;
4847
import java.util.Set;
4948
import java.util.UUID;
@@ -57,9 +56,7 @@
5756
import org.graalvm.polyglot.Context.Builder;
5857
import org.graalvm.polyglot.Engine;
5958
import org.graalvm.polyglot.PolyglotException;
60-
import org.graalvm.polyglot.PolyglotException.StackFrame;
6159
import org.graalvm.polyglot.Source;
62-
import org.graalvm.polyglot.SourceSection;
6360
import org.graalvm.polyglot.Value;
6461
import org.graalvm.shadowed.org.jline.reader.UserInterruptException;
6562

@@ -820,9 +817,7 @@ protected void launch(Builder contextBuilder) {
820817
evalNonInteractive(context, consoleHandler);
821818
rc = 0;
822819
} catch (PolyglotException e) {
823-
if (!e.isExit()) {
824-
printPythonLikeStackTrace(e);
825-
} else {
820+
if (e.isExit()) {
826821
rc = e.getExitStatus();
827822
}
828823
} catch (NoSuchFileException e) {
@@ -1007,41 +1002,6 @@ private static void printFileNotFoundException(NoSuchFileException e) {
10071002
System.err.println(GraalPythonMain.class.getCanonicalName() + ": can't open file '" + e.getFile() + "': " + reason);
10081003
}
10091004

1010-
private static void printPythonLikeStackTrace(PolyglotException e) {
1011-
// If we're running through the launcher and an exception escapes to here,
1012-
// we didn't go through the Python code to print it. That may be because
1013-
// it's an exception from another language. In this case, we still would
1014-
// like to print it like a Python exception.
1015-
ArrayList<String> stack = new ArrayList<>();
1016-
for (StackFrame frame : e.getPolyglotStackTrace()) {
1017-
if (frame.isGuestFrame()) {
1018-
StringBuilder sb = new StringBuilder();
1019-
SourceSection sourceSection = frame.getSourceLocation();
1020-
String rootName = frame.getRootName();
1021-
if (sourceSection != null) {
1022-
sb.append(" ");
1023-
String path = sourceSection.getSource().getPath();
1024-
if (path != null) {
1025-
sb.append("File ");
1026-
}
1027-
sb.append('"');
1028-
sb.append(sourceSection.getSource().getName());
1029-
sb.append("\", line ");
1030-
sb.append(sourceSection.getStartLine());
1031-
sb.append(", in ");
1032-
sb.append(rootName);
1033-
stack.add(sb.toString());
1034-
}
1035-
}
1036-
}
1037-
System.err.println("Traceback (most recent call last):");
1038-
ListIterator<String> listIterator = stack.listIterator(stack.size());
1039-
while (listIterator.hasPrevious()) {
1040-
System.err.println(listIterator.previous());
1041-
}
1042-
System.err.println(e.getMessage());
1043-
}
1044-
10451005
private void evalNonInteractive(Context context, ConsoleHandler consoleHandler) throws IOException {
10461006
// We need to setup the terminal even when not running the REPL because code may request
10471007
// input from the terminal.
@@ -1253,17 +1213,15 @@ private int readEvalPrint(Context context, ConsoleHandler consoleHandler) {
12531213
if (e.isExit()) {
12541214
// usually from quit
12551215
throw new ExitException(e.getExitStatus());
1256-
} else if (e.isHostException()) {
1257-
// we continue the repl even though the system may be broken
1258-
lastStatus = 1;
1259-
System.out.println(e.getMessage());
12601216
} else if (e.isInternalError()) {
1261-
System.err.println("An internal error occurred:");
1262-
printPythonLikeStackTrace(e);
1263-
1264-
// we continue the repl even though the system may be broken
1217+
/*
1218+
* The stacktrace should have been printed above by
1219+
* TopLevelExceptionHandler. We continue the repl even though the
1220+
* system may be broken
1221+
*/
1222+
System.err.println("An internal error occurred, continue at your own risk");
12651223
lastStatus = 1;
1266-
} else if (e.isGuestException()) {
1224+
} else {
12671225
// drop through to continue REPL and remember last eval was an error
12681226
lastStatus = 1;
12691227
}

Diff for: graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java

+18-2
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
import com.oracle.graal.python.builtins.objects.dict.PDict;
112112
import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum;
113113
import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.ErrorAndMessagePair;
114+
import com.oracle.graal.python.builtins.objects.function.PArguments;
114115
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
115116
import com.oracle.graal.python.builtins.objects.function.PFunction;
116117
import com.oracle.graal.python.builtins.objects.function.PKeyword;
@@ -143,10 +144,12 @@
143144
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
144145
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
145146
import com.oracle.graal.python.nodes.object.GetClassNode;
147+
import com.oracle.graal.python.nodes.object.GetOrCreateDictNode;
146148
import com.oracle.graal.python.nodes.statement.AbstractImportNode;
147149
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
148150
import com.oracle.graal.python.nodes.util.CastToTruffleStringNode;
149151
import com.oracle.graal.python.nodes.util.ToNativePrimitiveStorageNode;
152+
import com.oracle.graal.python.runtime.ExecutionContext;
150153
import com.oracle.graal.python.runtime.PosixSupportLibrary;
151154
import com.oracle.graal.python.runtime.PythonContext;
152155
import com.oracle.graal.python.runtime.PythonImageBuildOptions;
@@ -341,7 +344,7 @@ private void runFile(PythonContext context, TruffleString inputFilePath) {
341344
TruffleFile file = context.getPublicTruffleFileRelaxed(inputFilePath);
342345
builder = Source.newBuilder(PythonLanguage.ID, file);
343346
}
344-
source = builder.mimeType(PythonLanguage.MIME_TYPE).build();
347+
source = builder.mimeType(PythonLanguage.getCompileMimeType(0, 0)).build();
345348
// TODO we should handle non-IO errors better
346349
} catch (IOException e) {
347350
ErrorAndMessagePair error = OSErrorEnum.fromException(e, TruffleString.EqualNode.getUncached());
@@ -355,8 +358,21 @@ private void runFile(PythonContext context, TruffleString inputFilePath) {
355358
// The exit value is hardcoded in CPython too
356359
throw new PythonExitException(this, 2);
357360
}
361+
PythonLanguage language = context.getLanguage();
358362
CallTarget callTarget = context.getEnv().parsePublic(source);
359-
callTarget.call(PythonUtils.EMPTY_OBJECT_ARRAY);
363+
Object[] arguments = PArguments.create();
364+
PythonModule mainModule = context.getMainModule();
365+
PDict mainDict = GetOrCreateDictNode.executeUncached(mainModule);
366+
PArguments.setGlobals(arguments, mainModule);
367+
PArguments.setSpecialArgument(arguments, mainDict);
368+
PArguments.setException(arguments, PException.NO_EXCEPTION);
369+
context.initializeMainModule(inputFilePath);
370+
Object state = ExecutionContext.IndirectCalleeContext.enterIndirect(language, context, arguments);
371+
try {
372+
callTarget.call(arguments);
373+
} finally {
374+
ExecutionContext.IndirectCalleeContext.exit(language, context, state);
375+
}
360376
}
361377

362378
// Equivalent of CPython's pymain_run_module

Diff for: graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@
139139
import java.util.List;
140140
import java.util.Set;
141141

142-
import com.oracle.truffle.api.CompilerDirectives.ValueType;
143142
import org.graalvm.nativeimage.ImageInfo;
144143

145144
import com.oracle.graal.python.PythonLanguage;
@@ -171,7 +170,6 @@
171170
import com.oracle.graal.python.builtins.objects.dict.PDict;
172171
import com.oracle.graal.python.builtins.objects.exception.ExceptionNodes;
173172
import com.oracle.graal.python.builtins.objects.exception.GetEscapedExceptionNode;
174-
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
175173
import com.oracle.graal.python.builtins.objects.frame.PFrame;
176174
import com.oracle.graal.python.builtins.objects.frame.PFrame.Reference;
177175
import com.oracle.graal.python.builtins.objects.function.PArguments;
@@ -236,6 +234,7 @@
236234
import com.oracle.graal.python.util.PythonUtils;
237235
import com.oracle.truffle.api.CompilerDirectives;
238236
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
237+
import com.oracle.truffle.api.CompilerDirectives.ValueType;
239238
import com.oracle.truffle.api.Truffle;
240239
import com.oracle.truffle.api.TruffleLanguage.Env;
241240
import com.oracle.truffle.api.dsl.Bind;
@@ -1515,15 +1514,14 @@ void printExceptionRecursive(MaterializedFrame frame, PythonModule sys, Object o
15151514
protected void printException(MaterializedFrame frame, PythonModule sys, Object out, Object excValue) {
15161515
Object value = excValue;
15171516
final Object type = getObjectClass(value);
1518-
if (!PGuards.isPBaseException(value)) {
1517+
if (!PyExceptionInstanceCheckNode.executeUncached(value)) {
15191518
fileWriteString(frame, out, "TypeError: print_exception(): Exception expected for value, ");
15201519
fileWriteString(frame, out, getTypeName(type));
15211520
fileWriteString(frame, out, " found\n");
15221521
return;
15231522
}
15241523

1525-
final PBaseException exc = (PBaseException) value;
1526-
final Object tb = getExceptionTraceback(exc);
1524+
final Object tb = getExceptionTraceback(value);
15271525
if (tb instanceof PTraceback) {
15281526
printTraceBack(frame, sys, out, tb);
15291527
}

Diff for: graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java

+10-10
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
import com.oracle.truffle.api.CompilerDirectives;
7676
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
7777
import com.oracle.truffle.api.RootCallTarget;
78+
import com.oracle.truffle.api.exception.AbstractTruffleException;
7879
import com.oracle.truffle.api.frame.VirtualFrame;
7980
import com.oracle.truffle.api.interop.ExceptionType;
8081
import com.oracle.truffle.api.interop.InteropLibrary;
@@ -142,10 +143,9 @@ public Object execute(VirtualFrame frame) {
142143
assert pythonContext.getThreadState(lang).getCurrentException() == null;
143144
try {
144145
return run(frame);
145-
} catch (PException e) {
146+
} catch (AbstractTruffleException e) {
146147
assert !PArguments.isPythonFrame(frame);
147-
Object pythonException = e.getEscapedException();
148-
if (pythonException instanceof PBaseException managedException && getContext().isChildContext() && isSystemExit(managedException)) {
148+
if (e instanceof PException pe && pe.getEscapedException() instanceof PBaseException managedException && getContext().isChildContext() && isSystemExit(managedException)) {
149149
return handleChildContextExit(managedException);
150150
}
151151
throw handlePythonException(e);
@@ -171,8 +171,8 @@ private void checkInitialized() {
171171
}
172172

173173
@TruffleBoundary
174-
private PException handlePythonException(PException pException) {
175-
Object pythonException = pException.getEscapedException();
174+
private AbstractTruffleException handlePythonException(AbstractTruffleException e) {
175+
Object pythonException = e instanceof PException pe ? pe.getEscapedException() : e;
176176
if (pythonException instanceof PBaseException managedException && isSystemExit(managedException)) {
177177
handleSystemExit(managedException);
178178
}
@@ -186,8 +186,8 @@ private PException handlePythonException(PException pException) {
186186
sys.setAttribute(BuiltinNames.T_LAST_TRACEBACK, tb);
187187

188188
ExceptionUtils.printExceptionTraceback(getContext(), pythonException);
189-
if (PythonOptions.isPExceptionWithJavaStacktrace(getPythonLanguage())) {
190-
ExceptionUtils.printJavaStackTrace(pException);
189+
if (PythonOptions.isPExceptionWithJavaStacktrace(getPythonLanguage()) && e instanceof PException pe) {
190+
ExceptionUtils.printJavaStackTrace(pe);
191191
}
192192
if (!getSourceSection().getSource().isInteractive()) {
193193
if (getContext().isChildContext()) {
@@ -197,10 +197,10 @@ private PException handlePythonException(PException pException) {
197197
}
198198
}
199199
// Before we leave Python, format the message since outside the context
200-
if (pythonException instanceof PBaseException managedException) {
201-
pException.setMessage(managedException.getFormattedMessage());
200+
if (e instanceof PException pe && pythonException instanceof PBaseException managedException) {
201+
pe.setMessage(managedException.getFormattedMessage());
202202
}
203-
throw pException;
203+
throw e;
204204
}
205205

206206
private static boolean isSystemExit(PBaseException pythonException) {

0 commit comments

Comments
 (0)