]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-146011: Fix use-after-free in `signaldict_repr` after deletion (GH-153784...
authorBrij Kapadia <97006829+brijkapadia@users.noreply.github.com>
Fri, 24 Jul 2026 14:30:01 +0000 (10:30 -0400)
committerGitHub <noreply@github.com>
Fri, 24 Jul 2026 14:30:01 +0000 (14:30 +0000)
* [3.13] gh-146011: Fix use-after-free in `signaldict_repr` after deletion (GH-153784)
(cherry picked from commit 41a087acc2d04c5bc3db93b5367456f05ae400a4)

Co-authored-by: Brij Kapadia <97006829+brijkapadia@users.noreply.github.com>
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Victor Stinner <vstinner@python.org>
Lib/test/test_decimal.py
Misc/NEWS.d/next/Library/2026-07-15-21-56-40.gh-issue-146011.nWmHif.rst [new file with mode: 0644]
Modules/_decimal/_decimal.c

index 23107c603f8d413151add159d1dcd638e7f32880..fad648b537dc715460638d759756b892debeddfa 100644 (file)
@@ -4098,6 +4098,15 @@ class ContextFlags:
 @requires_cdecimal
 class CContextFlags(ContextFlags, unittest.TestCase):
     decimal = C
+
+    def test_signaldict_repr(self):
+        Context = self.decimal.Context
+        ctx = Context(prec=7)
+        mapping = ctx.flags
+        del ctx
+        with self.assertRaisesRegex(ValueError, 'invalid signal dict'):
+            repr(mapping)
+
 class PyContextFlags(ContextFlags, unittest.TestCase):
     decimal = P
 
diff --git a/Misc/NEWS.d/next/Library/2026-07-15-21-56-40.gh-issue-146011.nWmHif.rst b/Misc/NEWS.d/next/Library/2026-07-15-21-56-40.gh-issue-146011.nWmHif.rst
new file mode 100644 (file)
index 0000000..0cac025
--- /dev/null
@@ -0,0 +1,2 @@
+Fix a heap-use-after-free in the C implementation of :mod:`decimal`
+when calling :func:`repr` after deleting the :class:`~decimal.Context`.
index cbe7af132409a020371053892c8f24f93d6b860b..8590efd1fabe52abbc128fdbad76d14e0619a914 100644 (file)
@@ -1419,6 +1419,20 @@ context_traverse(PyDecContextObject *self, visitproc visit, void *arg)
 static int
 context_clear(PyDecContextObject *self)
 {
+    /* Since traps and flags hold a borrowed reference to the
+       flags stored in the context object, these references need
+       to be cleared when the context object is deallocated
+       because traps and flags can survive. See gh-146011. */
+    PyDecSignalDictObject *traps = (PyDecSignalDictObject *)self->traps;
+    PyDecSignalDictObject *flags = (PyDecSignalDictObject *)self->flags;
+
+    if (traps != NULL) {
+        traps->flags = NULL;
+    }
+    if (flags != NULL) {
+        flags->flags = NULL;
+    }
+
     Py_CLEAR(self->traps);
     Py_CLEAR(self->flags);
     return 0;