]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-146011: Fix use-after-free in `signaldict_repr` after deletion (#153784)
authorBrij Kapadia <97006829+brijkapadia@users.noreply.github.com>
Fri, 24 Jul 2026 12:21:43 +0000 (08:21 -0400)
committerGitHub <noreply@github.com>
Fri, 24 Jul 2026 12:21:43 +0000 (12:21 +0000)
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 a04ed0c83c07c4a272ebcea6eb9cdb9a84f56287..1c723b25784da11dcd3f14f4a8cf2b2d7db80f33 100644 (file)
@@ -4147,6 +4147,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 dc1b3c06bed9521470d5d63aa32987bccad25dc3..6fbce0ed85e695df1f5e165c18f37821f927e997 100644 (file)
@@ -1499,6 +1499,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;