diff options
author | Fred Drake <fdrake@acm.org> | 2000-06-28 17:49:30 (GMT) |
---|---|---|
committer | Fred Drake <fdrake@acm.org> | 2000-06-28 17:49:30 (GMT) |
commit | 541dc3b7b2606906e0ee2d9088a984443b1fa64c (patch) | |
tree | 5617b98464b3e3190cb34e5652fe265e4c3365f5 | |
parent | c82634c13cce7d846236eba8ab345c52cebc3567 (diff) | |
download | cpython-541dc3b7b2606906e0ee2d9088a984443b1fa64c.zip cpython-541dc3b7b2606906e0ee2d9088a984443b1fa64c.tar.gz cpython-541dc3b7b2606906e0ee2d9088a984443b1fa64c.tar.bz2 |
Trent Mick <trentm@activestate.com>:
The cause: Relatively recent (last month) patches to getargs.c added
overflow checking to the PyArg_Parse*() integral formatters thereby
restricting 'b' to unsigned char value and 'h','i', and 'l' to signed
integral values (i.e. if the incoming value is outside of the
specified bounds you get an OverflowError, previous it silently
overflowed).
The problem: This broke the array module (as Fredrik pointed out)
because *its* formatters relied on the loose allowance of signed and
unsigned ranges being able to pass through PyArg_Parse*()'s
formatters.
The fix: This patch fixes the array module to work with the more
strict bounds checking now in PyArg_Parse*().
How: If the type signature of a formatter in the arraymodule exactly
matches one in PyArg_Parse*(), then use that directly. If there is no
equivalent type signature in PyArg_Parse*() (e.g. there is no unsigned
int formatter in PyArg_Parse*()), then use the next one up and do some
extra bounds checking in the array module.
This partially closes SourceForge patch #100506.
-rw-r--r-- | Modules/arraymodule.c | 105 |
1 files changed, 95 insertions, 10 deletions
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 7966e0a..96ec793 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -114,11 +114,24 @@ b_setitem(ap, i, v) int i; PyObject *v; { - char x; - if (!PyArg_Parse(v, "b;array item must be integer", &x)) + short x; + /* PyArg_Parse's 'b' formatter is for an unsigned char, therefore + must use the next size up that is signed ('h') and manually do + the overflow checking */ + if (!PyArg_Parse(v, "h;array item must be integer", &x)) + return -1; + else if (x < CHAR_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed char is less than minimum"); + return -1; + } + else if (x > CHAR_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed char is greater than maximum"); return -1; + } if (i >= 0) - ((char *)ap->ob_item)[i] = x; + ((char *)ap->ob_item)[i] = (char)x; return 0; } @@ -131,7 +144,20 @@ BB_getitem(ap, i) return PyInt_FromLong(x); } -#define BB_setitem b_setitem +static int +BB_setitem(ap, i, v) + arrayobject *ap; + int i; + PyObject *v; +{ + unsigned char x; + /* 'B' == unsigned char, maps to PyArg_Parse's 'b' formatter */ + if (!PyArg_Parse(v, "b;array item must be integer", &x)) + return -1; + if (i >= 0) + ((char *)ap->ob_item)[i] = x; + return 0; +} static PyObject * h_getitem(ap, i) @@ -148,6 +174,7 @@ h_setitem(ap, i, v) PyObject *v; { short x; + /* 'h' == signed short, maps to PyArg_Parse's 'h' formatter */ if (!PyArg_Parse(v, "h;array item must be integer", &x)) return -1; if (i >= 0) @@ -163,7 +190,31 @@ HH_getitem(ap, i) return PyInt_FromLong((long) ((unsigned short *)ap->ob_item)[i]); } -#define HH_setitem h_setitem +static int +HH_setitem(ap, i, v) + arrayobject *ap; + int i; + PyObject *v; +{ + int x; + /* PyArg_Parse's 'h' formatter is for a signed short, therefore + must use the next size up and manually do the overflow checking */ + if (!PyArg_Parse(v, "i;array item must be integer", &x)) + return -1; + else if (x < 0) { + PyErr_SetString(PyExc_OverflowError, + "unsigned short is less than minimum"); + return -1; + } + else if (x > USHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "unsigned short is greater than maximum"); + return -1; + } + if (i >= 0) + ((short *)ap->ob_item)[i] = (short)x; + return 0; +} static PyObject * i_getitem(ap, i) @@ -180,6 +231,7 @@ i_setitem(ap, i, v) PyObject *v; { int x; + /* 'i' == signed int, maps to PyArg_Parse's 'i' formatter */ if (!PyArg_Parse(v, "i;array item must be integer", &x)) return -1; if (i >= 0) @@ -209,11 +261,25 @@ II_setitem(ap, i, v) return -1; } else { - if (!PyArg_Parse(v, "l;array item must be integer", &x)) + long y; + if (!PyArg_Parse(v, "l;array item must be integer", &y)) return -1; + if (y < 0) { + PyErr_SetString(PyExc_OverflowError, + "unsigned int is less than minimum"); + return -1; + } + x = (unsigned long)y; + + } + if (x > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "unsigned int is greater than maximum"); + return -1; } + if (i >= 0) - ((unsigned int *)ap->ob_item)[i] = x; + ((unsigned int *)ap->ob_item)[i] = (unsigned int)x; return 0; } @@ -260,9 +326,23 @@ LL_setitem(ap, i, v) return -1; } else { - if (!PyArg_Parse(v, "l;array item must be integer", &x)) + long y; + if (!PyArg_Parse(v, "l;array item must be integer", &y)) + return -1; + if (y < 0) { + PyErr_SetString(PyExc_OverflowError, + "unsigned long is less than minimum"); return -1; + } + x = (unsigned long)y; + + } + if (x > ULONG_MAX) { + PyErr_SetString(PyExc_OverflowError, + "unsigned long is greater than maximum"); + return -1; } + if (i >= 0) ((unsigned long *)ap->ob_item)[i] = x; return 0; @@ -725,8 +805,13 @@ array_buffer_info(self, args) arrayobject *self; PyObject *args; { - return Py_BuildValue("ll", - (long)(self->ob_item), (long)(self->ob_size)); + PyObject* retval = PyTuple_New(2); + if (!retval) return NULL; + + PyTuple_SET_ITEM(retval, 0, PyLong_FromVoidPtr(self->ob_item)); + PyTuple_SET_ITEM(retval, 1, PyInt_FromLong((long)(self->ob_size))); + + return retval; } static char buffer_info_doc [] = |