Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ae621ff

Browse files
committed
Guard against changes in the list size during a compare or sort.
1 parent 578de30 commit ae621ff

1 file changed

Lines changed: 31 additions & 22 deletions

File tree

Objects/listobject.c

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -283,9 +283,8 @@ static int
283283
list_compare(v, w)
284284
PyListObject *v, *w;
285285
{
286-
int len = (v->ob_size < w->ob_size) ? v->ob_size : w->ob_size;
287286
int i;
288-
for (i = 0; i < len; i++) {
287+
for (i = 0; i < v->ob_size && i < w->ob_size; i++) {
289288
int cmp = PyObject_Compare(v->ob_item[i], w->ob_item[i]);
290289
if (cmp != 0)
291290
return cmp;
@@ -587,18 +586,26 @@ listappend(self, args)
587586
function is NULL. */
588587

589588
static int
590-
docompare(x, y, compare)
589+
docompare(x, y, compare, list)
591590
PyObject *x;
592591
PyObject *y;
593592
PyObject *compare;
593+
PyListObject *list;
594594
{
595+
int size = list->ob_size; /* Number of elements to sort */
596+
PyObject **array = list->ob_item; /* Start of array to sort */
595597
PyObject *args, *res;
596598
int i;
597599

598600
if (compare == NULL) {
599601
i = PyObject_Compare(x, y);
600602
if (i && PyErr_Occurred())
601603
i = CMPERROR;
604+
else if (size != list->ob_size || array != list->ob_item) {
605+
PyErr_SetString(PyExc_SystemError,
606+
"list changed size during sort");
607+
i = CMPERROR;
608+
}
602609
return i;
603610
}
604611

@@ -615,6 +622,11 @@ docompare(x, y, compare)
615622
"comparison function should return int");
616623
return CMPERROR;
617624
}
625+
if (size != list->ob_size || array != list->ob_item) {
626+
PyErr_SetString(PyExc_SystemError,
627+
"list changed size during sort");
628+
return CMPERROR;
629+
}
618630
i = PyInt_AsLong(res);
619631
Py_DECREF(res);
620632
if (i < 0)
@@ -643,11 +655,12 @@ docompare(x, y, compare)
643655
(i.e. no items have been removed or duplicated). */
644656

645657
static int
646-
quicksort(array, size, compare)
647-
PyObject **array; /* Start of array to sort */
648-
int size; /* Number of elements to sort */
658+
quicksort(list, compare)
659+
PyListObject *list; /* List to sort */
649660
PyObject *compare;/* Comparison function object, or NULL for default */
650661
{
662+
int size = list->ob_size; /* Number of elements to sort */
663+
PyObject **array = list->ob_item; /* Start of array to sort */
651664
register PyObject *tmp, *pivot;
652665
register PyObject **l, **r, **p;
653666
PyObject **lo, **hi, **notp;
@@ -675,7 +688,8 @@ quicksort(array, size, compare)
675688
pivot = *r;
676689
do {
677690
p = l + ((r - l) >> 1);
678-
k = docompare(pivot, *p, compare);
691+
k = docompare(pivot, *p,
692+
compare, list);
679693
if (k == CMPERROR)
680694
return -1;
681695
if (k < 0)
@@ -699,19 +713,19 @@ quicksort(array, size, compare)
699713
p = lo + (n>>1); /* Middle */
700714
r = hi - 1; /* Last */
701715

702-
k = docompare(*p, *l, compare);
716+
k = docompare(*p, *l, compare, list);
703717
if (k == CMPERROR)
704718
return -1;
705719
if (k < 0)
706720
{ tmp = *p; *p = *l; *l = tmp; }
707721

708-
k = docompare(*r, *p, compare);
722+
k = docompare(*r, *p, compare, list);
709723
if (k == CMPERROR)
710724
return -1;
711725
if (k < 0)
712726
{ tmp = *r; *r = *p; *p = tmp; }
713727

714-
k = docompare(*p, *l, compare);
728+
k = docompare(*p, *l, compare, list);
715729
if (k == CMPERROR)
716730
return -1;
717731
if (k < 0)
@@ -727,7 +741,7 @@ quicksort(array, size, compare)
727741

728742
/* Move left index to element >= pivot */
729743
while (l < p) {
730-
k = docompare(*l, pivot, compare);
744+
k = docompare(*l, pivot, compare, list);
731745
if (k == CMPERROR)
732746
return -1;
733747
if (k < 0)
@@ -739,7 +753,7 @@ quicksort(array, size, compare)
739753
}
740754
/* Move right index to element <= pivot */
741755
while (r > p) {
742-
k = docompare(pivot, *r, compare);
756+
k = docompare(pivot, *r, compare, list);
743757
if (k == CMPERROR)
744758
return -1;
745759
if (k < 0)
@@ -804,7 +818,7 @@ quicksort(array, size, compare)
804818
* This wastes a compare if it fails, but can win big
805819
* when there are runs of duplicates.
806820
*/
807-
k = docompare(pivot, *l, compare);
821+
k = docompare(pivot, *l, compare, list);
808822
if (k == CMPERROR)
809823
return -1;
810824
if (!(k < 0)) {
@@ -817,7 +831,7 @@ quicksort(array, size, compare)
817831
*/
818832
while (r > lo) {
819833
/* because r-1 < p, *(r-1) <= pivot is known */
820-
k = docompare(*(r-1), pivot, compare);
834+
k = docompare(*(r-1), pivot, compare, list);
821835
if (k == CMPERROR)
822836
return -1;
823837
if (k < 0)
@@ -829,7 +843,7 @@ quicksort(array, size, compare)
829843
l++;
830844
while (l < hi) {
831845
/* because l > p, pivot <= *l is known */
832-
k = docompare(pivot, *l, compare);
846+
k = docompare(pivot, *l, compare, list);
833847
if (k == CMPERROR)
834848
return -1;
835849
if (k < 0)
@@ -866,8 +880,7 @@ listsort(self, compare)
866880
PyListObject *self;
867881
PyObject *compare;
868882
{
869-
/* XXX Don't you *dare* changing the list's length in compare()! */
870-
if (quicksort(self->ob_item, self->ob_size, compare) < 0)
883+
if (quicksort(self, compare) < 0)
871884
return NULL;
872885
Py_INCREF(Py_None);
873886
return Py_None;
@@ -922,11 +935,7 @@ PyList_Sort(v)
922935
PyErr_BadInternalCall();
923936
return -1;
924937
}
925-
v = listsort((PyListObject *)v, (PyObject *)NULL);
926-
if (v == NULL)
927-
return -1;
928-
Py_DECREF(v);
929-
return 0;
938+
return quicksort((PyListObject *)v, (PyObject *)NULL);
930939
}
931940

932941
PyObject *

0 commit comments

Comments
 (0)