Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
47a9d59d
Commit
47a9d59d
authored
Dec 21, 2015
by
Serhiy Storchaka
Browse files
Options
Browse Files
Download
Plain Diff
Issue #25902: Fixed various refcount issues in ElementTree iteration.
parents
0c477e6a
66c08d90
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
117 additions
and
36 deletions
+117
-36
Lib/test/test_xml_etree.py
Lib/test/test_xml_etree.py
+51
-0
Lib/xml/etree/ElementTree.py
Lib/xml/etree/ElementTree.py
+6
-4
Misc/NEWS
Misc/NEWS
+2
-0
Modules/_elementtree.c
Modules/_elementtree.c
+58
-32
No files found.
Lib/test/test_xml_etree.py
View file @
47a9d59d
...
@@ -1668,6 +1668,57 @@ class BugsTest(unittest.TestCase):
...
@@ -1668,6 +1668,57 @@ class BugsTest(unittest.TestCase):
ET
.
register_namespace
(
'test10777'
,
'http://myuri/'
)
ET
.
register_namespace
(
'test10777'
,
'http://myuri/'
)
ET
.
register_namespace
(
'test10777'
,
'http://myuri/'
)
ET
.
register_namespace
(
'test10777'
,
'http://myuri/'
)
def
test_lost_text
(
self
):
# Issue #25902: Borrowed text can disappear
class
Text
:
def
__bool__
(
self
):
e
.
text
=
'changed'
return
True
e
=
ET
.
Element
(
'tag'
)
e
.
text
=
Text
()
i
=
e
.
itertext
()
t
=
next
(
i
)
self
.
assertIsInstance
(
t
,
Text
)
self
.
assertIsInstance
(
e
.
text
,
str
)
self
.
assertEqual
(
e
.
text
,
'changed'
)
def
test_lost_tail
(
self
):
# Issue #25902: Borrowed tail can disappear
class
Text
:
def
__bool__
(
self
):
e
[
0
].
tail
=
'changed'
return
True
e
=
ET
.
Element
(
'root'
)
e
.
append
(
ET
.
Element
(
'tag'
))
e
[
0
].
tail
=
Text
()
i
=
e
.
itertext
()
t
=
next
(
i
)
self
.
assertIsInstance
(
t
,
Text
)
self
.
assertIsInstance
(
e
[
0
].
tail
,
str
)
self
.
assertEqual
(
e
[
0
].
tail
,
'changed'
)
def
test_lost_elem
(
self
):
# Issue #25902: Borrowed element can disappear
class
Tag
:
def
__eq__
(
self
,
other
):
e
[
0
]
=
ET
.
Element
(
'changed'
)
next
(
i
)
return
True
e
=
ET
.
Element
(
'root'
)
e
.
append
(
ET
.
Element
(
Tag
()))
e
.
append
(
ET
.
Element
(
'tag'
))
i
=
e
.
iter
(
'tag'
)
try
:
t
=
next
(
i
)
except
ValueError
:
self
.
skipTest
(
'generators are not reentrant'
)
self
.
assertIsInstance
(
t
.
tag
,
Tag
)
self
.
assertIsInstance
(
e
[
0
].
tag
,
str
)
self
.
assertEqual
(
e
[
0
].
tag
,
'changed'
)
# --------------------------------------------------------------------
# --------------------------------------------------------------------
...
...
Lib/xml/etree/ElementTree.py
View file @
47a9d59d
...
@@ -429,12 +429,14 @@ class Element:
...
@@ -429,12 +429,14 @@ class Element:
tag
=
self
.
tag
tag
=
self
.
tag
if
not
isinstance
(
tag
,
str
)
and
tag
is
not
None
:
if
not
isinstance
(
tag
,
str
)
and
tag
is
not
None
:
return
return
if
self
.
text
:
t
=
self
.
text
yield
self
.
text
if
t
:
yield
t
for
e
in
self
:
for
e
in
self
:
yield
from
e
.
itertext
()
yield
from
e
.
itertext
()
if
e
.
tail
:
t
=
e
.
tail
yield
e
.
tail
if
t
:
yield
t
def
SubElement
(
parent
,
tag
,
attrib
=
{},
**
extra
):
def
SubElement
(
parent
,
tag
,
attrib
=
{},
**
extra
):
...
...
Misc/NEWS
View file @
47a9d59d
...
@@ -115,6 +115,8 @@ Core and Builtins
...
@@ -115,6 +115,8 @@ Core and Builtins
Library
Library
-------
-------
- Issue #25902: Fixed various refcount issues in ElementTree iteration.
- Issue #22227: The TarFile iterator is reimplemented using generator.
- Issue #22227: The TarFile iterator is reimplemented using generator.
This implementation is simpler that using class.
This implementation is simpler that using class.
...
...
Modules/_elementtree.c
View file @
47a9d59d
...
@@ -2070,6 +2070,7 @@ elementiter_next(ElementIterObject *it)
...
@@ -2070,6 +2070,7 @@ elementiter_next(ElementIterObject *it)
ElementObject
*
cur_parent
;
ElementObject
*
cur_parent
;
Py_ssize_t
child_index
;
Py_ssize_t
child_index
;
int
rc
;
int
rc
;
ElementObject
*
elem
;
while
(
1
)
{
while
(
1
)
{
/* Handle the case reached in the beginning and end of iteration, where
/* Handle the case reached in the beginning and end of iteration, where
...
@@ -2083,38 +2084,47 @@ elementiter_next(ElementIterObject *it)
...
@@ -2083,38 +2084,47 @@ elementiter_next(ElementIterObject *it)
PyErr_SetNone
(
PyExc_StopIteration
);
PyErr_SetNone
(
PyExc_StopIteration
);
return
NULL
;
return
NULL
;
}
else
{
}
else
{
elem
=
it
->
root_element
;
it
->
parent_stack
=
parent_stack_push_new
(
it
->
parent_stack
,
it
->
parent_stack
=
parent_stack_push_new
(
it
->
parent_stack
,
it
->
root_element
);
elem
);
if
(
!
it
->
parent_stack
)
{
if
(
!
it
->
parent_stack
)
{
PyErr_NoMemory
();
PyErr_NoMemory
();
return
NULL
;
return
NULL
;
}
}
Py_INCREF
(
elem
);
it
->
root_done
=
1
;
it
->
root_done
=
1
;
rc
=
(
it
->
sought_tag
==
Py_None
);
rc
=
(
it
->
sought_tag
==
Py_None
);
if
(
!
rc
)
{
if
(
!
rc
)
{
rc
=
PyObject_RichCompareBool
(
it
->
root_element
->
tag
,
rc
=
PyObject_RichCompareBool
(
elem
->
tag
,
it
->
sought_tag
,
Py_EQ
);
it
->
sought_tag
,
Py_EQ
);
if
(
rc
<
0
)
if
(
rc
<
0
)
{
Py_DECREF
(
elem
);
return
NULL
;
return
NULL
;
}
}
}
if
(
rc
)
{
if
(
rc
)
{
if
(
it
->
gettext
)
{
if
(
it
->
gettext
)
{
PyObject
*
text
=
element_get_text
(
it
->
root_element
);
PyObject
*
text
=
element_get_text
(
elem
);
if
(
!
text
)
if
(
!
text
)
{
Py_DECREF
(
elem
);
return
NULL
;
return
NULL
;
}
Py_INCREF
(
text
);
Py_DECREF
(
elem
);
rc
=
PyObject_IsTrue
(
text
);
rc
=
PyObject_IsTrue
(
text
);
if
(
rc
>
0
)
return
text
;
Py_DECREF
(
text
);
if
(
rc
<
0
)
if
(
rc
<
0
)
return
NULL
;
return
NULL
;
if
(
rc
)
{
Py_INCREF
(
text
);
return
text
;
}
}
else
{
}
else
{
Py_INCREF
(
it
->
root_element
);
return
(
PyObject
*
)
elem
;
return
(
PyObject
*
)
it
->
root_element
;
}
}
}
}
else
{
Py_DECREF
(
elem
);
}
}
}
}
}
...
@@ -2124,54 +2134,68 @@ elementiter_next(ElementIterObject *it)
...
@@ -2124,54 +2134,68 @@ elementiter_next(ElementIterObject *it)
cur_parent
=
it
->
parent_stack
->
parent
;
cur_parent
=
it
->
parent_stack
->
parent
;
child_index
=
it
->
parent_stack
->
child_index
;
child_index
=
it
->
parent_stack
->
child_index
;
if
(
cur_parent
->
extra
&&
child_index
<
cur_parent
->
extra
->
length
)
{
if
(
cur_parent
->
extra
&&
child_index
<
cur_parent
->
extra
->
length
)
{
ElementObject
*
child
=
(
ElementObject
*
)
elem
=
(
ElementObject
*
)
cur_parent
->
extra
->
children
[
child_index
];
cur_parent
->
extra
->
children
[
child_index
];
it
->
parent_stack
->
child_index
++
;
it
->
parent_stack
->
child_index
++
;
it
->
parent_stack
=
parent_stack_push_new
(
it
->
parent_stack
,
it
->
parent_stack
=
parent_stack_push_new
(
it
->
parent_stack
,
child
);
elem
);
if
(
!
it
->
parent_stack
)
{
if
(
!
it
->
parent_stack
)
{
PyErr_NoMemory
();
PyErr_NoMemory
();
return
NULL
;
return
NULL
;
}
}
Py_INCREF
(
elem
);
if
(
it
->
gettext
)
{
if
(
it
->
gettext
)
{
PyObject
*
text
=
element_get_text
(
child
);
PyObject
*
text
=
element_get_text
(
elem
);
if
(
!
text
)
if
(
!
text
)
{
Py_DECREF
(
elem
);
return
NULL
;
return
NULL
;
}
Py_INCREF
(
text
);
Py_DECREF
(
elem
);
rc
=
PyObject_IsTrue
(
text
);
rc
=
PyObject_IsTrue
(
text
);
if
(
rc
>
0
)
return
text
;
Py_DECREF
(
text
);
if
(
rc
<
0
)
if
(
rc
<
0
)
return
NULL
;
return
NULL
;
if
(
rc
)
{
Py_INCREF
(
text
);
return
text
;
}
}
else
{
}
else
{
rc
=
(
it
->
sought_tag
==
Py_None
);
rc
=
(
it
->
sought_tag
==
Py_None
);
if
(
!
rc
)
{
if
(
!
rc
)
{
rc
=
PyObject_RichCompareBool
(
child
->
tag
,
rc
=
PyObject_RichCompareBool
(
elem
->
tag
,
it
->
sought_tag
,
Py_EQ
);
it
->
sought_tag
,
Py_EQ
);
if
(
rc
<
0
)
if
(
rc
<
0
)
{
Py_DECREF
(
elem
);
return
NULL
;
return
NULL
;
}
}
}
if
(
rc
)
{
if
(
rc
)
{
Py_INCREF
(
child
);
return
(
PyObject
*
)
elem
;
return
(
PyObject
*
)
child
;
}
}
Py_DECREF
(
elem
);
}
}
}
}
else
{
else
{
PyObject
*
tail
;
PyObject
*
tail
;
ParentLocator
*
next
=
it
->
parent_stack
->
next
;
ParentLocator
*
next
;
if
(
it
->
gettext
)
{
if
(
it
->
gettext
)
{
Py_INCREF
(
cur_parent
);
tail
=
element_get_tail
(
cur_parent
);
tail
=
element_get_tail
(
cur_parent
);
if
(
!
tail
)
if
(
!
tail
)
{
Py_DECREF
(
cur_parent
);
return
NULL
;
return
NULL
;
}
Py_INCREF
(
tail
);
Py_DECREF
(
cur_parent
);
}
}
else
else
{
tail
=
Py_None
;
tail
=
Py_None
;
Py_XDECREF
(
it
->
parent_stack
->
parent
);
Py_INCREF
(
tail
);
}
next
=
it
->
parent_stack
->
next
;
cur_parent
=
it
->
parent_stack
->
parent
;
PyObject_Free
(
it
->
parent_stack
);
PyObject_Free
(
it
->
parent_stack
);
it
->
parent_stack
=
next
;
it
->
parent_stack
=
next
;
Py_XDECREF
(
cur_parent
);
/* Note that extra condition on it->parent_stack->parent here;
/* Note that extra condition on it->parent_stack->parent here;
* this is because itertext() is supposed to only return *inner*
* this is because itertext() is supposed to only return *inner*
...
@@ -2179,12 +2203,14 @@ elementiter_next(ElementIterObject *it)
...
@@ -2179,12 +2203,14 @@ elementiter_next(ElementIterObject *it)
*/
*/
if
(
it
->
parent_stack
->
parent
)
{
if
(
it
->
parent_stack
->
parent
)
{
rc
=
PyObject_IsTrue
(
tail
);
rc
=
PyObject_IsTrue
(
tail
);
if
(
rc
>
0
)
return
tail
;
Py_DECREF
(
tail
);
if
(
rc
<
0
)
if
(
rc
<
0
)
return
NULL
;
return
NULL
;
if
(
rc
)
{
}
Py_INCREF
(
tail
);
else
{
return
tail
;
Py_DECREF
(
tail
);
}
}
}
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment