From e5ccc94bbb153431698b2391df625e8d47a93276 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 9 Mar 2020 20:03:38 +0200 Subject: bpo-38643: Raise SystemError instead of crashing when PyNumber_ToBase is called with invalid base. (GH-18863) --- Lib/test/test_capi.py | 14 ++++++++++++++ .../next/C API/2020-03-08-22-56-22.bpo-38643.k2ixx6.rst | 2 ++ Modules/_testcapimodule.c | 14 ++++++++++++++ Objects/abstract.c | 15 ++++++--------- 4 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2020-03-08-22-56-22.bpo-38643.k2ixx6.rst diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index ff18a21..5a85c48 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -502,6 +502,20 @@ class CAPITest(unittest.TestCase): # Test that subtype_dealloc decref the newly assigned __class__ only once self.assertEqual(new_type_refcnt, sys.getrefcount(_testcapi.HeapCTypeSubclass)) + def test_pynumber_tobase(self): + from _testcapi import pynumber_tobase + self.assertEqual(pynumber_tobase(123, 2), '0b1111011') + self.assertEqual(pynumber_tobase(123, 8), '0o173') + self.assertEqual(pynumber_tobase(123, 10), '123') + self.assertEqual(pynumber_tobase(123, 16), '0x7b') + self.assertEqual(pynumber_tobase(-123, 2), '-0b1111011') + self.assertEqual(pynumber_tobase(-123, 8), '-0o173') + self.assertEqual(pynumber_tobase(-123, 10), '-123') + self.assertEqual(pynumber_tobase(-123, 16), '-0x7b') + self.assertRaises(TypeError, pynumber_tobase, 123.0, 10) + self.assertRaises(TypeError, pynumber_tobase, '123', 10) + self.assertRaises(SystemError, pynumber_tobase, 123, 0) + class TestPendingCalls(unittest.TestCase): diff --git a/Misc/NEWS.d/next/C API/2020-03-08-22-56-22.bpo-38643.k2ixx6.rst b/Misc/NEWS.d/next/C API/2020-03-08-22-56-22.bpo-38643.k2ixx6.rst new file mode 100644 index 0000000..1e6472f --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-03-08-22-56-22.bpo-38643.k2ixx6.rst @@ -0,0 +1,2 @@ +:c:func:`PyNumber_ToBase` now raises a :exc:`SystemError` instead of +crashing when called with invalid base. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 23a27e3..2b871b8 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5259,6 +5259,19 @@ meth_fastcall_keywords(PyObject* self, PyObject* const* args, } +static PyObject* +pynumber_tobase(PyObject *module, PyObject *args) +{ + PyObject *obj; + int base; + if (!PyArg_ParseTuple(args, "Oi:pynumber_tobase", + &obj, &base)) { + return NULL; + } + return PyNumber_ToBase(obj, base); +} + + static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyMethodDef TestMethods[] = { @@ -5519,6 +5532,7 @@ static PyMethodDef TestMethods[] = { {"meth_noargs", meth_noargs, METH_NOARGS}, {"meth_fastcall", (PyCFunction)(void(*)(void))meth_fastcall, METH_FASTCALL}, {"meth_fastcall_keywords", (PyCFunction)(void(*)(void))meth_fastcall_keywords, METH_FASTCALL|METH_KEYWORDS}, + {"pynumber_tobase", pynumber_tobase, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/abstract.c b/Objects/abstract.c index accd72d..f9be422 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1551,18 +1551,15 @@ PyNumber_Float(PyObject *o) PyObject * PyNumber_ToBase(PyObject *n, int base) { - PyObject *res = NULL; + if (!(base == 2 || base == 8 || base == 10 || base == 16)) { + PyErr_SetString(PyExc_SystemError, + "PyNumber_ToBase: base must be 2, 8, 10 or 16"); + return NULL; + } PyObject *index = PyNumber_Index(n); - if (!index) return NULL; - if (PyLong_Check(index)) - res = _PyLong_Format(index, base); - else - /* It should not be possible to get here, as - PyNumber_Index already has a check for the same - condition */ - PyErr_SetString(PyExc_ValueError, "PyNumber_ToBase: index not int"); + PyObject *res = _PyLong_Format(index, base); Py_DECREF(index); return res; } -- cgit v0.12