mirror of
https://github.com/python/cpython.git
synced 2025-10-10 00:43:41 +00:00
Issue #23466: %c, %o, %x, and %X in bytes formatting now raise TypeError on
non-integer input.
This commit is contained in:
parent
7901b48a1f
commit
2c7b5a9d0d
3 changed files with 76 additions and 27 deletions
|
@ -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'")
|
||||||
|
|
|
@ -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).
|
||||||
|
|
|
@ -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));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue