Unverified Kaydet (Commit) 3c0a5a7c authored tarafından Miss Islington (bot)'s avatar Miss Islington (bot) Kaydeden (comit) GitHub

bpo-32056: Improve exceptions in aifc, wave and sunau. (GH-5951)

(cherry picked from commit 134cb01c)
Co-authored-by: 's avatarSerhiy Storchaka <storchaka@gmail.com>
üst fdd8e8b4
...@@ -467,6 +467,10 @@ class Aifc_read: ...@@ -467,6 +467,10 @@ class Aifc_read:
self._nframes = _read_long(chunk) self._nframes = _read_long(chunk)
self._sampwidth = (_read_short(chunk) + 7) // 8 self._sampwidth = (_read_short(chunk) + 7) // 8
self._framerate = int(_read_float(chunk)) self._framerate = int(_read_float(chunk))
if self._sampwidth <= 0:
raise Error('bad sample width')
if self._nchannels <= 0:
raise Error('bad # of channels')
self._framesize = self._nchannels * self._sampwidth self._framesize = self._nchannels * self._sampwidth
if self._aifc: if self._aifc:
#DEBUG: SGI's soundeditor produces a bad size :-( #DEBUG: SGI's soundeditor produces a bad size :-(
......
...@@ -208,6 +208,8 @@ class Au_read: ...@@ -208,6 +208,8 @@ class Au_read:
raise Error('unknown encoding') raise Error('unknown encoding')
self._framerate = int(_read_u32(file)) self._framerate = int(_read_u32(file))
self._nchannels = int(_read_u32(file)) self._nchannels = int(_read_u32(file))
if not self._nchannels:
raise Error('bad # of channels')
self._framesize = self._framesize * self._nchannels self._framesize = self._framesize * self._nchannels
if self._hdr_size > 24: if self._hdr_size > 24:
self._info = file.read(self._hdr_size - 24) self._info = file.read(self._hdr_size - 24)
......
...@@ -268,7 +268,8 @@ class AIFCLowLevelTest(unittest.TestCase): ...@@ -268,7 +268,8 @@ class AIFCLowLevelTest(unittest.TestCase):
def test_read_no_ssnd_chunk(self): def test_read_no_ssnd_chunk(self):
b = b'FORM' + struct.pack('>L', 4) + b'AIFC' b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
b += b'COMM' + struct.pack('>LhlhhLL', 38, 0, 0, 0, 0, 0, 0) b += b'COMM' + struct.pack('>LhlhhLL', 38, 1, 0, 8,
0x4000 | 12, 11025<<18, 0)
b += b'NONE' + struct.pack('B', 14) + b'not compressed' + b'\x00' b += b'NONE' + struct.pack('B', 14) + b'not compressed' + b'\x00'
with self.assertRaisesRegex(aifc.Error, 'COMM chunk and/or SSND chunk' with self.assertRaisesRegex(aifc.Error, 'COMM chunk and/or SSND chunk'
' missing'): ' missing'):
...@@ -276,13 +277,35 @@ class AIFCLowLevelTest(unittest.TestCase): ...@@ -276,13 +277,35 @@ class AIFCLowLevelTest(unittest.TestCase):
def test_read_wrong_compression_type(self): def test_read_wrong_compression_type(self):
b = b'FORM' + struct.pack('>L', 4) + b'AIFC' b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
b += b'COMM' + struct.pack('>LhlhhLL', 23, 0, 0, 0, 0, 0, 0) b += b'COMM' + struct.pack('>LhlhhLL', 23, 1, 0, 8,
0x4000 | 12, 11025<<18, 0)
b += b'WRNG' + struct.pack('B', 0) b += b'WRNG' + struct.pack('B', 0)
self.assertRaises(aifc.Error, aifc.open, io.BytesIO(b)) self.assertRaises(aifc.Error, aifc.open, io.BytesIO(b))
def test_read_wrong_number_of_channels(self):
for nchannels in 0, -1:
b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
b += b'COMM' + struct.pack('>LhlhhLL', 38, nchannels, 0, 8,
0x4000 | 12, 11025<<18, 0)
b += b'NONE' + struct.pack('B', 14) + b'not compressed' + b'\x00'
b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
with self.assertRaisesRegex(aifc.Error, 'bad # of channels'):
aifc.open(io.BytesIO(b))
def test_read_wrong_sample_width(self):
for sampwidth in 0, -1:
b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
b += b'COMM' + struct.pack('>LhlhhLL', 38, 1, 0, sampwidth,
0x4000 | 12, 11025<<18, 0)
b += b'NONE' + struct.pack('B', 14) + b'not compressed' + b'\x00'
b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
with self.assertRaisesRegex(aifc.Error, 'bad sample width'):
aifc.open(io.BytesIO(b))
def test_read_wrong_marks(self): def test_read_wrong_marks(self):
b = b'FORM' + struct.pack('>L', 4) + b'AIFF' b = b'FORM' + struct.pack('>L', 4) + b'AIFF'
b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) b += b'COMM' + struct.pack('>LhlhhLL', 18, 1, 0, 8,
0x4000 | 12, 11025<<18, 0)
b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
b += b'MARK' + struct.pack('>LhB', 3, 1, 1) b += b'MARK' + struct.pack('>LhB', 3, 1, 1)
with self.assertWarns(UserWarning) as cm: with self.assertWarns(UserWarning) as cm:
...@@ -293,7 +316,8 @@ class AIFCLowLevelTest(unittest.TestCase): ...@@ -293,7 +316,8 @@ class AIFCLowLevelTest(unittest.TestCase):
def test_read_comm_kludge_compname_even(self): def test_read_comm_kludge_compname_even(self):
b = b'FORM' + struct.pack('>L', 4) + b'AIFC' b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) b += b'COMM' + struct.pack('>LhlhhLL', 18, 1, 0, 8,
0x4000 | 12, 11025<<18, 0)
b += b'NONE' + struct.pack('B', 4) + b'even' + b'\x00' b += b'NONE' + struct.pack('B', 4) + b'even' + b'\x00'
b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
with self.assertWarns(UserWarning) as cm: with self.assertWarns(UserWarning) as cm:
...@@ -303,7 +327,8 @@ class AIFCLowLevelTest(unittest.TestCase): ...@@ -303,7 +327,8 @@ class AIFCLowLevelTest(unittest.TestCase):
def test_read_comm_kludge_compname_odd(self): def test_read_comm_kludge_compname_odd(self):
b = b'FORM' + struct.pack('>L', 4) + b'AIFC' b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) b += b'COMM' + struct.pack('>LhlhhLL', 18, 1, 0, 8,
0x4000 | 12, 11025<<18, 0)
b += b'NONE' + struct.pack('B', 3) + b'odd' b += b'NONE' + struct.pack('B', 3) + b'odd'
b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
with self.assertWarns(UserWarning) as cm: with self.assertWarns(UserWarning) as cm:
......
import unittest import unittest
from test import audiotests from test import audiotests
from audioop import byteswap from audioop import byteswap
import io
import struct
import sys import sys
import sunau import sunau
...@@ -121,5 +123,40 @@ class SunauMiscTests(audiotests.AudioMiscTests, unittest.TestCase): ...@@ -121,5 +123,40 @@ class SunauMiscTests(audiotests.AudioMiscTests, unittest.TestCase):
module = sunau module = sunau
class SunauLowLevelTest(unittest.TestCase):
def test_read_bad_magic_number(self):
b = b'SPA'
with self.assertRaises(EOFError):
sunau.open(io.BytesIO(b))
b = b'SPAM'
with self.assertRaisesRegex(sunau.Error, 'bad magic number'):
sunau.open(io.BytesIO(b))
def test_read_too_small_header(self):
b = struct.pack('>LLLLL', sunau.AUDIO_FILE_MAGIC, 20, 0,
sunau.AUDIO_FILE_ENCODING_LINEAR_8, 11025)
with self.assertRaisesRegex(sunau.Error, 'header size too small'):
sunau.open(io.BytesIO(b))
def test_read_too_large_header(self):
b = struct.pack('>LLLLLL', sunau.AUDIO_FILE_MAGIC, 124, 0,
sunau.AUDIO_FILE_ENCODING_LINEAR_8, 11025, 1)
b += b'\0' * 100
with self.assertRaisesRegex(sunau.Error, 'header size ridiculously large'):
sunau.open(io.BytesIO(b))
def test_read_wrong_encoding(self):
b = struct.pack('>LLLLLL', sunau.AUDIO_FILE_MAGIC, 24, 0, 0, 11025, 1)
with self.assertRaisesRegex(sunau.Error, r'encoding not \(yet\) supported'):
sunau.open(io.BytesIO(b))
def test_read_wrong_number_of_channels(self):
b = struct.pack('>LLLLLL', sunau.AUDIO_FILE_MAGIC, 24, 0,
sunau.AUDIO_FILE_ENCODING_LINEAR_8, 11025, 0)
with self.assertRaisesRegex(sunau.Error, 'bad # of channels'):
sunau.open(io.BytesIO(b))
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()
...@@ -2,6 +2,8 @@ import unittest ...@@ -2,6 +2,8 @@ import unittest
from test import audiotests from test import audiotests
from test import support from test import support
from audioop import byteswap from audioop import byteswap
import io
import struct
import sys import sys
import wave import wave
...@@ -111,5 +113,65 @@ class MiscTestCase(audiotests.AudioMiscTests, unittest.TestCase): ...@@ -111,5 +113,65 @@ class MiscTestCase(audiotests.AudioMiscTests, unittest.TestCase):
support.check__all__(self, wave, blacklist=blacklist) support.check__all__(self, wave, blacklist=blacklist)
class WaveLowLevelTest(unittest.TestCase):
def test_read_no_chunks(self):
b = b'SPAM'
with self.assertRaises(EOFError):
wave.open(io.BytesIO(b))
def test_read_no_riff_chunk(self):
b = b'SPAM' + struct.pack('<L', 0)
with self.assertRaisesRegex(wave.Error,
'file does not start with RIFF id'):
wave.open(io.BytesIO(b))
def test_read_not_wave(self):
b = b'RIFF' + struct.pack('<L', 4) + b'SPAM'
with self.assertRaisesRegex(wave.Error,
'not a WAVE file'):
wave.open(io.BytesIO(b))
def test_read_no_fmt_no_data_chunk(self):
b = b'RIFF' + struct.pack('<L', 4) + b'WAVE'
with self.assertRaisesRegex(wave.Error,
'fmt chunk and/or data chunk missing'):
wave.open(io.BytesIO(b))
def test_read_no_data_chunk(self):
b = b'RIFF' + struct.pack('<L', 28) + b'WAVE'
b += b'fmt ' + struct.pack('<LHHLLHH', 16, 1, 1, 11025, 11025, 1, 8)
with self.assertRaisesRegex(wave.Error,
'fmt chunk and/or data chunk missing'):
wave.open(io.BytesIO(b))
def test_read_no_fmt_chunk(self):
b = b'RIFF' + struct.pack('<L', 12) + b'WAVE'
b += b'data' + struct.pack('<L', 0)
with self.assertRaisesRegex(wave.Error, 'data chunk before fmt chunk'):
wave.open(io.BytesIO(b))
def test_read_wrong_form(self):
b = b'RIFF' + struct.pack('<L', 36) + b'WAVE'
b += b'fmt ' + struct.pack('<LHHLLHH', 16, 2, 1, 11025, 11025, 1, 1)
b += b'data' + struct.pack('<L', 0)
with self.assertRaisesRegex(wave.Error, 'unknown format: 2'):
wave.open(io.BytesIO(b))
def test_read_wrong_number_of_channels(self):
b = b'RIFF' + struct.pack('<L', 36) + b'WAVE'
b += b'fmt ' + struct.pack('<LHHLLHH', 16, 1, 0, 11025, 11025, 1, 8)
b += b'data' + struct.pack('<L', 0)
with self.assertRaisesRegex(wave.Error, 'bad # of channels'):
wave.open(io.BytesIO(b))
def test_read_wrong_sample_width(self):
b = b'RIFF' + struct.pack('<L', 36) + b'WAVE'
b += b'fmt ' + struct.pack('<LHHLLHH', 16, 1, 1, 11025, 11025, 1, 0)
b += b'data' + struct.pack('<L', 0)
with self.assertRaisesRegex(wave.Error, 'bad sample width'):
wave.open(io.BytesIO(b))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -253,12 +253,22 @@ class Wave_read: ...@@ -253,12 +253,22 @@ class Wave_read:
# #
def _read_fmt_chunk(self, chunk): def _read_fmt_chunk(self, chunk):
wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack_from('<HHLLH', chunk.read(14)) try:
wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack_from('<HHLLH', chunk.read(14))
except struct.error:
raise EOFError from None
if wFormatTag == WAVE_FORMAT_PCM: if wFormatTag == WAVE_FORMAT_PCM:
sampwidth = struct.unpack_from('<H', chunk.read(2))[0] try:
sampwidth = struct.unpack_from('<H', chunk.read(2))[0]
except struct.error:
raise EOFError from None
self._sampwidth = (sampwidth + 7) // 8 self._sampwidth = (sampwidth + 7) // 8
if not self._sampwidth:
raise Error('bad sample width')
else: else:
raise Error('unknown format: %r' % (wFormatTag,)) raise Error('unknown format: %r' % (wFormatTag,))
if not self._nchannels:
raise Error('bad # of channels')
self._framesize = self._nchannels * self._sampwidth self._framesize = self._nchannels * self._sampwidth
self._comptype = 'NONE' self._comptype = 'NONE'
self._compname = 'not compressed' self._compname = 'not compressed'
......
Improved exceptions raised for invalid number of channels and sample width
when read an audio file in modules :mod:`aifc`, :mod:`wave` and
:mod:`sunau`.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment