Skip to content

Conversation

@picnixz
Copy link
Member

@picnixz picnixz commented Nov 2, 2025

subtype for which `T.__new__` does not return an exception instance.
@picnixz picnixz force-pushed the fix/core/raise-from-140530 branch from a445dd3 to adb1bc4 Compare November 2, 2025 11:54
@picnixz picnixz added the 🔨 test-with-refleak-buildbots Test PR w/ refleak buildbots; report in status section label Nov 2, 2025
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by @picnixz for commit adb1bc4 🤖

Results will be shown at:

https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F140908%2Fmerge

If you want to schedule another build, you need to add the 🔨 test-with-refleak-buildbots label again.

@bedevere-bot bedevere-bot removed the 🔨 test-with-refleak-buildbots Test PR w/ refleak buildbots; report in status section label Nov 2, 2025
@picnixz picnixz added needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes labels Nov 2, 2025
self.fail("No exception raised")

def test_class_cause_nonexception_result(self):
class ConstructsNone(BaseException):
Copy link
Member

Choose a reason for hiding this comment

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

I think we should keep the old test and add the new test in?

Copy link
Member Author

Choose a reason for hiding this comment

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

The old test is actually testing the same code. The problem was that the returned value was immortal...

Copy link
Member Author

Choose a reason for hiding this comment

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

FTR:

if (PyExceptionClass_Check(cause)) {
	fixed_cause = _PyObject_CallNoArgs(cause);
	if (fixed_cause == NULL)
		goto raise_error;
	if (!PyExceptionInstance_Check(fixed_cause)) {
		_PyErr_Format(tstate, PyExc_TypeError,
			"calling %R should have returned an instance of "
			"BaseException, not %R",
			cause, Py_TYPE(fixed_cause));
        Py_DECREF(fixed_cause);
		goto raise_error;
	}
	Py_DECREF(cause);
}

Since cause is an exception class, we called __new__ and fixed_cause would have been None. We would then move to PyExceptionInstance_Check but since fixed_cause is immortal the refleak didn't appear.

Py_DECREF(fixed_cause);
goto raise_error;
}
Py_DECREF(cause);
Copy link
Member

Choose a reason for hiding this comment

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

Just checking so I'm clear: PyException_SetCause steals a reference right? That's why we're not decrefing fixed_cause here?

Copy link
Member Author

Choose a reason for hiding this comment

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

AFAIR, yes. PyException_Set* always steal refs IIRC, but I will check this again (it's always a pain to remember which function steals or borrows)

Copy link
Member

@efimov-mikhail efimov-mikhail Nov 9, 2025

Choose a reason for hiding this comment

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

Yes, PyException_SetCause steals a reference to cause:

/* Steals a reference to cause */
void
PyException_SetCause(PyObject *self, PyObject *cause)
{

Copy link
Member

@efimov-mikhail efimov-mikhail left a comment

Choose a reason for hiding this comment

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

LGTM

@picnixz picnixz merged commit 0c77e7c into python:main Nov 9, 2025
71 checks passed
@picnixz picnixz deleted the fix/core/raise-from-140530 branch November 9, 2025 12:41
@miss-islington-app
Copy link

Thanks @picnixz for the PR 🌮🎉.. I'm working now to backport this PR to: 3.13, 3.14.
🐍🍒⛏🤖

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Nov 9, 2025
… from cause` (pythonGH-140908)

Fix a reference leak in `raise E from T` when `T` is an exception
subtype for which `T.__new__` does not return an exception instance.
(cherry picked from commit 0c77e7c)

Co-authored-by: Bénédikt Tran <[email protected]>
@miss-islington-app
Copy link

Sorry, @picnixz, I could not cleanly backport this to 3.13 due to a conflict.
Please backport using cherry_picker on command line.

cherry_picker 0c77e7c23b5c270a3142105542c56c59b59c52a0 3.13

@bedevere-app
Copy link

bedevere-app bot commented Nov 9, 2025

GH-141282 is a backport of this pull request to the 3.14 branch.

@bedevere-app bedevere-app bot removed the needs backport to 3.14 bugs and security fixes label Nov 9, 2025
@bedevere-app
Copy link

bedevere-app bot commented Nov 9, 2025

GH-141283 is a backport of this pull request to the 3.13 branch.

@bedevere-app bedevere-app bot removed the needs backport to 3.13 bugs and security fixes label Nov 9, 2025
picnixz added a commit that referenced this pull request Nov 9, 2025
…c from cause` (GH-140908) (#141283)

gh-140530: fix a reference leak in an error path for `raise exc from cause` (#140908)

Fix a reference leak in `raise E from T` when `T` is an exception
subtype for which `T.__new__` does not return an exception instance.

(cherry picked from commit 0c77e7c)
picnixz added a commit that referenced this pull request Nov 9, 2025
…c from cause` (GH-140908) (#141282)

gh-140530: fix a reference leak in an error path for `raise exc from cause` (GH-140908)

Fix a reference leak in `raise E from T` when `T` is an exception
subtype for which `T.__new__` does not return an exception instance.
(cherry picked from commit 0c77e7c)

Co-authored-by: Bénédikt Tran <[email protected]>
StanFromIreland pushed a commit to StanFromIreland/cpython that referenced this pull request Dec 6, 2025
… from cause` (python#140908)

Fix a reference leak in `raise E from T` when `T` is an exception
subtype for which `T.__new__` does not return an exception instance.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants