Skip to content

Commit c9cb89d

Browse files
Uberimethane
authored andcommitted
bpo-29110: Fix file object leak in aifc.open when given invalid AIFF file. (GH-162)
(cherry picked from commit 03f68b6)
1 parent 4c78463 commit c9cb89d

File tree

3 files changed

+33
-13
lines changed

3 files changed

+33
-13
lines changed

Lib/aifc.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,15 @@ def initfp(self, file):
335335

336336
def __init__(self, f):
337337
if isinstance(f, str):
338-
f = builtins.open(f, 'rb')
339-
# else, assume it is an open file object already
340-
self.initfp(f)
338+
file_object = builtins.open(f, 'rb')
339+
try:
340+
self.initfp(file_object)
341+
except:
342+
file_object.close()
343+
raise
344+
else:
345+
# assume it is an open file object already
346+
self.initfp(f)
341347

342348
def __enter__(self):
343349
return self
@@ -534,16 +540,19 @@ class Aifc_write:
534540

535541
def __init__(self, f):
536542
if isinstance(f, str):
537-
filename = f
538-
f = builtins.open(f, 'wb')
539-
else:
540-
# else, assume it is an open file object already
541-
filename = '???'
542-
self.initfp(f)
543-
if filename[-5:] == '.aiff':
544-
self._aifc = 0
543+
file_object = builtins.open(f, 'wb')
544+
try:
545+
self.initfp(file_object)
546+
except:
547+
file_object.close()
548+
raise
549+
550+
# treat .aiff file extensions as non-compressed audio
551+
if f.endswith('.aiff'):
552+
self._aifc = 0
545553
else:
546-
self._aifc = 1
554+
# assume it is an open file object already
555+
self.initfp(f)
547556

548557
def initfp(self, file):
549558
self._file = file

Lib/test/test_aifc.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from test.support import findfile, TESTFN, unlink
1+
from test.support import check_no_resource_warning, findfile, TESTFN, unlink
22
import unittest
33
from test import audiotests
44
from audioop import byteswap
@@ -150,6 +150,14 @@ def test_skipunknown(self):
150150
#This file contains chunk types aifc doesn't recognize.
151151
self.f = aifc.open(findfile('Sine-1000Hz-300ms.aif'))
152152

153+
def test_close_opened_files_on_error(self):
154+
non_aifc_file = findfile('pluck-pcm8.wav', subdir='audiodata')
155+
with check_no_resource_warning(self):
156+
with self.assertRaises(aifc.Error):
157+
# Try opening a non-AIFC file, with the expectation that
158+
# `aifc.open` will fail (without raising a ResourceWarning)
159+
f = self.f = aifc.open(non_aifc_file, 'rb')
160+
153161
def test_params_added(self):
154162
f = self.f = aifc.open(TESTFN, 'wb')
155163
f.aiff()

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ Extension Modules
3232
Library
3333
-------
3434

35+
- bpo-29110: Fix file object leak in aifc.open() when file is given as a
36+
filesystem path and is not in valid AIFF format. Patch by Anthony Zhang.
37+
3538
- bpo-29532: Altering a kwarg dictionary passed to functools.partial()
3639
no longer affects a partial object after creation.
3740

0 commit comments

Comments
 (0)