Skip to content

Commit 7d20c51

Browse files
Clear the padding in the key and fix the test on Windows
The key is hashed and compared as raw bytes, so the uninitialized padding of the header made lookups miss at random. Import the extension module in a subprocess: it stays loaded, and on Windows its file cannot be removed, so the temporary directory leaked.
1 parent faa4640 commit 7d20c51

2 files changed

Lines changed: 24 additions & 22 deletions

File tree

Lib/test/test_import/__init__.py

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import stat
2121
import subprocess
2222
import sys
23-
import tempfile
2423
import textwrap
2524
import threading
2625
import time
@@ -1271,27 +1270,28 @@ def test_import_from_undecodable_path(self):
12711270
# gh-155247: the path of the extension module is not encodable
12721271
# in UTF-8.
12731272
origin = _testsinglephase.__file__
1274-
# The module is cached by its path, so restore it afterwards.
1275-
self.addCleanup(restore__testsinglephase)
1276-
tempdir = tempfile.mkdtemp()
1277-
# The copied extension module stays loaded, so on Windows it cannot
1278-
# be removed.
1279-
self.addCleanup(shutil.rmtree, tempdir, ignore_errors=True)
1280-
subdir = os.path.join(os.fsencode(tempdir),
1281-
os_helper.TESTFN_UNDECODABLE)
1282-
try:
1283-
os.mkdir(subdir)
1284-
except OSError:
1285-
self.skipTest('undecodable paths are not supported')
1286-
path = os.path.join(subdir, os.fsencode(os.path.basename(origin)))
1287-
shutil.copyfile(origin, path)
1288-
path = os.fsdecode(path)
1289-
spec = importlib.util.spec_from_file_location('_testsinglephase', path)
1290-
module = importlib.util.module_from_spec(spec)
1291-
spec.loader.exec_module(module)
1292-
self.assertEqual(module.__name__, '_testsinglephase')
1293-
self.assertEqual(module.__file__, path)
1294-
_testinternalcapi.clear_extension('_testsinglephase', path)
1273+
with os_helper.temp_dir() as tempdir:
1274+
subdir = os.path.join(os.fsencode(tempdir),
1275+
os_helper.TESTFN_UNDECODABLE)
1276+
try:
1277+
os.mkdir(subdir)
1278+
except OSError:
1279+
self.skipTest('undecodable paths are not supported')
1280+
path = os.path.join(subdir, os.fsencode(os.path.basename(origin)))
1281+
shutil.copyfile(origin, path)
1282+
# Import it in a subprocess: the extension module stays loaded,
1283+
# and on Windows its file cannot be removed.
1284+
script = textwrap.dedent(f"""
1285+
import importlib.util
1286+
path = {os.fsdecode(path)!a}
1287+
spec = importlib.util.spec_from_file_location(
1288+
'_testsinglephase', path)
1289+
module = importlib.util.module_from_spec(spec)
1290+
spec.loader.exec_module(module)
1291+
assert module.__name__ == '_testsinglephase', module.__name__
1292+
assert module.__file__ == path, module.__file__
1293+
""")
1294+
script_helper.assert_python_ok('-c', script)
12951295

12961296
def test_create_builtin(self):
12971297
class Spec:

Python/import.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,6 +1308,8 @@ hashtable_key_from_2_strings(PyObject *str1, PyObject *str2)
13081308
return NULL;
13091309
}
13101310

1311+
/* Clear the padding: the key is hashed and compared as raw bytes. */
1312+
memset(key, 0, sizeof(struct hashtable_key));
13111313
key->size = size;
13121314
key->kind1 = (unsigned char)kind1;
13131315
key->kind2 = (unsigned char)kind2;

0 commit comments

Comments
 (0)