-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Return value of <ExceptionGroup class>.split has insufficient checks leading to a type confusion bug #128049
Comments
Nice find! Raising a TypeError seems more appropriate here, would you like to send a PR? |
Sure |
I agree we should do something here, but raising a new exception while the interpreter is handling an exception from the program is not ideal if it swallows the user's exception. So we need to think that through. |
With the change I implemented, the new output is
|
Could you update the test to check that the original exception is chained? |
hmm, if I update the test to the following, then it final print statement executes class Evil(BaseExceptionGroup):
def split(self, *args):
return "NOT A TUPLE!"
print("Running...")
try:
try:
raise Evil("wow!", [Exception()])
except* Exception:
pass
except TypeError:
pass
print("done") But if the original exception is dependent on the ExceptionGroup split function executing correctly, how else can we go about it? |
On your branch I would expect it to work.
|
To clarify, the alternative suggestion is to treat anything other than a 2-tuple as a no-match, and raise a |
Though, chaining would be consistent with this:
|
For the test, you need to use a different type so that you're not catching everything. Something like this:
|
I've never worked with FormatUnraisable before, is this the correct way to use it? /* ... */
if (_PyBaseExceptionGroup_Check(exc_value)) {
PyObject *pair = PyObject_CallMethod(exc_value, "split", "(O)",
match_type);
if (pair == NULL) {
return -1;
}
if (!PyTuple_CheckExact(pair) || PyTuple_Size(pair) != 2) {
PyErr_Format(PyExc_TypeError,
"%s.split must return a 2-tuple",
Py_TYPE(exc_value)->tp_name);
PyErr_FormatUnraisable("Exception ignored on calling %s.split",
Py_TYPE(exc_value)->tp_name);
Py_DECREF(pair);
goto no_match;
}
*match = Py_NewRef(PyTuple_GET_ITEM(pair, 0));
*rest = Py_NewRef(PyTuple_GET_ITEM(pair, 1));
Py_DECREF(pair);
return 0;
}
no_match:
*match = Py_NewRef(Py_None);
*rest = Py_NewRef(exc_value);
return 0;
} If I don't put the PyErr_Format before it, I get an assertion failure of
With the changes above, I get this output
|
That looks right. But see my previous comment - I think it will be consistent with the other case to go with your first suggestion. |
So just keep it how it is in the PR then? |
Yes, but extend the test. |
Crash report
What happened?
The following code has checks to make sure the return value is a tuple and of size 2, but only in asserts which means that these checks wont happen on a non-debug build.
cpython/Python/ceval.c
Lines 2093 to 2101 in b92f101
So you can create an ExceptionGroup subclass with a custom
split
function that doesnt return a tuple, and it will try to interpret that object as a tuple.PoC
Output
CPython versions tested on:
3.11, 3.12, 3.13
Operating systems tested on:
Linux, Windows
Output from running 'python -VV' on the command line:
No response
Linked PRs
The text was updated successfully, but these errors were encountered: