diff options
author | Steve Dower <steve.dower@microsoft.com> | 2018-02-22 20:33:16 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-22 20:33:16 (GMT) |
commit | 1d3c518c5ecbd78478738f068f4f035f81f035f9 (patch) | |
tree | 9fa806636df61b86e6c40191ba8257c6ad39c525 | |
parent | 6eab93cfe5ee08a6168e5bb69474e461cc7ac535 (diff) | |
download | cpython-1d3c518c5ecbd78478738f068f4f035f81f035f9.zip cpython-1d3c518c5ecbd78478738f068f4f035f81f035f9.tar.gz cpython-1d3c518c5ecbd78478738f068f4f035f81f035f9.tar.bz2 |
bpo-32457: Improves handling of denormalized executable path when launching Python (GH-5756) (#5818)
-rw-r--r-- | Lib/test/test_cmd_line.py | 12 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Windows/2018-02-19-08-54-06.bpo-32457.vVP0Iz.rst | 1 | ||||
-rw-r--r-- | PC/getpathp.c | 35 |
3 files changed, 47 insertions, 1 deletions
diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index 32d2df9..38156b4 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -489,6 +489,18 @@ class CmdLineTest(unittest.TestCase): cwd=tmpdir) self.assertEqual(out.strip(), b"ok") + @unittest.skipUnless(sys.platform == 'win32', + 'bpo-32457 only applies on Windows') + def test_argv0_normalization(self): + args = sys.executable, '-c', 'print(0)' + prefix, exe = os.path.split(sys.executable) + executable = prefix + '\\.\\.\\.\\' + exe + + proc = subprocess.run(args, stdout=subprocess.PIPE, + executable=executable) + self.assertEqual(proc.returncode, 0, proc) + self.assertEqual(proc.stdout.strip(), b'0') + def test_main(): test.support.run_unittest(CmdLineTest) diff --git a/Misc/NEWS.d/next/Windows/2018-02-19-08-54-06.bpo-32457.vVP0Iz.rst b/Misc/NEWS.d/next/Windows/2018-02-19-08-54-06.bpo-32457.vVP0Iz.rst new file mode 100644 index 0000000..b55ec82 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2018-02-19-08-54-06.bpo-32457.vVP0Iz.rst @@ -0,0 +1 @@ +Improves handling of denormalized executable path when launching Python. diff --git a/PC/getpathp.c b/PC/getpathp.c index e7be704..af4af76 100644 --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -241,6 +241,36 @@ join(wchar_t *buffer, const wchar_t *stuff) } } +static int _PathCchCanonicalizeEx_Initialized = 0; +typedef HRESULT(__stdcall *PPathCchCanonicalizeEx) (PWSTR pszPathOut, size_t cchPathOut, + PCWSTR pszPathIn, unsigned long dwFlags); +static PPathCchCanonicalizeEx _PathCchCanonicalizeEx; + +static void canonicalize(wchar_t *buffer, const wchar_t *path) +{ + if (_PathCchCanonicalizeEx_Initialized == 0) { + HMODULE pathapi = LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll"); + if (pathapi) { + _PathCchCanonicalizeEx = (PPathCchCanonicalizeEx)GetProcAddress(pathapi, "PathCchCanonicalizeEx"); + } + else { + _PathCchCanonicalizeEx = NULL; + } + _PathCchCanonicalizeEx_Initialized = 1; + } + + if (_PathCchCanonicalizeEx) { + if (FAILED(_PathCchCanonicalizeEx(buffer, MAXPATHLEN + 1, path, 0))) { + Py_FatalError("buffer overflow in getpathp.c's canonicalize()"); + } + } + else { + if (!PathCanonicalizeW(buffer, path)) { + Py_FatalError("buffer overflow in getpathp.c's canonicalize()"); + } + } +} + /* gotlandmark only called by search_for_prefix, which ensures 'prefix' is null terminated in bounds. join() ensures 'landmark' can not overflow prefix if too long. @@ -431,6 +461,7 @@ static void get_progpath(void) { extern wchar_t *Py_GetProgramName(void); + wchar_t modulepath[MAXPATHLEN]; wchar_t *path = _wgetenv(L"PATH"); wchar_t *prog = Py_GetProgramName(); @@ -443,8 +474,10 @@ get_progpath(void) #else dllpath[0] = 0; #endif - if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN)) + if (GetModuleFileNameW(NULL, modulepath, MAXPATHLEN)) { + canonicalize(progpath, modulepath); return; + } if (prog == NULL || *prog == '\0') prog = L"python"; |