[3.7] bpo-38643: Raise SystemError instead of crashing when PyNumber_ToBase is called with invalid base. (GH-18863). (GH-18955)

(cherry picked from commit e5ccc94bbb)
This commit is contained in:
Serhiy Storchaka 2020-03-12 10:15:17 +02:00 committed by GitHub
parent 500999fbdf
commit 6f4e7fcfca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 9 deletions

View File

@ -315,6 +315,20 @@ class CAPITest(unittest.TestCase):
self.assertRaises(TypeError, _testcapi.get_mapping_values, bad_mapping)
self.assertRaises(TypeError, _testcapi.get_mapping_items, bad_mapping)
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):

View File

@ -0,0 +1,2 @@
:c:func:`PyNumber_ToBase` now raises a :exc:`SystemError` instead of
crashing when called with invalid base.

View File

@ -4653,6 +4653,19 @@ get_main_config(PyObject *self, PyObject *Py_UNUSED(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 PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS},
{"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS},
@ -4888,6 +4901,7 @@ static PyMethodDef TestMethods[] = {
{"get_global_config", get_global_config, METH_NOARGS},
{"get_core_config", get_core_config, METH_NOARGS},
{"get_main_config", get_main_config, METH_NOARGS},
{"pynumber_tobase", pynumber_tobase, METH_VARARGS},
{NULL, NULL} /* sentinel */
};

View File

@ -1480,18 +1480,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;
}