@@ -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___impl(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___impl(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
@@ -957,6 +972,7 @@ element_setstate_from_attributes(ElementObject *self,
957
972
PyObject * children )
958
973
{
959
974
Py_ssize_t i , nchildren ;
975
+ ElementObjectExtra * oldextra = NULL ;
960
976
961
977
if (!tag ) {
962
978
PyErr_SetString (PyExc_TypeError , "tag may not be NULL" );
@@ -975,41 +991,58 @@ element_setstate_from_attributes(ElementObject *self,
975
991
_set_joined_ptr (& self -> tail , tail );
976
992
977
993
/* Handle ATTRIB and CHILDREN. */
978
- if (!children && !attrib )
994
+ if (!children && !attrib ) {
979
995
Py_RETURN_NONE ;
996
+ }
980
997
981
998
/* Compute 'nchildren'. */
982
999
if (children ) {
983
1000
if (!PyList_Check (children )) {
984
1001
PyErr_SetString (PyExc_TypeError , "'_children' is not a list" );
985
1002
return NULL ;
986
1003
}
987
- nchildren = PyList_Size (children );
988
- }
989
- else {
990
- nchildren = 0 ;
991
- }
1004
+ nchildren = PyList_GET_SIZE (children );
992
1005
993
- /* Allocate 'extra'. */
994
- if (element_resize (self , nchildren )) {
995
- return NULL ;
996
- }
997
- assert (self -> extra && self -> extra -> allocated >= nchildren );
1006
+ /* (Re-)allocate 'extra'.
1007
+ Avoid DECREFs calling into this code again (cycles, etc.)
1008
+ */
1009
+ oldextra = self -> extra ;
1010
+ self -> extra = NULL ;
1011
+ if (element_resize (self , nchildren )) {
1012
+ assert (!self -> extra || !self -> extra -> length );
1013
+ clear_extra (self );
1014
+ self -> extra = oldextra ;
1015
+ return NULL ;
1016
+ }
1017
+ assert (self -> extra );
1018
+ assert (self -> extra -> allocated >= nchildren );
1019
+ if (oldextra ) {
1020
+ assert (self -> extra -> attrib == Py_None );
1021
+ self -> extra -> attrib = oldextra -> attrib ;
1022
+ oldextra -> attrib = Py_None ;
1023
+ }
998
1024
999
- /* Copy children */
1000
- for (i = 0 ; i < nchildren ; i ++ ) {
1001
- self -> extra -> children [i ] = PyList_GET_ITEM (children , i );
1002
- Py_INCREF (self -> extra -> children [i ]);
1003
- }
1025
+ /* Copy children */
1026
+ for (i = 0 ; i < nchildren ; i ++ ) {
1027
+ self -> extra -> children [i ] = PyList_GET_ITEM (children , i );
1028
+ Py_INCREF (self -> extra -> children [i ]);
1029
+ }
1004
1030
1005
- self -> extra -> length = nchildren ;
1006
- self -> extra -> allocated = nchildren ;
1031
+ assert (!self -> extra -> length );
1032
+ self -> extra -> length = nchildren ;
1033
+ }
1034
+ else {
1035
+ if (element_resize (self , 0 )) {
1036
+ return NULL ;
1037
+ }
1038
+ }
1007
1039
1008
1040
/* Stash attrib. */
1009
1041
if (attrib ) {
1010
1042
Py_INCREF (attrib );
1011
1043
Py_XSETREF (self -> extra -> attrib , attrib );
1012
1044
}
1045
+ dealloc_extra (oldextra );
1013
1046
1014
1047
Py_RETURN_NONE ;
1015
1048
}
0 commit comments