Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -42,11 +42,14 @@

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;

import java.io.IOException;

import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Context.Builder;
import org.graalvm.polyglot.PolyglotException;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.Value;
import org.junit.After;
Expand Down Expand Up @@ -83,6 +86,44 @@ public void tearDown() {
context.close();
}

@Test
public void exceptionFromExecThroughFinally() {
assertExceptionFromExec("""
def run(code):
try:
exec(code, {})
finally:
pass
""");
}

@Test
public void exceptionFromExecThroughExceptReraise() {
assertExceptionFromExec("""
def run(code):
try:
exec(code, {})
except BaseException:
raise
""");
}

private void assertExceptionFromExec(String supportCode) {
context.eval(Source.newBuilder("python", supportCode, "support.py").buildLiteral());
Value run = context.getBindings("python").getMember("run");
String[] code = {"undefined_name", "raise ValueError('boom')", "1 / 0"};
String[] messages = {"NameError: name 'undefined_name' is not defined", "ValueError: boom", "ZeroDivisionError: division by zero"};
// Exercise both the uncached and cached bytecode interpreters.
for (int round = 0; round < 10; round++) {
for (int i = 0; i < code.length; i++) {
String snippet = code[i];
PolyglotException exception = assertThrows(PolyglotException.class, () -> run.execute(snippet));
assertTrue(exception.isGuestException());
assertEquals(messages[i], exception.getMessage());
}
}
}

@Test
public void accessSuitePy() throws IOException {
Source suitePy = Source.newBuilder("python", "{ \"libraries\" : {\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,7 @@ private static Object doCreate(PythonObject moduleSpec, Node inliningTarget, Pyt
} catch (CannotCastException e) {
throw PRaiseNode.raiseStatic(inliningTarget, TypeError, ErrorMessages.BAD_ARG_TYPE_FOR_BUILTIN_OP);
} catch (ApiInitException ie) {
throw ie.reraise();
throw ie.reraise(inliningTarget);
} catch (ImportException ie) {
throw ie.reraise();
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -46,6 +46,7 @@
import com.oracle.graal.python.nodes.PConstructAndRaiseNode;
import com.oracle.graal.python.runtime.exception.PException;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.strings.TruffleString;

public abstract class LoadCExtException extends Exception {
Expand Down Expand Up @@ -89,9 +90,9 @@ public ApiInitException(TruffleString formatString, Object... formatArgs) {
}

@TruffleBoundary
public PException reraise() {
public PException reraise(Node node) {
if (cause instanceof PException pcause) {
throw pcause.getExceptionForReraise(false);
throw pcause.getExceptionForReraise(node, false);
} else if (cause != null) {
throw PConstructAndRaiseNode.getUncached().executeWithFmtMessageAndArgs(null, SystemError, ErrorMessages.M, new Object[]{cause}, null);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -109,7 +109,7 @@
* <li>{@link PException PException} must never be rethrown after it has been possibly exposed to
* the program, because its Truffle stacktrace may already be frozen, and it would not capture more
* frames. If you need to rethrow without the catching site appearing in the traceback, use
* {@link PException#getExceptionForReraise(boolean)} method to obtain a fresh {@link PException
* {@link PException#getExceptionForReraise} method to obtain a fresh {@link PException
* PException} to throw</li>
* </ul>
* </p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates.
* Copyright (c) 2017, 2026, Oracle and/or its affiliates.
* Copyright (c) 2013, Regents of the University of California
*
* All rights reserved.
Expand Down Expand Up @@ -137,7 +137,7 @@ static void reraise(VirtualFrame frame, @SuppressWarnings("unused") PNone type,
@Cached InlinedConditionProfile hasPException) {
AbstractTruffleException caughtException = getCaughtExceptionNode.execute(frame);
if (hasPException.profile(inliningTarget, caughtException instanceof PException)) {
PException exceptionToReraise = ((PException) caughtException).getExceptionForReraise(rootNodeVisible);
PException exceptionToReraise = ((PException) caughtException).getExceptionForReraise(inliningTarget, rootNodeVisible);
exceptionToReraise.dontTraceOnReraise();
throw exceptionToReraise;
} else if (caughtException != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1018,7 +1018,7 @@ private PException traceException(VirtualFrame frame, BytecodeNode bytecode, int
}
// The exception was reified already. Return a new exception that looks like this
// catch didn't happen.
result = result.getExceptionForReraise(!isInternal());
result = result.getExceptionForReraise(bytecode, !isInternal());
result.setCatchLocation(bci, bytecode);
}
}
Expand Down Expand Up @@ -3663,8 +3663,9 @@ public static void perform(VirtualFrame frame, Object typeOrExceptionObject, Obj
public static final class Reraise {
@Specialization
public static void doPException(PException ex,
@Bind BytecodeNode bytecode,
@Bind PBytecodeDSLRootNode root) {
PException pe = ex.getExceptionForReraise(!root.isInternal());
PException pe = ex.getExceptionForReraise(bytecode, !root.isInternal());
pe.dontTraceOnReraise();
throw pe;
}
Expand Down Expand Up @@ -4236,7 +4237,7 @@ public static void doExceptional(VirtualFrame frame,
Object result = callExit.execute(frame, exit, contextManager, excType, pythonException, excTraceback);
if (!isTrue.execute(frame, result)) {
if (exception instanceof PException pException) {
PException reraisedException = pException.getExceptionForReraise(!rootNode.isInternal());
PException reraisedException = pException.getExceptionForReraise(inliningTarget, !rootNode.isInternal());
reraisedException.dontTraceOnReraise();
throw reraisedException;
} else if (exception instanceof AbstractTruffleException ate) {
Expand Down Expand Up @@ -4334,7 +4335,7 @@ public static void doExceptional(VirtualFrame frame,
@Cached PyObjectIsTrueNode isTrue) {
if (!isTrue.execute(frame, result)) {
if (exception instanceof PException) {
throw ((PException) exception).getExceptionForReraise(!rootNode.isInternal());
throw ((PException) exception).getExceptionForReraise(inliningTarget, !rootNode.isInternal());
} else if (exception instanceof AbstractTruffleException) {
throw (AbstractTruffleException) exception;
} else {
Expand Down Expand Up @@ -4734,7 +4735,7 @@ static void doPException(PException exception,

@InliningCutoff
private static void reraiseException(PException exception, BytecodeNode bytecodeNode) {
throw exception.getExceptionForReraise(!((PBytecodeDSLRootNode) bytecodeNode.getRootNode()).internal);
throw exception.getExceptionForReraise(bytecodeNode, !((PBytecodeDSLRootNode) bytecodeNode.getRootNode()).internal);
}

@Specialization(guards = "!isPException(exception)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,9 +427,9 @@ public void notifyAddedTracebackFrame(Frame frame, boolean visible) {
* look like the last catch didn't happen, which is desired in `raise` without arguments, at the
* end of `finally`, `__exit__`...
*/
public PException getExceptionForReraise(boolean rootNodeVisible) {
public PException getExceptionForReraise(Node location, boolean rootNodeVisible) {
ensureReified();
PException pe = PException.fromObject(pythonException, getLocation(), false);
PException pe = PException.fromObjectFixUncachedLocation(pythonException, location, false);
pe.reraised = true;
if (pe.getUnreifiedException() instanceof PBaseExceptionGroup grp) {
grp.setContainsReraises(true);
Expand Down Expand Up @@ -465,10 +465,11 @@ boolean isException() {
}

@ExportMessage
RuntimeException throwException(@Exclusive @Cached GilNode gil) {
RuntimeException throwException(@Bind Node location,
@Exclusive @Cached GilNode gil) {
boolean mustRelease = gil.acquire();
try {
throw getExceptionForReraise(false);
throw getExceptionForReraise(location, false);
} finally {
gil.release(mustRelease);
}
Expand Down
Loading