summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_capi.py14
-rw-r--r--Misc/NEWS.d/next/C API/2020-03-08-22-56-22.bpo-38643.k2ixx6.rst2
-rw-r--r--Modules/_testcapimodule.c14
-rw-r--r--Objects/abstract.c15
4 files changed, 36 insertions, 9 deletions
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;
}