summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCharlie Zhao <zhaoyu_hit@qq.com>2023-07-31 12:34:16 (GMT)
committerGitHub <noreply@github.com>2023-07-31 12:34:16 (GMT)
commit99518bbbf47a198f8c51e82e7357ac7efdafdcd8 (patch)
treeac26477228907ac6240a5c6c432985d9229e5d49
parent8f080a290bd45f4664d3a457256310cc02883d7d (diff)
downloadcpython-99518bbbf47a198f8c51e82e7357ac7efdafdcd8.zip
cpython-99518bbbf47a198f8c51e82e7357ac7efdafdcd8.tar.gz
cpython-99518bbbf47a198f8c51e82e7357ac7efdafdcd8.tar.bz2
[3.12] gh-106263: Fix segfault in `signaldict_repr` in `_decimal` module (#… (#107491)
Co-authored-by: sunmy2019 <59365878+sunmy2019@users.noreply.github.com> (cherry picked from commit 3979150a0d406707f6d253d7c15fb32c1e005a77)
-rw-r--r--Lib/test/test_decimal.py30
-rw-r--r--Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst2
-rw-r--r--Modules/_decimal/_decimal.c29
-rw-r--r--Tools/c-analyzer/cpython/ignored.tsv1
4 files changed, 59 insertions, 3 deletions
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index 749496e..d0ba348 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -5682,6 +5682,36 @@ class CWhitebox(unittest.TestCase):
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 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 70e18ed..70b1398 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 afc28e5..78be97d 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 -