bpo-32457: Improves handling of denormalized executable path when launching Python (GH-5756) (#5818)

This commit is contained in:
Steve Dower 2018-02-22 12:33:16 -08:00 committed by GitHub
parent 6eab93cfe5
commit 1d3c518c5e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 1 deletions

View file

@ -489,6 +489,18 @@ class CmdLineTest(unittest.TestCase):
cwd=tmpdir) cwd=tmpdir)
self.assertEqual(out.strip(), b"ok") 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(): def test_main():
test.support.run_unittest(CmdLineTest) test.support.run_unittest(CmdLineTest)

View file

@ -0,0 +1 @@
Improves handling of denormalized executable path when launching Python.

View file

@ -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 /* gotlandmark only called by search_for_prefix, which ensures
'prefix' is null terminated in bounds. join() ensures 'prefix' is null terminated in bounds. join() ensures
'landmark' can not overflow prefix if too long. 'landmark' can not overflow prefix if too long.
@ -431,6 +461,7 @@ static void
get_progpath(void) get_progpath(void)
{ {
extern wchar_t *Py_GetProgramName(void); extern wchar_t *Py_GetProgramName(void);
wchar_t modulepath[MAXPATHLEN];
wchar_t *path = _wgetenv(L"PATH"); wchar_t *path = _wgetenv(L"PATH");
wchar_t *prog = Py_GetProgramName(); wchar_t *prog = Py_GetProgramName();
@ -443,8 +474,10 @@ get_progpath(void)
#else #else
dllpath[0] = 0; dllpath[0] = 0;
#endif #endif
if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN)) if (GetModuleFileNameW(NULL, modulepath, MAXPATHLEN)) {
canonicalize(progpath, modulepath);
return; return;
}
if (prog == NULL || *prog == '\0') if (prog == NULL || *prog == '\0')
prog = L"python"; prog = L"python";