bpo-35008: Fix possible leaks in Element.setstate(). (GH-9924) · python/cpython@bcbefe2 (original) (raw)
`@@ -233,11 +233,29 @@ create_extra(ElementObject* self, PyObject* attrib)
`
233
233
`}
`
234
234
``
235
235
`LOCAL(void)
`
236
``
`-
dealloc_extra(ElementObject* self)
`
``
236
`+
dealloc_extra(ElementObjectExtra *extra)
`
237
237
`{
`
238
``
`-
ElementObjectExtra *myextra;
`
239
238
`Py_ssize_t i;
`
240
239
``
``
240
`+
if (!extra)
`
``
241
`+
return;
`
``
242
+
``
243
`+
Py_DECREF(extra->attrib);
`
``
244
+
``
245
`+
for (i = 0; i < extra->length; i++)
`
``
246
`+
Py_DECREF(extra->children[i]);
`
``
247
+
``
248
`+
if (extra->children != extra->_children)
`
``
249
`+
PyObject_Free(extra->children);
`
``
250
+
``
251
`+
PyObject_Free(extra);
`
``
252
`+
}
`
``
253
+
``
254
`+
LOCAL(void)
`
``
255
`+
clear_extra(ElementObject* self)
`
``
256
`+
{
`
``
257
`+
ElementObjectExtra *myextra;
`
``
258
+
241
259
`if (!self->extra)
`
242
260
`return;
`
243
261
``
`@@ -246,15 +264,7 @@ dealloc_extra(ElementObject* self)
`
246
264
`myextra = self->extra;
`
247
265
`self->extra = NULL;
`
248
266
``
249
``
`-
Py_DECREF(myextra->attrib);
`
250
``
-
251
``
`-
for (i = 0; i < myextra->length; i++)
`
252
``
`-
Py_DECREF(myextra->children[i]);
`
253
``
-
254
``
`-
if (myextra->children != myextra->_children)
`
255
``
`-
PyObject_Free(myextra->children);
`
256
``
-
257
``
`-
PyObject_Free(myextra);
`
``
267
`+
dealloc_extra(myextra);
`
258
268
`}
`
259
269
``
260
270
`/* Convenience internal function to create new Element objects with the given
`
`@@ -420,6 +430,7 @@ element_resize(ElementObject* self, Py_ssize_t extra)
`
420
430
`Py_ssize_t size;
`
421
431
`PyObject* *children;
`
422
432
``
``
433
`+
assert(extra >= 0);
`
423
434
`/* make sure self->children can hold the given number of extra
`
424
435
` elements. set an exception and return -1 if allocation failed */
`
425
436
``
`@@ -624,7 +635,7 @@ element_gc_clear(ElementObject *self)
`
624
635
`/* After dropping all references from extra, it's no longer valid anyway,
`
625
636
` * so fully deallocate it.
`
626
637
` */
`
627
``
`-
dealloc_extra(self);
`
``
638
`+
clear_extra(self);
`
628
639
`return 0;
`
629
640
`}
`
630
641
``
`@@ -676,7 +687,7 @@ static PyObject *
`
676
687
`_elementtree_Element_clear_impl(ElementObject *self)
`
677
688
`/[clinic end generated code: output=8bcd7a51f94cfff6 input=3c719ff94bf45dd6]/
`
678
689
`{
`
679
``
`-
dealloc_extra(self);
`
``
690
`+
clear_extra(self);
`
680
691
``
681
692
`Py_INCREF(Py_None);
`
682
693
`_set_joined_ptr(&self->text, Py_None);
`
`@@ -710,6 +721,7 @@ _elementtree_Element___copy___impl(ElementObject *self)
`
710
721
`Py_INCREF(JOIN_OBJ(self->tail));
`
711
722
`_set_joined_ptr(&element->tail, self->tail);
`
712
723
``
``
724
`+
assert(!element->extra || !element->extra->length);
`
713
725
`if (self->extra) {
`
714
726
`if (element_resize(element, self->extra->length) < 0) {
`
715
727
`Py_DECREF(element);
`
`@@ -721,6 +733,7 @@ _elementtree_Element___copy___impl(ElementObject *self)
`
721
733
`element->extra->children[i] = self->extra->children[i];
`
722
734
` }
`
723
735
``
``
736
`+
assert(!element->extra->length);
`
724
737
`element->extra->length = self->extra->length;
`
725
738
` }
`
726
739
``
`@@ -783,6 +796,7 @@ elementtree_Element___deepcopy_(ElementObject *self, PyObject *memo)
`
783
796
` goto error;
`
784
797
`_set_joined_ptr(&element->tail, JOIN_SET(tail, JOIN_GET(self->tail)));
`
785
798
``
``
799
`+
assert(!element->extra || !element->extra->length);
`
786
800
`if (self->extra) {
`
787
801
`if (element_resize(element, self->extra->length) < 0)
`
788
802
` goto error;
`
`@@ -796,6 +810,7 @@ elementtree_Element___deepcopy_(ElementObject *self, PyObject *memo)
`
796
810
`element->extra->children[i] = child;
`
797
811
` }
`
798
812
``
``
813
`+
assert(!element->extra->length);
`
799
814
`element->extra->length = self->extra->length;
`
800
815
` }
`
801
816
``
`@@ -956,6 +971,7 @@ element_setstate_from_attributes(ElementObject *self,
`
956
971
`PyObject *children)
`
957
972
`{
`
958
973
`Py_ssize_t i, nchildren;
`
``
974
`+
ElementObjectExtra *oldextra = NULL;
`
959
975
``
960
976
`if (!tag) {
`
961
977
`PyErr_SetString(PyExc_TypeError, "tag may not be NULL");
`
`@@ -974,41 +990,58 @@ element_setstate_from_attributes(ElementObject *self,
`
974
990
`_set_joined_ptr(&self->tail, tail);
`
975
991
``
976
992
`/* Handle ATTRIB and CHILDREN. */
`
977
``
`-
if (!children && !attrib)
`
``
993
`+
if (!children && !attrib) {
`
978
994
`Py_RETURN_NONE;
`
``
995
`+
}
`
979
996
``
980
997
`/* Compute 'nchildren'. */
`
981
998
`if (children) {
`
982
999
`if (!PyList_Check(children)) {
`
983
1000
`PyErr_SetString(PyExc_TypeError, "'_children' is not a list");
`
984
1001
`return NULL;
`
985
1002
` }
`
986
``
`-
nchildren = PyList_Size(children);
`
987
``
`-
}
`
988
``
`-
else {
`
989
``
`-
nchildren = 0;
`
990
``
`-
}
`
``
1003
`+
nchildren = PyList_GET_SIZE(children);
`
991
1004
``
992
``
`-
/* Allocate 'extra'. */
`
993
``
`-
if (element_resize(self, nchildren)) {
`
994
``
`-
return NULL;
`
995
``
`-
}
`
996
``
`-
assert(self->extra && self->extra->allocated >= nchildren);
`
``
1005
`+
/* (Re-)allocate 'extra'.
`
``
1006
`+
Avoid DECREFs calling into this code again (cycles, etc.)
`
``
1007
`+
*/
`
``
1008
`+
oldextra = self->extra;
`
``
1009
`+
self->extra = NULL;
`
``
1010
`+
if (element_resize(self, nchildren)) {
`
``
1011
`+
assert(!self->extra || !self->extra->length);
`
``
1012
`+
clear_extra(self);
`
``
1013
`+
self->extra = oldextra;
`
``
1014
`+
return NULL;
`
``
1015
`+
}
`
``
1016
`+
assert(self->extra);
`
``
1017
`+
assert(self->extra->allocated >= nchildren);
`
``
1018
`+
if (oldextra) {
`
``
1019
`+
assert(self->extra->attrib == Py_None);
`
``
1020
`+
self->extra->attrib = oldextra->attrib;
`
``
1021
`+
oldextra->attrib = Py_None;
`
``
1022
`+
}
`
997
1023
``
998
``
`-
/* Copy children */
`
999
``
`-
for (i = 0; i < nchildren; i++) {
`
1000
``
`-
self->extra->children[i] = PyList_GET_ITEM(children, i);
`
1001
``
`-
Py_INCREF(self->extra->children[i]);
`
1002
``
`-
}
`
``
1024
`+
/* Copy children */
`
``
1025
`+
for (i = 0; i < nchildren; i++) {
`
``
1026
`+
self->extra->children[i] = PyList_GET_ITEM(children, i);
`
``
1027
`+
Py_INCREF(self->extra->children[i]);
`
``
1028
`+
}
`
1003
1029
``
1004
``
`-
self->extra->length = nchildren;
`
1005
``
`-
self->extra->allocated = nchildren;
`
``
1030
`+
assert(!self->extra->length);
`
``
1031
`+
self->extra->length = nchildren;
`
``
1032
`+
}
`
``
1033
`+
else {
`
``
1034
`+
if (element_resize(self, 0)) {
`
``
1035
`+
return NULL;
`
``
1036
`+
}
`
``
1037
`+
}
`
1006
1038
``
1007
1039
`/* Stash attrib. */
`
1008
1040
`if (attrib) {
`
1009
1041
`Py_INCREF(attrib);
`
1010
1042
`Py_XSETREF(self->extra->attrib, attrib);
`
1011
1043
` }
`
``
1044
`+
dealloc_extra(oldextra);
`
1012
1045
``
1013
1046
`Py_RETURN_NONE;
`
1014
1047
`}
`