]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-150988: Fix refleak in `OSError` when attrs are set before `super().__init__(...
authorLukas Geiger <lukas.geiger94@gmail.com>
Wed, 10 Jun 2026 12:27:11 +0000 (13:27 +0100)
committerGitHub <noreply@github.com>
Wed, 10 Jun 2026 12:27:11 +0000 (12:27 +0000)
Co-authored-by: Victor Stinner <vstinner@python.org>
Lib/test/test_exceptions.py
Misc/NEWS.d/next/Core_and_Builtins/2026-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst [new file with mode: 0644]
Objects/exceptions.c

index 3f5fcb29b442dec86352495ca2ee2a9ae6da957e..df7a04273b9b41cc081d2568d8f83742a1f1601a 100644 (file)
@@ -1714,6 +1714,20 @@ class ExceptionTests(unittest.TestCase):
         gc_collect()  # For PyPy or other GCs.
         self.assertEqual(wr(), None)
 
+    def test_oserror_reinit_leak(self):
+        # gh-150988: Check for memory leak when re-initializing OSError.
+        # Previously, setting OSError attributes in a subclass
+        # before calling super().__init__() leaked memory.
+        class LeakingOSError(OSError):
+            def __init__(self, code, message, filename, filename2):
+                self.strerror = message
+                self.filename = filename
+                self.filename2 = filename2
+                super().__init__(code, message, filename, None, filename2)
+
+        exc = LeakingOSError(1, "some message", "filename.py", "filename2.py")
+        exc.__init__(2, "another message", "filename3.py", "filename4.py")
+
     def test_errno_ENOTDIR(self):
         # Issue #12802: "not a directory" errors are ENOTDIR even on Windows
         with self.assertRaises(OSError) as cm:
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-05-22-52-41.gh-issue-150988.fDKfMJ.rst
new file mode 100644 (file)
index 0000000..6fb70a1
--- /dev/null
@@ -0,0 +1,2 @@
+Fix a reference leak in :exc:`OSError` when attributes are set before
+``super().__init__()``.
index 34a7844c857732ea0e641be8f1ae4a80ab23a8d7..149595e64cec1445e495918b550801666f992381 100644 (file)
@@ -2140,10 +2140,10 @@ oserror_init(PyOSErrorObject *self, PyObject **p_args,
                 return -1;
         }
         else {
-            self->filename = Py_NewRef(filename);
+            Py_XSETREF(self->filename, Py_NewRef(filename));
 
             if (filename2 && filename2 != Py_None) {
-                self->filename2 = Py_NewRef(filename2);
+                Py_XSETREF(self->filename2, Py_NewRef(filename2));
             }
 
             if (nargs >= 2 && nargs <= 5) {
@@ -2158,10 +2158,10 @@ oserror_init(PyOSErrorObject *self, PyObject **p_args,
             }
         }
     }
-    self->myerrno = Py_XNewRef(myerrno);
-    self->strerror = Py_XNewRef(strerror);
+    Py_XSETREF(self->myerrno, Py_XNewRef(myerrno));
+    Py_XSETREF(self->strerror, Py_XNewRef(strerror));
 #ifdef MS_WINDOWS
-    self->winerror = Py_XNewRef(winerror);
+    Py_XSETREF(self->winerror, Py_XNewRef(winerror));
 #endif
 
     /* Steals the reference to args */