summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@microsoft.com>2018-02-22 20:33:16 (GMT)
committerGitHub <noreply@github.com>2018-02-22 20:33:16 (GMT)
commit1d3c518c5ecbd78478738f068f4f035f81f035f9 (patch)
tree9fa806636df61b86e6c40191ba8257c6ad39c525
parent6eab93cfe5ee08a6168e5bb69474e461cc7ac535 (diff)
downloadcpython-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.py12
-rw-r--r--Misc/NEWS.d/next/Windows/2018-02-19-08-54-06.bpo-32457.vVP0Iz.rst1
-rw-r--r--PC/getpathp.c35
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";