From 3979150a0d406707f6d253d7c15fb32c1e005a77 Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Sun, 30 Jul 2023 16:28:54 +0800 Subject: gh-106263: Fix segfault in `signaldict_repr` in `_decimal` module (#106270) Co-authored-by: sunmy2019 <59365878+sunmy2019@users.noreply.github.com> --- Lib/test/test_decimal.py | 30 ++++++++++++++++++++ .../2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst | 2 ++ Modules/_decimal/_decimal.c | 32 +++++++++++++++++++--- Tools/c-analyzer/cpython/ignored.tsv | 1 + 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index db67f37..fc66a30 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -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 index 0000000..2376381 --- /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 7a20697..585214c 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -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)); } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index cf6d3b2..099f20b 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_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 - -- cgit v0.12