summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/c-api/init.rst5
-rw-r--r--Include/internal/pystate.h25
-rw-r--r--Include/pystate.h3
-rw-r--r--Modules/getpath.c17
-rw-r--r--Modules/main.c38
-rw-r--r--PC/getpathp.c21
-rw-r--r--Python/pathconfig.c161
-rw-r--r--Python/pylifecycle.c7
8 files changed, 180 insertions, 97 deletions
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index a9927ab..a3113a3 100644
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -40,7 +40,6 @@ The following functions can be safely called before Python is initialized:
* :c:func:`Py_GetCompiler`
* :c:func:`Py_GetCopyright`
* :c:func:`Py_GetPlatform`
- * :c:func:`Py_GetProgramName`
* :c:func:`Py_GetVersion`
* Utilities:
@@ -59,8 +58,8 @@ The following functions can be safely called before Python is initialized:
The following functions **should not be called** before
:c:func:`Py_Initialize`: :c:func:`Py_EncodeLocale`, :c:func:`Py_GetPath`,
:c:func:`Py_GetPrefix`, :c:func:`Py_GetExecPrefix`,
- :c:func:`Py_GetProgramFullPath`, :c:func:`Py_GetPythonHome` and
- :c:func:`PyEval_InitThreads`.
+ :c:func:`Py_GetProgramFullPath`, :c:func:`Py_GetPythonHome`,
+ :c:func:`Py_GetProgramName` and :c:func:`PyEval_InitThreads`.
.. _global-conf-vars:
diff --git a/Include/internal/pystate.h b/Include/internal/pystate.h
index 9d85319..b933421 100644
--- a/Include/internal/pystate.h
+++ b/Include/internal/pystate.h
@@ -48,12 +48,35 @@ typedef struct {
#endif
/* Set by Py_SetPath(), or computed by _PyPathConfig_Init() */
wchar_t *module_search_path;
+ /* Python program name */
+ wchar_t *program_name;
+ /* Set by Py_SetPythonHome() or PYTHONHOME environment variable */
+ wchar_t *home;
} _PyPathConfig;
-#define _PyPathConfig_INIT {.module_search_path = NULL}
+#ifdef MS_WINDOWS
+#define _PyPathConfig_INIT \
+ {.program_full_path = NULL, \
+ .prefix = NULL, \
+ .dll_path = NULL, \
+ .module_search_path = NULL, \
+ .program_name = NULL, \
+ .home = NULL}
+#else
+#define _PyPathConfig_INIT \
+ {.program_full_path = NULL, \
+ .prefix = NULL, \
+ .exec_prefix = NULL, \
+ .module_search_path = NULL, \
+ .program_name = NULL, \
+ .home = NULL}
+#endif
PyAPI_DATA(_PyPathConfig) _Py_path_config;
+PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate(
+ _PyPathConfig *config,
+ const _PyMainInterpreterConfig *main_config);
PyAPI_FUNC(void) _PyPathConfig_Clear(_PyPathConfig *config);
diff --git a/Include/pystate.h b/Include/pystate.h
index 60d001c..1d8aab6 100644
--- a/Include/pystate.h
+++ b/Include/pystate.h
@@ -72,7 +72,8 @@ typedef struct {
(_PyMainInterpreterConfig){\
.install_signal_handlers = -1, \
.module_search_path_env = NULL, \
- .home = NULL}
+ .home = NULL, \
+ .program_name = NULL}
typedef struct _is {
diff --git a/Modules/getpath.c b/Modules/getpath.c
index 8554dbe..fc2b544 100644
--- a/Modules/getpath.c
+++ b/Modules/getpath.c
@@ -1008,16 +1008,10 @@ calculate_path_impl(const _PyMainInterpreterConfig *main_config,
}
-/* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
- and Py_GetProgramFullPath() */
_PyInitError
-_PyPathConfig_Init(const _PyMainInterpreterConfig *main_config)
+_PyPathConfig_Calculate(_PyPathConfig *config,
+ const _PyMainInterpreterConfig *main_config)
{
- if (_Py_path_config.module_search_path) {
- /* Already initialized */
- return _Py_INIT_OK();
- }
-
PyCalculatePath calculate;
memset(&calculate, 0, sizeof(calculate));
@@ -1026,16 +1020,11 @@ _PyPathConfig_Init(const _PyMainInterpreterConfig *main_config)
goto done;
}
- _PyPathConfig new_path_config;
- memset(&new_path_config, 0, sizeof(new_path_config));
-
- err = calculate_path_impl(main_config, &calculate, &new_path_config);
+ err = calculate_path_impl(main_config, &calculate, config);
if (_Py_INIT_FAILED(err)) {
- _PyPathConfig_Clear(&new_path_config);
goto done;
}
- _Py_path_config = new_path_config;
err = _Py_INIT_OK();
done:
diff --git a/Modules/main.c b/Modules/main.c
index 6c6c801..84706e1 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -876,6 +876,16 @@ static _PyInitError
config_get_program_name(_PyMainInterpreterConfig *config)
{
assert(config->program_name == NULL);
+
+ /* If Py_SetProgramName() was called, use its value */
+ wchar_t *program_name = _Py_path_config.program_name;
+ if (program_name != NULL) {
+ config->program_name = _PyMem_RawWcsdup(program_name);
+ if (config->program_name == NULL) {
+ return _Py_INIT_NO_MEMORY();
+ }
+ }
+
#ifdef __APPLE__
char *p;
/* On MacOS X, when the Python interpreter is embedded in an
@@ -914,6 +924,7 @@ config_get_program_name(_PyMainInterpreterConfig *config)
}
#endif /* WITH_NEXT_FRAMEWORK */
#endif /* __APPLE__ */
+
return _Py_INIT_OK();
}
@@ -948,13 +959,6 @@ pymain_init_main_interpreter(_PyMain *pymain)
{
_PyInitError err;
- /* TODO: Print any exceptions raised by these operations */
- err = _PyMainInterpreterConfig_Read(&pymain->config);
- if (_Py_INIT_FAILED(err)) {
- pymain->err = err;
- return -1;
- }
-
err = _Py_InitializeMainInterpreter(&pymain->config);
if (_Py_INIT_FAILED(err)) {
pymain->err = err;
@@ -1412,14 +1416,13 @@ config_init_pythonpath(_PyMainInterpreterConfig *config)
static _PyInitError
-config_init_pythonhome(_PyMainInterpreterConfig *config)
+config_init_home(_PyMainInterpreterConfig *config)
{
wchar_t *home;
- home = Py_GetPythonHome();
+ /* If Py_SetPythonHome() was called, use its value */
+ home = _Py_path_config.home;
if (home) {
- /* Py_SetPythonHome() has been called before Py_Main(),
- use its value */
config->home = _PyMem_RawWcsdup(home);
if (config->home == NULL) {
return _Py_INIT_NO_MEMORY();
@@ -1439,7 +1442,7 @@ config_init_pythonhome(_PyMainInterpreterConfig *config)
_PyInitError
_PyMainInterpreterConfig_ReadEnv(_PyMainInterpreterConfig *config)
{
- _PyInitError err = config_init_pythonhome(config);
+ _PyInitError err = config_init_home(config);
if (_Py_INIT_FAILED(err)) {
return err;
}
@@ -1543,6 +1546,12 @@ pymain_parse_cmdline_envvars_impl(_PyMain *pymain)
return -1;
}
+ _PyInitError err = _PyMainInterpreterConfig_Read(&pymain->config);
+ if (_Py_INIT_FAILED(err)) {
+ pymain->err = err;
+ return -1;
+ }
+
return 0;
}
@@ -1566,11 +1575,6 @@ pymain_init_python(_PyMain *pymain)
{
pymain_init_stdio(pymain);
- Py_SetProgramName(pymain->config.program_name);
- /* Don't free program_name here: the argument to Py_SetProgramName
- must remain valid until Py_FinalizeEx is called. The string is freed
- by pymain_free(). */
-
pymain->err = _Py_InitializeCore(&pymain->core_config);
if (_Py_INIT_FAILED(pymain->err)) {
return -1;
diff --git a/PC/getpathp.c b/PC/getpathp.c
index 3a0ebc1..08ed8cc 100644
--- a/PC/getpathp.c
+++ b/PC/getpathp.c
@@ -1058,38 +1058,23 @@ calculate_free(PyCalculatePath *calculate)
}
-/* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
- and Py_GetProgramFullPath() */
_PyInitError
-_PyPathConfig_Init(const _PyMainInterpreterConfig *main_config)
+_PyPathConfig_Calculate(_PyPathConfig *config,
+ const _PyMainInterpreterConfig *main_config)
{
- if (_Py_path_config.module_search_path) {
- /* Already initialized */
- return _Py_INIT_OK();
- }
-
- _PyInitError err;
-
PyCalculatePath calculate;
memset(&calculate, 0, sizeof(calculate));
calculate_init(&calculate, main_config);
- _PyPathConfig new_path_config;
- memset(&new_path_config, 0, sizeof(new_path_config));
-
- err = calculate_path_impl(main_config, &calculate, &new_path_config);
+ _PyInitError err = calculate_path_impl(main_config, &calculate, config);
if (_Py_INIT_FAILED(err)) {
goto done;
}
- _Py_path_config = new_path_config;
err = _Py_INIT_OK();
done:
- if (_Py_INIT_FAILED(err)) {
- _PyPathConfig_Clear(&new_path_config);
- }
calculate_free(&calculate);
return err;
}
diff --git a/Python/pathconfig.c b/Python/pathconfig.c
index daa2227..6a03f7d 100644
--- a/Python/pathconfig.c
+++ b/Python/pathconfig.c
@@ -10,17 +10,17 @@ extern "C" {
_PyPathConfig _Py_path_config = _PyPathConfig_INIT;
-#ifdef MS_WINDOWS
-static wchar_t *progname = L"python";
-#else
-static wchar_t *progname = L"python3";
-#endif
-static wchar_t *default_home = NULL;
void
_PyPathConfig_Clear(_PyPathConfig *config)
{
+ /* _PyMem_SetDefaultAllocator() is needed to get a known memory allocator,
+ since Py_SetPath(), Py_SetPythonHome() and Py_SetProgramName() can be
+ called before Py_Initialize() which can changes the memory allocator. */
+ PyMemAllocatorEx old_alloc;
+ _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+
#define CLEAR(ATTR) \
do { \
PyMem_RawFree(ATTR); \
@@ -35,57 +35,64 @@ _PyPathConfig_Clear(_PyPathConfig *config)
CLEAR(config->exec_prefix);
#endif
CLEAR(config->module_search_path);
+ CLEAR(config->home);
+ CLEAR(config->program_name);
#undef CLEAR
-}
-
-void
-Py_SetProgramName(wchar_t *pn)
-{
- if (pn && *pn)
- progname = pn;
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
}
-wchar_t *
-Py_GetProgramName(void)
+/* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
+ and Py_GetProgramFullPath() */
+_PyInitError
+_PyPathConfig_Init(const _PyMainInterpreterConfig *main_config)
{
- return progname;
-}
-
-
-void
-Py_SetPythonHome(wchar_t *home)
-{
- default_home = home;
-}
+ if (_Py_path_config.module_search_path) {
+ /* Already initialized */
+ return _Py_INIT_OK();
+ }
+ _PyInitError err;
+ _PyPathConfig new_config = _PyPathConfig_INIT;
-wchar_t*
-Py_GetPythonHome(void)
-{
- /* 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];
+ PyMemAllocatorEx old_alloc;
+ _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
- if (default_home) {
- return default_home;
+ /* Calculate program_full_path, prefix, exec_prefix (Unix)
+ or dll_path (Windows), and module_search_path */
+ err = _PyPathConfig_Calculate(&new_config, main_config);
+ if (_Py_INIT_FAILED(err)) {
+ _PyPathConfig_Clear(&new_config);
+ goto done;
}
- char *home = Py_GETENV("PYTHONHOME");
- if (!home) {
- return NULL;
+ /* Copy home and program_name from main_config */
+ if (main_config->home != NULL) {
+ new_config.home = _PyMem_RawWcsdup(main_config->home);
+ if (new_config.home == NULL) {
+ err = _Py_INIT_NO_MEMORY();
+ goto done;
+ }
+ }
+ else {
+ new_config.home = 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;
+ new_config.program_name = _PyMem_RawWcsdup(main_config->program_name);
+ if (new_config.program_name == NULL) {
+ err = _Py_INIT_NO_MEMORY();
+ goto done;
}
- return buffer;
+ _PyPathConfig_Clear(&_Py_path_config);
+ _Py_path_config = new_config;
+
+ err = _Py_INIT_OK();
+
+done:
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+ return err;
}
@@ -134,6 +141,9 @@ Py_SetPath(const wchar_t *path)
return;
}
+ PyMemAllocatorEx old_alloc;
+ _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+
_PyPathConfig new_config;
new_config.program_full_path = _PyMem_RawWcsdup(Py_GetProgramName());
new_config.prefix = _PyMem_RawWcsdup(L"");
@@ -144,8 +154,58 @@ Py_SetPath(const wchar_t *path)
#endif
new_config.module_search_path = _PyMem_RawWcsdup(path);
+ /* steal the home and program_name values (to leave them unchanged) */
+ new_config.home = _Py_path_config.home;
+ _Py_path_config.home = NULL;
+ new_config.program_name = _Py_path_config.program_name;
+ _Py_path_config.program_name = NULL;
+
_PyPathConfig_Clear(&_Py_path_config);
_Py_path_config = new_config;
+
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+}
+
+
+void
+Py_SetPythonHome(wchar_t *home)
+{
+ if (home == NULL) {
+ return;
+ }
+
+ PyMemAllocatorEx old_alloc;
+ _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+
+ PyMem_RawFree(_Py_path_config.home);
+ _Py_path_config.home = _PyMem_RawWcsdup(home);
+
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+
+ if (_Py_path_config.home == NULL) {
+ Py_FatalError("Py_SetPythonHome() failed: out of memory");
+ }
+}
+
+
+void
+Py_SetProgramName(wchar_t *program_name)
+{
+ if (program_name == NULL || program_name[0] == L'\0') {
+ return;
+ }
+
+ PyMemAllocatorEx old_alloc;
+ _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+
+ PyMem_RawFree(_Py_path_config.program_name);
+ _Py_path_config.program_name = _PyMem_RawWcsdup(program_name);
+
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+
+ if (_Py_path_config.program_name == NULL) {
+ Py_FatalError("Py_SetProgramName() failed: out of memory");
+ }
}
@@ -184,6 +244,23 @@ Py_GetProgramFullPath(void)
return _Py_path_config.program_full_path;
}
+
+wchar_t*
+Py_GetPythonHome(void)
+{
+ pathconfig_global_init();
+ return _Py_path_config.home;
+}
+
+
+wchar_t *
+Py_GetProgramName(void)
+{
+ pathconfig_global_init();
+ return _Py_path_config.program_name;
+}
+
+
#ifdef __cplusplus
}
#endif
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 8d71154..523397f 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -804,7 +804,12 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *config)
}
if (config->program_name == NULL) {
- config->program_name = _PyMem_RawWcsdup(Py_GetProgramName());
+#ifdef MS_WINDOWS
+ const wchar_t *program_name = L"python";
+#else
+ const wchar_t *program_name = L"python3";
+#endif
+ config->program_name = _PyMem_RawWcsdup(program_name);
if (config->program_name == NULL) {
return _Py_INIT_NO_MEMORY();
}