Commit 40228912 authored by Mark Dickinson's avatar Mark Dickinson

Fix possible undefined behaviour from signed overflow in struct module.

Backport of revisions 81897, 81898 and 81902 from py3k.
parent b65bd2e3
......@@ -526,6 +526,12 @@ class StructTest(unittest.TestCase):
def test_crasher(self):
self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
def test_count_overflow(self):
hugecount = '{}b'.format(sys.maxsize+1)
self.assertRaises(struct.error, struct.calcsize, hugecount)
hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
self.assertRaises(struct.error, struct.calcsize, hugecount2)
def test_main():
run_unittest(StructTest)
......
......@@ -1188,16 +1188,19 @@ getentry(int c, const formatdef *f)
}
/* Align a size according to a format code */
/* Align a size according to a format code. Return -1 on overflow. */
static int
static Py_ssize_t
align(Py_ssize_t size, char c, const formatdef *e)
{
Py_ssize_t extra;
if (e->format == c) {
if (e->alignment) {
size = ((size + e->alignment - 1)
/ e->alignment)
* e->alignment;
if (e->alignment && size > 0) {
extra = (e->alignment - 1) - (size - 1) % (e->alignment);
if (extra > PY_SSIZE_T_MAX - size)
return -1;
size += extra;
}
}
return size;
......@@ -1216,7 +1219,7 @@ prepare_s(PyStructObject *self)
const char *s;
const char *fmt;
char c;
Py_ssize_t size, len, num, itemsize, x;
Py_ssize_t size, len, num, itemsize;
fmt = PyString_AS_STRING(self->s_format);
......@@ -1231,14 +1234,13 @@ prepare_s(PyStructObject *self)
if ('0' <= c && c <= '9') {
num = c - '0';
while ('0' <= (c = *s++) && c <= '9') {
x = num*10 + (c - '0');
if (x/10 != num) {
PyErr_SetString(
StructError,
"overflow in item count");
return -1;
}
num = x;
/* overflow-safe version of
if (num*10 + (c - '0') > PY_SSIZE_T_MAX) { ... } */
if (num >= PY_SSIZE_T_MAX / 10 && (
num > PY_SSIZE_T_MAX / 10 ||
(c - '0') > PY_SSIZE_T_MAX % 10))
goto overflow;
num = num*10 + (c - '0');
}
if (c == '\0')
break;
......@@ -1259,13 +1261,13 @@ prepare_s(PyStructObject *self)
itemsize = e->size;
size = align(size, c, e);
x = num * itemsize;
size += x;
if (x/itemsize != num || size < 0) {
PyErr_SetString(StructError,
"total struct size too long");
return -1;
}
if (size == -1)
goto overflow;
/* if (size + num * itemsize > PY_SSIZE_T_MAX) { ... } */
if (num > (PY_SSIZE_T_MAX - size) / itemsize)
goto overflow;
size += num * itemsize;
}
/* check for overflow */
......@@ -1324,6 +1326,11 @@ prepare_s(PyStructObject *self)
codes->size = 0;
return 0;
overflow:
PyErr_SetString(StructError,
"total struct size too long");
return -1;
}
static PyObject *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment