Skip to content

Commit 1d3c518

Browse files
authoredFeb 22, 2018
bpo-32457: Improves handling of denormalized executable path when launching Python (pythonGH-5756) (python#5818)
1 parent 6eab93c commit 1d3c518

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed
 

‎Lib/test/test_cmd_line.py

+12
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,18 @@ def test_isolatedmode(self):
489489
cwd=tmpdir)
490490
self.assertEqual(out.strip(), b"ok")
491491

492+
@unittest.skipUnless(sys.platform == 'win32',
493+
'bpo-32457 only applies on Windows')
494+
def test_argv0_normalization(self):
495+
args = sys.executable, '-c', 'print(0)'
496+
prefix, exe = os.path.split(sys.executable)
497+
executable = prefix + '\\.\\.\\.\\' + exe
498+
499+
proc = subprocess.run(args, stdout=subprocess.PIPE,
500+
executable=executable)
501+
self.assertEqual(proc.returncode, 0, proc)
502+
self.assertEqual(proc.stdout.strip(), b'0')
503+
492504

493505
def test_main():
494506
test.support.run_unittest(CmdLineTest)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improves handling of denormalized executable path when launching Python.

‎PC/getpathp.c

+34-1
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,36 @@ join(wchar_t *buffer, const wchar_t *stuff)
241241
}
242242
}
243243

244+
static int _PathCchCanonicalizeEx_Initialized = 0;
245+
typedef HRESULT(__stdcall *PPathCchCanonicalizeEx) (PWSTR pszPathOut, size_t cchPathOut,
246+
PCWSTR pszPathIn, unsigned long dwFlags);
247+
static PPathCchCanonicalizeEx _PathCchCanonicalizeEx;
248+
249+
static void canonicalize(wchar_t *buffer, const wchar_t *path)
250+
{
251+
if (_PathCchCanonicalizeEx_Initialized == 0) {
252+
HMODULE pathapi = LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll");
253+
if (pathapi) {
254+
_PathCchCanonicalizeEx = (PPathCchCanonicalizeEx)GetProcAddress(pathapi, "PathCchCanonicalizeEx");
255+
}
256+
else {
257+
_PathCchCanonicalizeEx = NULL;
258+
}
259+
_PathCchCanonicalizeEx_Initialized = 1;
260+
}
261+
262+
if (_PathCchCanonicalizeEx) {
263+
if (FAILED(_PathCchCanonicalizeEx(buffer, MAXPATHLEN + 1, path, 0))) {
264+
Py_FatalError("buffer overflow in getpathp.c's canonicalize()");
265+
}
266+
}
267+
else {
268+
if (!PathCanonicalizeW(buffer, path)) {
269+
Py_FatalError("buffer overflow in getpathp.c's canonicalize()");
270+
}
271+
}
272+
}
273+
244274
/* gotlandmark only called by search_for_prefix, which ensures
245275
'prefix' is null terminated in bounds. join() ensures
246276
'landmark' can not overflow prefix if too long.
@@ -431,6 +461,7 @@ static void
431461
get_progpath(void)
432462
{
433463
extern wchar_t *Py_GetProgramName(void);
464+
wchar_t modulepath[MAXPATHLEN];
434465
wchar_t *path = _wgetenv(L"PATH");
435466
wchar_t *prog = Py_GetProgramName();
436467

@@ -443,8 +474,10 @@ get_progpath(void)
443474
#else
444475
dllpath[0] = 0;
445476
#endif
446-
if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN))
477+
if (GetModuleFileNameW(NULL, modulepath, MAXPATHLEN)) {
478+
canonicalize(progpath, modulepath);
447479
return;
480+
}
448481
if (prog == NULL || *prog == '\0')
449482
prog = L"python";
450483

0 commit comments

Comments
 (0)