Skip to content

Commit 99518bb

Browse files
[3.12] gh-106263: Fix segfault in signaldict_repr in _decimal module (#… (#107491)
Co-authored-by: sunmy2019 <[email protected]> (cherry picked from commit 3979150)
1 parent 8f080a2 commit 99518bb

File tree

4 files changed

+59
-3
lines changed

4 files changed

+59
-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: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,14 +246,12 @@ value_error_int(const char *mesg)
246246
return -1;
247247
}
248248

249-
#ifdef CONFIG_32
250249
static PyObject *
251250
value_error_ptr(const char *mesg)
252251
{
253252
PyErr_SetString(PyExc_ValueError, mesg);
254253
return NULL;
255254
}
256-
#endif
257255

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

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

550550
static Py_ssize_t
551-
signaldict_len(PyObject *self UNUSED)
551+
signaldict_len(PyObject *self)
552552
{
553+
if (SdFlagAddr(self) == NULL) {
554+
return value_error_int(INVALID_SIGNALDICT_ERROR_MSG);
555+
}
553556
return SIGNAL_MAP_LEN;
554557
}
555558

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

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

568577
flag = exception_as_flag(key);
569578
if (flag & DEC_ERRORS) {
@@ -579,6 +588,10 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value)
579588
uint32_t flag;
580589
int x;
581590

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

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

616633
for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) {
@@ -632,6 +649,9 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op)
632649
PyObject *res = Py_NotImplemented;
633650

634651
assert(PyDecSignalDict_Check(v));
652+
if ((SdFlagAddr(v) == NULL) || (SdFlagAddr(w) == NULL)) {
653+
return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
654+
}
635655

636656
if (op == Py_EQ || op == Py_NE) {
637657
if (PyDecSignalDict_Check(w)) {
@@ -660,6 +680,9 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op)
660680
static PyObject *
661681
signaldict_copy(PyObject *self, PyObject *args UNUSED)
662682
{
683+
if (SdFlagAddr(self) == NULL) {
684+
return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
685+
}
663686
return flags_as_dict(SdFlags(self));
664687
}
665688

Tools/c-analyzer/cpython/ignored.tsv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ Modules/_decimal/_decimal.c - invalid_rounding_err -
213213
Modules/_decimal/_decimal.c - invalid_signals_err -
214214
Modules/_decimal/_decimal.c - signal_map -
215215
Modules/_decimal/_decimal.c - ssize_constants -
216+
Modules/_decimal/_decimal.c - INVALID_SIGNALDICT_ERROR_MSG -
216217
Modules/_elementtree.c - ExpatMemoryHandler -
217218
Modules/_hashopenssl.c - py_hashes -
218219
Modules/_hacl/Hacl_Hash_SHA1.c - _h0 -

0 commit comments

Comments
 (0)