Skip to content

Commit a15d06c

Browse files
[3.11] gh-106263: Fix segfault in signaldict_repr in _decimal module (#… (#107490)
Co-authored-by: sunmy2019 <[email protected]> (cherry picked from commit 3979150)
1 parent 81d0c7c commit a15d06c

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

Lib/test/test_decimal.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5682,6 +5682,36 @@ def test_maxcontext_exact_arith(self):
56825682
self.assertEqual(Decimal(400) ** -1, Decimal('0.0025'))
56835683

56845684

5685+
def test_c_signaldict_segfault(self):
5686+
# See gh-106263 for details.
5687+
SignalDict = type(C.Context().flags)
5688+
sd = SignalDict()
5689+
err_msg = "invalid signal dict"
5690+
5691+
with self.assertRaisesRegex(ValueError, err_msg):
5692+
len(sd)
5693+
5694+
with self.assertRaisesRegex(ValueError, err_msg):
5695+
iter(sd)
5696+
5697+
with self.assertRaisesRegex(ValueError, err_msg):
5698+
repr(sd)
5699+
5700+
with self.assertRaisesRegex(ValueError, err_msg):
5701+
sd[C.InvalidOperation] = True
5702+
5703+
with self.assertRaisesRegex(ValueError, err_msg):
5704+
sd[C.InvalidOperation]
5705+
5706+
with self.assertRaisesRegex(ValueError, err_msg):
5707+
sd == C.Context().flags
5708+
5709+
with self.assertRaisesRegex(ValueError, err_msg):
5710+
C.Context().flags == sd
5711+
5712+
with self.assertRaisesRegex(ValueError, err_msg):
5713+
sd.copy()
5714+
56855715
@requires_docstrings
56865716
@requires_cdecimal
56875717
class SignatureTest(unittest.TestCase):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crash when calling ``repr`` with a manually constructed SignalDict object.
2+
Patch by Charlie Zhao.

Modules/_decimal/_decimal.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,14 +247,12 @@ value_error_int(const char *mesg)
247247
return -1;
248248
}
249249

250-
#ifdef CONFIG_32
251250
static PyObject *
252251
value_error_ptr(const char *mesg)
253252
{
254253
PyErr_SetString(PyExc_ValueError, mesg);
255254
return NULL;
256255
}
257-
#endif
258256

259257
static int
260258
type_error_int(const char *mesg)
@@ -541,6 +539,8 @@ getround(PyObject *v)
541539
initialized to new SignalDicts. Once a SignalDict is tied to
542540
a context, it cannot be deleted. */
543541

542+
static const char *INVALID_SIGNALDICT_ERROR_MSG = "invalid signal dict";
543+
544544
static int
545545
signaldict_init(PyObject *self, PyObject *args UNUSED, PyObject *kwds UNUSED)
546546
{
@@ -549,22 +549,31 @@ signaldict_init(PyObject *self, PyObject *args UNUSED, PyObject *kwds UNUSED)
549549
}
550550

551551
static Py_ssize_t
552-
signaldict_len(PyObject *self UNUSED)
552+
signaldict_len(PyObject *self)
553553
{
554+
if (SdFlagAddr(self) == NULL) {
555+
return value_error_int(INVALID_SIGNALDICT_ERROR_MSG);
556+
}
554557
return SIGNAL_MAP_LEN;
555558
}
556559

557560
static PyObject *SignalTuple;
558561
static PyObject *
559562
signaldict_iter(PyObject *self UNUSED)
560563
{
564+
if (SdFlagAddr(self) == NULL) {
565+
return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
566+
}
561567
return PyTuple_Type.tp_iter(SignalTuple);
562568
}
563569

564570
static PyObject *
565571
signaldict_getitem(PyObject *self, PyObject *key)
566572
{
567573
uint32_t flag;
574+
if (SdFlagAddr(self) == NULL) {
575+
return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
576+
}
568577

569578
flag = exception_as_flag(key);
570579
if (flag & DEC_ERRORS) {
@@ -580,6 +589,10 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value)
580589
uint32_t flag;
581590
int x;
582591

592+
if (SdFlagAddr(self) == NULL) {
593+
return value_error_int(INVALID_SIGNALDICT_ERROR_MSG);
594+
}
595+
583596
if (value == NULL) {
584597
return value_error_int("signal keys cannot be deleted");
585598
}
@@ -612,6 +625,10 @@ signaldict_repr(PyObject *self)
612625
const char *b[SIGNAL_MAP_LEN]; /* bool */
613626
int i;
614627

628+
if (SdFlagAddr(self) == NULL) {
629+
return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
630+
}
631+
615632
assert(SIGNAL_MAP_LEN == 9);
616633

617634
for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) {
@@ -634,6 +651,10 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op)
634651

635652
assert(PyDecSignalDict_Check(v));
636653

654+
if ((SdFlagAddr(v) == NULL) || (SdFlagAddr(w) == NULL)) {
655+
return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
656+
}
657+
637658
if (op == Py_EQ || op == Py_NE) {
638659
if (PyDecSignalDict_Check(w)) {
639660
res = (SdFlags(v)==SdFlags(w)) ^ (op==Py_NE) ? Py_True : Py_False;
@@ -662,6 +683,9 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op)
662683
static PyObject *
663684
signaldict_copy(PyObject *self, PyObject *args UNUSED)
664685
{
686+
if (SdFlagAddr(self) == NULL) {
687+
return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
688+
}
665689
return flags_as_dict(SdFlags(self));
666690
}
667691

Tools/c-analyzer/cpython/ignored.tsv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,7 @@ Modules/_decimal/_decimal.c - invalid_rounding_err -
14321432
Modules/_decimal/_decimal.c - invalid_signals_err -
14331433
Modules/_decimal/_decimal.c - signal_map -
14341434
Modules/_decimal/_decimal.c - ssize_constants -
1435+
Modules/_decimal/_decimal.c - INVALID_SIGNALDICT_ERROR_MSG -
14351436
Modules/_elementtree.c - ExpatMemoryHandler -
14361437
Modules/_io/_iomodule.c - static_types -
14371438
Modules/_io/textio.c - encodefuncs -

0 commit comments

Comments
 (0)