Skip to content

Commit b1147e4

Browse files
authored
bpo-34170: Rework _PyCoreConfig_Read() to avoid side effect (GH-8353)
Rework _PyCoreConfig_Read() function which *reads* core configuration to not *modify* the path configuration. A new _PyCoreConfig_SetPathConfig() function now recreates the path configuration from the core configuration. This function is now called very late in _Py_InitializeCore(), just before calling initimport(). Changes: * Add _PyCoreConfig.dll_path * Py_SetPath() now fails with a fatal python error on memory allocation failure. * Rename _PyPathConfig_Calculate() to _PyPathConfig_Calculate_impl() * Replace _PyPathConfig_Init() with _PyPathConfig_Calculate(): the function now requires a _PyPathConfig * Add _PyPathConfig_SetGlobal() to set the _Py_path_config global variable. * Add _PyCoreConfig_InitPathConfig(): compute the path configuration * Add _PyCoreConfig_SetPathConfig(): set path configuration from core configuration * Rename wstrlist_append() to _Py_wstrlist_append() * _Py_wstrlist_append() now handles integer overflow.
1 parent 94487d4 commit b1147e4

File tree

8 files changed

+358
-146
lines changed

8 files changed

+358
-146
lines changed

Include/internal/pystate.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ struct _gilstate_runtime_state {
3737
#define _PyGILState_check_enabled _PyRuntime.gilstate.check_enabled
3838

3939

40-
typedef struct {
40+
typedef struct _PyPathConfig {
4141
/* Full path to the Python program */
4242
wchar_t *program_full_path;
4343
wchar_t *prefix;
@@ -59,11 +59,15 @@ typedef struct {
5959

6060
PyAPI_DATA(_PyPathConfig) _Py_path_config;
6161

62-
PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate(
62+
PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate_impl(
6363
_PyPathConfig *config,
6464
const _PyCoreConfig *core_config);
65-
PyAPI_FUNC(void) _PyPathConfig_Clear(_PyPathConfig *config);
65+
PyAPI_FUNC(void) _PyPathConfig_ClearGlobal(void);
6666

67+
PyAPI_FUNC(_PyInitError) _Py_wstrlist_append(
68+
int *len,
69+
wchar_t ***list,
70+
const wchar_t *str);
6771

6872
/* interpreter state */
6973

Include/pylifecycle.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ PyAPI_FUNC(void) _PyCoreConfig_Clear(_PyCoreConfig *);
5959
PyAPI_FUNC(int) _PyCoreConfig_Copy(
6060
_PyCoreConfig *config,
6161
const _PyCoreConfig *config2);
62+
PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitPathConfig(_PyCoreConfig *config);
63+
PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetPathConfig(
64+
const _PyCoreConfig *config);
6265

6366
PyAPI_FUNC(_PyInitError) _PyMainInterpreterConfig_Read(
6467
_PyMainInterpreterConfig *config,
@@ -116,7 +119,11 @@ PyAPI_FUNC(wchar_t *) Py_GetPrefix(void);
116119
PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void);
117120
PyAPI_FUNC(wchar_t *) Py_GetPath(void);
118121
#ifdef Py_BUILD_CORE
119-
PyAPI_FUNC(_PyInitError) _PyPathConfig_Init(const _PyCoreConfig *core_config);
122+
struct _PyPathConfig;
123+
typedef struct _PyPathConfig _PyPathConfig;
124+
125+
PyAPI_FUNC(_PyInitError) _PyPathConfig_SetGlobal(
126+
const _PyPathConfig *config);
120127
PyAPI_FUNC(PyObject*) _PyPathConfig_ComputeArgv0(int argc, wchar_t **argv);
121128
PyAPI_FUNC(int) _Py_FindEnvConfigValue(
122129
FILE *env_file,

Include/pystate.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ typedef struct {
7171
wchar_t *base_prefix; /* sys.base_prefix */
7272
wchar_t *exec_prefix; /* sys.exec_prefix */
7373
wchar_t *base_exec_prefix; /* sys.base_exec_prefix */
74+
#ifdef MS_WINDOWS
75+
wchar_t *dll_path; /* Windows DLL path */
76+
#endif
7477

7578
/* Private fields */
7679
int _disable_importlib; /* Needed by freeze_importlib */

Modules/getpath.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,7 @@ calculate_path_impl(const _PyCoreConfig *core_config,
946946

947947

948948
_PyInitError
949-
_PyPathConfig_Calculate(_PyPathConfig *config, const _PyCoreConfig *core_config)
949+
_PyPathConfig_Calculate_impl(_PyPathConfig *config, const _PyCoreConfig *core_config)
950950
{
951951
PyCalculatePath calculate;
952952
memset(&calculate, 0, sizeof(calculate));

Modules/main.c

Lines changed: 27 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ pymain_free_raw(_PyMain *pymain)
650650
configuration options set before Py_Initialize() which should
651651
remain valid after Py_Finalize(), since
652652
Py_Initialize()-Py_Finalize() can be called multiple times. */
653-
_PyPathConfig_Clear(&_Py_path_config);
653+
_PyPathConfig_ClearGlobal();
654654

655655
pymain_clear_config(pymain);
656656

@@ -701,9 +701,13 @@ pymain_run_main_from_importer(_PyMain *pymain)
701701
}
702702

703703

704-
static _PyInitError
705-
wstrlist_append(int *len, wchar_t ***list, const wchar_t *str)
704+
_PyInitError
705+
_Py_wstrlist_append(int *len, wchar_t ***list, const wchar_t *str)
706706
{
707+
if (*len == INT_MAX) {
708+
/* len+1 would overflow */
709+
return _Py_INIT_NO_MEMORY();
710+
}
707711
wchar_t *str2 = _PyMem_RawWcsdup(str);
708712
if (str2 == NULL) {
709713
return _Py_INIT_NO_MEMORY();
@@ -725,7 +729,7 @@ wstrlist_append(int *len, wchar_t ***list, const wchar_t *str)
725729
static int
726730
pymain_wstrlist_append(_PyMain *pymain, int *len, wchar_t ***list, const wchar_t *str)
727731
{
728-
_PyInitError err = wstrlist_append(len, list, str);
732+
_PyInitError err = _Py_wstrlist_append(len, list, str);
729733
if (_Py_INIT_FAILED(err)) {
730734
pymain->err = err;
731735
return -1;
@@ -972,9 +976,9 @@ static _PyInitError
972976
config_add_warnings_optlist(_PyCoreConfig *config, int len, wchar_t **options)
973977
{
974978
for (int i = 0; i < len; i++) {
975-
_PyInitError err = wstrlist_append(&config->nwarnoption,
976-
&config->warnoptions,
977-
options[i]);
979+
_PyInitError err = _Py_wstrlist_append(&config->nwarnoption,
980+
&config->warnoptions,
981+
options[i]);
978982
if (_Py_INIT_FAILED(err)) {
979983
return err;
980984
}
@@ -1006,9 +1010,9 @@ config_init_warnoptions(_PyCoreConfig *config, _Py_CommandLineDetails *cmdline)
10061010
*/
10071011

10081012
if (config->dev_mode) {
1009-
err = wstrlist_append(&config->nwarnoption,
1010-
&config->warnoptions,
1011-
L"default");
1013+
err = _Py_wstrlist_append(&config->nwarnoption,
1014+
&config->warnoptions,
1015+
L"default");
10121016
if (_Py_INIT_FAILED(err)) {
10131017
return err;
10141018
}
@@ -1040,9 +1044,9 @@ config_init_warnoptions(_PyCoreConfig *config, _Py_CommandLineDetails *cmdline)
10401044
else {
10411045
filter = L"default::BytesWarning";
10421046
}
1043-
err = wstrlist_append(&config->nwarnoption,
1044-
&config->warnoptions,
1045-
filter);
1047+
err = _Py_wstrlist_append(&config->nwarnoption,
1048+
&config->warnoptions,
1049+
filter);
10461050
if (_Py_INIT_FAILED(err)) {
10471051
return err;
10481052
}
@@ -1077,9 +1081,9 @@ cmdline_init_env_warnoptions(_Py_CommandLineDetails *cmdline)
10771081
warning != NULL;
10781082
warning = WCSTOK(NULL, L",", &context))
10791083
{
1080-
_PyInitError err = wstrlist_append(&cmdline->nenv_warnoption,
1081-
&cmdline->env_warnoptions,
1082-
warning);
1084+
_PyInitError err = _Py_wstrlist_append(&cmdline->nenv_warnoption,
1085+
&cmdline->env_warnoptions,
1086+
warning);
10831087
if (_Py_INIT_FAILED(err)) {
10841088
PyMem_RawFree(env);
10851089
return err;
@@ -2099,101 +2103,6 @@ config_init_locale(_PyCoreConfig *config)
20992103
}
21002104

21012105

2102-
static _PyInitError
2103-
config_init_module_search_paths(_PyCoreConfig *config)
2104-
{
2105-
assert(config->module_search_paths == NULL);
2106-
assert(config->nmodule_search_path < 0);
2107-
2108-
config->nmodule_search_path = 0;
2109-
2110-
const wchar_t *sys_path = Py_GetPath();
2111-
const wchar_t delim = DELIM;
2112-
const wchar_t *p = sys_path;
2113-
while (1) {
2114-
p = wcschr(sys_path, delim);
2115-
if (p == NULL) {
2116-
p = sys_path + wcslen(sys_path); /* End of string */
2117-
}
2118-
2119-
size_t path_len = (p - sys_path);
2120-
wchar_t *path = PyMem_RawMalloc((path_len + 1) * sizeof(wchar_t));
2121-
if (path == NULL) {
2122-
return _Py_INIT_NO_MEMORY();
2123-
}
2124-
memcpy(path, sys_path, path_len * sizeof(wchar_t));
2125-
path[path_len] = L'\0';
2126-
2127-
_PyInitError err = wstrlist_append(&config->nmodule_search_path,
2128-
&config->module_search_paths,
2129-
path);
2130-
PyMem_RawFree(path);
2131-
if (_Py_INIT_FAILED(err)) {
2132-
return err;
2133-
}
2134-
2135-
if (*p == '\0') {
2136-
break;
2137-
}
2138-
sys_path = p + 1;
2139-
}
2140-
return _Py_INIT_OK();
2141-
}
2142-
2143-
2144-
static _PyInitError
2145-
config_init_path_config(_PyCoreConfig *config)
2146-
{
2147-
_PyInitError err = _PyPathConfig_Init(config);
2148-
if (_Py_INIT_FAILED(err)) {
2149-
return err;
2150-
}
2151-
2152-
if (config->nmodule_search_path < 0) {
2153-
err = config_init_module_search_paths(config);
2154-
if (_Py_INIT_FAILED(err)) {
2155-
return err;
2156-
}
2157-
}
2158-
2159-
if (config->executable == NULL) {
2160-
config->executable = _PyMem_RawWcsdup(Py_GetProgramFullPath());
2161-
if (config->executable == NULL) {
2162-
return _Py_INIT_NO_MEMORY();
2163-
}
2164-
}
2165-
2166-
if (config->prefix == NULL) {
2167-
config->prefix = _PyMem_RawWcsdup(Py_GetPrefix());
2168-
if (config->prefix == NULL) {
2169-
return _Py_INIT_NO_MEMORY();
2170-
}
2171-
}
2172-
2173-
if (config->exec_prefix == NULL) {
2174-
config->exec_prefix = _PyMem_RawWcsdup(Py_GetExecPrefix());
2175-
if (config->exec_prefix == NULL) {
2176-
return _Py_INIT_NO_MEMORY();
2177-
}
2178-
}
2179-
2180-
if (config->base_prefix == NULL) {
2181-
config->base_prefix = _PyMem_RawWcsdup(config->prefix);
2182-
if (config->base_prefix == NULL) {
2183-
return _Py_INIT_NO_MEMORY();
2184-
}
2185-
}
2186-
2187-
if (config->base_exec_prefix == NULL) {
2188-
config->base_exec_prefix = _PyMem_RawWcsdup(config->exec_prefix);
2189-
if (config->base_exec_prefix == NULL) {
2190-
return _Py_INIT_NO_MEMORY();
2191-
}
2192-
}
2193-
2194-
return _Py_INIT_OK();
2195-
}
2196-
21972106
/* Read configuration settings from standard locations
21982107
*
21992108
* This function doesn't make any changes to the interpreter state - it
@@ -2252,7 +2161,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
22522161
}
22532162

22542163
if (!config->_disable_importlib) {
2255-
err = config_init_path_config(config);
2164+
err = _PyCoreConfig_InitPathConfig(config);
22562165
if (_Py_INIT_FAILED(err)) {
22572166
return err;
22582167
}
@@ -2294,6 +2203,9 @@ _PyCoreConfig_Clear(_PyCoreConfig *config)
22942203
CLEAR(config->prefix);
22952204
CLEAR(config->base_prefix);
22962205
CLEAR(config->exec_prefix);
2206+
#ifdef MS_WINDOWS
2207+
CLEAR(config->dll_path);
2208+
#endif
22972209
CLEAR(config->base_exec_prefix);
22982210
#undef CLEAR
22992211
#undef CLEAR_WSTRLIST
@@ -2356,6 +2268,9 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
23562268
COPY_STR_ATTR(prefix);
23572269
COPY_STR_ATTR(base_prefix);
23582270
COPY_STR_ATTR(exec_prefix);
2271+
#ifdef MS_WINDOWS
2272+
COPY_STR_ATTR(dll_path);
2273+
#endif
23592274
COPY_STR_ATTR(base_exec_prefix);
23602275

23612276
#undef COPY_ATTR

PC/getpathp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,7 @@ calculate_free(PyCalculatePath *calculate)
10001000

10011001

10021002
_PyInitError
1003-
_PyPathConfig_Calculate(_PyPathConfig *config, const _PyCoreConfig *core_config)
1003+
_PyPathConfig_Calculate_impl(_PyPathConfig *config, const _PyCoreConfig *core_config)
10041004
{
10051005
PyCalculatePath calculate;
10061006
memset(&calculate, 0, sizeof(calculate));

0 commit comments

Comments
 (0)