@@ -813,11 +813,16 @@ _elementtree_Element___deepcopy___impl(ElementObject *self, PyObject *memo)
813813
814814    PyTypeObject  * tp  =  Py_TYPE (self );
815815    elementtreestate  * st  =  get_elementtree_state_by_type (tp );
816+     // Since the 'tag' attribute is undeletable, deepcopy() should be safe. 
816817    tag  =  deepcopy (st , self -> tag , memo );
818+     assert (self -> tag  !=  NULL );
817819    if  (!tag )
818820        return  NULL ;
819821
820822    if  (self -> extra  &&  self -> extra -> attrib ) {
823+         // While deepcopy(self->extra->attrib) may cause 'self->extra' to be 
824+         // NULL, we do not use it afterawrds without checking this, so no need 
825+         // to temporarily incref 'self->extra->attrib'. 
821826        attrib  =  deepcopy (st , self -> extra -> attrib , memo );
822827        if  (!attrib ) {
823828            Py_DECREF (tag );
@@ -835,12 +840,16 @@ _elementtree_Element___deepcopy___impl(ElementObject *self, PyObject *memo)
835840    if  (!element )
836841        return  NULL ;
837842
843+     // Since the 'text' attribute is undeletable, deepcopy() should be safe. 
838844    text  =  deepcopy (st , JOIN_OBJ (self -> text ), memo );
845+     assert (JOIN_OBJ (self -> text ) !=  NULL );
839846    if  (!text )
840847        goto error ;
841848    _set_joined_ptr (& element -> text , JOIN_SET (text , JOIN_GET (self -> text )));
842849
850+     // Since the 'tail' attribute is undeletable, deepcopy() should be safe. 
843851    tail  =  deepcopy (st , JOIN_OBJ (self -> tail ), memo );
852+     assert (JOIN_OBJ (self -> tail ) !=  NULL );
844853    if  (!tail )
845854        goto error ;
846855    _set_joined_ptr (& element -> tail , JOIN_SET (tail , JOIN_GET (self -> tail )));
@@ -850,9 +859,11 @@ _elementtree_Element___deepcopy___impl(ElementObject *self, PyObject *memo)
850859        if  (element_resize (element , self -> extra -> length ) <  0 )
851860            goto error ;
852861
853-         // TODO(picnixz): check for an evil child's __deepcopy__ on 'self' 
854-         for  (i  =  0 ; i  <  self -> extra -> length ; i ++ ) {
855-             PyObject *  child  =  deepcopy (st , self -> extra -> children [i ], memo );
862+         // TODO(picnixz): should we protect against mutations from 'memo'? 
863+         for  (i  =  0 ; self -> extra  &&  i  <  self -> extra -> length ; i ++ ) {
864+             PyObject *  itemi  =  Py_NewRef (self -> extra -> children [i ]);
865+             PyObject *  child  =  deepcopy (st , itemi , memo );
866+             Py_DECREF (itemi );
856867            if  (!child  ||  !Element_Check (st , child )) {
857868                if  (child ) {
858869                    raise_type_error (child );
@@ -865,7 +876,12 @@ _elementtree_Element___deepcopy___impl(ElementObject *self, PyObject *memo)
865876        }
866877
867878        assert (!element -> extra -> length );
868-         element -> extra -> length  =  self -> extra -> length ;
879+         /* 
880+          * The original 'self->extra' may be gone at this point if deepcopy() 
881+          * had side-effects. However, 'i' is the number of copied items that 
882+          * we were able to successfully copy. 
883+          */ 
884+         element -> extra -> length  =  i ;
869885    }
870886
871887    /* add object to memo dictionary (so deepcopy won't visit it again) */ 
0 commit comments