Skip to content

Commit 7a58862

Browse files
bpo-43650: Fix MemoryError on zip.read in shutil._unpack_zipfile for large files (GH-25058) (GH-26190)
`shutil.unpack_archive()` tries to read the whole file into memory, making no use of any kind of smaller buffer. Process crashes for really large files: I.e. archive: ~1.7G, unpacked: ~10G. Before the crash it can easily take away all available RAM on smaller systems. Had to pull the code form `zipfile.Zipfile.extractall()` to fix this Automerge-Triggered-By: GH:gpshead (cherry picked from commit f32c795) Co-authored-by: Igor Bolshakov <[email protected]>
1 parent 60fa8b3 commit 7a58862

File tree

2 files changed

+8
-10
lines changed

2 files changed

+8
-10
lines changed

Lib/shutil.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,20 +1161,16 @@ def _unpack_zipfile(filename, extract_dir):
11611161
if name.startswith('/') or '..' in name:
11621162
continue
11631163

1164-
target = os.path.join(extract_dir, *name.split('/'))
1165-
if not target:
1164+
targetpath = os.path.join(extract_dir, *name.split('/'))
1165+
if not targetpath:
11661166
continue
11671167

1168-
_ensure_directory(target)
1168+
_ensure_directory(targetpath)
11691169
if not name.endswith('/'):
11701170
# file
1171-
data = zip.read(info.filename)
1172-
f = open(target, 'wb')
1173-
try:
1174-
f.write(data)
1175-
finally:
1176-
f.close()
1177-
del data
1171+
with zip.open(name, 'r') as source, \
1172+
open(targetpath, 'wb') as target:
1173+
copyfileobj(source, target)
11781174
finally:
11791175
zip.close()
11801176

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :exc:`MemoryError` in :func:`shutil.unpack_archive` which fails inside
2+
:func:`shutil._unpack_zipfile` on large files. Patch by Igor Bolshakov.

0 commit comments

Comments
 (0)