Serhiy Storchaka added the comment:
Oh, sorry. I again forgot to upload a patch.
----------
keywords: +patch
Added file: http://bugs.python.org/file36800/issue11145.patch
_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue11145>
_______________________________________
diff -r a3e18dd8f267 Lib/test/test_format.py
--- a/Lib/test/test_format.py Sat Oct 04 15:04:41 2014 +0300
+++ b/Lib/test/test_format.py Sat Oct 04 20:07:18 2014 +0300
@@ -299,6 +299,39 @@ class FormatTest(unittest.TestCase):
else:
raise TestFailed, '"%*d"%(maxsize, -127) should fail'
+ def test_invalid_special_methods(self):
+ tests = []
+ for f in 'sriduoxXfge':
+ tests.append(('%' + f, 1, TypeError))
+ for r in ['', '-', 'L', '-L']:
+ for f in 'iduoxX':
+ tests.append(('%' + f, r, ValueError))
+ tests.append(('%o', 'abc', ValueError))
+ for r in ('abc', '0abc', '0x', '0xL'):
+ for f in 'xX':
+ tests.append(('%' + f, r, ValueError))
+
+ class X(long):
+ def __repr__(self):
+ return result
+ def __str__(self):
+ return result
+ def __oct__(self):
+ return result
+ def __hex__(self):
+ return result
+ def __float__(self):
+ return result
+ for fmt, result, exc in tests:
+ try:
+ fmt % X()
+ except exc:
+ pass
+ else:
+ self.fail('%s not raised for %r format of %r' %
+ (exc.__name__, fmt, result))
+
+
def test_main():
test_support.run_unittest(FormatTest)
diff -r a3e18dd8f267 Objects/stringobject.c
--- a/Objects/stringobject.c Sat Oct 04 15:04:41 2014 +0300
+++ b/Objects/stringobject.c Sat Oct 04 20:07:18 2014 +0300
@@ -4015,17 +4015,22 @@ PyObject*
Py_ssize_t llen;
int numdigits; /* len == numnondigits + numdigits */
int numnondigits = 0;
+ const char *method;
+ int modify = (type == 'X');
switch (type) {
case 'd':
case 'u':
+ method = "str";
result = Py_TYPE(val)->tp_str(val);
break;
case 'o':
+ method = "oct";
result = Py_TYPE(val)->tp_as_number->nb_oct(val);
break;
case 'x':
case 'X':
+ method = "hex";
numnondigits = 2;
result = Py_TYPE(val)->tp_as_number->nb_hex(val);
break;
@@ -4041,25 +4046,39 @@ PyObject*
return NULL;
}
- /* To modify the string in-place, there can only be one reference. */
- if (Py_REFCNT(result) != 1) {
- PyErr_BadInternalCall();
- return NULL;
- }
- llen = PyString_Size(result);
+ llen = PyString_GET_SIZE(result);
if (llen > INT_MAX) {
PyErr_SetString(PyExc_ValueError, "string too large in
_PyString_FormatLong");
+ Py_DECREF(result);
return NULL;
}
len = (int)llen;
- if (buf[len-1] == 'L') {
+ if (len > 0 && buf[len-1] == 'L') {
--len;
- buf[len] = '\0';
+ if (len == 0)
+ goto error;
+ modify = 1;
+ }
+ /* To modify the string in-place, there can only be one reference. */
+ if (modify && (llen <= 1 || Py_REFCNT(result) != 1)) {
+ /* Do not use PyString_FromStringAndSize(buf, len) because it can
+ * return existing object if len <= 1. */
+ PyObject *r1 = PyString_FromStringAndSize(NULL, len);
+ if (!r1) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ assert(len == 0 || Py_REFCNT(r1) == 1);
+ memcpy(PyString_AS_STRING(r1), buf, len);
+ Py_DECREF(result);
+ result = r1;
+ buf = PyString_AS_STRING(result);
}
sign = buf[0] == '-';
numnondigits += sign;
numdigits = len - numnondigits;
- assert(numdigits > 0);
+ if (numdigits <= 0)
+ goto error;
/* Get rid of base marker unless F_ALT */
if ((flags & F_ALT) == 0) {
@@ -4067,7 +4086,8 @@ PyObject*
int skipped = 0;
switch (type) {
case 'o':
- assert(buf[sign] == '0');
+ if (buf[sign] != '0')
+ goto error;
/* If 0 is only digit, leave it alone. */
if (numdigits > 1) {
skipped = 1;
@@ -4076,8 +4096,9 @@ PyObject*
break;
case 'x':
case 'X':
- assert(buf[sign] == '0');
- assert(buf[sign + 1] == 'x');
+ if (buf[sign] != '0' ||
+ buf[sign + 1] != 'x')
+ goto error;
skipped = 2;
numnondigits -= 2;
break;
@@ -4126,6 +4147,12 @@ PyObject*
*pbuf = buf;
*plen = len;
return result;
+
+error:
+ PyErr_Format(PyExc_ValueError, "%%%c format: invalid result of %s.__%s__",
+ type, Py_TYPE(val)->tp_name, method);
+ Py_DECREF(result);
+ return NULL;
}
Py_LOCAL_INLINE(int)
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com