From 7a7693e9cb12e5571c76331db56a28eef9acb6e0 Mon Sep 17 00:00:00 2001 From: "E. M. Bray" Date: Fri, 5 Oct 2018 13:38:50 +0200 Subject: [PATCH] bpo-28441: Ensure `.exe` suffix in `sys.executable` on MinGW and Cygwin (GH-4348) This is needed to even the run the test suite on buildbots for affected platforms; e.g.: ``` ./python.exe ./Tools/scripts/run_tests.py -j 1 -u all -W --slowest --fail-env-changed --timeout=11700 -j2 /home/embray/src/python/test-worker/3.x.test-worker/build/python -u -W default -bb -E -W error::BytesWarning -m test -r -w -j 1 -u all -W --slowest --fail-env-changed --timeout=11700 -j2 Traceback (most recent call last): File "./Tools/scripts/run_tests.py", line 56, in main(sys.argv[1:]) File "./Tools/scripts/run_tests.py", line 52, in main os.execv(sys.executable, args) PermissionError: [Errno 13] Permission denied make: *** [Makefile:1073: buildbottest] Error 1 ``` --- .../2018-10-04-15-53-14.bpo-28441.2sQENe.rst | 3 ++ Modules/getpath.c | 45 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2018-10-04-15-53-14.bpo-28441.2sQENe.rst diff --git a/Misc/NEWS.d/next/Library/2018-10-04-15-53-14.bpo-28441.2sQENe.rst b/Misc/NEWS.d/next/Library/2018-10-04-15-53-14.bpo-28441.2sQENe.rst new file mode 100644 index 0000000000..45143c2a54 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-10-04-15-53-14.bpo-28441.2sQENe.rst @@ -0,0 +1,3 @@ +On Cygwin and MinGW, ensure that ``sys.executable`` always includes the full +filename in the path, including the ``.exe`` suffix (unless it is a symbolic +link). diff --git a/Modules/getpath.c b/Modules/getpath.c index 041cb14b4b..521bc6e35e 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -296,6 +296,41 @@ absolutize(wchar_t *path) } +#if defined(__CYGWIN__) || defined(__MINGW32__) +/* add_exe_suffix requires that progpath be allocated at least + MAXPATHLEN + 1 bytes. +*/ + +#ifndef EXE_SUFFIX +#define EXE_SUFFIX L".exe" +#endif + +static void +add_exe_suffix(wchar_t *progpath) +{ + /* Check for already have an executable suffix */ + size_t n = wcslen(progpath); + size_t s = wcslen(EXE_SUFFIX); + if (wcsncasecmp(EXE_SUFFIX, progpath+n-s, s) != 0) { + if (n + s > MAXPATHLEN) { + Py_FatalError("progpath overflow in getpath.c's add_exe_suffix()"); + } + /* Save original path for revert */ + wchar_t orig[MAXPATHLEN+1]; + wcsncpy(orig, progpath, MAXPATHLEN); + + wcsncpy(progpath+n, EXE_SUFFIX, s); + progpath[n+s] = '\0'; + + if (!isxfile(progpath)) { + /* Path that added suffix is invalid */ + wcsncpy(progpath, orig, MAXPATHLEN); + } + } +} +#endif + + /* search_for_prefix requires that argv0_path be no more than MAXPATHLEN bytes long. */ @@ -605,6 +640,16 @@ calculate_program_full_path(const _PyCoreConfig *core_config, if (program_full_path[0] != SEP && program_full_path[0] != '\0') { absolutize(program_full_path); } +#if defined(__CYGWIN__) || defined(__MINGW32__) + /* For these platforms it is necessary to ensure that the .exe suffix + * is appended to the filename, otherwise there is potential for + * sys.executable to return the name of a directory under the same + * path (bpo-28441). + */ + if (program_full_path[0] != '\0') { + add_exe_suffix(program_full_path); + } +#endif config->program_full_path = _PyMem_RawWcsdup(program_full_path); if (config->program_full_path == NULL) { -- 2.40.0