]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-146011: Fix use-after-free in `signaldict_repr` after deletion (GH-153784...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Fri, 24 Jul 2026 14:15:18 +0000 (16:15 +0200)
committerGitHub <noreply@github.com>
Fri, 24 Jul 2026 14:15:18 +0000 (14:15 +0000)
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 c621b7ac08c3ac0fcbd0e228a7a1abf7e05c08f1..7e3896ed34e7bae32d6f89cc4484e9c03185db26 100644 (file)
@@ -4142,6 +4142,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 a7f12e1b291e0ec37cd48fc9048b490f7e34b5a0..bead9b99309bddf5134784b7506b913e7ea686b7 100644 (file)
@@ -1452,6 +1452,20 @@ static int
 context_clear(PyObject *op)
 {
     PyDecContextObject *self = _PyDecContextObject_CAST(op);
+    /* 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_CAST(self->traps);
+    PyDecSignalDictObject *flags = _PyDecSignalDictObject_CAST(self->flags);
+
+    if (traps != NULL) {
+        traps->flags = NULL;
+    }
+    if (flags != NULL) {
+        flags->flags = NULL;
+    }
+
     Py_CLEAR(self->traps);
     Py_CLEAR(self->flags);
     return 0;