Skip to content

Commit

Permalink
bpo-34170: Rework _PyCoreConfig_Read() to avoid side effect (GH-8353)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
vstinner committed Jul 21, 2018
1 parent 94487d4 commit b1147e4
Show file tree
Hide file tree
Showing 8 changed files with 358 additions and 146 deletions.
10 changes: 7 additions & 3 deletions Include/internal/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ struct _gilstate_runtime_state {
#define _PyGILState_check_enabled _PyRuntime.gilstate.check_enabled


typedef struct {
typedef struct _PyPathConfig {
/* Full path to the Python program */
wchar_t *program_full_path;
wchar_t *prefix;
Expand All @@ -59,11 +59,15 @@ typedef struct {

PyAPI_DATA(_PyPathConfig) _Py_path_config;

PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate(
PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate_impl(
_PyPathConfig *config,
const _PyCoreConfig *core_config);
PyAPI_FUNC(void) _PyPathConfig_Clear(_PyPathConfig *config);
PyAPI_FUNC(void) _PyPathConfig_ClearGlobal(void);

PyAPI_FUNC(_PyInitError) _Py_wstrlist_append(
int *len,
wchar_t ***list,
const wchar_t *str);

/* interpreter state */

Expand Down
9 changes: 8 additions & 1 deletion Include/pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ PyAPI_FUNC(void) _PyCoreConfig_Clear(_PyCoreConfig *);
PyAPI_FUNC(int) _PyCoreConfig_Copy(
_PyCoreConfig *config,
const _PyCoreConfig *config2);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitPathConfig(_PyCoreConfig *config);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_SetPathConfig(
const _PyCoreConfig *config);

PyAPI_FUNC(_PyInitError) _PyMainInterpreterConfig_Read(
_PyMainInterpreterConfig *config,
Expand Down Expand Up @@ -116,7 +119,11 @@ 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(_PyInitError) _PyPathConfig_Init(const _PyCoreConfig *core_config);
struct _PyPathConfig;
typedef struct _PyPathConfig _PyPathConfig;

PyAPI_FUNC(_PyInitError) _PyPathConfig_SetGlobal(
const _PyPathConfig *config);
PyAPI_FUNC(PyObject*) _PyPathConfig_ComputeArgv0(int argc, wchar_t **argv);
PyAPI_FUNC(int) _Py_FindEnvConfigValue(
FILE *env_file,
Expand Down
3 changes: 3 additions & 0 deletions Include/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ typedef struct {
wchar_t *base_prefix; /* sys.base_prefix */
wchar_t *exec_prefix; /* sys.exec_prefix */
wchar_t *base_exec_prefix; /* sys.base_exec_prefix */
#ifdef MS_WINDOWS
wchar_t *dll_path; /* Windows DLL path */
#endif

/* Private fields */
int _disable_importlib; /* Needed by freeze_importlib */
Expand Down
2 changes: 1 addition & 1 deletion Modules/getpath.c
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@ calculate_path_impl(const _PyCoreConfig *core_config,


_PyInitError
_PyPathConfig_Calculate(_PyPathConfig *config, const _PyCoreConfig *core_config)
_PyPathConfig_Calculate_impl(_PyPathConfig *config, const _PyCoreConfig *core_config)
{
PyCalculatePath calculate;
memset(&calculate, 0, sizeof(calculate));
Expand Down
139 changes: 27 additions & 112 deletions Modules/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ pymain_free_raw(_PyMain *pymain)
configuration options set before Py_Initialize() which should
remain valid after Py_Finalize(), since
Py_Initialize()-Py_Finalize() can be called multiple times. */
_PyPathConfig_Clear(&_Py_path_config);
_PyPathConfig_ClearGlobal();

pymain_clear_config(pymain);

Expand Down Expand Up @@ -701,9 +701,13 @@ pymain_run_main_from_importer(_PyMain *pymain)
}


static _PyInitError
wstrlist_append(int *len, wchar_t ***list, const wchar_t *str)
_PyInitError
_Py_wstrlist_append(int *len, wchar_t ***list, const wchar_t *str)
{
if (*len == INT_MAX) {
/* len+1 would overflow */
return _Py_INIT_NO_MEMORY();
}
wchar_t *str2 = _PyMem_RawWcsdup(str);
if (str2 == NULL) {
return _Py_INIT_NO_MEMORY();
Expand All @@ -725,7 +729,7 @@ wstrlist_append(int *len, wchar_t ***list, const wchar_t *str)
static int
pymain_wstrlist_append(_PyMain *pymain, int *len, wchar_t ***list, const wchar_t *str)
{
_PyInitError err = wstrlist_append(len, list, str);
_PyInitError err = _Py_wstrlist_append(len, list, str);
if (_Py_INIT_FAILED(err)) {
pymain->err = err;
return -1;
Expand Down Expand Up @@ -972,9 +976,9 @@ static _PyInitError
config_add_warnings_optlist(_PyCoreConfig *config, int len, wchar_t **options)
{
for (int i = 0; i < len; i++) {
_PyInitError err = wstrlist_append(&config->nwarnoption,
&config->warnoptions,
options[i]);
_PyInitError err = _Py_wstrlist_append(&config->nwarnoption,
&config->warnoptions,
options[i]);
if (_Py_INIT_FAILED(err)) {
return err;
}
Expand Down Expand Up @@ -1006,9 +1010,9 @@ config_init_warnoptions(_PyCoreConfig *config, _Py_CommandLineDetails *cmdline)
*/

if (config->dev_mode) {
err = wstrlist_append(&config->nwarnoption,
&config->warnoptions,
L"default");
err = _Py_wstrlist_append(&config->nwarnoption,
&config->warnoptions,
L"default");
if (_Py_INIT_FAILED(err)) {
return err;
}
Expand Down Expand Up @@ -1040,9 +1044,9 @@ config_init_warnoptions(_PyCoreConfig *config, _Py_CommandLineDetails *cmdline)
else {
filter = L"default::BytesWarning";
}
err = wstrlist_append(&config->nwarnoption,
&config->warnoptions,
filter);
err = _Py_wstrlist_append(&config->nwarnoption,
&config->warnoptions,
filter);
if (_Py_INIT_FAILED(err)) {
return err;
}
Expand Down Expand Up @@ -1077,9 +1081,9 @@ cmdline_init_env_warnoptions(_Py_CommandLineDetails *cmdline)
warning != NULL;
warning = WCSTOK(NULL, L",", &context))
{
_PyInitError err = wstrlist_append(&cmdline->nenv_warnoption,
&cmdline->env_warnoptions,
warning);
_PyInitError err = _Py_wstrlist_append(&cmdline->nenv_warnoption,
&cmdline->env_warnoptions,
warning);
if (_Py_INIT_FAILED(err)) {
PyMem_RawFree(env);
return err;
Expand Down Expand Up @@ -2099,101 +2103,6 @@ config_init_locale(_PyCoreConfig *config)
}


static _PyInitError
config_init_module_search_paths(_PyCoreConfig *config)
{
assert(config->module_search_paths == NULL);
assert(config->nmodule_search_path < 0);

config->nmodule_search_path = 0;

const wchar_t *sys_path = Py_GetPath();
const wchar_t delim = DELIM;
const wchar_t *p = sys_path;
while (1) {
p = wcschr(sys_path, delim);
if (p == NULL) {
p = sys_path + wcslen(sys_path); /* End of string */
}

size_t path_len = (p - sys_path);
wchar_t *path = PyMem_RawMalloc((path_len + 1) * sizeof(wchar_t));
if (path == NULL) {
return _Py_INIT_NO_MEMORY();
}
memcpy(path, sys_path, path_len * sizeof(wchar_t));
path[path_len] = L'\0';

_PyInitError err = wstrlist_append(&config->nmodule_search_path,
&config->module_search_paths,
path);
PyMem_RawFree(path);
if (_Py_INIT_FAILED(err)) {
return err;
}

if (*p == '\0') {
break;
}
sys_path = p + 1;
}
return _Py_INIT_OK();
}


static _PyInitError
config_init_path_config(_PyCoreConfig *config)
{
_PyInitError err = _PyPathConfig_Init(config);
if (_Py_INIT_FAILED(err)) {
return err;
}

if (config->nmodule_search_path < 0) {
err = config_init_module_search_paths(config);
if (_Py_INIT_FAILED(err)) {
return err;
}
}

if (config->executable == NULL) {
config->executable = _PyMem_RawWcsdup(Py_GetProgramFullPath());
if (config->executable == NULL) {
return _Py_INIT_NO_MEMORY();
}
}

if (config->prefix == NULL) {
config->prefix = _PyMem_RawWcsdup(Py_GetPrefix());
if (config->prefix == NULL) {
return _Py_INIT_NO_MEMORY();
}
}

if (config->exec_prefix == NULL) {
config->exec_prefix = _PyMem_RawWcsdup(Py_GetExecPrefix());
if (config->exec_prefix == NULL) {
return _Py_INIT_NO_MEMORY();
}
}

if (config->base_prefix == NULL) {
config->base_prefix = _PyMem_RawWcsdup(config->prefix);
if (config->base_prefix == NULL) {
return _Py_INIT_NO_MEMORY();
}
}

if (config->base_exec_prefix == NULL) {
config->base_exec_prefix = _PyMem_RawWcsdup(config->exec_prefix);
if (config->base_exec_prefix == NULL) {
return _Py_INIT_NO_MEMORY();
}
}

return _Py_INIT_OK();
}

/* Read configuration settings from standard locations
*
* This function doesn't make any changes to the interpreter state - it
Expand Down Expand Up @@ -2252,7 +2161,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
}

if (!config->_disable_importlib) {
err = config_init_path_config(config);
err = _PyCoreConfig_InitPathConfig(config);
if (_Py_INIT_FAILED(err)) {
return err;
}
Expand Down Expand Up @@ -2294,6 +2203,9 @@ _PyCoreConfig_Clear(_PyCoreConfig *config)
CLEAR(config->prefix);
CLEAR(config->base_prefix);
CLEAR(config->exec_prefix);
#ifdef MS_WINDOWS
CLEAR(config->dll_path);
#endif
CLEAR(config->base_exec_prefix);
#undef CLEAR
#undef CLEAR_WSTRLIST
Expand Down Expand Up @@ -2356,6 +2268,9 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
COPY_STR_ATTR(prefix);
COPY_STR_ATTR(base_prefix);
COPY_STR_ATTR(exec_prefix);
#ifdef MS_WINDOWS
COPY_STR_ATTR(dll_path);
#endif
COPY_STR_ATTR(base_exec_prefix);

#undef COPY_ATTR
Expand Down
2 changes: 1 addition & 1 deletion PC/getpathp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ calculate_free(PyCalculatePath *calculate)


_PyInitError
_PyPathConfig_Calculate(_PyPathConfig *config, const _PyCoreConfig *core_config)
_PyPathConfig_Calculate_impl(_PyPathConfig *config, const _PyCoreConfig *core_config)
{
PyCalculatePath calculate;
memset(&calculate, 0, sizeof(calculate));
Expand Down
Loading

0 comments on commit b1147e4

Please sign in to comment.