apport ftbfs with Python 3.12 as the default

Bug #2051512 reported by Matthias Klose
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Apport
Fix Released
High
Unassigned
apport (Ubuntu)
Fix Released
High
Unassigned
Noble
Fix Released
High
Unassigned
python3-defaults (Ubuntu)
New
Undecided
Unassigned
Noble
New
Undecided
Unassigned
python3.12 (Ubuntu)
New
Undecided
Unassigned
Noble
New
Undecided
Unassigned

Bug Description

[Description]

Python 3.12 gzip.GZipFile.write() outputs truncated data in some cases (maybe all?)

[Test Plan]

Run the following script:

import gzip
import io
out = io.BytesIO()
gzip.GzipFile("foo", mode="wb", fileobj=out, mtime=0).write(b"FooFoo")
# print(out.getvalue())
print(gzip.decompress(out.getvalue()))

Expected output (as on Python 3.11):
FooFoo

Buggy output (tail end of the stack trace):
EOFError: Compressed file ended before the end-of-stream marker was reached

[Original report]

debian/rules override_dh_auto_test
make[1]: Entering directory '/<<PKGBUILDDIR>>'
tests/run-linters --errors-only
Skipping mypy tests, mypy is not installed
Running pylint...
************* Module apport-retrace
bin/apport-retrace:577:44: E0601: Using variable 'crashid' before assignment (used-before-assignment)
make[1]: *** [debian/rules:23: override_dh_auto_test] Error 2
make[1]: Leaving directory '/<<PKGBUILDDIR>>'
make: *** [debian/rules:4: binary] Error 2

Related branches

Matthias Klose (doko)
Changed in apport (Ubuntu):
status: New → Confirmed
importance: Undecided → High
tags: added: ftbfs rls-nn-incoming
Revision history for this message
Vladimir Petko (vpa1977) wrote :
Download full text (32.3 KiB)

After fixing uninitialized variable or ignoring linter, the following test failures occur:

=================================== FAILURES ===================================
_________________________ TestApportUnpack.test_unpack _________________________

self = <tests.integration.test_apport_unpack.TestApportUnpack testMethod=test_unpack>

    def test_unpack(self):
        """apport-unpack for all possible data types"""
        process = self._call_apport_unpack([self.report_file, self.unpack_dir])
        self.assertEqual(process.returncode, 0)
        self.assertEqual(process.stderr, "")
        self.assertEqual(process.stdout, "")

        self.assertEqual(self._get_unpack("utf8"), self.utf8_str)
        self.assertEqual(self._get_unpack("unicode"), self.utf8_str)
        self.assertEqual(self._get_unpack("binary"), self.bindata)
> self.assertEqual(self._get_unpack("compressed"), b"FooFoo!")
E AssertionError: b'' != b'FooFoo!'

tests/integration/test_apport_unpack.py:65: AssertionError
___________________________ T.test_compressed_values ___________________________

self = <tests.integration.test_problem_report.T testMethod=test_compressed_values>

    def test_compressed_values(self):
        """Handle of CompressedValue values."""
        large_val = b"A" * 5000000

        pr = problem_report.ProblemReport()
        pr["Foo"] = problem_report.CompressedValue(b"FooFoo!")
        pr["Bin"] = problem_report.CompressedValue()
        pr["Bin"].set_value(bin_data)
        pr["Large"] = problem_report.CompressedValue(large_val)

        self.assertTrue(isinstance(pr["Foo"], problem_report.CompressedValue))
        self.assertTrue(isinstance(pr["Bin"], problem_report.CompressedValue))
> self.assertEqual(pr["Foo"].get_value(), b"FooFoo!")

tests/integration/test_problem_report.py:42:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
problem_report.py:79: in get_value
    return gzip.GzipFile(fileobj=io.BytesIO(self.gzipvalue)).read()
/usr/lib/python3.12/gzip.py:324: in read
    return self._buffer.read(size)
/usr/lib/python3.12/_compression.py:118: in readall
    while data := self.read(sys.maxsize):
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <gzip._GzipReader object at 0x7f287a41e260>, size = 9223372036854775807

    def read(self, size=-1):
        if size < 0:
            return self.readall()
        # size=0 is special because decompress(max_length=0) is not supported
        if not size:
            return b""

        # For certain input data, a single
        # call to decompress() may not return
        # any data. In this case, retry until we get some data or reach EOF.
        while True:
            if self._decompressor.eof:
                # Ending case: we've come to the end of a member in the file,
                # so finish up this member, and read a new gzip header.
                # Check the CRC and file size, and set the flag so we read
                # a new member
                self._read_eof()
                self._new_member = True
                self._decompressor = self._decomp_factory(
              ...

tags: added: update-excuse
tags: added: foundations-todo
removed: rls-nn-incoming
Simon Chopin (schopin)
description: updated
Revision history for this message
Simon Chopin (schopin) wrote :

After further investigations into the gzip issue in python 3.12, it turns out there was an undocumented change: it is now a buffered writer. So the fire&forget pattern used in the snippet above doesn't work anymore, we now need to use it as a proper IO object instead.

I still think this should be reported upstream because of the documentation issue, but I'll work on changing the apport code to Do The Right Thing.

Revision history for this message
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package apport - 2.27.0-0ubuntu7

---------------
apport (2.27.0-0ubuntu7) noble; urgency=medium

  [ Benjamin Drung ]
  * Rely on pybuild in dh_auto_* targets
  * Introduce the separate apport-core-dump-handler package that registers as
    kernel crash dump handler. This is needed for the upcoming systemd-coredump
    support.
  * Move systemd units from /lib to /usr/lib

  [ Simon Chopin ]
  * Rework apport-retrace to handle unbound crashid (LP: #2051512)
  * fix: use context manager when manipulating GzipFiles (LP: #2051512)

 -- Benjamin Drung <email address hidden> Wed, 14 Feb 2024 16:51:44 +0100

Changed in apport (Ubuntu Noble):
status: Confirmed → Fix Released
Benjamin Drung (bdrung)
Changed in apport:
milestone: none → 2.28.0
status: New → Fix Committed
importance: Undecided → High
Benjamin Drung (bdrung)
Changed in apport:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.