mirror of https://github.com/python/cpython
Prevent expandtabs() on string and unicode objects from causing a segfault when
a large width is passed on 32-bit platforms. Found by Google. It would be good for people to review this especially carefully and verify I don't have an off by one error and there is no other way to cause overflow.
This commit is contained in:
parent
11c58c4c8d
commit
66e64e2b6a
|
@ -1,4 +1,6 @@
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
import sys
|
||||||
from test import test_support, string_tests
|
from test import test_support, string_tests
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,6 +84,15 @@ class StrTest(
|
||||||
self.assertEqual(str(Foo9("foo")), "string")
|
self.assertEqual(str(Foo9("foo")), "string")
|
||||||
self.assertEqual(unicode(Foo9("foo")), u"not unicode")
|
self.assertEqual(unicode(Foo9("foo")), u"not unicode")
|
||||||
|
|
||||||
|
def test_expandtabs_overflows_gracefully(self):
|
||||||
|
# This test only affects 32-bit platforms because expandtabs can only take
|
||||||
|
# an int as the max value, not a 64-bit C long. If expandtabs is changed
|
||||||
|
# to take a 64-bit long, this test should apply to all platforms.
|
||||||
|
if sys.maxint > (1 << 32):
|
||||||
|
return
|
||||||
|
self.assertRaises(OverflowError, 't\tt\t'.expandtabs, sys.maxint)
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
test_support.run_unittest(StrTest)
|
test_support.run_unittest(StrTest)
|
||||||
|
|
||||||
|
|
|
@ -817,8 +817,13 @@ class UnicodeTest(
|
||||||
self.assertEqual(repr(s1()), '\\n')
|
self.assertEqual(repr(s1()), '\\n')
|
||||||
self.assertEqual(repr(s2()), '\\n')
|
self.assertEqual(repr(s2()), '\\n')
|
||||||
|
|
||||||
|
def test_expandtabs_overflows_gracefully(self):
|
||||||
|
# This test only affects 32-bit platforms because expandtabs can only take
|
||||||
|
# an int as the max value, not a 64-bit C long. If expandtabs is changed
|
||||||
|
# to take a 64-bit long, this test should apply to all platforms.
|
||||||
|
if sys.maxint > (1 << 32):
|
||||||
|
return
|
||||||
|
self.assertRaises(OverflowError, u't\tt\t'.expandtabs, sys.maxint)
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
|
|
|
@ -12,6 +12,9 @@ What's New in Python 2.5.2c1?
|
||||||
Core and builtins
|
Core and builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Prevent expandtabs() on string and unicode objects from causing a segfault when
|
||||||
|
a large width is passed on 32-bit platforms.
|
||||||
|
|
||||||
- Bug #1733488: Fix compilation of bufferobject.c on AIX.
|
- Bug #1733488: Fix compilation of bufferobject.c on AIX.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3298,7 +3298,7 @@ string_expandtabs(PyStringObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
const char *e, *p;
|
const char *e, *p;
|
||||||
char *q;
|
char *q;
|
||||||
Py_ssize_t i, j;
|
Py_ssize_t i, j, old_j;
|
||||||
PyObject *u;
|
PyObject *u;
|
||||||
int tabsize = 8;
|
int tabsize = 8;
|
||||||
|
|
||||||
|
@ -3306,12 +3306,18 @@ string_expandtabs(PyStringObject *self, PyObject *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* First pass: determine size of output string */
|
/* First pass: determine size of output string */
|
||||||
i = j = 0;
|
i = j = old_j = 0;
|
||||||
e = PyString_AS_STRING(self) + PyString_GET_SIZE(self);
|
e = PyString_AS_STRING(self) + PyString_GET_SIZE(self);
|
||||||
for (p = PyString_AS_STRING(self); p < e; p++)
|
for (p = PyString_AS_STRING(self); p < e; p++)
|
||||||
if (*p == '\t') {
|
if (*p == '\t') {
|
||||||
if (tabsize > 0)
|
if (tabsize > 0) {
|
||||||
j += tabsize - (j % tabsize);
|
j += tabsize - (j % tabsize);
|
||||||
|
if (old_j > j) {
|
||||||
|
PyErr_SetString(PyExc_OverflowError, "new string is too long");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
old_j = j;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
j++;
|
j++;
|
||||||
|
@ -3321,6 +3327,11 @@ string_expandtabs(PyStringObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((i + j) < 0) {
|
||||||
|
PyErr_SetString(PyExc_OverflowError, "new string is too long");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Second pass: create output string and fill it */
|
/* Second pass: create output string and fill it */
|
||||||
u = PyString_FromStringAndSize(NULL, i + j);
|
u = PyString_FromStringAndSize(NULL, i + j);
|
||||||
if (!u)
|
if (!u)
|
||||||
|
|
|
@ -5686,7 +5686,7 @@ unicode_expandtabs(PyUnicodeObject *self, PyObject *args)
|
||||||
Py_UNICODE *e;
|
Py_UNICODE *e;
|
||||||
Py_UNICODE *p;
|
Py_UNICODE *p;
|
||||||
Py_UNICODE *q;
|
Py_UNICODE *q;
|
||||||
Py_ssize_t i, j;
|
Py_ssize_t i, j, old_j;
|
||||||
PyUnicodeObject *u;
|
PyUnicodeObject *u;
|
||||||
int tabsize = 8;
|
int tabsize = 8;
|
||||||
|
|
||||||
|
@ -5694,12 +5694,18 @@ unicode_expandtabs(PyUnicodeObject *self, PyObject *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* First pass: determine size of output string */
|
/* First pass: determine size of output string */
|
||||||
i = j = 0;
|
i = j = old_j = 0;
|
||||||
e = self->str + self->length;
|
e = self->str + self->length;
|
||||||
for (p = self->str; p < e; p++)
|
for (p = self->str; p < e; p++)
|
||||||
if (*p == '\t') {
|
if (*p == '\t') {
|
||||||
if (tabsize > 0)
|
if (tabsize > 0) {
|
||||||
j += tabsize - (j % tabsize);
|
j += tabsize - (j % tabsize);
|
||||||
|
if (old_j > j) {
|
||||||
|
PyErr_SetString(PyExc_OverflowError, "new string is too long");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
old_j = j;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
j++;
|
j++;
|
||||||
|
@ -5709,6 +5715,11 @@ unicode_expandtabs(PyUnicodeObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((i + j) < 0) {
|
||||||
|
PyErr_SetString(PyExc_OverflowError, "new string is too long");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Second pass: create output string and fill it */
|
/* Second pass: create output string and fill it */
|
||||||
u = _PyUnicode_New(i + j);
|
u = _PyUnicode_New(i + j);
|
||||||
if (!u)
|
if (!u)
|
||||||
|
|
Loading…
Reference in New Issue