Skip to content

Commit 47d2d92

Browse files
committed
Correctly handle closing a file descriptor
- could have closed the wrong fd - fixes #988
1 parent a1210c9 commit 47d2d92

File tree

3 files changed

+25
-9
lines changed

3 files changed

+25
-9
lines changed

pyfakefs/fake_file.py

+23-7
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,11 @@ def fileno(self) -> int:
845845

846846
def close(self) -> None:
847847
"""Close the file."""
848+
self.close_fd(self.filedes)
849+
850+
def close_fd(self, fd: Optional[int]) -> None:
851+
"""Close the file for the given file descriptor."""
852+
848853
# ignore closing a closed file
849854
if not self._is_open():
850855
return
@@ -864,11 +869,11 @@ def close(self) -> None:
864869
if self._filesystem.is_windows_fs and self._changed:
865870
self.file_object.st_mtime = helpers.now()
866871

867-
assert self.filedes is not None
872+
assert fd is not None
868873
if self._closefd:
869-
self._filesystem.close_open_file(self.filedes)
874+
self._filesystem.close_open_file(fd)
870875
else:
871-
open_files = self._filesystem.open_files[self.filedes]
876+
open_files = self._filesystem.open_files[fd]
872877
assert open_files is not None
873878
open_files.remove(self)
874879
if self.delete_on_close:
@@ -1256,6 +1261,9 @@ def read(self, n: int = -1) -> bytes:
12561261
def close(self) -> None:
12571262
"""We do not support closing standard streams."""
12581263

1264+
def close_fd(self, fd: Optional[int]) -> None:
1265+
"""We do not support closing standard streams."""
1266+
12591267
def is_stream(self) -> bool:
12601268
return True
12611269

@@ -1287,8 +1295,12 @@ def fileno(self) -> int:
12871295

12881296
def close(self) -> None:
12891297
"""Close the directory."""
1290-
assert self.filedes is not None
1291-
self._filesystem.close_open_file(self.filedes)
1298+
self.close_fd(self.filedes)
1299+
1300+
def close_fd(self, fd: Optional[int]) -> None:
1301+
"""Close the directory."""
1302+
assert fd is not None
1303+
self._filesystem.close_open_file(fd)
12921304

12931305

12941306
class FakePipeWrapper:
@@ -1351,8 +1363,12 @@ def write(self, contents: bytes) -> int:
13511363

13521364
def close(self) -> None:
13531365
"""Close the pipe descriptor."""
1354-
assert self.filedes is not None
1355-
open_files = self._filesystem.open_files[self.filedes]
1366+
self.close_fd(self.filedes)
1367+
1368+
def close_fd(self, fd: Optional[int]) -> None:
1369+
"""Close the pipe descriptor with the given file descriptor."""
1370+
assert fd is not None
1371+
open_files = self._filesystem.open_files[fd]
13561372
assert open_files is not None
13571373
open_files.remove(self)
13581374
if self.real_file:

pyfakefs/fake_os.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ def close(self, fd: int) -> None:
326326
TypeError: if file descriptor is not an integer.
327327
"""
328328
file_handle = self.filesystem.get_open_file(fd)
329-
file_handle.close()
329+
file_handle.close_fd(fd)
330330

331331
def dup(self, fd: int) -> int:
332332
file_handle = self.filesystem.get_open_file(fd)

pyfakefs/tests/fake_os_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3014,8 +3014,8 @@ def test_dup(self):
30143014
fd2 = self.os.dup(fd1)
30153015
self.assertEqual(b"hey", self.os.read(fd1, 3))
30163016
self.assertEqual(b"there", self.os.read(fd1, 10))
3017-
self.os.close(fd1)
30183017
self.os.close(fd2)
3018+
self.os.close(fd1)
30193019

30203020
def test_dup_uses_freed_fd(self):
30213021
file_path1 = self.make_path("foo.txt")

0 commit comments

Comments
 (0)