Skip to content

Commit 32cc566

Browse files
author
antoine.pitrou
committed
Issue #4583: crash after resizing an array.array which has buffer exports.
git-svn-id: http://svn.python.org/projects/python/branches/py3k@67840 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent f94c3e8 commit 32cc566

3 files changed

Lines changed: 68 additions & 98 deletions

File tree

Lib/test/test_array.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from weakref import proxy
99
import array, io, math
1010
from pickle import loads, dumps
11+
import operator
1112

1213
class ArraySubclass(array.array):
1314
pass
@@ -709,8 +710,23 @@ def test_coveritertraverse(self):
709710

710711
def test_buffer(self):
711712
a = array.array(self.typecode, self.example)
712-
b = bytes(memoryview(a))
713+
m = memoryview(a)
714+
b = bytes(m)
715+
self.assertEqual(b, a.tostring())
713716
self.assertEqual(b[0], a.tostring()[0])
717+
# Resizing is forbidden when there are buffer exports
718+
self.assertRaises(BufferError, a.append, a[0])
719+
self.assertRaises(BufferError, a.extend, a[0:1])
720+
self.assertRaises(BufferError, a.remove, a[0])
721+
self.assertRaises(BufferError, a.fromlist, a.tolist())
722+
self.assertRaises(BufferError, a.fromstring, a.tostring())
723+
if self.typecode == 'u':
724+
self.assertRaises(BufferError, a.fromunicode, a.tounicode())
725+
self.assertRaises(BufferError, operator.setitem, a, slice(0, 0), a)
726+
self.assertRaises(BufferError, operator.delitem, a, 0)
727+
self.assertRaises(BufferError, operator.delitem, a, slice(0, 1))
728+
self.assertRaises(BufferError, operator.irepeat, a, 2)
729+
self.assertRaises(BufferError, operator.irepeat, a, 0)
714730

715731
def test_weakref(self):
716732
s = array.array(self.typecode, self.example)

Misc/NEWS

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Python News
77
What's New in Python 3.1 alpha 0
88
================================
99

10-
*Release date: XX-XXX-2008*
10+
*Release date: XX-XXX-200X*
1111

1212
Core and Builtins
1313
-----------------
@@ -132,6 +132,10 @@ Extension Modules
132132
- Issues #3167, #3682: Fix test_math failures for log, log10 on Solaris,
133133
OpenBSD.
134134

135+
- Issue #4583: array.array would not always prohibit resizing when a buffer
136+
has been exported, resulting in an interpreter crash when accessing the
137+
buffer.
138+
135139
Build
136140
-----
137141

Modules/arraymodule.c

Lines changed: 46 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,15 @@ array_resize(arrayobject *self, Py_ssize_t newsize)
4949
char *items;
5050
size_t _new_size;
5151

52+
if (self->ob_exports > 0 && newsize != Py_SIZE(self)) {
53+
PyErr_SetString(PyExc_BufferError,
54+
"cannot resize an array that is exporting buffers");
55+
return -1;
56+
}
57+
5258
/* Bypass realloc() when a previous overallocation is large enough
5359
to accommodate the newsize. If the newsize is 16 smaller than the
54-
current size, then proceed with the realloc() to shrink the list.
60+
current size, then proceed with the realloc() to shrink the array.
5561
*/
5662

5763
if (self->allocated >= newsize &&
@@ -61,11 +67,13 @@ array_resize(arrayobject *self, Py_ssize_t newsize)
6167
return 0;
6268
}
6369

64-
if (self->ob_exports > 0) {
65-
PyErr_SetString(PyExc_BufferError,
66-
"cannot resize an array that is exporting data");
67-
return -1;
68-
}
70+
if (newsize == 0) {
71+
PyMem_FREE(self->ob_item);
72+
self->ob_item = NULL;
73+
Py_SIZE(self) = 0;
74+
self->allocated = 0;
75+
return 0;
76+
}
6977

7078
/* This over-allocates proportional to the array size, making room
7179
* for additional growth. The over-allocation is mild, but is
@@ -731,25 +739,15 @@ array_ass_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
731739
memmove(item + (ihigh+d)*a->ob_descr->itemsize,
732740
item + ihigh*a->ob_descr->itemsize,
733741
(Py_SIZE(a)-ihigh)*a->ob_descr->itemsize);
734-
Py_SIZE(a) += d;
735-
PyMem_RESIZE(item, char, Py_SIZE(a)*a->ob_descr->itemsize);
736-
/* Can't fail */
737-
a->ob_item = item;
738-
a->allocated = Py_SIZE(a);
742+
if (array_resize(a, Py_SIZE(a) + d) == -1)
743+
return -1;
739744
}
740745
else if (d > 0) { /* Insert d items */
741-
PyMem_RESIZE(item, char,
742-
(Py_SIZE(a) + d)*a->ob_descr->itemsize);
743-
if (item == NULL) {
744-
PyErr_NoMemory();
746+
if (array_resize(a, Py_SIZE(a) + d))
745747
return -1;
746-
}
747748
memmove(item + (ihigh+d)*a->ob_descr->itemsize,
748749
item + ihigh*a->ob_descr->itemsize,
749750
(Py_SIZE(a)-ihigh)*a->ob_descr->itemsize);
750-
a->ob_item = item;
751-
Py_SIZE(a) += d;
752-
a->allocated = Py_SIZE(a);
753751
}
754752
if (n > 0)
755753
memcpy(item + ilow*a->ob_descr->itemsize, b->ob_item,
@@ -804,8 +802,7 @@ array_iter_extend(arrayobject *self, PyObject *bb)
804802
static int
805803
array_do_extend(arrayobject *self, PyObject *bb)
806804
{
807-
Py_ssize_t size;
808-
char *old_item;
805+
Py_ssize_t size, oldsize;
809806

810807
if (!array_Check(bb))
811808
return array_iter_extend(self, bb);
@@ -820,18 +817,12 @@ array_do_extend(arrayobject *self, PyObject *bb)
820817
PyErr_NoMemory();
821818
return -1;
822819
}
823-
size = Py_SIZE(self) + Py_SIZE(b);
824-
old_item = self->ob_item;
825-
PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize);
826-
if (self->ob_item == NULL) {
827-
self->ob_item = old_item;
828-
PyErr_NoMemory();
820+
oldsize = Py_SIZE(self);
821+
size = oldsize + Py_SIZE(b);
822+
if (array_resize(self, size) == -1)
829823
return -1;
830-
}
831-
memcpy(self->ob_item + Py_SIZE(self)*self->ob_descr->itemsize,
832-
b->ob_item, Py_SIZE(b)*b->ob_descr->itemsize);
833-
Py_SIZE(self) = size;
834-
self->allocated = size;
824+
memcpy(self->ob_item + oldsize * self->ob_descr->itemsize,
825+
b->ob_item, Py_SIZE(b) * b->ob_descr->itemsize);
835826

836827
return 0;
837828
#undef b
@@ -867,27 +858,15 @@ array_inplace_repeat(arrayobject *self, Py_ssize_t n)
867858
return PyErr_NoMemory();
868859
}
869860
size = Py_SIZE(self) * self->ob_descr->itemsize;
870-
if (n == 0) {
871-
PyMem_FREE(items);
872-
self->ob_item = NULL;
873-
Py_SIZE(self) = 0;
874-
self->allocated = 0;
861+
if (n > 0 && size > PY_SSIZE_T_MAX / n) {
862+
return PyErr_NoMemory();
875863
}
876-
else {
877-
if (size > PY_SSIZE_T_MAX / n) {
878-
return PyErr_NoMemory();
879-
}
880-
PyMem_RESIZE(items, char, n * size);
881-
if (items == NULL)
882-
return PyErr_NoMemory();
883-
p = items;
884-
for (i = 1; i < n; i++) {
885-
p += size;
886-
memcpy(p, items, size);
887-
}
888-
self->ob_item = items;
889-
Py_SIZE(self) *= n;
890-
self->allocated = Py_SIZE(self);
864+
if (array_resize(self, n * Py_SIZE(self)) == -1)
865+
return NULL;
866+
items = p = self->ob_item;
867+
for (i = 1; i < n; i++) {
868+
p += size;
869+
memcpy(p, items, size);
891870
}
892871
}
893872
Py_INCREF(self);
@@ -1312,36 +1291,22 @@ static PyObject *
13121291
array_fromlist(arrayobject *self, PyObject *list)
13131292
{
13141293
Py_ssize_t n;
1315-
Py_ssize_t itemsize = self->ob_descr->itemsize;
13161294

13171295
if (!PyList_Check(list)) {
13181296
PyErr_SetString(PyExc_TypeError, "arg must be list");
13191297
return NULL;
13201298
}
13211299
n = PyList_Size(list);
13221300
if (n > 0) {
1323-
char *item = self->ob_item;
1324-
Py_ssize_t i;
1325-
PyMem_RESIZE(item, char, (Py_SIZE(self) + n) * itemsize);
1326-
if (item == NULL) {
1327-
PyErr_NoMemory();
1301+
Py_ssize_t i, old_size;
1302+
old_size = Py_SIZE(self);
1303+
if (array_resize(self, old_size + n) == -1)
13281304
return NULL;
1329-
}
1330-
self->ob_item = item;
1331-
Py_SIZE(self) += n;
1332-
self->allocated = Py_SIZE(self);
13331305
for (i = 0; i < n; i++) {
13341306
PyObject *v = PyList_GetItem(list, i);
13351307
if ((*self->ob_descr->setitem)(self,
13361308
Py_SIZE(self) - n + i, v) != 0) {
1337-
Py_SIZE(self) -= n;
1338-
if (itemsize && (Py_SIZE(self) > PY_SSIZE_T_MAX / itemsize)) {
1339-
return PyErr_NoMemory();
1340-
}
1341-
PyMem_RESIZE(item, char,
1342-
Py_SIZE(self) * itemsize);
1343-
self->ob_item = item;
1344-
self->allocated = Py_SIZE(self);
1309+
array_resize(self, old_size);
13451310
return NULL;
13461311
}
13471312
}
@@ -1395,21 +1360,15 @@ array_fromstring(arrayobject *self, PyObject *args)
13951360
}
13961361
n = n / itemsize;
13971362
if (n > 0) {
1398-
char *item = self->ob_item;
1399-
if ((n > PY_SSIZE_T_MAX - Py_SIZE(self)) ||
1400-
((Py_SIZE(self) + n) > PY_SSIZE_T_MAX / itemsize)) {
1363+
Py_ssize_t old_size = Py_SIZE(self);
1364+
if ((n > PY_SSIZE_T_MAX - old_size) ||
1365+
((old_size + n) > PY_SSIZE_T_MAX / itemsize)) {
14011366
return PyErr_NoMemory();
14021367
}
1403-
PyMem_RESIZE(item, char, (Py_SIZE(self) + n) * itemsize);
1404-
if (item == NULL) {
1405-
PyErr_NoMemory();
1368+
if (array_resize(self, old_size + n) == -1)
14061369
return NULL;
1407-
}
1408-
self->ob_item = item;
1409-
Py_SIZE(self) += n;
1410-
self->allocated = Py_SIZE(self);
1411-
memcpy(item + (Py_SIZE(self) - n) * itemsize,
1412-
str, itemsize*n);
1370+
memcpy(self->ob_item + old_size * itemsize,
1371+
str, n * itemsize);
14131372
}
14141373
Py_INCREF(Py_None);
14151374
return Py_None;
@@ -1458,19 +1417,10 @@ array_fromunicode(arrayobject *self, PyObject *args)
14581417
return NULL;
14591418
}
14601419
if (n > 0) {
1461-
Py_UNICODE *item = (Py_UNICODE *) self->ob_item;
1462-
if (Py_SIZE(self) > PY_SSIZE_T_MAX - n) {
1463-
return PyErr_NoMemory();
1464-
}
1465-
PyMem_RESIZE(item, Py_UNICODE, Py_SIZE(self) + n);
1466-
if (item == NULL) {
1467-
PyErr_NoMemory();
1420+
Py_ssize_t old_size = Py_SIZE(self);
1421+
if (array_resize(self, old_size + n) == -1)
14681422
return NULL;
1469-
}
1470-
self->ob_item = (char *) item;
1471-
Py_SIZE(self) += n;
1472-
self->allocated = Py_SIZE(self);
1473-
memcpy(item + Py_SIZE(self) - n,
1423+
memcpy(self->ob_item + old_size * sizeof(Py_UNICODE),
14741424
ustr, n * sizeof(Py_UNICODE));
14751425
}
14761426

@@ -1740,12 +1690,12 @@ array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value)
17401690
self->ob_item + stop * itemsize,
17411691
(Py_SIZE(self) - stop) * itemsize);
17421692
if (array_resize(self, Py_SIZE(self) +
1743-
needed - slicelength) < 0)
1693+
needed - slicelength) < 0)
17441694
return -1;
17451695
}
17461696
else if (slicelength < needed) {
17471697
if (array_resize(self, Py_SIZE(self) +
1748-
needed - slicelength) < 0)
1698+
needed - slicelength) < 0)
17491699
return -1;
17501700
memmove(self->ob_item + (start + needed) * itemsize,
17511701
self->ob_item + stop * itemsize,

0 commit comments

Comments
 (0)