https://github.com/python/cpython/commit/41a087acc2d04c5bc3db93b5367456f05ae400a4
commit: 41a087acc2d04c5bc3db93b5367456f05ae400a4
branch: main
author: Brij Kapadia <[email protected]>
committer: vstinner <[email protected]>
date: 2026-07-24T12:21:43Z
summary:

gh-146011: Fix use-after-free in `signaldict_repr` after deletion (#153784)

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Victor Stinner <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-07-15-21-56-40.gh-issue-146011.nWmHif.rst
M Lib/test/test_decimal.py
M Modules/_decimal/_decimal.c

diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index a04ed0c83c07c4a..1c723b25784da11 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -4147,6 +4147,15 @@ def test_float_operation_default(self):
 @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
index 000000000000000..0cac0257040bd6b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-07-15-21-56-40.gh-issue-146011.nWmHif.rst
@@ -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`.
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
index dc1b3c06bed9521..6fbce0ed85e695d 100644
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -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;

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to