mirror of https://github.com/python/cpython.git
Fix possible undefined behaviour from signed overflow in struct module.
Backport of revisions 81897, 81898 and 81902 from py3k.
This commit is contained in:
parent
b65bd2e3eb
commit
40228912c8
|
@ -526,6 +526,12 @@ def test_bool(self):
|
||||||
def test_crasher(self):
|
def test_crasher(self):
|
||||||
self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
|
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():
|
def test_main():
|
||||||
run_unittest(StructTest)
|
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)
|
align(Py_ssize_t size, char c, const formatdef *e)
|
||||||
{
|
{
|
||||||
|
Py_ssize_t extra;
|
||||||
|
|
||||||
if (e->format == c) {
|
if (e->format == c) {
|
||||||
if (e->alignment) {
|
if (e->alignment && size > 0) {
|
||||||
size = ((size + e->alignment - 1)
|
extra = (e->alignment - 1) - (size - 1) % (e->alignment);
|
||||||
/ e->alignment)
|
if (extra > PY_SSIZE_T_MAX - size)
|
||||||
* e->alignment;
|
return -1;
|
||||||
|
size += extra;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
|
@ -1216,7 +1219,7 @@ prepare_s(PyStructObject *self)
|
||||||
const char *s;
|
const char *s;
|
||||||
const char *fmt;
|
const char *fmt;
|
||||||
char c;
|
char c;
|
||||||
Py_ssize_t size, len, num, itemsize, x;
|
Py_ssize_t size, len, num, itemsize;
|
||||||
|
|
||||||
fmt = PyString_AS_STRING(self->s_format);
|
fmt = PyString_AS_STRING(self->s_format);
|
||||||
|
|
||||||
|
@ -1231,14 +1234,13 @@ prepare_s(PyStructObject *self)
|
||||||
if ('0' <= c && c <= '9') {
|
if ('0' <= c && c <= '9') {
|
||||||
num = c - '0';
|
num = c - '0';
|
||||||
while ('0' <= (c = *s++) && c <= '9') {
|
while ('0' <= (c = *s++) && c <= '9') {
|
||||||
x = num*10 + (c - '0');
|
/* overflow-safe version of
|
||||||
if (x/10 != num) {
|
if (num*10 + (c - '0') > PY_SSIZE_T_MAX) { ... } */
|
||||||
PyErr_SetString(
|
if (num >= PY_SSIZE_T_MAX / 10 && (
|
||||||
StructError,
|
num > PY_SSIZE_T_MAX / 10 ||
|
||||||
"overflow in item count");
|
(c - '0') > PY_SSIZE_T_MAX % 10))
|
||||||
return -1;
|
goto overflow;
|
||||||
}
|
num = num*10 + (c - '0');
|
||||||
num = x;
|
|
||||||
}
|
}
|
||||||
if (c == '\0')
|
if (c == '\0')
|
||||||
break;
|
break;
|
||||||
|
@ -1259,13 +1261,13 @@ prepare_s(PyStructObject *self)
|
||||||
|
|
||||||
itemsize = e->size;
|
itemsize = e->size;
|
||||||
size = align(size, c, e);
|
size = align(size, c, e);
|
||||||
x = num * itemsize;
|
if (size == -1)
|
||||||
size += x;
|
goto overflow;
|
||||||
if (x/itemsize != num || size < 0) {
|
|
||||||
PyErr_SetString(StructError,
|
/* if (size + num * itemsize > PY_SSIZE_T_MAX) { ... } */
|
||||||
"total struct size too long");
|
if (num > (PY_SSIZE_T_MAX - size) / itemsize)
|
||||||
return -1;
|
goto overflow;
|
||||||
}
|
size += num * itemsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for overflow */
|
/* check for overflow */
|
||||||
|
@ -1324,6 +1326,11 @@ prepare_s(PyStructObject *self)
|
||||||
codes->size = 0;
|
codes->size = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
overflow:
|
||||||
|
PyErr_SetString(StructError,
|
||||||
|
"total struct size too long");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
Loading…
Reference in New Issue