[Python-checkins] python/dist/src/Objects listobject.c,2.215,2.216
tim_one at users.sourceforge.net
tim_one at users.sourceforge.net
Sat Jul 31 04:24:22 CEST 2004
Update of /cvsroot/python/python/dist/src/Objects
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7074/Objects
Modified Files:
listobject.c
Log Message:
Armin asked for a list_ass_slice review in his checkin, so here's the
result.
list_resize(): Document the intent. Code is increasingly relying on
subtle aspects of its behavior, and they deserve to be spelled out.
list_ass_slice(): A bit more simplification, by giving it a common
error exit and initializing more values.
Be clearer in comments about what "size" means (# of elements? # of
bytes?).
While the number of elements in a list slice must fit in an int, there's
no guarantee that the number of bytes occupied by the slice will. That
malloc() and memmove() take size_t arguments is a hint about that <wink>.
So changed to use size_t where appropriate.
ihigh - ilow should always be >= 0, but we never asserted that. We do
now.
The loop decref'ing the recycled slice had a subtle insecurity: C doesn't
guarantee that a pointer one slot *before* an array will compare "less
than" to a pointer within the array (it does guarantee that a pointer
one beyond the end of the array compares as expected). This was actually
an issue in KSR's C implementation, so isn't purely theoretical. Python
probably has other "go backwards" loops with a similar glitch.
list_clear() is OK (it marches an integer backwards, not a pointer).
Index: listobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/listobject.c,v
retrieving revision 2.215
retrieving revision 2.216
diff -C2 -d -r2.215 -r2.216
*** listobject.c 30 Jul 2004 11:38:22 -0000 2.215
--- listobject.c 31 Jul 2004 02:24:20 -0000 2.216
***************
*** 9,12 ****
--- 9,25 ----
#endif
+ /* Ensure ob_item has room for at least newsize elements, and set
+ * ob_size to newsize. If newsize > ob_size on entry, the content
+ * of the new slots at exit is undefined heap trash; it's the caller's
+ * responsiblity to overwrite them with sane values.
+ * The number of allocated elements may grow, shrink, or stay the same.
+ * Failure is impossible if newsize <= self.allocated on entry, although
+ * that partly relies on an assumption that the system realloc() never
+ * fails when passed a number of bytes <= the number of bytes last
+ * allocated (the C standard doesn't guarantee this, but it's hard to
+ * imagine a realloc implementation where it wouldn't be true).
+ * Note that self->ob_item may change, and even if newsize is less
+ * than ob_size on entry.
+ */
static int
list_resize(PyListObject *self, int newsize)
***************
*** 19,23 ****
current size, then proceed with the realloc() to shrink the list.
*/
-
if (self->allocated >= newsize && self->ob_size < newsize + 16) {
assert(self->ob_item != NULL || newsize == 0);
--- 32,35 ----
***************
*** 517,529 ****
we temporarily copy the items that are deleted from the
list. :-( */
- PyObject **recycle, **p;
PyObject *recycled[8];
PyObject **item;
PyObject **vitem = NULL;
PyObject *v_as_SF = NULL; /* PySequence_Fast(v) */
! int n; /* Size of replacement list */
int d; /* Change in size */
int k; /* Loop index */
! int s;
#define b ((PyListObject *)v)
if (v == NULL)
--- 529,543 ----
we temporarily copy the items that are deleted from the
list. :-( */
PyObject *recycled[8];
+ PyObject **recycle = recycled; /* will allocate more if needed */
PyObject **item;
PyObject **vitem = NULL;
PyObject *v_as_SF = NULL; /* PySequence_Fast(v) */
! int n; /* # of elements in replacement list */
! int norig; /* # of elements in list getting replaced */
int d; /* Change in size */
int k; /* Loop index */
! size_t s;
! int result = -1; /* guilty until proved innocent */
#define b ((PyListObject *)v)
if (v == NULL)
***************
*** 532,546 ****
if (a == b) {
/* Special case "a[i:j] = a" -- copy b first */
- int ret;
v = list_slice(b, 0, b->ob_size);
if (v == NULL)
! return -1;
! ret = list_ass_slice(a, ilow, ihigh, v);
Py_DECREF(v);
! return ret;
}
v_as_SF = PySequence_Fast(v, "can only assign an iterable");
if(v_as_SF == NULL)
! return -1;
n = PySequence_Fast_GET_SIZE(v_as_SF);
vitem = PySequence_Fast_ITEMS(v_as_SF);
--- 546,559 ----
if (a == b) {
/* Special case "a[i:j] = a" -- copy b first */
v = list_slice(b, 0, b->ob_size);
if (v == NULL)
! return result;
! result = list_ass_slice(a, ilow, ihigh, v);
Py_DECREF(v);
! return result;
}
v_as_SF = PySequence_Fast(v, "can only assign an iterable");
if(v_as_SF == NULL)
! goto Error;
n = PySequence_Fast_GET_SIZE(v_as_SF);
vitem = PySequence_Fast_ITEMS(v_as_SF);
***************
*** 550,553 ****
--- 563,567 ----
else if (ilow > a->ob_size)
ilow = a->ob_size;
+
if (ihigh < ilow)
ihigh = ilow;
***************
*** 555,559 ****
ihigh = a->ob_size;
! d = n - (ihigh-ilow);
if (a->ob_size + d == 0) {
Py_XDECREF(v_as_SF);
--- 569,575 ----
ihigh = a->ob_size;
! norig = ihigh - ilow;
! assert(norig >= 0);
! d = n - norig;
if (a->ob_size + d == 0) {
Py_XDECREF(v_as_SF);
***************
*** 561,578 ****
}
item = a->ob_item;
! /* recycle the ihigh-ilow items that we are about to remove */
! s = (ihigh - ilow)*sizeof(PyObject *);
if (s > sizeof(recycled)) {
recycle = (PyObject **)PyMem_MALLOC(s);
if (recycle == NULL) {
PyErr_NoMemory();
! Py_XDECREF(v_as_SF);
! return -1;
}
}
- else
- recycle = recycled;
- p = recycle + (ihigh - ilow);
memcpy(recycle, &item[ilow], s);
if (d < 0) { /* Delete -d items */
memmove(&item[ihigh+d], &item[ihigh],
--- 577,591 ----
}
item = a->ob_item;
! /* recycle the items that we are about to remove */
! s = norig * sizeof(PyObject *);
if (s > sizeof(recycled)) {
recycle = (PyObject **)PyMem_MALLOC(s);
if (recycle == NULL) {
PyErr_NoMemory();
! goto Error;
}
}
memcpy(recycle, &item[ilow], s);
+
if (d < 0) { /* Delete -d items */
memmove(&item[ihigh+d], &item[ihigh],
***************
*** 583,592 ****
else if (d > 0) { /* Insert d items */
s = a->ob_size;
! if (list_resize(a, s+d) == -1) {
! if (recycle != recycled)
! PyMem_FREE(recycle);
! Py_XDECREF(v_as_SF);
! return -1;
! }
item = a->ob_item;
memmove(&item[ihigh+d], &item[ihigh],
--- 596,601 ----
else if (d > 0) { /* Insert d items */
s = a->ob_size;
! if (list_resize(a, s+d) < 0)
! goto Error;
item = a->ob_item;
memmove(&item[ihigh+d], &item[ihigh],
***************
*** 598,607 ****
item[ilow] = w;
}
! while (--p >= recycle)
! Py_XDECREF(*p);
if (recycle != recycled)
PyMem_FREE(recycle);
Py_XDECREF(v_as_SF);
! return 0;
#undef b
}
--- 607,625 ----
item[ilow] = w;
}
! /* Convoluted: there's some obscure reason for wanting to do
! * the decrefs "backwards", but C doesn't guarantee you can compute
! * a pointer to one slot *before* an allocated vector. So checking
! * for item >= recycle is incorrect.
! */
! for (item = recycle + norig; item > recycle; ) {
! --item;
! Py_XDECREF(*item);
! }
! result = 0;
! Error:
if (recycle != recycled)
PyMem_FREE(recycle);
Py_XDECREF(v_as_SF);
! return result;
#undef b
}
More information about the Python-checkins
mailing list