From f04ebe2a4d68b194deeb438e9185efdafc10a832 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 25 Nov 2017 00:01:23 +0100 Subject: [PATCH] bpo-32030: Add _PyMainInterpreterConfig.program_name (#4548) * Py_Main() now calls Py_SetProgramName() earlier to be able to get the program name in _PyMainInterpreterConfig_ReadEnv(). * Rename prog to program_name * Rename progpath to program_name --- Include/pystate.h | 2 ++ Modules/getpath.c | 60 +++++++++++++++++++++++-------------------- Modules/main.c | 21 +++++++++++---- PC/getpathp.c | 61 ++++++++++++++++++++------------------------ Python/pylifecycle.c | 22 +++++++++++++--- 5 files changed, 96 insertions(+), 70 deletions(-) diff --git a/Include/pystate.h b/Include/pystate.h index 533851fc028..60d001c4926 100644 --- a/Include/pystate.h +++ b/Include/pystate.h @@ -64,6 +64,8 @@ typedef struct { wchar_t *module_search_path_env; /* PYTHONHOME environment variable, see also Py_SetPythonHome(). */ wchar_t *home; + /* Program name, see also Py_GetProgramName() */ + wchar_t *program_name; } _PyMainInterpreterConfig; #define _PyMainInterpreterConfig_INIT \ diff --git a/Modules/getpath.c b/Modules/getpath.c index db28eaf66df..9078aa81b32 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -112,7 +112,7 @@ extern "C" { typedef struct { wchar_t prefix[MAXPATHLEN+1]; wchar_t exec_prefix[MAXPATHLEN+1]; - wchar_t progpath[MAXPATHLEN+1]; + wchar_t program_name[MAXPATHLEN+1]; wchar_t *module_search_path; } PyPathConfig; @@ -121,7 +121,7 @@ typedef struct { wchar_t *home; /* PYTHONHOME environment variable */ wchar_t *module_search_path_env; /* PYTHONPATH environment variable */ - wchar_t *prog; /* Program name */ + wchar_t *program_name; /* Program name */ wchar_t *pythonpath; /* PYTHONPATH define */ wchar_t *prefix; /* PREFIX define */ wchar_t *exec_prefix; /* EXEC_PREFIX define */ @@ -602,8 +602,8 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config) * other way to find a directory to start the search from. If * $PATH isn't exported, you lose. */ - if (wcschr(calculate->prog, SEP)) { - wcsncpy(config->progpath, calculate->prog, MAXPATHLEN); + if (wcschr(calculate->program_name, SEP)) { + wcsncpy(config->program_name, calculate->program_name, MAXPATHLEN); } #ifdef __APPLE__ /* On Mac OS X, if a script uses an interpreter of the form @@ -616,11 +616,13 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config) * will fail if a relative path was used. but in that case, * absolutize() should help us out below */ - else if(0 == _NSGetExecutablePath(execpath, &nsexeclength) && execpath[0] == SEP) { - size_t r = mbstowcs(config->progpath, execpath, MAXPATHLEN+1); + else if(0 == _NSGetExecutablePath(execpath, &nsexeclength) && + execpath[0] == SEP) + { + size_t r = mbstowcs(config->program_name, execpath, MAXPATHLEN+1); if (r == (size_t)-1 || r > MAXPATHLEN) { /* Could not convert execpath, or it's too long. */ - config->progpath[0] = '\0'; + config->program_name[0] = '\0'; } } #endif /* __APPLE__ */ @@ -634,30 +636,30 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config) if (len > MAXPATHLEN) { len = MAXPATHLEN; } - wcsncpy(config->progpath, path, len); - *(config->progpath + len) = '\0'; + wcsncpy(config->program_name, path, len); + *(config->program_name + len) = '\0'; } else { - wcsncpy(config->progpath, path, MAXPATHLEN); + wcsncpy(config->program_name, path, MAXPATHLEN); } - joinpath(config->progpath, calculate->prog); - if (isxfile(config->progpath)) { + joinpath(config->program_name, calculate->program_name); + if (isxfile(config->program_name)) { break; } if (!delim) { - config->progpath[0] = L'\0'; + config->program_name[0] = L'\0'; break; } path = delim + 1; } } else { - config->progpath[0] = '\0'; + config->program_name[0] = '\0'; } - if (config->progpath[0] != SEP && config->progpath[0] != '\0') { - absolutize(config->progpath); + if (config->program_name[0] != SEP && config->program_name[0] != '\0') { + absolutize(config->program_name); } } @@ -665,7 +667,7 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config) static void calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config) { - wcsncpy(calculate->argv0_path, config->progpath, MAXPATHLEN); + wcsncpy(calculate->argv0_path, config->program_name, MAXPATHLEN); calculate->argv0_path[MAXPATHLEN] = '\0'; #ifdef WITH_NEXT_FRAMEWORK @@ -700,10 +702,10 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config) if (!ismodule(calculate->argv0_path)) { /* We are in the build directory so use the name of the executable - we know that the absolute path is passed */ - wcsncpy(calculate->argv0_path, config->progpath, MAXPATHLEN); + wcsncpy(calculate->argv0_path, config->program_name, MAXPATHLEN); } else { - /* Use the location of the library as the progpath */ + /* Use the location of the library as the program_name */ wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN); } PyMem_RawFree(wbuf); @@ -712,7 +714,7 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config) #if HAVE_READLINK wchar_t tmpbuffer[MAXPATHLEN+1]; - int linklen = _Py_wreadlink(config->progpath, tmpbuffer, MAXPATHLEN); + int linklen = _Py_wreadlink(config->program_name, tmpbuffer, MAXPATHLEN); while (linklen != -1) { if (tmpbuffer[0] == SEP) { /* tmpbuffer should never be longer than MAXPATHLEN, @@ -720,7 +722,7 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config) wcsncpy(calculate->argv0_path, tmpbuffer, MAXPATHLEN); } else { - /* Interpret relative to progpath */ + /* Interpret relative to program_name */ reduce(calculate->argv0_path); joinpath(calculate->argv0_path, tmpbuffer); } @@ -897,6 +899,7 @@ calculate_init(PyCalculatePath *calculate, { calculate->home = main_config->home; calculate->module_search_path_env = main_config->module_search_path_env; + calculate->program_name = main_config->program_name; size_t len; char *path = getenv("PATH"); @@ -907,8 +910,6 @@ calculate_init(PyCalculatePath *calculate, } } - calculate->prog = Py_GetProgramName(); - calculate->pythonpath = Py_DecodeLocale(PYTHONPATH, &len); if (!calculate->pythonpath) { return DECODE_LOCALE_ERR("PYTHONPATH define", len); @@ -950,7 +951,9 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config) calculate_zip_path(calculate, config); calculate_exec_prefix(calculate, config); - if ((!calculate->prefix_found || !calculate->exec_prefix_found) && !Py_FrozenFlag) { + if ((!calculate->prefix_found || !calculate->exec_prefix_found) && + !Py_FrozenFlag) + { fprintf(stderr, "Consider setting $PYTHONHOME to [:]\n"); } @@ -1018,10 +1021,11 @@ Py_SetPath(const wchar_t *path) return; } - wchar_t *prog = Py_GetProgramName(); - wcsncpy(path_config.progpath, prog, MAXPATHLEN); + wchar_t *program_name = Py_GetProgramName(); + wcsncpy(path_config.program_name, program_name, MAXPATHLEN); path_config.exec_prefix[0] = path_config.prefix[0] = L'\0'; - path_config.module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t)); + size_t size = (wcslen(path) + 1) * sizeof(wchar_t); + path_config.module_search_path = PyMem_RawMalloc(size); if (path_config.module_search_path != NULL) { wcscpy(path_config.module_search_path, path); } @@ -1074,7 +1078,7 @@ Py_GetProgramFullPath(void) if (!path_config.module_search_path) { calculate_path(NULL); } - return path_config.progpath; + return path_config.program_name; } #ifdef __cplusplus diff --git a/Modules/main.c b/Modules/main.c index 5b0c0493841..dca165dad2c 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -1452,6 +1452,13 @@ _PyMainInterpreterConfig_ReadEnv(_PyMainInterpreterConfig *config) return err; } + /* FIXME: _PyMainInterpreterConfig_Read() has the same code. Remove it + here? See also pymain_get_program_name() and pymain_parse_envvars(). */ + config->program_name = _PyMem_RawWcsdup(Py_GetProgramName()); + if (config->program_name == NULL) { + return _Py_INIT_NO_MEMORY(); + } + return _Py_INIT_OK(); } @@ -1480,6 +1487,15 @@ pymain_parse_envvars(_PyMain *pymain) } core_config->allocator = Py_GETENV("PYTHONMALLOC"); + /* FIXME: move pymain_get_program_name() code into + _PyMainInterpreterConfig_ReadEnv(). + Problem: _PyMainInterpreterConfig_ReadEnv() doesn't have access + to argv[0]. */ + Py_SetProgramName(pymain->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(). */ + _PyInitError err = _PyMainInterpreterConfig_ReadEnv(&pymain->config); if (_Py_INIT_FAILED(pymain->err)) { pymain->err = err; @@ -1569,11 +1585,6 @@ pymain_init_python(_PyMain *pymain) return -1; } - Py_SetProgramName(pymain->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(). */ - if (pymain_add_xoptions(pymain)) { return -1; } diff --git a/PC/getpathp.c b/PC/getpathp.c index 5adf16d6f27..38e433b6dcd 100644 --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -118,7 +118,7 @@ typedef struct { wchar_t prefix[MAXPATHLEN+1]; - wchar_t progpath[MAXPATHLEN+1]; + wchar_t program_name[MAXPATHLEN+1]; wchar_t dllpath[MAXPATHLEN+1]; wchar_t *module_search_path; } PyPathConfig; @@ -132,7 +132,7 @@ typedef struct { wchar_t *machine_path; /* from HKEY_LOCAL_MACHINE */ wchar_t *user_path; /* from HKEY_CURRENT_USER */ - wchar_t *prog; /* Program name */ + wchar_t *program_name; /* Program name */ wchar_t argv0_path[MAXPATHLEN+1]; wchar_t zip_path[MAXPATHLEN+1]; } PyCalculatePath; @@ -484,22 +484,22 @@ done: static void -get_progpath(PyCalculatePath *calculate, wchar_t *progpath, wchar_t *dllpath) +get_progpath(PyCalculatePath *calculate, PyPathConfig *config) { wchar_t *path = calculate->path_env; #ifdef Py_ENABLE_SHARED extern HANDLE PyWin_DLLhModule; - /* static init of progpath ensures final char remains \0 */ + /* static init of program_name ensures final char remains \0 */ if (PyWin_DLLhModule) { - if (!GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN)) { - dllpath[0] = 0; + if (!GetModuleFileNameW(PyWin_DLLhModule, config->dllpath, MAXPATHLEN)) { + config->dllpath[0] = 0; } } #else - dllpath[0] = 0; + config->dllpath[0] = 0; #endif - if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN)) { + if (GetModuleFileNameW(NULL, config->program_name, MAXPATHLEN)) { return; } @@ -509,12 +509,12 @@ get_progpath(PyCalculatePath *calculate, wchar_t *progpath, wchar_t *dllpath) * $PATH isn't exported, you lose. */ #ifdef ALTSEP - if (wcschr(calculate->prog, SEP) || wcschr(calculate->prog, ALTSEP)) + if (wcschr(calculate->program_name, SEP) || wcschr(calculate->program_name, ALTSEP)) #else - if (wcschr(calculate->prog, SEP)) + if (wcschr(calculate->program_name, SEP)) #endif { - wcsncpy(progpath, calculate->prog, MAXPATHLEN); + wcsncpy(config->program_name, calculate->program_name, MAXPATHLEN); } else if (path) { while (1) { @@ -524,28 +524,28 @@ get_progpath(PyCalculatePath *calculate, wchar_t *progpath, wchar_t *dllpath) size_t len = delim - path; /* ensure we can't overwrite buffer */ len = min(MAXPATHLEN,len); - wcsncpy(progpath, path, len); - *(progpath + len) = '\0'; + wcsncpy(config->program_name, path, len); + *(config->program_name + len) = '\0'; } else { - wcsncpy(progpath, path, MAXPATHLEN); + wcsncpy(config->program_name, path, MAXPATHLEN); } /* join() is safe for MAXPATHLEN+1 size buffer */ - join(progpath, calculate->prog); - if (exists(progpath)) { + join(config->program_name, calculate->program_name); + if (exists(config->program_name)) { break; } if (!delim) { - progpath[0] = '\0'; + config->program_name[0] = '\0'; break; } path = delim + 1; } } else { - progpath[0] = '\0'; + config->program_name[0] = '\0'; } } @@ -695,14 +695,9 @@ calculate_init(PyCalculatePath *calculate, { calculate->home = main_config->home; calculate->module_search_path_env = main_config->module_search_path_env; + calculate->program_name = main_config->program_name; calculate->path_env = _wgetenv(L"PATH"); - - wchar_t *prog = Py_GetProgramName(); - if (prog == NULL || *prog == '\0') { - prog = L"python"; - } - calculate->prog = prog; } @@ -714,8 +709,8 @@ get_pth_filename(wchar_t *spbuffer, PyPathConfig *config) return 1; } } - if (config->progpath[0]) { - if (!change_ext(spbuffer, config->progpath, L"._pth") && exists(spbuffer)) { + if (config->program_name[0]) { + if (!change_ext(spbuffer, config->program_name, L"._pth") && exists(spbuffer)) { return 1; } } @@ -784,9 +779,9 @@ static void calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config, const _PyMainInterpreterConfig *main_config) { - get_progpath(calculate, config->progpath, config->dllpath); - /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */ - wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, config->progpath); + get_progpath(calculate, config); + /* program_name guaranteed \0 terminated in MAXPATH+1 bytes. */ + wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, config->program_name); reduce(calculate->argv0_path); /* Search for a sys.path file */ @@ -798,7 +793,7 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config, /* Calculate zip archive path from DLL or exe path */ change_ext(calculate->zip_path, - config->dllpath[0] ? config->dllpath : config->progpath, + config->dllpath[0] ? config->dllpath : config->program_name, L".zip"); if (calculate->home == NULL || *calculate->home == '\0') { @@ -1057,8 +1052,8 @@ Py_SetPath(const wchar_t *path) return; } - wchar_t *prog = Py_GetProgramName(); - wcsncpy(path_config.progpath, prog, MAXPATHLEN); + wchar_t *program_name = Py_GetProgramName(); + wcsncpy(path_config.program_name, program_name, MAXPATHLEN); path_config.prefix[0] = L'\0'; path_config.module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t)); if (path_config.module_search_path != NULL) { @@ -1110,7 +1105,7 @@ Py_GetProgramFullPath(void) if (!path_config.module_search_path) { calculate_path(NULL); } - return path_config.progpath; + return path_config.program_name; } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index e36b6c1b057..714be3768f6 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -802,6 +802,14 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *config) if (config->install_signal_handlers < 0) { config->install_signal_handlers = 1; } + + if (config->program_name == NULL) { + config->program_name = _PyMem_RawWcsdup(Py_GetProgramName()); + if (config->program_name == NULL) { + return _Py_INIT_NO_MEMORY(); + } + } + return _Py_INIT_OK(); } @@ -809,10 +817,16 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *config) void _PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *config) { - PyMem_RawFree(config->module_search_path_env); - config->module_search_path_env = NULL; - PyMem_RawFree(config->home); - config->home = NULL; +#define CLEAR(ATTR) \ + do { \ + PyMem_RawFree(ATTR); \ + ATTR = NULL; \ + } while (0) + + CLEAR(config->module_search_path_env); + CLEAR(config->home); + CLEAR(config->program_name); +#undef CLEAR }