]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-106263: Fix segfault in `signaldict_repr` in `_decimal` module (#106270)
authorCharlie Zhao <zhaoyu_hit@qq.com>
Sun, 30 Jul 2023 08:28:54 +0000 (16:28 +0800)
committerGitHub <noreply@github.com>
Sun, 30 Jul 2023 08:28:54 +0000 (13:58 +0530)
Co-authored-by: sunmy2019 <59365878+sunmy2019@users.noreply.github.com>
Lib/test/test_decimal.py
Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst [new file with mode: 0644]
Modules/_decimal/_decimal.c
Tools/c-analyzer/cpython/ignored.tsv

index db67f37608f1f24db36de81d3356133a8be1722a..fc66a309788ac15e07aaeb529cec4aebe6d7c417 100644 (file)
@@ -5701,6 +5701,36 @@ class CWhitebox(unittest.TestCase):
         ContextManager = type(C.localcontext())
         check_disallow_instantiation(self, ContextManager)
 
+    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 (file)
index 0000000..2376381
--- /dev/null
@@ -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
index 7a206973975cc86916f36b74bbac4d7e1ea03aca..585214cc45d6cd974a88619c624ff1f16d95ae01 100644 (file)
@@ -314,14 +314,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)
@@ -608,6 +606,8 @@ getround(decimal_state *state, 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)
 {
@@ -616,14 +616,20 @@ 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;
 }
 
 static PyObject *
 signaldict_iter(PyObject *self)
 {
+    if (SdFlagAddr(self) == NULL) {
+        return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
+    }
     decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     return PyTuple_Type.tp_iter(state->SignalTuple);
 }
@@ -632,6 +638,9 @@ static PyObject *
 signaldict_getitem(PyObject *self, PyObject *key)
 {
     uint32_t flag;
+    if (SdFlagAddr(self) == NULL) {
+        return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG);
+    }
     decimal_state *state = get_module_state_by_def(Py_TYPE(self));
 
     flag = exception_as_flag(state, key);
@@ -648,11 +657,15 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value)
     uint32_t flag;
     int x;
 
-    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
+    if (SdFlagAddr(self) == NULL) {
+        return value_error_int(INVALID_SIGNALDICT_ERROR_MSG);
+    }
+
     if (value == NULL) {
         return value_error_int("signal keys cannot be deleted");
     }
 
+    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     flag = exception_as_flag(state, key);
     if (flag & DEC_ERRORS) {
         return -1;
@@ -697,6 +710,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);
 
     decimal_state *state = get_module_state_by_def(Py_TYPE(self));
@@ -721,6 +738,10 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op)
     decimal_state *state = find_state_left_or_right(v, w);
     assert(PyDecSignalDict_Check(state, 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(state, w)) {
             res = (SdFlags(v)==SdFlags(w)) ^ (op==Py_NE) ? Py_True : Py_False;
@@ -748,6 +769,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);
+    }
     decimal_state *state = get_module_state_by_def(Py_TYPE(self));
     return flags_as_dict(state, SdFlags(self));
 }
index cf6d3b24435238415b17168b1ad0ae45ae3d1e46..099f20b5a1b43358e48bd9e9fb461e8080723a02 100644 (file)
@@ -213,6 +213,7 @@ Modules/_decimal/_decimal.c -       invalid_rounding_err    -
 Modules/_decimal/_decimal.c    -       invalid_signals_err     -
 Modules/_decimal/_decimal.c    -       signal_map_template     -
 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     -