bpo-38234: Py_SetPath() uses the program full path (GH-16357)

Py_SetPath() now sets sys.executable to the program full path
(Py_GetProgramFullPath()), rather than to the program name
(Py_GetProgramName()).

Fix also memory leaks in pathconfig_set_from_config().
This commit is contained in:
Victor Stinner 2019-09-24 17:44:15 +02:00 committed by GitHub
parent b0e1ae5f54
commit 1ce152a42e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 21 additions and 6 deletions

View file

@ -472,8 +472,8 @@ Process-wide parameters
dependent delimiter character, which is ``':'`` on Unix and Mac OS X, ``';'`` dependent delimiter character, which is ``':'`` on Unix and Mac OS X, ``';'``
on Windows. on Windows.
This also causes :data:`sys.executable` to be set only to the raw program This also causes :data:`sys.executable` to be set to the program
name (see :c:func:`Py_SetProgramName`) and for :data:`sys.prefix` and full path (see :c:func:`Py_GetProgramFullPath`) and for :data:`sys.prefix` and
:data:`sys.exec_prefix` to be empty. It is up to the caller to modify these :data:`sys.exec_prefix` to be empty. It is up to the caller to modify these
if required after calling :c:func:`Py_Initialize`. if required after calling :c:func:`Py_Initialize`.
@ -483,6 +483,10 @@ Process-wide parameters
The path argument is copied internally, so the caller may free it after the The path argument is copied internally, so the caller may free it after the
call completes. call completes.
.. versionchanged:: 3.8
The program full path is now used for :data:`sys.executable`, instead
of the program name.
.. c:function:: const char* Py_GetVersion() .. c:function:: const char* Py_GetVersion()

View file

@ -1347,6 +1347,11 @@ Build and C API Changes
parameter for indicating the number of positional-only arguments. parameter for indicating the number of positional-only arguments.
(Contributed by Pablo Galindo in :issue:`37221`.) (Contributed by Pablo Galindo in :issue:`37221`.)
* :c:func:`Py_SetPath` now sets :data:`sys.executable` to the program full
path (:c:func:`Py_GetProgramFullPath`) rather than to the program name
(:c:func:`Py_GetProgramName`).
(Contributed by Victor Stinner in :issue:`38234`.)
Deprecated Deprecated
========== ==========

View file

@ -0,0 +1,3 @@
:c:func:`Py_SetPath` now sets :data:`sys.executable` to the program full
path (:c:func:`Py_GetProgramFullPath`) rather than to the program name
(:c:func:`Py_GetProgramName`).

View file

@ -23,6 +23,7 @@ wchar_t *_Py_dll_path = NULL;
static int static int
copy_wstr(wchar_t **dst, const wchar_t *src) copy_wstr(wchar_t **dst, const wchar_t *src)
{ {
assert(*dst == NULL);
if (src != NULL) { if (src != NULL) {
*dst = _PyMem_RawWcsdup(src); *dst = _PyMem_RawWcsdup(src);
if (*dst == NULL) { if (*dst == NULL) {
@ -172,6 +173,7 @@ pathconfig_set_from_config(_PyPathConfig *pathconfig, const PyConfig *config)
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
if (config->module_search_paths_set) { if (config->module_search_paths_set) {
PyMem_RawFree(pathconfig->module_search_path);
pathconfig->module_search_path = _PyWideStringList_Join(&config->module_search_paths, DELIM); pathconfig->module_search_path = _PyWideStringList_Join(&config->module_search_paths, DELIM);
if (pathconfig->module_search_path == NULL) { if (pathconfig->module_search_path == NULL) {
goto no_memory; goto no_memory;
@ -180,6 +182,8 @@ pathconfig_set_from_config(_PyPathConfig *pathconfig, const PyConfig *config)
#define COPY_CONFIG(PATH_ATTR, CONFIG_ATTR) \ #define COPY_CONFIG(PATH_ATTR, CONFIG_ATTR) \
if (config->CONFIG_ATTR) { \ if (config->CONFIG_ATTR) { \
PyMem_RawFree(pathconfig->PATH_ATTR); \
pathconfig->PATH_ATTR = NULL; \
if (copy_wstr(&pathconfig->PATH_ATTR, config->CONFIG_ATTR) < 0) { \ if (copy_wstr(&pathconfig->PATH_ATTR, config->CONFIG_ATTR) < 0) { \
goto no_memory; \ goto no_memory; \
} \ } \
@ -455,16 +459,15 @@ Py_SetPath(const wchar_t *path)
PyMemAllocatorEx old_alloc; PyMemAllocatorEx old_alloc;
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
/* Getting the program name calls pathconfig_global_init() */ /* Getting the program full path calls pathconfig_global_init() */
wchar_t *program_name = _PyMem_RawWcsdup(Py_GetProgramName()); wchar_t *program_full_path = _PyMem_RawWcsdup(Py_GetProgramFullPath());
PyMem_RawFree(_Py_path_config.program_full_path); PyMem_RawFree(_Py_path_config.program_full_path);
PyMem_RawFree(_Py_path_config.prefix); PyMem_RawFree(_Py_path_config.prefix);
PyMem_RawFree(_Py_path_config.exec_prefix); PyMem_RawFree(_Py_path_config.exec_prefix);
PyMem_RawFree(_Py_path_config.module_search_path); PyMem_RawFree(_Py_path_config.module_search_path);
/* Copy program_name to program_full_path */ _Py_path_config.program_full_path = program_full_path;
_Py_path_config.program_full_path = program_name;
_Py_path_config.prefix = _PyMem_RawWcsdup(L""); _Py_path_config.prefix = _PyMem_RawWcsdup(L"");
_Py_path_config.exec_prefix = _PyMem_RawWcsdup(L""); _Py_path_config.exec_prefix = _PyMem_RawWcsdup(L"");
_Py_path_config.module_search_path = _PyMem_RawWcsdup(path); _Py_path_config.module_search_path = _PyMem_RawWcsdup(path);