Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2c7b5a9

Browse files
Issue #23466: %c, %o, %x, and %X in bytes formatting now raise TypeError on
non-integer input.
1 parent 7901b48 commit 2c7b5a9

3 files changed

Lines changed: 76 additions & 27 deletions

File tree

Lib/test/test_format.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,18 @@ def test_exc(formatstr, args, exception, excmsg):
272272
#test_exc(unicode('abc %\u3000','raw-unicode-escape'), 1, ValueError,
273273
# "unsupported format character '?' (0x3000) at index 5")
274274
test_exc('%d', '1', TypeError, "%d format: a number is required, not str")
275+
test_exc('%x', '1', TypeError, "%x format: a number is required, not str")
276+
test_exc('%x', 3.14, TypeError, "%x format: an integer is required, not float")
275277
test_exc('%g', '1', TypeError, "a float is required")
276278
test_exc('no format', '1', TypeError,
277279
"not all arguments converted during string formatting")
280+
test_exc('%c', -1, OverflowError, "%c arg not in range(0x110000)")
281+
test_exc('%c', sys.maxunicode+1, OverflowError,
282+
"%c arg not in range(0x110000)")
283+
#test_exc('%c', 2**128, OverflowError, "%c arg not in range(0x110000)")
284+
test_exc('%c', 3.14, TypeError, "%c requires int or char")
285+
test_exc('%c', 'ab', TypeError, "%c requires int or char")
286+
test_exc('%c', b'x', TypeError, "%c requires int or char")
278287

279288
if maxsize == 2**31-1:
280289
# crashes 2.2.1 and earlier:
@@ -339,6 +348,8 @@ def test_exc(formatstr, args, exception, excmsg):
339348
"%d format: a number is required, not str")
340349
test_exc(b'%d', b'1', TypeError,
341350
"%d format: a number is required, not bytes")
351+
test_exc(b'%x', 3.14, TypeError,
352+
"%x format: an integer is required, not float")
342353
test_exc(b'%g', '1', TypeError, "float argument required, not str")
343354
test_exc(b'%g', b'1', TypeError, "float argument required, not bytes")
344355
test_exc(b'no format', 7, TypeError,
@@ -347,11 +358,17 @@ def test_exc(formatstr, args, exception, excmsg):
347358
"not all arguments converted during bytes formatting")
348359
test_exc(b'no format', bytearray(b'1'), TypeError,
349360
"not all arguments converted during bytes formatting")
361+
test_exc(b"%c", -1, TypeError,
362+
"%c requires an integer in range(256) or a single byte")
350363
test_exc(b"%c", 256, TypeError,
351364
"%c requires an integer in range(256) or a single byte")
365+
test_exc(b"%c", 2**128, TypeError,
366+
"%c requires an integer in range(256) or a single byte")
352367
test_exc(b"%c", b"Za", TypeError,
353368
"%c requires an integer in range(256) or a single byte")
354-
test_exc(b"%c", "Yb", TypeError,
369+
test_exc(b"%c", "Y", TypeError,
370+
"%c requires an integer in range(256) or a single byte")
371+
test_exc(b"%c", 3.14, TypeError,
355372
"%c requires an integer in range(256) or a single byte")
356373
test_exc(b"%b", "Xc", TypeError,
357374
"%b requires bytes, or an object that implements __bytes__, not 'str'")

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ Release date: 2015-03-28
3636
Core and Builtins
3737
-----------------
3838

39+
- Issue #23466: %c, %o, %x, and %X in bytes formatting now raise TypeError on
40+
non-integer input.
41+
3942
- Issue #23573: Increased performance of string search operations (str.find,
4043
str.index, str.count, the in operator, str.split, str.partition) with
4144
arguments of different kinds (UCS1, UCS2, UCS4).

Objects/bytesobject.c

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,41 @@ formatfloat(PyObject *v, int flags, int prec, int type)
433433
return result;
434434
}
435435

436-
Py_LOCAL_INLINE(int)
436+
static PyObject *
437+
formatlong(PyObject *v, int flags, int prec, int type)
438+
{
439+
PyObject *result, *iobj;
440+
if (type == 'i')
441+
type = 'd';
442+
if (PyLong_Check(v))
443+
return _PyUnicode_FormatLong(v, flags & F_ALT, prec, type);
444+
if (PyNumber_Check(v)) {
445+
/* make sure number is a type of integer for o, x, and X */
446+
if (type == 'o' || type == 'x' || type == 'X')
447+
iobj = PyNumber_Index(v);
448+
else
449+
iobj = PyNumber_Long(v);
450+
if (iobj == NULL) {
451+
if (!PyErr_ExceptionMatches(PyExc_TypeError))
452+
return NULL;
453+
}
454+
else if (!PyLong_Check(iobj))
455+
Py_CLEAR(iobj);
456+
if (iobj != NULL) {
457+
result = _PyUnicode_FormatLong(iobj, flags & F_ALT, prec, type);
458+
Py_DECREF(iobj);
459+
return result;
460+
}
461+
}
462+
PyErr_Format(PyExc_TypeError,
463+
"%%%c format: %s is required, not %.200s", type,
464+
(type == 'o' || type == 'x' || type == 'X') ? "an integer"
465+
: "a number",
466+
Py_TYPE(v)->tp_name);
467+
return NULL;
468+
}
469+
470+
static int
437471
byte_converter(PyObject *arg, char *p)
438472
{
439473
if (PyBytes_Check(arg) && PyBytes_Size(arg) == 1) {
@@ -445,12 +479,29 @@ byte_converter(PyObject *arg, char *p)
445479
return 1;
446480
}
447481
else {
448-
long ival = PyLong_AsLong(arg);
449-
if (0 <= ival && ival <= 255) {
482+
PyObject *iobj;
483+
long ival;
484+
int overflow;
485+
/* make sure number is a type of integer */
486+
if (PyLong_Check(arg)) {
487+
ival = PyLong_AsLongAndOverflow(arg, &overflow);
488+
}
489+
else {
490+
iobj = PyNumber_Index(arg);
491+
if (iobj == NULL) {
492+
if (!PyErr_ExceptionMatches(PyExc_TypeError))
493+
return 0;
494+
goto onError;
495+
}
496+
ival = PyLong_AsLongAndOverflow(iobj, &overflow);
497+
Py_DECREF(iobj);
498+
}
499+
if (!overflow && 0 <= ival && ival <= 255) {
450500
*p = (char)ival;
451501
return 1;
452502
}
453503
}
504+
onError:
454505
PyErr_SetString(PyExc_TypeError,
455506
"%c requires an integer in range(256) or a single byte");
456507
return 0;
@@ -561,7 +612,6 @@ _PyBytes_Format(PyObject *format, PyObject *args)
561612
int prec = -1;
562613
int c = '\0';
563614
int fill;
564-
PyObject *iobj;
565615
PyObject *v = NULL;
566616
PyObject *temp = NULL;
567617
const char *pbuf = NULL;
@@ -747,28 +797,7 @@ _PyBytes_Format(PyObject *format, PyObject *args)
747797
case 'o':
748798
case 'x':
749799
case 'X':
750-
if (c == 'i')
751-
c = 'd';
752-
iobj = NULL;
753-
if (PyNumber_Check(v)) {
754-
if ((PyLong_Check(v))) {
755-
iobj = v;
756-
Py_INCREF(iobj);
757-
}
758-
else {
759-
iobj = PyNumber_Long(v);
760-
if (iobj != NULL && !PyLong_Check(iobj))
761-
Py_CLEAR(iobj);
762-
}
763-
}
764-
if (iobj == NULL) {
765-
PyErr_Format(PyExc_TypeError,
766-
"%%%c format: a number is required, "
767-
"not %.200s", c, Py_TYPE(v)->tp_name);
768-
goto error;
769-
}
770-
temp = _PyUnicode_FormatLong(iobj, flags & F_ALT, prec, c);
771-
Py_DECREF(iobj);
800+
temp = formatlong(v, flags, prec, c);
772801
if (!temp)
773802
goto error;
774803
assert(PyUnicode_IS_ASCII(temp));

0 commit comments

Comments
 (0)