Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9344ede

Browse files
[3.11] gh-101438: Avoid reference cycle in ElementTree.iterparse. (GH-114269) (GH-114500)
The iterator returned by ElementTree.iterparse() may hold on to a file descriptor. The reference cycle prevented prompt clean-up of the file descriptor if the returned iterator was not exhausted. (cherry picked from commit ce01ab5) Co-authored-by: Sam Gross <[email protected]>
1 parent e85f4c6 commit 9344ede

File tree

2 files changed

+21
-10
lines changed

2 files changed

+21
-10
lines changed

Lib/xml/etree/ElementTree.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
import collections
100100
import collections.abc
101101
import contextlib
102+
import weakref
102103

103104
from . import ElementPath
104105

@@ -1238,13 +1239,14 @@ def iterparse(source, events=None, parser=None):
12381239
# parser argument of iterparse is removed, this can be killed.
12391240
pullparser = XMLPullParser(events=events, _parser=parser)
12401241

1241-
def iterator(source):
1242+
if not hasattr(source, "read"):
1243+
source = open(source, "rb")
1244+
close_source = True
1245+
else:
12421246
close_source = False
1247+
1248+
def iterator(source):
12431249
try:
1244-
if not hasattr(source, "read"):
1245-
source = open(source, "rb")
1246-
close_source = True
1247-
yield None
12481250
while True:
12491251
yield from pullparser.read_events()
12501252
# load event buffer
@@ -1254,18 +1256,23 @@ def iterator(source):
12541256
pullparser.feed(data)
12551257
root = pullparser._close_and_return_root()
12561258
yield from pullparser.read_events()
1257-
it.root = root
1259+
it = wr()
1260+
if it is not None:
1261+
it.root = root
12581262
finally:
12591263
if close_source:
12601264
source.close()
12611265

12621266
class IterParseIterator(collections.abc.Iterator):
12631267
__next__ = iterator(source).__next__
1264-
it = IterParseIterator()
1265-
it.root = None
1266-
del iterator, IterParseIterator
12671268

1268-
next(it)
1269+
def __del__(self):
1270+
if close_source:
1271+
source.close()
1272+
1273+
it = IterParseIterator()
1274+
wr = weakref.ref(it)
1275+
del IterParseIterator
12691276
return it
12701277

12711278

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Avoid reference cycle in ElementTree.iterparse. The iterator returned by
2+
``ElementTree.iterparse`` may hold on to a file descriptor. The reference
3+
cycle prevented prompt clean-up of the file descriptor if the returned
4+
iterator was not exhausted.

0 commit comments

Comments
 (0)