Skip to content

Commit 0e8b607

Browse files
miss-islingtonbrijkapadiablurb-it[bot]vstinner
authored
[3.14] gh-146011: Fix use-after-free in signaldict_repr after deletion (GH-153784) (#154600)
gh-146011: Fix use-after-free in `signaldict_repr` after deletion (GH-153784) (cherry picked from commit 41a087a) 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>
1 parent 5337461 commit 0e8b607

3 files changed

Lines changed: 25 additions & 0 deletions

File tree

Lib/test/test_decimal.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4142,6 +4142,15 @@ def test_float_operation_default(self):
41424142
@requires_cdecimal
41434143
class CContextFlags(ContextFlags, unittest.TestCase):
41444144
decimal = C
4145+
4146+
def test_signaldict_repr(self):
4147+
Context = self.decimal.Context
4148+
ctx = Context(prec=7)
4149+
mapping = ctx.flags
4150+
del ctx
4151+
with self.assertRaisesRegex(ValueError, 'invalid signal dict'):
4152+
repr(mapping)
4153+
41454154
class PyContextFlags(ContextFlags, unittest.TestCase):
41464155
decimal = P
41474156

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a heap-use-after-free in the C implementation of :mod:`decimal`
2+
when calling :func:`repr` after deleting the :class:`~decimal.Context`.

Modules/_decimal/_decimal.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,20 @@ static int
14521452
context_clear(PyObject *op)
14531453
{
14541454
PyDecContextObject *self = _PyDecContextObject_CAST(op);
1455+
/* Since traps and flags hold a borrowed reference to the
1456+
flags stored in the context object, these references need
1457+
to be cleared when the context object is deallocated
1458+
because traps and flags can survive. See gh-146011. */
1459+
PyDecSignalDictObject *traps = _PyDecSignalDictObject_CAST(self->traps);
1460+
PyDecSignalDictObject *flags = _PyDecSignalDictObject_CAST(self->flags);
1461+
1462+
if (traps != NULL) {
1463+
traps->flags = NULL;
1464+
}
1465+
if (flags != NULL) {
1466+
flags->flags = NULL;
1467+
}
1468+
14551469
Py_CLEAR(self->traps);
14561470
Py_CLEAR(self->flags);
14571471
return 0;

0 commit comments

Comments
 (0)