Issue #23466: %c, %o, %x, and %X in bytes formatting now raise TypeError on

non-integer input.
This commit is contained in:
Serhiy Storchaka 2015-03-30 09:19:08 +03:00
parent 7901b48a1f
commit 2c7b5a9d0d
3 changed files with 76 additions and 27 deletions

View file

@ -272,9 +272,18 @@ class FormatTest(unittest.TestCase):
#test_exc(unicode('abc %\u3000','raw-unicode-escape'), 1, ValueError, #test_exc(unicode('abc %\u3000','raw-unicode-escape'), 1, ValueError,
# "unsupported format character '?' (0x3000) at index 5") # "unsupported format character '?' (0x3000) at index 5")
test_exc('%d', '1', TypeError, "%d format: a number is required, not str") test_exc('%d', '1', TypeError, "%d format: a number is required, not str")
test_exc('%x', '1', TypeError, "%x format: a number is required, not str")
test_exc('%x', 3.14, TypeError, "%x format: an integer is required, not float")
test_exc('%g', '1', TypeError, "a float is required") test_exc('%g', '1', TypeError, "a float is required")
test_exc('no format', '1', TypeError, test_exc('no format', '1', TypeError,
"not all arguments converted during string formatting") "not all arguments converted during string formatting")
test_exc('%c', -1, OverflowError, "%c arg not in range(0x110000)")
test_exc('%c', sys.maxunicode+1, OverflowError,
"%c arg not in range(0x110000)")
#test_exc('%c', 2**128, OverflowError, "%c arg not in range(0x110000)")
test_exc('%c', 3.14, TypeError, "%c requires int or char")
test_exc('%c', 'ab', TypeError, "%c requires int or char")
test_exc('%c', b'x', TypeError, "%c requires int or char")
if maxsize == 2**31-1: if maxsize == 2**31-1:
# crashes 2.2.1 and earlier: # crashes 2.2.1 and earlier:
@ -339,6 +348,8 @@ class FormatTest(unittest.TestCase):
"%d format: a number is required, not str") "%d format: a number is required, not str")
test_exc(b'%d', b'1', TypeError, test_exc(b'%d', b'1', TypeError,
"%d format: a number is required, not bytes") "%d format: a number is required, not bytes")
test_exc(b'%x', 3.14, TypeError,
"%x format: an integer is required, not float")
test_exc(b'%g', '1', TypeError, "float argument required, not str") test_exc(b'%g', '1', TypeError, "float argument required, not str")
test_exc(b'%g', b'1', TypeError, "float argument required, not bytes") test_exc(b'%g', b'1', TypeError, "float argument required, not bytes")
test_exc(b'no format', 7, TypeError, test_exc(b'no format', 7, TypeError,
@ -347,11 +358,17 @@ class FormatTest(unittest.TestCase):
"not all arguments converted during bytes formatting") "not all arguments converted during bytes formatting")
test_exc(b'no format', bytearray(b'1'), TypeError, test_exc(b'no format', bytearray(b'1'), TypeError,
"not all arguments converted during bytes formatting") "not all arguments converted during bytes formatting")
test_exc(b"%c", -1, TypeError,
"%c requires an integer in range(256) or a single byte")
test_exc(b"%c", 256, TypeError, test_exc(b"%c", 256, TypeError,
"%c requires an integer in range(256) or a single byte") "%c requires an integer in range(256) or a single byte")
test_exc(b"%c", 2**128, TypeError,
"%c requires an integer in range(256) or a single byte")
test_exc(b"%c", b"Za", TypeError, test_exc(b"%c", b"Za", TypeError,
"%c requires an integer in range(256) or a single byte") "%c requires an integer in range(256) or a single byte")
test_exc(b"%c", "Yb", TypeError, test_exc(b"%c", "Y", TypeError,
"%c requires an integer in range(256) or a single byte")
test_exc(b"%c", 3.14, TypeError,
"%c requires an integer in range(256) or a single byte") "%c requires an integer in range(256) or a single byte")
test_exc(b"%b", "Xc", TypeError, test_exc(b"%b", "Xc", TypeError,
"%b requires bytes, or an object that implements __bytes__, not 'str'") "%b requires bytes, or an object that implements __bytes__, not 'str'")

View file

@ -36,6 +36,9 @@ Release date: 2015-03-28
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #23466: %c, %o, %x, and %X in bytes formatting now raise TypeError on
non-integer input.
- Issue #23573: Increased performance of string search operations (str.find, - Issue #23573: Increased performance of string search operations (str.find,
str.index, str.count, the in operator, str.split, str.partition) with str.index, str.count, the in operator, str.split, str.partition) with
arguments of different kinds (UCS1, UCS2, UCS4). arguments of different kinds (UCS1, UCS2, UCS4).

View file

@ -433,7 +433,41 @@ formatfloat(PyObject *v, int flags, int prec, int type)
return result; return result;
} }
Py_LOCAL_INLINE(int) static PyObject *
formatlong(PyObject *v, int flags, int prec, int type)
{
PyObject *result, *iobj;
if (type == 'i')
type = 'd';
if (PyLong_Check(v))
return _PyUnicode_FormatLong(v, flags & F_ALT, prec, type);
if (PyNumber_Check(v)) {
/* make sure number is a type of integer for o, x, and X */
if (type == 'o' || type == 'x' || type == 'X')
iobj = PyNumber_Index(v);
else
iobj = PyNumber_Long(v);
if (iobj == NULL) {
if (!PyErr_ExceptionMatches(PyExc_TypeError))
return NULL;
}
else if (!PyLong_Check(iobj))
Py_CLEAR(iobj);
if (iobj != NULL) {
result = _PyUnicode_FormatLong(iobj, flags & F_ALT, prec, type);
Py_DECREF(iobj);
return result;
}
}
PyErr_Format(PyExc_TypeError,
"%%%c format: %s is required, not %.200s", type,
(type == 'o' || type == 'x' || type == 'X') ? "an integer"
: "a number",
Py_TYPE(v)->tp_name);
return NULL;
}
static int
byte_converter(PyObject *arg, char *p) byte_converter(PyObject *arg, char *p)
{ {
if (PyBytes_Check(arg) && PyBytes_Size(arg) == 1) { if (PyBytes_Check(arg) && PyBytes_Size(arg) == 1) {
@ -445,12 +479,29 @@ byte_converter(PyObject *arg, char *p)
return 1; return 1;
} }
else { else {
long ival = PyLong_AsLong(arg); PyObject *iobj;
if (0 <= ival && ival <= 255) { long ival;
int overflow;
/* make sure number is a type of integer */
if (PyLong_Check(arg)) {
ival = PyLong_AsLongAndOverflow(arg, &overflow);
}
else {
iobj = PyNumber_Index(arg);
if (iobj == NULL) {
if (!PyErr_ExceptionMatches(PyExc_TypeError))
return 0;
goto onError;
}
ival = PyLong_AsLongAndOverflow(iobj, &overflow);
Py_DECREF(iobj);
}
if (!overflow && 0 <= ival && ival <= 255) {
*p = (char)ival; *p = (char)ival;
return 1; return 1;
} }
} }
onError:
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"%c requires an integer in range(256) or a single byte"); "%c requires an integer in range(256) or a single byte");
return 0; return 0;
@ -561,7 +612,6 @@ _PyBytes_Format(PyObject *format, PyObject *args)
int prec = -1; int prec = -1;
int c = '\0'; int c = '\0';
int fill; int fill;
PyObject *iobj;
PyObject *v = NULL; PyObject *v = NULL;
PyObject *temp = NULL; PyObject *temp = NULL;
const char *pbuf = NULL; const char *pbuf = NULL;
@ -747,28 +797,7 @@ _PyBytes_Format(PyObject *format, PyObject *args)
case 'o': case 'o':
case 'x': case 'x':
case 'X': case 'X':
if (c == 'i') temp = formatlong(v, flags, prec, c);
c = 'd';
iobj = NULL;
if (PyNumber_Check(v)) {
if ((PyLong_Check(v))) {
iobj = v;
Py_INCREF(iobj);
}
else {
iobj = PyNumber_Long(v);
if (iobj != NULL && !PyLong_Check(iobj))
Py_CLEAR(iobj);
}
}
if (iobj == NULL) {
PyErr_Format(PyExc_TypeError,
"%%%c format: a number is required, "
"not %.200s", c, Py_TYPE(v)->tp_name);
goto error;
}
temp = _PyUnicode_FormatLong(iobj, flags & F_ALT, prec, c);
Py_DECREF(iobj);
if (!temp) if (!temp)
goto error; goto error;
assert(PyUnicode_IS_ASCII(temp)); assert(PyUnicode_IS_ASCII(temp));