gh-86768: Raise OSError when seeking a pipe on Windows (GH-133137) · python/cpython@d65bf51 · GitHub
Skip to content

Commit d65bf51

Browse files
gh-86768: Raise OSError when seeking a pipe on Windows (GH-133137)
Previously os.lseek() and file seek() silently succeeded for pipes, and seekable() wrongly returned True. Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent 4b04d5a commit d65bf51

6 files changed

Lines changed: 40 additions & 5 deletions

File tree

Doc/whatsnew/3.16.rst

Lines changed: 7 additions & 0 deletions

Lib/test/test_os/test_os.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2993,6 +2993,14 @@ def test_ftruncate(self):
29932993
def test_lseek(self):
29942994
self.check(os.lseek, 0, 0)
29952995

2996+
@unittest.skipUnless(hasattr(os, 'lseek'), 'test needs os.lseek()')
2997+
@unittest.skipUnless(hasattr(os, 'pipe'), "need os.pipe()")
2998+
def test_lseek_on_pipe(self):
2999+
rfd, wfd = os.pipe()
3000+
self.addCleanup(os.close, rfd)
3001+
self.addCleanup(os.close, wfd)
3002+
self.assertRaises(OSError, os.lseek, rfd, 123, os.SEEK_END)
3003+
29963004
@unittest.skipUnless(hasattr(os, 'read'), 'test needs os.read()')
29973005
def test_read(self):
29983006
self.check(os.read, 1)

Lib/test/test_winapi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def test_namedpipe(self):
152152
# Pipe instance is available, so this passes
153153
_winapi.WaitNamedPipe(pipe_name, 0)
154154

155-
with open(pipe_name, 'w+b') as pipe2:
155+
with open(pipe_name, 'w+b', buffering=0) as pipe2:
156156
# No instances available, so this times out
157157
# (WinError 121 does not get mapped to TimeoutError)
158158
with self.assertRaises(OSError):
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
:func:`os.lseek` and :meth:`~io.IOBase.seek` of file objects now raise
2+
:exc:`OSError` for pipes on Windows, and :meth:`~io.IOBase.seekable` now
3+
returns ``False`` for them. Previously seeking a pipe silently appeared to
4+
succeed. As a consequence, opening a pipe in a read-write binary mode
5+
(``'r+b'`` or ``'w+b'``) now raises :exc:`io.UnsupportedOperation` unless
6+
buffering is disabled.

Modules/_io/fileio.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,14 @@ portable_lseek(fileio *self, PyObject *posobj, int whence, bool suppress_pipe_er
992992
Py_BEGIN_ALLOW_THREADS
993993
_Py_BEGIN_SUPPRESS_IPH
994994
#ifdef MS_WINDOWS
995-
res = _lseeki64(fd, pos, whence);
995+
HANDLE h = (HANDLE)_get_osfhandle(fd);
996+
if (h != INVALID_HANDLE_VALUE && GetFileType(h) == FILE_TYPE_PIPE) {
997+
res = -1;
998+
errno = ESPIPE;
999+
}
1000+
else {
1001+
res = _lseeki64(fd, pos, whence);
1002+
}
9961003
#else
9971004
res = lseek(fd, pos, whence);
9981005
#endif

Modules/posixmodule.c

Lines changed: 10 additions & 3 deletions

0 commit comments

Comments
 (0)