[Python-checkins] [3.12] gh-106263: Fix segfault in `signaldict_repr` in `_decimal` module (#… (#107491)

ambv webhook-mailer at python.org
Mon Jul 31 08:34:20 EDT 2023


https://github.com/python/cpython/commit/99518bbbf47a198f8c51e82e7357ac7efdafdcd8
commit: 99518bbbf47a198f8c51e82e7357ac7efdafdcd8
branch: 3.12
author: Charlie Zhao <zhaoyu_hit at qq.com>
committer: ambv <lukasz at langa.pl>
date: 2023-07-31T14:34:16+02:00
summary:

[3.12] gh-106263: Fix segfault in `signaldict_repr`  in `_decimal` module (#… (#107491)

Co-authored-by: sunmy2019 <59365878+sunmy2019 at users.noreply.github.com>

(cherry picked from commit 3979150a0d406707f6d253d7c15fb32c1e005a77)

files:
A Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst
M Lib/test/test_decimal.py
M Modules/_decimal/_decimal.c
M Tools/c-analyzer/cpython/ignored.tsv

diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index 749496e3e9455..d0ba34803c21e 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -5682,6 +5682,36 @@ def test_maxcontext_exact_arith(self):
             self.assertEqual(Decimal(400) ** -1, Decimal('0.0025'))
 
 
+    def test_c_signaldict_segfault(self):
+        # See gh-106263 for details.
+        SignalDict = type(C.Context().flags)
+        sd = SignalDict()
+        err_msg = "invalid signal dict"
+
+        with self.assertRaisesRegex(ValueError, err_msg):
+            len(sd)
+
+        with self.assertRaisesRegex(ValueError, err_msg):
+            iter(sd)
+
+        with self.assertRaisesRegex(ValueError, err_msg):
+            repr(sd)
+
+        with self.assertRaisesRegex(ValueError, err_msg):
+            sd[C.InvalidOperation] = True
+
+        with self.assertRaisesRegex(ValueError, err_msg):
+            sd[C.InvalidOperation]
+
+        with self.assertRaisesRegex(ValueError, err_msg):
+            sd == C.Context().flags
+
+        with self.assertRaisesRegex(ValueError, err_msg):
+            C.Context().flags == sd
+
+        with self.assertRaisesRegex(ValueError, err_msg):
+            sd.copy()
+
 @requires_docstrings
 @requires_cdecimal
 class SignatureTest(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst b/Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst
new file mode 100644
index 0000000000000..23763818d84ba
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst
@@ -0,0 +1,2 @@
+Fix crash when calling ``repr`` with a manually constructed SignalDict object.
+Patch by Charlie Zhao.
\ No newline at end of file
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
index 70e18edb46453..70b13982bb0cc 100644
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -246,14 +246,12 @@ value_error_int(const char *mesg)
     return -1;
 }
 
-#ifdef CONFIG_32
 static PyObject *
 value_error_ptr(const char *mesg)
 {
     PyErr_SetString(PyExc_ValueError, mesg);
     return NULL;
 }
-#endif
 
 static int
 type_error_int(const char *mesg)
@@ -540,6 +538,8 @@ getround(PyObject *v)
    initialized to new SignalDicts. Once a SignalDict is tied to
    a context, it cannot be deleted. */
 
+static const char *INVALID_SIGNALDICT_ERROR_MSG = "invalid signal dict";
+
 static int
 signaldict_init(PyObject *self, PyObject *args UNUSED, PyObject *kwds UNUSED)
 {
@@ -548,8 +548,11 @@ signaldict_init(PyObject *self, PyObject *args UNUSED, PyObject *kwds UNUSED)
 }
 
 static Py_ssize_t
-signaldict_len(PyObject *self UNUSED)
+signaldict_len(PyObject *self)
 {
+    if (SdFlagAddr(self) == NULL) {
+        return value_error_int(INVALID_SIGNALDICT_ERROR_MSG);
+    }
     return SIGNAL_MAP_LEN;
 }
 
@@ -557,6 +560,9 @@ static PyObject *SignalTuple;
 static PyObject *
 signaldict_iter(PyObject *self UNUSED)
 {
+    if (SdFlagAddr(self) == NULL) {
+        return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
+    }
     return PyTuple_Type.tp_iter(SignalTuple);
 }
 
@@ -564,6 +570,9 @@ static PyObject *
 signaldict_getitem(PyObject *self, PyObject *key)
 {
     uint32_t flag;
+    if (SdFlagAddr(self) == NULL) {
+        return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
+    }
 
     flag = exception_as_flag(key);
     if (flag & DEC_ERRORS) {
@@ -579,6 +588,10 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value)
     uint32_t flag;
     int x;
 
+    if (SdFlagAddr(self) == NULL) {
+        return value_error_int(INVALID_SIGNALDICT_ERROR_MSG);
+    }
+
     if (value == NULL) {
         return value_error_int("signal keys cannot be deleted");
     }
@@ -611,6 +624,10 @@ signaldict_repr(PyObject *self)
     const char *b[SIGNAL_MAP_LEN]; /* bool */
     int i;
 
+    if (SdFlagAddr(self) == NULL) {
+        return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
+    }
+
     assert(SIGNAL_MAP_LEN == 9);
 
     for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) {
@@ -632,6 +649,9 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op)
     PyObject *res = Py_NotImplemented;
 
     assert(PyDecSignalDict_Check(v));
+    if ((SdFlagAddr(v) == NULL) || (SdFlagAddr(w) == NULL)) {
+        return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
+    }
 
     if (op == Py_EQ || op == Py_NE) {
         if (PyDecSignalDict_Check(w)) {
@@ -660,6 +680,9 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op)
 static PyObject *
 signaldict_copy(PyObject *self, PyObject *args UNUSED)
 {
+    if (SdFlagAddr(self) == NULL) {
+        return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
+    }
     return flags_as_dict(SdFlags(self));
 }
 
diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv
index afc28e551813b..78be97da41b50 100644
--- a/Tools/c-analyzer/cpython/ignored.tsv
+++ b/Tools/c-analyzer/cpython/ignored.tsv
@@ -213,6 +213,7 @@ Modules/_decimal/_decimal.c	-	invalid_rounding_err	-
 Modules/_decimal/_decimal.c	-	invalid_signals_err	-
 Modules/_decimal/_decimal.c	-	signal_map	-
 Modules/_decimal/_decimal.c	-	ssize_constants	-
+Modules/_decimal/_decimal.c	-	INVALID_SIGNALDICT_ERROR_MSG	-
 Modules/_elementtree.c	-	ExpatMemoryHandler	-
 Modules/_hashopenssl.c	-	py_hashes	-
 Modules/_hacl/Hacl_Hash_SHA1.c	-	_h0	-



More information about the Python-checkins mailing list