Issue #4935: The overflow checking code in the expandtabs() method common

to str, bytes and bytearray could be optimized away by the compiler (*), letting
the interpreter segfault instead of raising an error.

(*) or at least it is our interpretation
This commit is contained in:
Antoine Pitrou 2009-01-13 22:59:11 +00:00
parent b9d1a4ddc3
commit 8d4e505aa8
2 changed files with 39 additions and 42 deletions

View File

@ -12,6 +12,10 @@ What's New in Python 3.1 alpha 0
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #4935: The overflow checking code in the expandtabs() method common
to str, bytes and bytearray could be optimized away by the compiler, letting
the interpreter segfault instead of raising an error.
- Issue #3720: Fix a crash when an iterator modifies its class and removes its - Issue #3720: Fix a crash when an iterator modifies its class and removes its
__next__ method. __next__ method.

View File

@ -22,76 +22,69 @@ stringlib_expandtabs(PyObject *self, PyObject *args)
{ {
const char *e, *p; const char *e, *p;
char *q; char *q;
Py_ssize_t i, j, old_j; size_t i, j;
PyObject *u; PyObject *u;
int tabsize = 8; int tabsize = 8;
if (!PyArg_ParseTuple(args, "|i:expandtabs", &tabsize)) if (!PyArg_ParseTuple(args, "|i:expandtabs", &tabsize))
return NULL; return NULL;
/* First pass: determine size of output string */ /* First pass: determine size of output string */
i = j = old_j = 0; i = j = 0;
e = STRINGLIB_STR(self) + STRINGLIB_LEN(self); e = STRINGLIB_STR(self) + STRINGLIB_LEN(self);
for (p = STRINGLIB_STR(self); p < e; p++) for (p = STRINGLIB_STR(self); p < e; p++)
if (*p == '\t') { if (*p == '\t') {
if (tabsize > 0) { if (tabsize > 0) {
j += tabsize - (j % tabsize); j += tabsize - (j % tabsize);
/* XXX: this depends on a signed integer overflow to < 0 */ if (j > PY_SSIZE_T_MAX) {
/* C compilers, including gcc, do -NOT- guarantee this. */
if (old_j > j) {
PyErr_SetString(PyExc_OverflowError,
"result is too long");
return NULL;
}
old_j = j;
}
}
else {
j++;
if (*p == '\n' || *p == '\r') {
i += j;
old_j = j = 0;
/* XXX: this depends on a signed integer overflow to < 0 */
/* C compilers, including gcc, do -NOT- guarantee this. */
if (i < 0) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"result is too long"); "result is too long");
return NULL; return NULL;
} }
} }
} }
else {
if ((i + j) < 0) { j++;
/* XXX: this depends on a signed integer overflow to < 0 */ if (*p == '\n' || *p == '\r') {
/* C compilers, including gcc, do -NOT- guarantee this. */ i += j;
j = 0;
if (i > PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError,
"result is too long");
return NULL;
}
}
}
if ((i + j) > PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError, "result is too long"); PyErr_SetString(PyExc_OverflowError, "result is too long");
return NULL; return NULL;
} }
/* Second pass: create output string and fill it */ /* Second pass: create output string and fill it */
u = STRINGLIB_NEW(NULL, i + j); u = STRINGLIB_NEW(NULL, i + j);
if (!u) if (!u)
return NULL; return NULL;
j = 0; j = 0;
q = STRINGLIB_STR(u); q = STRINGLIB_STR(u);
for (p = STRINGLIB_STR(self); p < e; p++) for (p = STRINGLIB_STR(self); p < e; p++)
if (*p == '\t') { if (*p == '\t') {
if (tabsize > 0) { if (tabsize > 0) {
i = tabsize - (j % tabsize); i = tabsize - (j % tabsize);
j += i; j += i;
while (i--) while (i--)
*q++ = ' '; *q++ = ' ';
} }
} }
else { else {
j++; j++;
*q++ = *p; *q++ = *p;
if (*p == '\n' || *p == '\r') if (*p == '\n' || *p == '\r')
j = 0; j = 0;
} }
return u; return u;
} }