Skip to content

Commit cdabbc1

Browse files
gpsheadsrittau
andauthored
[3.13] gh-122179: Fix hashlib.file_digest and non-blocking I/O (GH-132787)
gh-122179: Fix hashlib.file_digest and non-blocking I/O (GH-122183) * Fix hashlib.file_digest and non-blocking I/O * Add documentation around this behavior * Add versionchanged (cherry picked from commit 2b47f46) Co-authored-by: Sebastian Rittau <[email protected]>
1 parent bb59fde commit cdabbc1

File tree

4 files changed

+22
-1
lines changed

4 files changed

+22
-1
lines changed

Doc/library/hashlib.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,10 @@ a file or file-like object.
270270
*fileobj* must be a file-like object opened for reading in binary mode.
271271
It accepts file objects from builtin :func:`open`, :class:`~io.BytesIO`
272272
instances, SocketIO objects from :meth:`socket.socket.makefile`, and
273-
similar. The function may bypass Python's I/O and use the file descriptor
273+
similar. *fileobj* must be opened in blocking mode, otherwise a
274+
:exc:`BlockingIOError` may be raised.
275+
276+
The function may bypass Python's I/O and use the file descriptor
274277
from :meth:`~io.IOBase.fileno` directly. *fileobj* must be assumed to be
275278
in an unknown state after this function returns or raises. It is up to
276279
the caller to close *fileobj*.
@@ -299,6 +302,10 @@ a file or file-like object.
299302

300303
.. versionadded:: 3.11
301304

305+
.. versionchanged:: next
306+
Now raises a :exc:`BlockingIOError` if the file is opened in blocking
307+
mode. Previously, spurious null bytes were added to the digest.
308+
302309

303310
Key derivation
304311
--------------

Lib/hashlib.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ def file_digest(fileobj, digest, /, *, _bufsize=2**18):
231231
view = memoryview(buf)
232232
while True:
233233
size = fileobj.readinto(buf)
234+
if size is None:
235+
raise BlockingIOError("I/O operation would block.")
234236
if size == 0:
235237
break # EOF
236238
digestobj.update(view[:size])

Lib/test/test_hashlib.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,15 @@ def test_file_digest(self):
11901190
with open(os_helper.TESTFN, "wb") as f:
11911191
hashlib.file_digest(f, "sha256")
11921192

1193+
class NonBlocking:
1194+
def readinto(self, buf):
1195+
return None
1196+
def readable(self):
1197+
return True
1198+
1199+
with self.assertRaises(BlockingIOError):
1200+
hashlib.file_digest(NonBlocking(), hashlib.sha256)
1201+
11931202

11941203
if __name__ == "__main__":
11951204
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:func:`hashlib.file_digest` now raises :exc:`BlockingIOError` when no data
2+
is available during non-blocking I/O. Before, it added spurious null bytes
3+
to the digest.

0 commit comments

Comments
 (0)