From 004251059b9c5e48d47cb30b94bcb92cb44d3adf Mon Sep 17 00:00:00 2001 From: Oren Milman Date: Mon, 13 Mar 2017 00:37:05 +0200 Subject: [PATCH] bpo-29730: replace some calls to PyNumber_Check and improve some error messages (#650) --- Modules/_io/_iomodule.c | 7 ++++--- Modules/_io/bytesio.c | 8 +++++++- Modules/_io/stringio.c | 8 +++++--- Modules/mmapmodule.c | 7 ++++--- Objects/bytes_methods.c | 34 +++++++++++++++++++--------------- 5 files changed, 39 insertions(+), 25 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 8f0b72a55bd..5d804ece79f 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -549,14 +549,15 @@ _PyIO_ConvertSsize_t(PyObject *obj, void *result) { if (obj == Py_None) { limit = -1; } - else if (PyNumber_Check(obj)) { + else if (PyIndex_Check(obj)) { limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError); - if (limit == -1 && PyErr_Occurred()) + if (limit == -1 && PyErr_Occurred()) { return 0; + } } else { PyErr_Format(PyExc_TypeError, - "integer argument expected, got '%.200s'", + "argument should be integer or None, not '%.200s'", Py_TYPE(obj)->tp_name); return 0; } diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 0a0e5e72d7e..59b917d0bda 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -578,12 +578,18 @@ _io_BytesIO_truncate_impl(bytesio *self, PyObject *arg) /* Truncate to current position if no argument is passed. */ size = self->pos; } - else { + else if (PyIndex_Check(arg)) { size = PyNumber_AsSsize_t(arg, PyExc_OverflowError); if (size == -1 && PyErr_Occurred()) { return NULL; } } + else { + PyErr_Format(PyExc_TypeError, + "argument should be integer or None, not '%.200s'", + Py_TYPE(arg)->tp_name); + return NULL; + } if (size < 0) { PyErr_Format(PyExc_ValueError, diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 788dcb19845..a73171fd8f6 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -458,17 +458,19 @@ _io_StringIO_truncate_impl(stringio *self, PyObject *arg) CHECK_INITIALIZED(self); CHECK_CLOSED(self); - if (PyNumber_Check(arg)) { + if (PyIndex_Check(arg)) { size = PyNumber_AsSsize_t(arg, PyExc_OverflowError); - if (size == -1 && PyErr_Occurred()) + if (size == -1 && PyErr_Occurred()) { return NULL; + } } else if (arg == Py_None) { /* Truncate to current position if no argument is passed. */ size = self->pos; } else { - PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'", + PyErr_Format(PyExc_TypeError, + "argument should be integer or None, not '%.200s'", Py_TYPE(arg)->tp_name); return NULL; } diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 7a94464e7b2..7c15d377cfd 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -247,14 +247,15 @@ mmap_convert_ssize_t(PyObject *obj, void *result) { if (obj == Py_None) { limit = -1; } - else if (PyNumber_Check(obj)) { + else if (PyIndex_Check(obj)) { limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError); - if (limit == -1 && PyErr_Occurred()) + if (limit == -1 && PyErr_Occurred()) { return 0; + } } else { PyErr_Format(PyExc_TypeError, - "integer argument expected, got '%.200s'", + "argument should be integer or None, not '%.200s'", Py_TYPE(obj)->tp_name); return 0; } diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c index d5c4fe6346f..85d9ceea52d 100644 --- a/Objects/bytes_methods.c +++ b/Objects/bytes_methods.c @@ -399,12 +399,15 @@ _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to) #include "stringlib/find.h" /* -Wraps stringlib_parse_args_finds() and additionally checks whether the -first argument is an integer in range(0, 256). +Wraps stringlib_parse_args_finds() and additionally checks the first +argument type. -If this is the case, writes the integer value to the byte parameter -and sets subobj to NULL. Otherwise, sets the first argument to subobj -and doesn't touch byte. The other parameters are similar to those of +In case the first argument is a bytes-like object, sets it to subobj, +and doesn't touch the byte parameter. +In case it is an integer in range(0, 256), writes the integer value +to byte, and sets subobj to NULL. + +The other parameters are similar to those of stringlib_parse_args_finds(). */ @@ -415,27 +418,28 @@ parse_args_finds_byte(const char *function_name, PyObject *args, { PyObject *tmp_subobj; Py_ssize_t ival; - PyObject *err; if(!stringlib_parse_args_finds(function_name, args, &tmp_subobj, start, end)) return 0; - if (!PyNumber_Check(tmp_subobj)) { + if (PyObject_CheckBuffer(tmp_subobj)) { *subobj = tmp_subobj; return 1; } - ival = PyNumber_AsSsize_t(tmp_subobj, PyExc_OverflowError); - if (ival == -1) { - err = PyErr_Occurred(); - if (err && !PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) { - PyErr_Clear(); - *subobj = tmp_subobj; - return 1; - } + if (!PyIndex_Check(tmp_subobj)) { + PyErr_Format(PyExc_TypeError, + "argument should be integer or bytes-like object, " + "not '%.200s'", + Py_TYPE(tmp_subobj)->tp_name); + return 0; } + ival = PyNumber_AsSsize_t(tmp_subobj, NULL); + if (ival == -1 && PyErr_Occurred()) { + return 0; + } if (ival < 0 || ival > 255) { PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)"); return 0;