Skip to content

Commit bfad768

Browse files
lgeigervstinner
authored andcommitted
gh-150988: Fix refleak in OSError when attrs are set before super().__init__() (GH-150990)
(cherry picked from commit f2a0f82) Co-authored-by: Lukas Geiger <lukas.geiger94@gmail.com> Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent 52ee56a commit bfad768

3 files changed

Lines changed: 21 additions & 5 deletions

File tree

Lib/test/test_exceptions.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1662,6 +1662,20 @@ def inner():
16621662
gc_collect() # For PyPy or other GCs.
16631663
self.assertEqual(wr(), None)
16641664

1665+
def test_oserror_reinit_leak(self):
1666+
# gh-150988: Check for memory leak when re-initializing OSError.
1667+
# Previously, setting OSError attributes in a subclass
1668+
# before calling super().__init__() leaked memory.
1669+
class LeakingOSError(OSError):
1670+
def __init__(self, code, message, filename, filename2):
1671+
self.strerror = message
1672+
self.filename = filename
1673+
self.filename2 = filename2
1674+
super().__init__(code, message, filename, None, filename2)
1675+
1676+
exc = LeakingOSError(1, "some message", "filename.py", "filename2.py")
1677+
exc.__init__(2, "another message", "filename3.py", "filename4.py")
1678+
16651679
def test_errno_ENOTDIR(self):
16661680
# Issue #12802: "not a directory" errors are ENOTDIR even on Windows
16671681
with self.assertRaises(OSError) as cm:
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a reference leak in :exc:`OSError` when attributes are set before
2+
``super().__init__()``.

Objects/exceptions.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,10 +1846,10 @@ oserror_init(PyOSErrorObject *self, PyObject **p_args,
18461846
return -1;
18471847
}
18481848
else {
1849-
self->filename = Py_NewRef(filename);
1849+
Py_XSETREF(self->filename, Py_NewRef(filename));
18501850

18511851
if (filename2 && filename2 != Py_None) {
1852-
self->filename2 = Py_NewRef(filename2);
1852+
Py_XSETREF(self->filename2, Py_NewRef(filename2));
18531853
}
18541854

18551855
if (nargs >= 2 && nargs <= 5) {
@@ -1864,10 +1864,10 @@ oserror_init(PyOSErrorObject *self, PyObject **p_args,
18641864
}
18651865
}
18661866
}
1867-
self->myerrno = Py_XNewRef(myerrno);
1868-
self->strerror = Py_XNewRef(strerror);
1867+
Py_XSETREF(self->myerrno, Py_XNewRef(myerrno));
1868+
Py_XSETREF(self->strerror, Py_XNewRef(strerror));
18691869
#ifdef MS_WINDOWS
1870-
self->winerror = Py_XNewRef(winerror);
1870+
Py_XSETREF(self->winerror, Py_XNewRef(winerror));
18711871
#endif
18721872

18731873
/* Steals the reference to args */

0 commit comments

Comments
 (0)