Skip to content

gh-156204: Guard recursion in PyErr_GivenExceptionMatches - #156205

Open
BHUVANSH855 wants to merge 9 commits into
python:mainfrom
BHUVANSH855:fix-err-given-exception-matches-recursion
Open

BHUVANSH855 wants to merge 9 commits into
python:mainfrom
BHUVANSH855:fix-err-given-exception-matches-recursion

Conversation

@BHUVANSH855

@BHUVANSH855 BHUVANSH855 commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

Fixes issue gh-156204.

PyErr_GivenExceptionMatches in Python/errors.c recursively unpacks tuple targets without recursion checks, causing native C stack exhaustion and a SIGSEGV when given deeply nested exception tuples.

This change:

  • Guards recursion in PyErr_GivenExceptionMatches via Py_EnterRecursiveCall() and Py_LeaveRecursiveCall().
  • Adds a _testcapi.err_givenexceptionmatches() helper and a regression test in Lib/test/test_exceptions.py.
  • Adds a blurb NEWS entry.

Verified: with Python/errors.c reverted to the pre-fix version the new test segfaults; with the fix it passes.

Comment thread Lib/test/test_exceptions.py Outdated
Comment thread Misc/NEWS.d/next/Core_and_Builtins/2026-08-21-18-49-12.gh-issue-156204.ZusA7e.rst Outdated
@read-the-docs-community

Copy link
Copy Markdown

Documentation build overview

📚 cpython-previews | 🛠️ Build #34178190 | 📁 Comparing b6be6c5 against main (999a046)

  🔍 Preview build  

2 files changed
± c-api/exceptions.html
± whatsnew/changelog.html

Comment thread Doc/c-api/exceptions.rst Outdated
Comment thread Modules/_testcapi/exceptions.c Outdated
Comment thread Python/errors.c
@iritkatriel

Copy link
Copy Markdown
Member

Looks like some test is failing.

@BHUVANSH855

Copy link
Copy Markdown
Contributor Author

Looks like some test is failing.

hi, the failing checks were unrelated to this PR, as the PR was stale form some days, so I updated the branch and synced it to the current main.
Hope this time no check fails.

Comment thread Python/errors.c
n = PyTuple_Size(exc);
for (i = 0; i < n; i++) {
if (Py_EnterRecursiveCall(" in PyErr_GivenExceptionMatches")) {
return 0;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PyErr_GivenExceptionMatches doesn't have a way to indicate an error, so we can't return with an exception set. Let's emit an unraisable exception here if we hit the recursion error.

Comment thread Modules/_testcapi/exceptions.c Outdated
{
assert(!PyErr_Occurred());
int res = PyErr_GivenExceptionMatches(err, exc);
if (res == 0 && PyErr_Occurred()) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the API contract for PyErr_GivenExceptionMatches. We can't make the function set new exceptions without breaking code.

Comment thread Python/errors.c Outdated
Py_ssize_t i, n;
n = PyTuple_Size(exc);
for (i = 0; i < n; i++) {
if (Py_EnterRecursiveCall(" in PyErr_GivenExceptionMatches")) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message can appear in Python code that may not know about the C API, so I don't think we should explicitly mention PyErr_GivenExceptionMatches here. Let's say something like "while checking exception tuple"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants