Skip to content

Commit 36628f2

Browse files
committed
post-merge
1 parent b5b7922 commit 36628f2

File tree

8 files changed

+333
-138
lines changed

8 files changed

+333
-138
lines changed

Lib/hashlib.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@
8080
}
8181

8282
def __get_builtin_constructor(name):
83+
if not isinstance(name, str):
84+
# Since this function is only used by new(), we use the same
85+
# exception as _hashlib.new() when 'name' is of incorrect type.
86+
err = f"new() argument 'name' must be str, not {type(name).__name__}"
87+
raise TypeError(err)
8388
cache = __builtin_constructor_cache
8489
constructor = cache.get(name)
8590
if constructor is not None:
@@ -120,10 +125,13 @@ def __get_builtin_constructor(name):
120125
if constructor is not None:
121126
return constructor
122127

123-
raise ValueError('unsupported hash type ' + name)
128+
# Keep the message in sync with hashlib.h::HASHLIB_UNSUPPORTED_ALGORITHM.
129+
raise ValueError(f'unsupported hash algorithm {name}')
124130

125131

126132
def __get_openssl_constructor(name):
133+
# This function is only used until the module has been initialized.
134+
assert isinstance(name, str), "invalid call to __get_openssl_constructor()"
127135
if name in __block_openssl_constructor:
128136
# Prefer our builtin blake2 implementation.
129137
return __get_builtin_constructor(name)
@@ -154,6 +162,8 @@ def __hash_new(name, *args, **kwargs):
154162
optionally initialized with data (which must be a bytes-like object).
155163
"""
156164
if name in __block_openssl_constructor:
165+
# __block_openssl_constructor is expected to contain strings only
166+
assert isinstance(name, str), f"unexpected name: {name}"
157167
# Prefer our builtin blake2 implementation.
158168
return __get_builtin_constructor(name)(*args, **kwargs)
159169
try:

Lib/hmac.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@
2626
digest_size = None
2727

2828

29+
def _is_shake_constructor(digest_like):
30+
if isinstance(digest_like, str):
31+
name = digest_like
32+
else:
33+
h = digest_like() if callable(digest_like) else digest_like.new()
34+
if not isinstance(name := getattr(h, "name", None), str):
35+
return False
36+
return name.startswith(("shake", "SHAKE"))
37+
38+
2939
def _get_digest_constructor(digest_like):
3040
if callable(digest_like):
3141
return digest_like
@@ -109,6 +119,8 @@ def _init_old(self, key, msg, digestmod):
109119
import warnings
110120

111121
digest_cons = _get_digest_constructor(digestmod)
122+
if _is_shake_constructor(digest_cons):
123+
raise ValueError(f"unsupported hash algorithm {digestmod}")
112124

113125
self._hmac = None
114126
self._outer = digest_cons()
@@ -243,6 +255,8 @@ def digest(key, msg, digest):
243255

244256
def _compute_digest_fallback(key, msg, digest):
245257
digest_cons = _get_digest_constructor(digest)
258+
if _is_shake_constructor(digest_cons):
259+
raise ValueError(f"unsupported hash algorithm {digest}")
246260
inner = digest_cons()
247261
outer = digest_cons()
248262
blocksize = getattr(inner, 'block_size', 64)

Lib/test/test_hashlib.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,9 @@ def test_clinic_signature_errors(self):
343343

344344
def test_unknown_hash(self):
345345
self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')
346-
self.assertRaises(TypeError, hashlib.new, 1)
346+
# ensure that the exception message remains consistent
347+
err = re.escape("new() argument 'name' must be str, not int")
348+
self.assertRaisesRegex(TypeError, err, hashlib.new, 1)
347349

348350
def test_new_upper_to_lower(self):
349351
self.assertEqual(hashlib.new("SHA256").name, "sha256")
@@ -370,7 +372,9 @@ def test_get_builtin_constructor(self):
370372
sys.modules['_md5'] = _md5
371373
else:
372374
del sys.modules['_md5']
373-
self.assertRaises(TypeError, get_builtin_constructor, 3)
375+
# ensure that the exception message remains consistent
376+
err = re.escape("new() argument 'name' must be str, not int")
377+
self.assertRaises(TypeError, err, get_builtin_constructor, 3)
374378
constructor = get_builtin_constructor('md5')
375379
self.assertIs(constructor, _md5.md5)
376380
self.assertEqual(sorted(builtin_constructor_cache), ['MD5', 'md5'])

Lib/test/test_hmac.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,7 @@ def raiser():
960960
with self.assertRaisesRegex(RuntimeError, "custom exception"):
961961
func(b'key', b'msg', raiser)
962962

963-
with self.assertRaisesRegex(ValueError, 'hash type'):
963+
with self.assertRaisesRegex(ValueError, 'unsupported hash algorithm'):
964964
func(b'key', b'msg', 'unknown')
965965

966966
with self.assertRaisesRegex(AttributeError, 'new'):

Lib/test/test_remote_pdb.py

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import unittest
1212
import unittest.mock
1313
from contextlib import closing, contextmanager, redirect_stdout, redirect_stderr, ExitStack
14-
from test.support import is_wasi, cpython_only, force_color, requires_subprocess, SHORT_TIMEOUT
14+
from test.support import is_wasi, cpython_only, force_color, requires_subprocess, SHORT_TIMEOUT, subTests
1515
from test.support.os_helper import TESTFN, unlink
1616
from typing import List
1717

@@ -279,37 +279,50 @@ def test_handling_other_message(self):
279279
expected_stdout="Some message.\n",
280280
)
281281

282-
def test_handling_help_for_command(self):
283-
"""Test handling a request to display help for a command."""
282+
@unittest.skipIf(sys.flags.optimize >= 2, "Help not available for -OO")
283+
@subTests(
284+
"help_request,expected_substring",
285+
[
286+
# a request to display help for a command
287+
({"help": "ll"}, "Usage: ll | longlist"),
288+
# a request to display a help overview
289+
({"help": ""}, "type help <topic>"),
290+
# a request to display the full PDB manual
291+
({"help": "pdb"}, ">>> import pdb"),
292+
],
293+
)
294+
def test_handling_help_when_available(self, help_request, expected_substring):
295+
"""Test handling help requests when help is available."""
284296
incoming = [
285-
("server", {"help": "ll"}),
297+
("server", help_request),
286298
]
287299
self.do_test(
288300
incoming=incoming,
289301
expected_outgoing=[],
290-
expected_stdout_substring="Usage: ll | longlist",
302+
expected_stdout_substring=expected_substring,
291303
)
292304

293-
def test_handling_help_without_a_specific_topic(self):
294-
"""Test handling a request to display a help overview."""
305+
@unittest.skipIf(sys.flags.optimize < 2, "Needs -OO")
306+
@subTests(
307+
"help_request,expected_substring",
308+
[
309+
# a request to display help for a command
310+
({"help": "ll"}, "No help for 'll'"),
311+
# a request to display a help overview
312+
({"help": ""}, "Undocumented commands"),
313+
# a request to display the full PDB manual
314+
({"help": "pdb"}, "No help for 'pdb'"),
315+
],
316+
)
317+
def test_handling_help_when_not_available(self, help_request, expected_substring):
318+
"""Test handling help requests when help is not available."""
295319
incoming = [
296-
("server", {"help": ""}),
320+
("server", help_request),
297321
]
298322
self.do_test(
299323
incoming=incoming,
300324
expected_outgoing=[],
301-
expected_stdout_substring="type help <topic>",
302-
)
303-
304-
def test_handling_help_pdb(self):
305-
"""Test handling a request to display the full PDB manual."""
306-
incoming = [
307-
("server", {"help": "pdb"}),
308-
]
309-
self.do_test(
310-
incoming=incoming,
311-
expected_outgoing=[],
312-
expected_stdout_substring=">>> import pdb",
325+
expected_stdout_substring=expected_substring,
313326
)
314327

315328
def test_handling_pdb_prompts(self):

0 commit comments

Comments
 (0)