Skip to content

Commit dcf6171

Browse files
authored
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].
1 parent f5f336a commit dcf6171

File tree

5 files changed

+51
-28
lines changed

5 files changed

+51
-28
lines changed

Include/internal/pycore_pathconfig.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ PyAPI_FUNC(_PyInitError) _PyPathConfig_SetGlobal(
4444
PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate_impl(
4545
_PyPathConfig *config,
4646
const _PyCoreConfig *core_config);
47-
PyAPI_FUNC(PyObject*) _PyPathConfig_ComputeArgv0(const _PyWstrList *argv);
47+
PyAPI_FUNC(int) _PyPathConfig_ComputeSysPath0(
48+
const _PyWstrList *argv,
49+
PyObject **path0);
4850
PyAPI_FUNC(int) _Py_FindEnvConfigValue(
4951
FILE *env_file,
5052
const wchar_t *key,
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
At Python initialization, the current directory is no longer prepended to
2+
:data:`sys.path` if it has been removed.

Modules/main.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -780,18 +780,20 @@ pymain_run_python(PyInterpreterState *interp, int *exitcode)
780780
}
781781
}
782782
else if (!config->preconfig.isolated) {
783-
PyObject *path0 = _PyPathConfig_ComputeArgv0(&config->argv);
784-
if (path0 == NULL) {
785-
err = _Py_INIT_NO_MEMORY();
786-
goto done;
787-
}
783+
PyObject *path0 = NULL;
784+
if (_PyPathConfig_ComputeSysPath0(&config->argv, &path0)) {
785+
if (path0 == NULL) {
786+
err = _Py_INIT_NO_MEMORY();
787+
goto done;
788+
}
788789

789-
if (pymain_sys_path_add_path0(interp, path0) < 0) {
790+
if (pymain_sys_path_add_path0(interp, path0) < 0) {
791+
Py_DECREF(path0);
792+
err = _Py_INIT_EXIT(1);
793+
goto done;
794+
}
790795
Py_DECREF(path0);
791-
err = _Py_INIT_EXIT(1);
792-
goto done;
793796
}
794-
Py_DECREF(path0);
795797
}
796798

797799
PyCompilerFlags cf = {.cf_flags = 0, .cf_feature_version = PY_MINOR_VERSION};

Python/pathconfig.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -566,9 +566,18 @@ Py_GetProgramName(void)
566566
return _Py_path_config.program_name;
567567
}
568568

569-
/* Compute argv[0] which will be prepended to sys.argv */
570-
PyObject*
571-
_PyPathConfig_ComputeArgv0(const _PyWstrList *argv)
569+
/* Compute module search path from argv[0] or the current working
570+
directory ("-m module" case) which will be prepended to sys.argv:
571+
sys.path[0].
572+
573+
Return 1 if the path is correctly resolved, but *path0_p can be NULL
574+
if the Unicode object fail to be created.
575+
576+
Return 0 if it fails to resolve the full path (and *path0_p will be NULL),
577+
for example if the current working directory has been removed (bpo-36236).
578+
*/
579+
int
580+
_PyPathConfig_ComputeSysPath0(const _PyWstrList *argv, PyObject **path0_p)
572581
{
573582
assert(_PyWstrList_CheckConsistency(argv));
574583

@@ -588,21 +597,26 @@ _PyPathConfig_ComputeArgv0(const _PyWstrList *argv)
588597
wchar_t fullpath[MAX_PATH];
589598
#endif
590599

600+
assert(*path0_p == NULL);
601+
591602
if (argv->length > 0) {
592603
argv0 = argv->items[0];
593604
have_module_arg = (wcscmp(argv0, L"-m") == 0);
594605
have_script_arg = !have_module_arg && (wcscmp(argv0, L"-c") != 0);
595606
}
596607

597608
if (have_module_arg) {
598-
#if defined(HAVE_REALPATH) || defined(MS_WINDOWS)
599-
_Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath));
609+
#if defined(HAVE_REALPATH) || defined(MS_WINDOWS)
610+
if (!_Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath))) {
611+
*path0_p = NULL;
612+
return 0;
613+
}
600614
argv0 = fullpath;
601615
n = wcslen(argv0);
602-
#else
616+
#else
603617
argv0 = L".";
604618
n = 1;
605-
#endif
619+
#endif
606620
}
607621

608622
#ifdef HAVE_READLINK
@@ -675,7 +689,8 @@ _PyPathConfig_ComputeArgv0(const _PyWstrList *argv)
675689
}
676690
#endif /* All others */
677691

678-
return PyUnicode_FromWideChar(argv0, n);
692+
*path0_p = PyUnicode_FromWideChar(argv0, n);
693+
return 1;
679694
}
680695

681696

Python/sysmodule.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,19 +2781,21 @@ PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath)
27812781
/* If argv[0] is not '-c' nor '-m', prepend argv[0] to sys.path.
27822782
If argv[0] is a symlink, use the real path. */
27832783
const _PyWstrList argv_list = {.length = argc, .items = argv};
2784-
PyObject *argv0 = _PyPathConfig_ComputeArgv0(&argv_list);
2785-
if (argv0 == NULL) {
2786-
Py_FatalError("can't compute path0 from argv");
2787-
}
2784+
PyObject *path0 = NULL;
2785+
if (_PyPathConfig_ComputeSysPath0(&argv_list, &path0)) {
2786+
if (path0 == NULL) {
2787+
Py_FatalError("can't compute path0 from argv");
2788+
}
27882789

2789-
PyObject *sys_path = _PySys_GetObjectId(&PyId_path);
2790-
if (sys_path != NULL) {
2791-
if (PyList_Insert(sys_path, 0, argv0) < 0) {
2792-
Py_DECREF(argv0);
2793-
Py_FatalError("can't prepend path0 to sys.path");
2790+
PyObject *sys_path = _PySys_GetObjectId(&PyId_path);
2791+
if (sys_path != NULL) {
2792+
if (PyList_Insert(sys_path, 0, path0) < 0) {
2793+
Py_DECREF(path0);
2794+
Py_FatalError("can't prepend path0 to sys.path");
2795+
}
27942796
}
2797+
Py_DECREF(path0);
27952798
}
2796-
Py_DECREF(argv0);
27972799
}
27982800
}
27992801

0 commit comments

Comments
 (0)