@@ -233,11 +233,29 @@ create_extra(ElementObject* self, PyObject* attrib)
233233}
234234
235235LOCAL (void )
236- dealloc_extra (ElementObject * self )
236+ dealloc_extra (ElementObjectExtra * extra )
237237{
238- ElementObjectExtra * myextra ;
239238 Py_ssize_t i ;
240239
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+
241259 if (!self -> extra )
242260 return ;
243261
@@ -246,15 +264,7 @@ dealloc_extra(ElementObject* self)
246264 myextra = self -> extra ;
247265 self -> extra = NULL ;
248266
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 );
258268}
259269
260270/* Convenience internal function to create new Element objects with the given
@@ -420,6 +430,7 @@ element_resize(ElementObject* self, Py_ssize_t extra)
420430 Py_ssize_t size ;
421431 PyObject * * children ;
422432
433+ assert (extra >= 0 );
423434 /* make sure self->children can hold the given number of extra
424435 elements. set an exception and return -1 if allocation failed */
425436
@@ -624,7 +635,7 @@ element_gc_clear(ElementObject *self)
624635 /* After dropping all references from extra, it's no longer valid anyway,
625636 * so fully deallocate it.
626637 */
627- dealloc_extra (self );
638+ clear_extra (self );
628639 return 0 ;
629640}
630641
@@ -676,7 +687,7 @@ static PyObject *
676687_elementtree_Element_clear_impl (ElementObject * self )
677688/*[clinic end generated code: output=8bcd7a51f94cfff6 input=3c719ff94bf45dd6]*/
678689{
679- dealloc_extra (self );
690+ clear_extra (self );
680691
681692 Py_INCREF (Py_None );
682693 _set_joined_ptr (& self - > text , Py_None );
@@ -710,6 +721,7 @@ _elementtree_Element___copy___impl(ElementObject *self)
710721 Py_INCREF (JOIN_OBJ (self -> tail ));
711722 _set_joined_ptr (& element -> tail , self -> tail );
712723
724+ assert (!element -> extra || !element -> extra -> length );
713725 if (self -> extra ) {
714726 if (element_resize (element , self -> extra -> length ) < 0 ) {
715727 Py_DECREF (element );
@@ -721,6 +733,7 @@ _elementtree_Element___copy___impl(ElementObject *self)
721733 element -> extra -> children [i ] = self -> extra -> children [i ];
722734 }
723735
736+ assert (!element -> extra -> length );
724737 element -> extra -> length = self -> extra -> length ;
725738 }
726739
@@ -783,6 +796,7 @@ _elementtree_Element___deepcopy__(ElementObject *self, PyObject *memo)
783796 goto error ;
784797 _set_joined_ptr (& element -> tail , JOIN_SET (tail , JOIN_GET (self -> tail )));
785798
799+ assert (!element -> extra || !element -> extra -> length );
786800 if (self -> extra ) {
787801 if (element_resize (element , self -> extra -> length ) < 0 )
788802 goto error ;
@@ -796,6 +810,7 @@ _elementtree_Element___deepcopy__(ElementObject *self, PyObject *memo)
796810 element -> extra -> children [i ] = child ;
797811 }
798812
813+ assert (!element -> extra -> length );
799814 element -> extra -> length = self -> extra -> length ;
800815 }
801816
@@ -956,6 +971,7 @@ element_setstate_from_attributes(ElementObject *self,
956971 PyObject * children )
957972{
958973 Py_ssize_t i , nchildren ;
974+ ElementObjectExtra * oldextra = NULL ;
959975
960976 if (!tag ) {
961977 PyErr_SetString (PyExc_TypeError , "tag may not be NULL" );
@@ -974,41 +990,58 @@ element_setstate_from_attributes(ElementObject *self,
974990 _set_joined_ptr (& self -> tail , tail );
975991
976992 /* Handle ATTRIB and CHILDREN. */
977- if (!children && !attrib )
993+ if (!children && !attrib ) {
978994 Py_RETURN_NONE ;
995+ }
979996
980997 /* Compute 'nchildren'. */
981998 if (children ) {
982999 if (!PyList_Check (children )) {
9831000 PyErr_SetString (PyExc_TypeError , "'_children' is not a list" );
9841001 return NULL ;
9851002 }
986- nchildren = PyList_Size (children );
987- }
988- else {
989- nchildren = 0 ;
990- }
1003+ nchildren = PyList_GET_SIZE (children );
9911004
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+ }
9971023
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+ }
10031029
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+ }
10061038
10071039 /* Stash attrib. */
10081040 if (attrib ) {
10091041 Py_INCREF (attrib );
10101042 Py_XSETREF (self -> extra -> attrib , attrib );
10111043 }
1044+ dealloc_extra (oldextra );
10121045
10131046 Py_RETURN_NONE ;
10141047}
0 commit comments