From 471693408ee1b61e8d46cf559f3b67e2accc80b9 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Tue, 26 Jul 2022 20:18:44 +0100 Subject: [PATCH 1/3] gh-95285: py.exe launcher fails with short argv0 --- Lib/test/test_launcher.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_launcher.py b/Lib/test/test_launcher.py index 50a2e8c03d6473..4ef6b401da370b 100644 --- a/Lib/test/test_launcher.py +++ b/Lib/test/test_launcher.py @@ -187,7 +187,7 @@ def find_py(cls): ) return py_exe - def run_py(self, args, env=None, allow_fail=False, expect_returncode=0): + def run_py(self, args, env=None, allow_fail=False, expect_returncode=0, short_argv0=False): if not self.py_exe: self.py_exe = self.find_py() @@ -198,9 +198,14 @@ def run_py(self, args, env=None, allow_fail=False, expect_returncode=0): "PYLAUNCHER_DEBUG": "1", "PYLAUNCHER_DRYRUN": "1", } + cwd, py_exe = None, self.py_exe + if short_argv0: + cwd, py_exe = str(py_exe.parent), f'"{py_exe.name}"' with subprocess.Popen( - [self.py_exe, *args], + [py_exe, *args], env=env, + cwd=cwd, + executable=self.py_exe, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -539,6 +544,14 @@ def test_py3_shebang_nl(self): self.assertEqual("3.100-arm64", data["SearchInfo.tag"]) self.assertEqual(f"X.Y-arm64.exe -X fake_arg_for_test -prearg {script} -postarg", data["stdout"].strip()) + def test_py_shebang_short_argv0(self): + with self.py_ini(TEST_PY_COMMANDS): + with self.script("#! /usr/bin/env python -prearg") as script: + data = self.run_py([script, "-postarg"], short_argv0=True) + self.assertEqual("PythonTestSuite", data["SearchInfo.company"]) + self.assertEqual("3.100", data["SearchInfo.tag"]) + self.assertEqual(f"X.Y.exe -prearg {script} -postarg", data["stdout"].strip()) + def test_install(self): data = self.run_py(["-V:3.10"], env={"PYLAUNCHER_ALWAYS_INSTALL": "1"}, expect_returncode=111) cmd = data["stdout"].strip() From 18ace98e12fabc0b6b8e0de97140c63981dde111 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Tue, 26 Jul 2022 20:31:30 +0100 Subject: [PATCH 2/3] Improve test and fix bug --- Lib/test/test_launcher.py | 17 ++++++++--------- PC/launcher2.c | 3 +++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_launcher.py b/Lib/test/test_launcher.py index 4ef6b401da370b..b4009a99a705af 100644 --- a/Lib/test/test_launcher.py +++ b/Lib/test/test_launcher.py @@ -149,7 +149,7 @@ class RunPyMixin: @classmethod def find_py(cls): py_exe = None - if sysconfig.is_python_build(True): + if sysconfig.is_python_build(): py_exe = Path(sys.executable).parent / PY_EXE else: for p in os.getenv("PATH").split(";"): @@ -187,7 +187,7 @@ def find_py(cls): ) return py_exe - def run_py(self, args, env=None, allow_fail=False, expect_returncode=0, short_argv0=False): + def run_py(self, args, env=None, allow_fail=False, expect_returncode=0, argv=None): if not self.py_exe: self.py_exe = self.find_py() @@ -198,13 +198,11 @@ def run_py(self, args, env=None, allow_fail=False, expect_returncode=0, short_ar "PYLAUNCHER_DEBUG": "1", "PYLAUNCHER_DRYRUN": "1", } - cwd, py_exe = None, self.py_exe - if short_argv0: - cwd, py_exe = str(py_exe.parent), f'"{py_exe.name}"' + if not argv: + argv = [self.py_exe, *args] with subprocess.Popen( - [py_exe, *args], + argv, env=env, - cwd=cwd, executable=self.py_exe, stdin=subprocess.PIPE, stdout=subprocess.PIPE, @@ -547,10 +545,11 @@ def test_py3_shebang_nl(self): def test_py_shebang_short_argv0(self): with self.py_ini(TEST_PY_COMMANDS): with self.script("#! /usr/bin/env python -prearg") as script: - data = self.run_py([script, "-postarg"], short_argv0=True) + # Override argv to only pass "py.exe" as the command + data = self.run_py([script, "-postarg"], argv=f'"py.exe" "{script}" -postarg') self.assertEqual("PythonTestSuite", data["SearchInfo.company"]) self.assertEqual("3.100", data["SearchInfo.tag"]) - self.assertEqual(f"X.Y.exe -prearg {script} -postarg", data["stdout"].strip()) + self.assertEqual(f'X.Y.exe -prearg "{script}" -postarg', data["stdout"].strip()) def test_install(self): data = self.run_py(["-V:3.10"], env={"PYLAUNCHER_ALWAYS_INSTALL": "1"}, expect_returncode=111) diff --git a/PC/launcher2.c b/PC/launcher2.c index c8ed1b0f7c8a6d..31b5617771e9b9 100644 --- a/PC/launcher2.c +++ b/PC/launcher2.c @@ -580,6 +580,9 @@ parseCommandLine(SearchInfo *search) break; } } + if (tail == search->originalCmdLine && tail[0] == L'"') { + ++tail; + } // Without special cases, we can now fill in the search struct int tailLen = (int)(end ? (end - tail) : wcsnlen_s(tail, MAXLEN)); search->executableLength = -1; From 6c9b4a65910fd7d4bc31788cbfa83d5c51e26e05 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Tue, 26 Jul 2022 20:33:19 +0100 Subject: [PATCH 3/3] Add NEWS --- .../next/Windows/2022-07-26-20-33-12.gh-issue-95285.w6fa22.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Windows/2022-07-26-20-33-12.gh-issue-95285.w6fa22.rst diff --git a/Misc/NEWS.d/next/Windows/2022-07-26-20-33-12.gh-issue-95285.w6fa22.rst b/Misc/NEWS.d/next/Windows/2022-07-26-20-33-12.gh-issue-95285.w6fa22.rst new file mode 100644 index 00000000000000..76b38e7803ccac --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-07-26-20-33-12.gh-issue-95285.w6fa22.rst @@ -0,0 +1,2 @@ +Fix :ref:`launcher` handling of command lines where it is only passed a +short executable name.