Skip to content

Commit 41a087a

Browse files
brijkapadiablurb-it[bot]vstinner
authored
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 <vstinner@python.org>
1 parent da46947 commit 41a087a

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
@@ -4147,6 +4147,15 @@ def test_float_operation_default(self):
41474147
@requires_cdecimal
41484148
class CContextFlags(ContextFlags, unittest.TestCase):
41494149
decimal = C
4150+
4151+
def test_signaldict_repr(self):
4152+
Context = self.decimal.Context
4153+
ctx = Context(prec=7)
4154+
mapping = ctx.flags
4155+
del ctx
4156+
with self.assertRaisesRegex(ValueError, 'invalid signal dict'):
4157+
repr(mapping)
4158+
41504159
class PyContextFlags(ContextFlags, unittest.TestCase):
41514160
decimal = P
41524161

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
@@ -1499,6 +1499,20 @@ static int
14991499
context_clear(PyObject *op)
15001500
{
15011501
PyDecContextObject *self = _PyDecContextObject_CAST(op);
1502+
/* Since traps and flags hold a borrowed reference to the
1503+
flags stored in the context object, these references need
1504+
to be cleared when the context object is deallocated
1505+
because traps and flags can survive. See gh-146011. */
1506+
PyDecSignalDictObject *traps = _PyDecSignalDictObject_CAST(self->traps);
1507+
PyDecSignalDictObject *flags = _PyDecSignalDictObject_CAST(self->flags);
1508+
1509+
if (traps != NULL) {
1510+
traps->flags = NULL;
1511+
}
1512+
if (flags != NULL) {
1513+
flags->flags = NULL;
1514+
}
1515+
15021516
Py_CLEAR(self->traps);
15031517
Py_CLEAR(self->flags);
15041518
return 0;

0 commit comments

Comments
 (0)