From e73896241e55f452656fd8070eb79f344091bca0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 2 Jul 2020 10:05:35 +0300 Subject: [PATCH] [3.8] bpo-41043: Escape literal part of the path for glob(). (GH-20994). (GH-21277) (cherry picked from commit 935586845815f5b4c7814794413f6a812d4bd45f) --- Lib/distutils/command/build_py.py | 6 +++--- Lib/idlelib/tree.py | 2 +- Lib/imghdr.py | 2 +- Lib/pdb.py | 2 +- Lib/sndhdr.py | 2 +- Lib/test/_test_multiprocessing.py | 2 +- Lib/test/libregrtest/main.py | 2 +- Lib/test/support/__init__.py | 2 +- Lib/test/test_bz2.py | 2 +- Lib/test/test_crashers.py | 2 +- Lib/test/test_dbm.py | 2 +- Lib/test/test_import/__init__.py | 2 +- Lib/test/test_mailbox.py | 4 ++-- Lib/test/test_regrtest.py | 2 +- Lib/test/test_site.py | 2 +- Lib/test/test_tokenize.py | 2 +- Lib/test/test_unicode_file.py | 2 +- Lib/webbrowser.py | 2 +- .../next/Library/2020-06-20-00-19-30.bpo-41043.p-Pk-H.rst | 2 ++ Tools/c-globals/check-c-globals.py | 4 +++- Tools/ssl/make_ssl_data.py | 2 +- setup.py | 8 ++++---- 22 files changed, 31 insertions(+), 27 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-06-20-00-19-30.bpo-41043.p-Pk-H.rst diff --git a/Lib/distutils/command/build_py.py b/Lib/distutils/command/build_py.py index cf0ca57c320..edc2171cd12 100644 --- a/Lib/distutils/command/build_py.py +++ b/Lib/distutils/command/build_py.py @@ -5,7 +5,7 @@ Implements the Distutils 'build_py' command.""" import os import importlib.util import sys -from glob import glob +import glob from distutils.core import Command from distutils.errors import * @@ -125,7 +125,7 @@ class build_py (Command): files = [] for pattern in globs: # Each pattern has to be converted to a platform-specific path - filelist = glob(os.path.join(src_dir, convert_path(pattern))) + filelist = glob.glob(os.path.join(glob.escape(src_dir), convert_path(pattern))) # Files that match more than one pattern are only added once files.extend([fn for fn in filelist if fn not in files and os.path.isfile(fn)]) @@ -216,7 +216,7 @@ class build_py (Command): def find_package_modules(self, package, package_dir): self.check_package(package, package_dir) - module_files = glob(os.path.join(package_dir, "*.py")) + module_files = glob.glob(os.path.join(glob.escape(package_dir), "*.py")) modules = [] setup_script = os.path.abspath(self.distribution.script_name) diff --git a/Lib/idlelib/tree.py b/Lib/idlelib/tree.py index 6229be4e5a8..5947268f5c3 100644 --- a/Lib/idlelib/tree.py +++ b/Lib/idlelib/tree.py @@ -38,7 +38,7 @@ def listicons(icondir=ICONDIR): """Utility to display the available icons.""" root = Tk() import glob - list = glob.glob(os.path.join(icondir, "*.gif")) + list = glob.glob(os.path.join(glob.escape(icondir), "*.gif")) list.sort() images = [] row = column = 0 diff --git a/Lib/imghdr.py b/Lib/imghdr.py index 76e8abb2d58..6e01fd85746 100644 --- a/Lib/imghdr.py +++ b/Lib/imghdr.py @@ -152,7 +152,7 @@ def testall(list, recursive, toplevel): if recursive or toplevel: print('recursing down:') import glob - names = glob.glob(os.path.join(filename, '*')) + names = glob.glob(os.path.join(glob.escape(filename), '*')) testall(names, recursive, 0) else: print('*** directory (use -r) ***') diff --git a/Lib/pdb.py b/Lib/pdb.py index 931a0394461..081023526c0 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -474,7 +474,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): except Exception: ret = [] # Then, try to complete file names as well. - globs = glob.glob(text + '*') + globs = glob.glob(glob.escape(text) + '*') for fn in globs: if os.path.isdir(fn): ret.append(fn + '/') diff --git a/Lib/sndhdr.py b/Lib/sndhdr.py index 594353136f5..96595c69744 100644 --- a/Lib/sndhdr.py +++ b/Lib/sndhdr.py @@ -241,7 +241,7 @@ def testall(list, recursive, toplevel): if recursive or toplevel: print('recursing down:') import glob - names = glob.glob(os.path.join(filename, '*')) + names = glob.glob(os.path.join(glob.escape(filename), '*')) testall(names, recursive, 0) else: print('*** directory (use -r) ***') diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 87f5044148f..8626aa37c18 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -4222,7 +4222,7 @@ class _TestImportStar(unittest.TestCase): def get_module_names(self): import glob folder = os.path.dirname(multiprocessing.__file__) - pattern = os.path.join(folder, '*.py') + pattern = os.path.join(glob.escape(folder), '*.py') files = glob.glob(pattern) modules = [os.path.splitext(os.path.split(f)[1])[0] for f in files] modules = ['multiprocessing.' + m for m in modules] diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index 95b4856c8be..adf31cc9494 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -602,7 +602,7 @@ class Regrtest: def cleanup(self): import glob - path = os.path.join(self.tmp_dir, 'test_python_*') + path = os.path.join(glob.escape(self.tmp_dir), 'test_python_*') print("Cleanup %s directory" % self.tmp_dir) for name in glob.glob(path): if os.path.isdir(name): diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 937766b8ce7..fb09e0623e5 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2625,7 +2625,7 @@ class PythonSymlink: dll, os.path.join(dest_dir, os.path.basename(dll)) )) - for runtime in glob.glob(os.path.join(src_dir, "vcruntime*.dll")): + for runtime in glob.glob(os.path.join(glob.escape(src_dir), "vcruntime*.dll")): self._also_link.append(( runtime, os.path.join(dest_dir, os.path.basename(runtime)) diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py index eb2f72ee4a5..2591f0a6ac4 100644 --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -69,7 +69,7 @@ class BaseTest(unittest.TestCase): # simply use the bigger test data for all tests. test_size = 0 BIG_TEXT = bytearray(128*1024) - for fname in glob.glob(os.path.join(os.path.dirname(__file__), '*.py')): + for fname in glob.glob(os.path.join(glob.escape(os.path.dirname(__file__)), '*.py')): with open(fname, 'rb') as fh: test_size += fh.readinto(memoryview(BIG_TEXT)[test_size:]) if test_size > 128*1024: diff --git a/Lib/test/test_crashers.py b/Lib/test/test_crashers.py index 58dfd001da3..31b712028f8 100644 --- a/Lib/test/test_crashers.py +++ b/Lib/test/test_crashers.py @@ -11,7 +11,7 @@ import test.support from test.support.script_helper import assert_python_failure CRASHER_DIR = os.path.join(os.path.dirname(__file__), "crashers") -CRASHER_FILES = os.path.join(CRASHER_DIR, "*.py") +CRASHER_FILES = os.path.join(glob.escape(CRASHER_DIR), "*.py") infinite_loops = ["infinite_loop_re.py", "nasty_eq_vs_dict.py"] diff --git a/Lib/test/test_dbm.py b/Lib/test/test_dbm.py index 1db3bef6f41..571da973aab 100644 --- a/Lib/test/test_dbm.py +++ b/Lib/test/test_dbm.py @@ -33,7 +33,7 @@ def dbm_iterator(): def delete_files(): # we don't know the precise name the underlying database uses # so we use glob to locate all names - for f in glob.glob(_fname + "*"): + for f in glob.glob(glob.escape(_fname) + "*"): test.support.unlink(f) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index f037821dda2..52f0491679f 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -478,7 +478,7 @@ class ImportTests(unittest.TestCase): pyexe = os.path.join(tmp, os.path.basename(sys.executable)) shutil.copy(sys.executable, pyexe) shutil.copy(dllname, tmp) - for f in glob.glob(os.path.join(sys.prefix, "vcruntime*.dll")): + for f in glob.glob(os.path.join(glob.escape(sys.prefix), "vcruntime*.dll")): shutil.copy(f, tmp) shutil.copy(pydname, tmp2) diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py index 0995b1e386d..effac97d8f9 100644 --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -979,7 +979,7 @@ class _TestMboxMMDF(_TestSingleFile): super().tearDown() self._box.close() self._delete_recursively(self._path) - for lock_remnant in glob.glob(self._path + '.*'): + for lock_remnant in glob.glob(glob.escape(self._path) + '.*'): support.unlink(lock_remnant) def assertMailboxEmpty(self): @@ -1311,7 +1311,7 @@ class TestBabyl(_TestSingleFile, unittest.TestCase): super().tearDown() self._box.close() self._delete_recursively(self._path) - for lock_remnant in glob.glob(self._path + '.*'): + for lock_remnant in glob.glob(glob.escape(self._path) + '.*'): support.unlink(lock_remnant) def test_labels(self): diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index e2fa1977ba6..f89b1af7743 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -559,7 +559,7 @@ class CheckActualTests(BaseTestCase): args = ['-Wd', '-E', '-bb', '-m', 'test.regrtest', '--list-tests'] output = self.run_python(args) rough_number_of_tests_found = len(output.splitlines()) - actual_testsuite_glob = os.path.join(os.path.dirname(__file__), + actual_testsuite_glob = os.path.join(glob.escape(os.path.dirname(__file__)), 'test*.py') rough_counted_test_py_files = len(glob.glob(actual_testsuite_glob)) # We're not trying to duplicate test finding logic in here, diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index 1bbc6979368..9a047fd4669 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -526,7 +526,7 @@ class StartupImportTests(unittest.TestCase): # found in sys.path (see site.addpackage()). Skip the test if at least # one .pth file is found. for path in isolated_paths: - pth_files = glob.glob(os.path.join(path, "*.pth")) + pth_files = glob.glob(os.path.join(glob.escape(path), "*.pth")) if pth_files: self.skipTest(f"found {len(pth_files)} .pth files in: {path}") diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 4c90092893a..6de7aa87bb2 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1605,7 +1605,7 @@ class TestRoundtrip(TestCase): import glob, random fn = support.findfile("tokenize_tests.txt") tempdir = os.path.dirname(fn) or os.curdir - testfiles = glob.glob(os.path.join(tempdir, "test*.py")) + testfiles = glob.glob(os.path.join(glob.escape(tempdir), "test*.py")) # Tokenize is broken on test_pep3131.py because regular expressions are # broken on the obscure unicode identifiers in it. *sigh* diff --git a/Lib/test/test_unicode_file.py b/Lib/test/test_unicode_file.py index b16e4c5b3bd..e8feb42c6b0 100644 --- a/Lib/test/test_unicode_file.py +++ b/Lib/test/test_unicode_file.py @@ -40,7 +40,7 @@ class TestUnicodeFiles(unittest.TestCase): self._do_copyish(filename, filename) # Filename should appear in glob output self.assertTrue( - os.path.abspath(filename)==os.path.abspath(glob.glob(filename)[0])) + os.path.abspath(filename)==os.path.abspath(glob.glob(glob.escape(filename))[0])) # basename should appear in listdir. path, base = os.path.split(os.path.abspath(filename)) file_list = os.listdir(path) diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index 53e0efc967a..cea91308ce1 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -413,7 +413,7 @@ class Grail(BaseBrowser): tempdir = os.path.join(tempfile.gettempdir(), ".grail-unix") user = pwd.getpwuid(os.getuid())[0] - filename = os.path.join(tempdir, user + "-*") + filename = os.path.join(glob.escape(tempdir), glob.escape(user) + "-*") maybes = glob.glob(filename) if not maybes: return None diff --git a/Misc/NEWS.d/next/Library/2020-06-20-00-19-30.bpo-41043.p-Pk-H.rst b/Misc/NEWS.d/next/Library/2020-06-20-00-19-30.bpo-41043.p-Pk-H.rst new file mode 100644 index 00000000000..9c6020eb8d7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-06-20-00-19-30.bpo-41043.p-Pk-H.rst @@ -0,0 +1,2 @@ +Fixed the use of :func:`~glob.glob` in the stdlib: literal part of the path +is now always correctly escaped. diff --git a/Tools/c-globals/check-c-globals.py b/Tools/c-globals/check-c-globals.py index e68ed9271fe..1371f927423 100644 --- a/Tools/c-globals/check-c-globals.py +++ b/Tools/c-globals/check-c-globals.py @@ -37,7 +37,9 @@ IGNORED_VARS = { def find_capi_vars(root): capi_vars = {} for dirname in SOURCE_DIRS: - for filename in glob.glob(os.path.join(ROOT_DIR, dirname, '**/*.[hc]'), + for filename in glob.glob(os.path.join( + glob.escape(os.path.join(ROOT_DIR, dirname)), + '**/*.[hc]'), recursive=True): with open(filename) as file: for name in _find_capi_vars(file): diff --git a/Tools/ssl/make_ssl_data.py b/Tools/ssl/make_ssl_data.py index d60f352882e..c39e38c5069 100755 --- a/Tools/ssl/make_ssl_data.py +++ b/Tools/ssl/make_ssl_data.py @@ -39,7 +39,7 @@ if __name__ == "__main__": f = sys.stdout if use_stdout else open(outfile, "w") # mnemonic -> (library code, error prefix, header file) error_libraries = {} - for error_header in glob.glob(os.path.join(openssl_inc, 'include/openssl/*err.h')): + for error_header in glob.glob(os.path.join(glob.escape(openssl_inc), 'include/openssl/*err.h')): base = os.path.basename(error_header) if base in ('buffererr.h', 'objectserr.h', 'storeerr.h'): # Deprecated in 3.0. diff --git a/setup.py b/setup.py index b168ed4082f..6340669fffd 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ import os import re import sys import sysconfig -from glob import glob +from glob import glob, escape from distutils import log from distutils.command.build_ext import build_ext @@ -339,7 +339,7 @@ class PyBuildExt(build_ext): # Python header files headers = [sysconfig.get_config_h_filename()] - headers += glob(os.path.join(sysconfig.get_path('include'), "*.h")) + headers += glob(os.path.join(escape(sysconfig.get_path('include')), "*.h")) # The sysconfig variables built by makesetup that list the already # built modules and the disabled modules as configured by the Setup @@ -2256,7 +2256,7 @@ class PyBuildExt(build_ext): self.add(Extension('_sha1', ['sha1module.c'], depends=['hashlib.h'])) - blake2_deps = glob(os.path.join(self.srcdir, + blake2_deps = glob(os.path.join(escape(self.srcdir), 'Modules/_blake2/impl/*')) blake2_deps.append('hashlib.h') @@ -2266,7 +2266,7 @@ class PyBuildExt(build_ext): '_blake2/blake2s_impl.c'], depends=blake2_deps)) - sha3_deps = glob(os.path.join(self.srcdir, + sha3_deps = glob(os.path.join(escape(self.srcdir), 'Modules/_sha3/kcp/*')) sha3_deps.append('hashlib.h') self.add(Extension('_sha3',