From dcf617152e1d4c4a5e7965733928858a9c0936ca Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 19 Mar 2019 16:09:27 +0100 Subject: [PATCH] bpo-36236: Handle removed cwd at Python init (GH-12424) At Python initialization, the current directory is no longer prepended to sys.path if it has been removed. Rename _PyPathConfig_ComputeArgv0() to _PyPathConfig_ComputeSysPath0() to avoid confusion between argv[0] and sys.path[0]. --- Include/internal/pycore_pathconfig.h | 4 ++- .../2019-03-19-03-08-26.bpo-36236.5qN9qK.rst | 2 ++ Modules/main.c | 20 ++++++------ Python/pathconfig.c | 31 ++++++++++++++----- Python/sysmodule.c | 24 +++++++------- 5 files changed, 52 insertions(+), 29 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-03-19-03-08-26.bpo-36236.5qN9qK.rst diff --git a/Include/internal/pycore_pathconfig.h b/Include/internal/pycore_pathconfig.h index d0938df5414..80d86a0dd1b 100644 --- a/Include/internal/pycore_pathconfig.h +++ b/Include/internal/pycore_pathconfig.h @@ -44,7 +44,9 @@ PyAPI_FUNC(_PyInitError) _PyPathConfig_SetGlobal( PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate_impl( _PyPathConfig *config, const _PyCoreConfig *core_config); -PyAPI_FUNC(PyObject*) _PyPathConfig_ComputeArgv0(const _PyWstrList *argv); +PyAPI_FUNC(int) _PyPathConfig_ComputeSysPath0( + const _PyWstrList *argv, + PyObject **path0); PyAPI_FUNC(int) _Py_FindEnvConfigValue( FILE *env_file, const wchar_t *key, diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-03-19-03-08-26.bpo-36236.5qN9qK.rst b/Misc/NEWS.d/next/Core and Builtins/2019-03-19-03-08-26.bpo-36236.5qN9qK.rst new file mode 100644 index 00000000000..e1c1182d181 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-03-19-03-08-26.bpo-36236.5qN9qK.rst @@ -0,0 +1,2 @@ +At Python initialization, the current directory is no longer prepended to +:data:`sys.path` if it has been removed. diff --git a/Modules/main.c b/Modules/main.c index 99396b73c65..df4eca5aae8 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -780,18 +780,20 @@ pymain_run_python(PyInterpreterState *interp, int *exitcode) } } else if (!config->preconfig.isolated) { - PyObject *path0 = _PyPathConfig_ComputeArgv0(&config->argv); - if (path0 == NULL) { - err = _Py_INIT_NO_MEMORY(); - goto done; - } + PyObject *path0 = NULL; + if (_PyPathConfig_ComputeSysPath0(&config->argv, &path0)) { + if (path0 == NULL) { + err = _Py_INIT_NO_MEMORY(); + goto done; + } - if (pymain_sys_path_add_path0(interp, path0) < 0) { + if (pymain_sys_path_add_path0(interp, path0) < 0) { + Py_DECREF(path0); + err = _Py_INIT_EXIT(1); + goto done; + } Py_DECREF(path0); - err = _Py_INIT_EXIT(1); - goto done; } - Py_DECREF(path0); } PyCompilerFlags cf = {.cf_flags = 0, .cf_feature_version = PY_MINOR_VERSION}; diff --git a/Python/pathconfig.c b/Python/pathconfig.c index f1818eb3076..743e1cd1ac0 100644 --- a/Python/pathconfig.c +++ b/Python/pathconfig.c @@ -566,9 +566,18 @@ Py_GetProgramName(void) return _Py_path_config.program_name; } -/* Compute argv[0] which will be prepended to sys.argv */ -PyObject* -_PyPathConfig_ComputeArgv0(const _PyWstrList *argv) +/* Compute module search path from argv[0] or the current working + directory ("-m module" case) which will be prepended to sys.argv: + sys.path[0]. + + Return 1 if the path is correctly resolved, but *path0_p can be NULL + if the Unicode object fail to be created. + + Return 0 if it fails to resolve the full path (and *path0_p will be NULL), + for example if the current working directory has been removed (bpo-36236). + */ +int +_PyPathConfig_ComputeSysPath0(const _PyWstrList *argv, PyObject **path0_p) { assert(_PyWstrList_CheckConsistency(argv)); @@ -588,6 +597,8 @@ _PyPathConfig_ComputeArgv0(const _PyWstrList *argv) wchar_t fullpath[MAX_PATH]; #endif + assert(*path0_p == NULL); + if (argv->length > 0) { argv0 = argv->items[0]; have_module_arg = (wcscmp(argv0, L"-m") == 0); @@ -595,14 +606,17 @@ _PyPathConfig_ComputeArgv0(const _PyWstrList *argv) } if (have_module_arg) { - #if defined(HAVE_REALPATH) || defined(MS_WINDOWS) - _Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath)); +#if defined(HAVE_REALPATH) || defined(MS_WINDOWS) + if (!_Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath))) { + *path0_p = NULL; + return 0; + } argv0 = fullpath; n = wcslen(argv0); - #else +#else argv0 = L"."; n = 1; - #endif +#endif } #ifdef HAVE_READLINK @@ -675,7 +689,8 @@ _PyPathConfig_ComputeArgv0(const _PyWstrList *argv) } #endif /* All others */ - return PyUnicode_FromWideChar(argv0, n); + *path0_p = PyUnicode_FromWideChar(argv0, n); + return 1; } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index b3330a01f7c..4351a7fb370 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2781,19 +2781,21 @@ PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath) /* If argv[0] is not '-c' nor '-m', prepend argv[0] to sys.path. If argv[0] is a symlink, use the real path. */ const _PyWstrList argv_list = {.length = argc, .items = argv}; - PyObject *argv0 = _PyPathConfig_ComputeArgv0(&argv_list); - if (argv0 == NULL) { - Py_FatalError("can't compute path0 from argv"); - } - - PyObject *sys_path = _PySys_GetObjectId(&PyId_path); - if (sys_path != NULL) { - if (PyList_Insert(sys_path, 0, argv0) < 0) { - Py_DECREF(argv0); - Py_FatalError("can't prepend path0 to sys.path"); + PyObject *path0 = NULL; + if (_PyPathConfig_ComputeSysPath0(&argv_list, &path0)) { + if (path0 == NULL) { + Py_FatalError("can't compute path0 from argv"); } + + PyObject *sys_path = _PySys_GetObjectId(&PyId_path); + if (sys_path != NULL) { + if (PyList_Insert(sys_path, 0, path0) < 0) { + Py_DECREF(path0); + Py_FatalError("can't prepend path0 to sys.path"); + } + } + Py_DECREF(path0); } - Py_DECREF(argv0); } }