From ff3f783112ce57cc57284b8cad22df06c688f234 Mon Sep 17 00:00:00 2001 From: "Michiel W. Beijen" Date: Wed, 25 Feb 2026 23:13:26 +0100 Subject: [PATCH] gh-117716: Fix wave RIFF padding for data chunks wave.Wave_write now writes the required RIFF pad byte when the data chunk size is odd. Update RIFF chunk size calculations in both header writing and header patching so they include the alignment pad byte when present. Add a regression test in test_wave.py that verifies odd-sized writes are padded, RIFF size is correct, and roundtrip reads preserve frame data. --- Lib/test/test_wave.py | 24 +++++++++++++++++++ Lib/wave.py | 6 +++-- ...-02-25-22-20-00.gh-issue-117716.w6kYp9.rst | 1 + 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-02-25-22-20-00.gh-issue-117716.w6kYp9.rst diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index 86886ac768f6d2..d3723c04820d9d 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -430,6 +430,30 @@ def test_setframerate_rounds(self, arg, expected): f.setframerate(arg) self.assertEqual(f.getframerate(), expected) + def test_write_odd_data_chunk_pads_and_updates_riff_size(self): + # gh-117716: odd-sized data chunks must be padded with one zero byte. + with io.BytesIO() as output: + with wave.open(output, mode='wb') as w: + w.setnchannels(1) + w.setsampwidth(1) + w.setframerate(48000) + w.writeframes(b'\x80') + + value = output.getvalue() + + self.assertEqual(value[-1], 0) + self.assertEqual( + int.from_bytes(value[4:8], byteorder='little'), + 38, + ) + + with wave.open(io.BytesIO(value), mode='rb') as r: + self.assertEqual(r.getnchannels(), 1) + self.assertEqual(r.getsampwidth(), 1) + self.assertEqual(r.getframerate(), 48000) + self.assertEqual(r.getnframes(), 1) + self.assertEqual(r.readframes(-1), b'\x80') + class WaveOpen(unittest.TestCase): def test_open_pathlike(self): diff --git a/Lib/wave.py b/Lib/wave.py index 6e84c107b9fb20..c4e1a493a7ec7f 100644 --- a/Lib/wave.py +++ b/Lib/wave.py @@ -611,6 +611,8 @@ def close(self): try: if self._file: self._ensure_header_written(0) + if self._datawritten & 1: + self._file.write(b'\x00') if self._datalength != self._datawritten: self._patchheader() self._file.flush() @@ -651,7 +653,7 @@ def _write_header(self, initlength): has_fact = self._needs_fact_chunk() header_overhead = 36 + (12 if has_fact else 0) self._file.write(struct.pack('