Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-129726: Breakgzip.GzipFile reference loop#130055

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
vstinner merged 3 commits intopython:mainfromcmaloney:gh-129796-gzipclose
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletionLib/gzip.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,7 @@
import builtins
import io
import _compression
import weakref
Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

the ordering of imports here is painful to me, but resisted bringing to PEP8 because this fix needs backporting.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Please reformat these imports for PEP 8 :-) I will handle merge conflicts on backports if needed.

cmaloney reacted with thumbs up emoji

__all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"]

Expand DownExpand Up@@ -226,7 +227,8 @@ def __init__(self, filename=None, mode=None,
0)
self._write_mtime = mtime
self._buffer_size = _WRITE_BUFFER_SIZE
self._buffer = io.BufferedWriter(_WriteBufferStream(self),
write_wrap = _WriteBufferStream(weakref.proxy(self))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Would it be possible to modify _WriteBufferStream to use a simpler weakref.ref() to store gzip_file instead? This object is private so we can change its API.

Something like:

class_WriteBufferStream(io.RawIOBase):"""Minimal object to pass WriteBuffer flushes into GzipFile"""def__init__(self,gzip_file):self.gzip_file=weakref.ref(gzip_file)defwrite(self,data):gzip_file=self.gzip_file()ifgzip_fileisNone:raiseRuntimeError("lost gzip_file")returngzip_file._write_raw(data)

cmaloney reacted with eyes emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Updated to your suggestion here. I Spent a bit of time trying to remove_WriteBufferStream andjust useweakref.proxy, but getting soGzipFile.write has a differentwrite function from the underlyingself._buffer: BufferedWriter (which needs to useself._write_raw) led me in a lot of circles. More understandable for things I tried to just keep_WriteBufferStream.

self._buffer = io.BufferedWriter(write_wrap,
buffer_size=self._buffer_size)
else:
raise ValueError("Invalid mode: {!r}".format(mode))
Expand Down
13 changes: 13 additions & 0 deletionsLib/test/test_gzip.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,12 +3,14 @@

import array
import functools
import gc
import io
import os
import struct
import sys
import unittest
from subprocess import PIPE, Popen
from test.support import catch_unraisable_exception
from test.support import import_helper
from test.support import os_helper
from test.support import _4G, bigmemtest, requires_subprocess
Expand DownExpand Up@@ -859,6 +861,17 @@ def test_write_seek_write(self):
self.assertEqual(gzip.decompress(data), message * 2)


def test_refloop_unraisable(self):
# Ensure a GzipFile referring to a temporary fileobj deletes cleanly.
# Previously an unraisable exception would occur on close because the
# fileobj would be closed before the GzipFile as the result of a
# reference loop. See issue gh-129726
with catch_unraisable_exception() as cm:
gzip.GzipFile(fileobj=io.BytesIO(), mode="w")
gc.collect()
self.assertIsNone(cm.unraisable)


class TestOpen(BaseTest):
def test_binary_modes(self):
uncompressed = data1 * 50
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
Fix :class:`gzip.GzipFile` raising an unraisable exception during garbage
collection when referring to a temporary object by breaking the reference
loop with :mod:`weakref`.
Loading

[8]ページ先頭

©2009-2025 Movatter.jp