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('