diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h index 5eaa74edab8..3b603c87ad4 100644 --- a/Include/pylifecycle.h +++ b/Include/pylifecycle.h @@ -12,6 +12,10 @@ PyAPI_FUNC(wchar_t *) Py_GetProgramName(void); PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *); PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void); +#ifdef Py_BUILD_CORE +PyAPI_FUNC(wchar_t *) _Py_GetPythonHomeWithConfig( + const _PyMainInterpreterConfig *config); +#endif #ifndef Py_LIMITED_API /* Only used by applications that embed the interpreter and need to @@ -94,7 +98,8 @@ PyAPI_FUNC(wchar_t *) Py_GetPrefix(void); PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void); PyAPI_FUNC(wchar_t *) Py_GetPath(void); #ifdef Py_BUILD_CORE -PyAPI_FUNC(wchar_t *) _Py_GetPathWithConfig(_PyMainInterpreterConfig *config); +PyAPI_FUNC(wchar_t *) _Py_GetPathWithConfig( + const _PyMainInterpreterConfig *config); #endif PyAPI_FUNC(void) Py_SetPath(const wchar_t *); #ifdef MS_WINDOWS diff --git a/Include/pystate.h b/Include/pystate.h index b2739f1db25..ab6400cddc8 100644 --- a/Include/pystate.h +++ b/Include/pystate.h @@ -61,12 +61,15 @@ typedef struct { typedef struct { int install_signal_handlers; wchar_t *module_search_path_env; /* PYTHONPATH environment variable */ + wchar_t *pythonhome; /* PYTHONHOME environment variable, + see also Py_SetPythonHome(). */ } _PyMainInterpreterConfig; #define _PyMainInterpreterConfig_INIT \ (_PyMainInterpreterConfig){\ .install_signal_handlers = -1, \ - .module_search_path_env = NULL} + .module_search_path_env = NULL, \ + .pythonhome = NULL} typedef struct _is { diff --git a/Include/warnings.h b/Include/warnings.h index a3f83ff6967..25f715e3a8b 100644 --- a/Include/warnings.h +++ b/Include/warnings.h @@ -7,6 +7,9 @@ extern "C" { #ifndef Py_LIMITED_API PyAPI_FUNC(PyObject*) _PyWarnings_Init(void); #endif +#ifdef Py_BUILD_CORE +PyAPI_FUNC(PyObject*) _PyWarnings_InitWithConfig(const _PyCoreConfig *config); +#endif PyAPI_FUNC(int) PyErr_WarnEx( PyObject *category, diff --git a/Modules/getpath.c b/Modules/getpath.c index ead143280b7..62f5e695849 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -456,13 +456,13 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home, } static void -calculate_path(_PyMainInterpreterConfig *config) +calculate_path(const _PyMainInterpreterConfig *config) { extern wchar_t *Py_GetProgramName(void); static const wchar_t delimiter[2] = {DELIM, '\0'}; static const wchar_t separator[2] = {SEP, '\0'}; - wchar_t *home = Py_GetPythonHome(); + wchar_t *home = _Py_GetPythonHomeWithConfig(config); char *_path = getenv("PATH"); wchar_t *path_buffer = NULL; wchar_t *path = NULL; @@ -858,7 +858,7 @@ Py_SetPath(const wchar_t *path) } wchar_t * -_Py_GetPathWithConfig(_PyMainInterpreterConfig *config) +_Py_GetPathWithConfig(const _PyMainInterpreterConfig *config) { if (!module_search_path) { calculate_path(config); diff --git a/Modules/main.c b/Modules/main.c index 8390af29238..07e0d2aa85c 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -400,7 +400,6 @@ typedef struct { _PyInitError err; /* PYTHONWARNINGS env var */ _Py_OptList env_warning_options; - /* PYTHONPATH env var */ int argc; wchar_t **argv; } _PyMain; @@ -1368,43 +1367,94 @@ pymain_set_flags_from_env(_PyMain *pymain) static int -pymain_init_pythonpath(_PyMain *pymain) +pymain_get_env_var_dup(_PyMain *pymain, wchar_t **dest, + wchar_t *wname, char *name) { if (Py_IgnoreEnvironmentFlag) { + *dest = NULL; return 0; } #ifdef MS_WINDOWS - wchar_t *path = _wgetenv(L"PYTHONPATH"); - if (!path || path[0] == '\0') { + wchar_t *var = _wgetenv(wname); + if (!var || var[0] == '\0') { + *dest = NULL; return 0; } - wchar_t *path2 = pymain_wstrdup(pymain, path); - if (path2 == NULL) { + wchar_t *copy = pymain_wstrdup(pymain, var); + if (copy == NULL) { return -1; } - pymain->config.module_search_path_env = path2; + *dest = copy; #else - char *path = pymain_get_env_var("PYTHONPATH"); - if (!path) { + char *var = getenv(name); + if (!var || var[0] == '\0') { + *dest = NULL; return 0; } size_t len; - wchar_t *wpath = Py_DecodeLocale(path, &len); - if (!wpath) { + wchar_t *wvar = Py_DecodeLocale(var, &len); + if (!wvar) { if (len == (size_t)-2) { - pymain->err = _Py_INIT_ERR("failed to decode PYTHONHOME"); + /* don't set pymain->err */ + return -2; } else { pymain->err = INIT_NO_MEMORY(); + return -1; + } + } + *dest = wvar; +#endif + return 0; +} + + +static int +pymain_init_pythonpath(_PyMain *pymain) +{ + wchar_t *path; + int res = pymain_get_env_var_dup(pymain, &path, + L"PYTHONPATH", "PYTHONPATH"); + if (res < 0) { + if (res == -2) { + pymain->err = _Py_INIT_ERR("failed to decode PYTHONPATH"); } return -1; } - pymain->config.module_search_path_env = wpath; -#endif + pymain->config.module_search_path_env = path; + return 0; +} + + +static int +pymain_init_pythonhome(_PyMain *pymain) +{ + wchar_t *home; + + home = Py_GetPythonHome(); + if (home) { + /* Py_SetPythonHome() has been called before Py_Main(), + use its value */ + pymain->config.pythonhome = pymain_wstrdup(pymain, home); + if (pymain->config.pythonhome == NULL) { + return -1; + } + return 0; + } + + int res = pymain_get_env_var_dup(pymain, &home, + L"PYTHONHOME", "PYTHONHOME"); + if (res < 0) { + if (res == -2) { + pymain->err = _Py_INIT_ERR("failed to decode PYTHONHOME"); + } + return -1; + } + pymain->config.pythonhome = home; return 0; } @@ -1433,6 +1483,9 @@ pymain_parse_envvars(_PyMain *pymain) if (pymain_init_pythonpath(pymain) < 0) { return -1; } + if (pymain_init_pythonhome(pymain) < 0) { + return -1; + } /* -X options */ if (pymain_get_xoption(pymain, L"showrefcount")) { diff --git a/PC/getpathp.c b/PC/getpathp.c index 1d18faed450..4756dc8abbb 100644 --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -624,12 +624,12 @@ error: static void -calculate_path(_PyMainInterpreterConfig *config) +calculate_path(const _PyMainInterpreterConfig *config) { wchar_t argv0_path[MAXPATHLEN+1]; wchar_t *buf; size_t bufsz; - wchar_t *pythonhome = Py_GetPythonHome(); + wchar_t *pythonhome = _Py_GetPythonHomeWithConfig(config); wchar_t *envpath = NULL; int skiphome, skipdefault; @@ -899,7 +899,7 @@ Py_SetPath(const wchar_t *path) } wchar_t * -_Py_GetPathWithConfig(_PyMainInterpreterConfig *config) +_Py_GetPathWithConfig(const _PyMainInterpreterConfig *config) { if (!module_search_path) { calculate_path(config); diff --git a/Python/_warnings.c b/Python/_warnings.c index d865f0ad2c0..36d649fda10 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -1185,10 +1185,9 @@ create_filter(PyObject *category, const char *action) } static PyObject * -init_filters(void) +init_filters(const _PyCoreConfig *config) { - PyInterpreterState *interp = PyThreadState_GET()->interp; - int dev_mode = interp->core_config.dev_mode; + int dev_mode = config->dev_mode; Py_ssize_t count = 2; if (dev_mode) { @@ -1264,8 +1263,8 @@ static struct PyModuleDef warningsmodule = { }; -PyMODINIT_FUNC -_PyWarnings_Init(void) +PyObject* +_PyWarnings_InitWithConfig(const _PyCoreConfig *config) { PyObject *m; @@ -1274,7 +1273,7 @@ _PyWarnings_Init(void) return NULL; if (_PyRuntime.warnings.filters == NULL) { - _PyRuntime.warnings.filters = init_filters(); + _PyRuntime.warnings.filters = init_filters(config); if (_PyRuntime.warnings.filters == NULL) return NULL; } @@ -1305,3 +1304,12 @@ _PyWarnings_Init(void) _PyRuntime.warnings.filters_version = 0; return m; } + + +PyMODINIT_FUNC +_PyWarnings_Init(void) +{ + PyInterpreterState *interp = PyThreadState_GET()->interp; + const _PyCoreConfig *config = &interp->core_config; + return _PyWarnings_InitWithConfig(config); +} diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 552501d23ca..5bbbbc68f08 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -767,7 +767,9 @@ _Py_InitializeCore(const _PyCoreConfig *config) } /* Initialize _warnings. */ - _PyWarnings_Init(); + if (_PyWarnings_InitWithConfig(&interp->core_config) == NULL) { + return _Py_INIT_ERR("can't initialize warnings"); + } /* This call sets up builtin and frozen import support */ if (!interp->core_config._disable_importlib) { @@ -880,7 +882,7 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config) return err; } - if (config->install_signal_handlers) { + if (interp->config.install_signal_handlers) { err = initsigs(); /* Signal handling stuff, including initintr() */ if (_Py_INIT_FAILED(err)) { return err; @@ -1468,7 +1470,6 @@ Py_GetProgramName(void) } static wchar_t *default_home = NULL; -static wchar_t env_home[MAXPATHLEN+1]; void Py_SetPythonHome(wchar_t *home) @@ -1476,21 +1477,41 @@ Py_SetPythonHome(wchar_t *home) default_home = home; } +wchar_t * +_Py_GetPythonHomeWithConfig(const _PyMainInterpreterConfig *config) +{ + /* Use a static buffer to avoid heap memory allocation failure. + Py_GetPythonHome() doesn't allow to report error, and the caller + doesn't release memory. */ + static wchar_t buffer[MAXPATHLEN+1]; + + if (default_home) { + return default_home; + } + + if (config) { + return config->pythonhome; + } + + char *home = Py_GETENV("PYTHONHOME"); + if (!home) { + return NULL; + } + + size_t size = Py_ARRAY_LENGTH(buffer); + size_t r = mbstowcs(buffer, home, size); + if (r == (size_t)-1 || r >= size) { + /* conversion failed or the static buffer is too small */ + return NULL; + } + + return buffer; +} + wchar_t * Py_GetPythonHome(void) { - wchar_t *home = default_home; - if (home == NULL && !Py_IgnoreEnvironmentFlag) { - char* chome = Py_GETENV("PYTHONHOME"); - if (chome) { - size_t size = Py_ARRAY_LENGTH(env_home); - size_t r = mbstowcs(env_home, chome, size); - if (r != (size_t)-1 && r < size) - home = env_home; - } - - } - return home; + return _Py_GetPythonHomeWithConfig(NULL); } /* Add the __main__ module */