From 74f6568bbd3e70806ea3219e8bacb386ad802ccf Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 15 Mar 2019 15:08:05 +0100 Subject: bpo-36301: Add _PyWstrList structure (GH-12343) Replace messy _Py_wstrlist_xxx() functions with a new clean _PyWstrList structure and new _PyWstrList_xxx() functions. Changes: * Add _PyCoreConfig.use_module_search_paths to decide if _PyCoreConfig.module_search_paths should be computed or not, to support empty search path list. * _PyWstrList_Clear() sets length to 0 and items to NULL, whereas _Py_wstrlist_clear() only freed memory. * _PyWstrList_Append() returns an int, whereas _Py_wstrlist_append() returned _PyInitError. * _PyWstrList uses Py_ssize_t for the length, instead of int. * Replace (int, wchar_t**) with _PyWstrList in: * _PyPreConfig * _PyCoreConfig * _PyPreCmdline * _PyCmdline * Replace "int orig_argv; wchar_t **orig_argv;" with "_PyWstrList orig_argv". * _PyCmdline and _PyPreCmdline now also copy wchar_argv. * Rename _PyArgv_Decode() to _PyArgv_AsWstrList(). * PySys_SetArgvEx() now pass the fixed (argc, argv) to _PyPathConfig_ComputeArgv0() (don't pass negative argc or NULL argv). * _PyOS_GetOpt() uses Py_ssize_t --- Include/cpython/coreconfig.h | 42 ++-- Include/internal/pycore_coreconfig.h | 37 ++-- Include/internal/pycore_getopt.h | 6 +- Include/internal/pycore_pathconfig.h | 2 +- Modules/main.c | 25 +-- Programs/_testembed.c | 12 +- Python/coreconfig.c | 364 ++++++++++++++++------------------- Python/getopt.c | 8 +- Python/pathconfig.c | 40 ++-- Python/preconfig.c | 69 +++---- Python/sysmodule.c | 43 +++-- 11 files changed, 303 insertions(+), 345 deletions(-) diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h index 2673576..bd28c37 100644 --- a/Include/cpython/coreconfig.h +++ b/Include/cpython/coreconfig.h @@ -46,6 +46,18 @@ typedef struct { #define _Py_INIT_FAILED(err) \ (err.msg != NULL || err.exitcode != -1) +/* --- _PyWstrList ------------------------------------------------ */ + +typedef struct { + /* If length is greater than zero, items must be non-NULL + and all items strings must be non-NULL */ + Py_ssize_t length; + wchar_t **items; +} _PyWstrList; + +#define _PyWstrList_INIT (_PyWstrList){.length = 0, .items = NULL} + + /* --- _PyPreConfig ----------------------------------------------- */ typedef struct { @@ -162,19 +174,12 @@ typedef struct { char *filesystem_encoding; char *filesystem_errors; - wchar_t *pycache_prefix; /* PYTHONPYCACHEPREFIX, -X pycache_prefix=PATH */ - - wchar_t *program_name; /* Program name, see also Py_GetProgramName() */ - int argc; /* Number of command line arguments, - -1 means unset */ - wchar_t **argv; /* Command line arguments */ - wchar_t *program; /* argv[0] or "" */ - - int nxoption; /* Number of -X options */ - wchar_t **xoptions; /* -X options */ - - int nwarnoption; /* Number of warnings options */ - wchar_t **warnoptions; /* Warnings options */ + wchar_t *pycache_prefix; /* PYTHONPYCACHEPREFIX, -X pycache_prefix=PATH */ + wchar_t *program_name; /* Program name, see also Py_GetProgramName() */ + _PyWstrList argv; /* Command line arguments */ + wchar_t *program; /* argv[0] or "" */ + _PyWstrList xoptions; /* Command line -X options */ + _PyWstrList warnoptions; /* Warnings options */ /* Path configuration inputs */ wchar_t *module_search_path_env; /* PYTHONPATH environment variable */ @@ -182,9 +187,11 @@ typedef struct { see also Py_SetPythonHome(). */ /* Path configuration outputs */ - int nmodule_search_path; /* Number of sys.path paths, - -1 means unset */ - wchar_t **module_search_paths; /* sys.path paths */ + int use_module_search_paths; /* If non-zero, use module_search_paths */ + _PyWstrList module_search_paths; /* sys.path paths. Computed if + use_module_search_paths is equal + to zero. */ + wchar_t *executable; /* sys.executable */ wchar_t *prefix; /* sys.prefix */ wchar_t *base_prefix; /* sys.base_prefix */ @@ -366,8 +373,7 @@ typedef struct { .use_hash_seed = -1, \ .faulthandler = -1, \ .tracemalloc = -1, \ - .argc = -1, \ - .nmodule_search_path = -1, \ + .use_module_search_paths = 0, \ .site_import = -1, \ .bytes_warning = -1, \ .inspect = -1, \ diff --git a/Include/internal/pycore_coreconfig.h b/Include/internal/pycore_coreconfig.h index 153309d..8c5a072 100644 --- a/Include/internal/pycore_coreconfig.h +++ b/Include/internal/pycore_coreconfig.h @@ -8,39 +8,38 @@ extern "C" { # error "this header requires Py_BUILD_CORE or Py_BUILD_CORE_BUILTIN defined" #endif -/* --- _Py_wstrlist ----------------------------------------------- */ - -PyAPI_FUNC(void) _Py_wstrlist_clear( - int len, - wchar_t **list); -PyAPI_FUNC(wchar_t**) _Py_wstrlist_copy( - int len, - wchar_t * const *list); -PyAPI_FUNC(_PyInitError) _Py_wstrlist_append( - int *len, - wchar_t ***list, - const wchar_t *str); -PyAPI_FUNC(PyObject*) _Py_wstrlist_as_pylist( - int len, - wchar_t **list); + +/* --- _PyWstrList ------------------------------------------------ */ + +#ifndef NDEBUG +PyAPI_FUNC(int) _PyWstrList_CheckConsistency(const _PyWstrList *list); +#endif +PyAPI_FUNC(void) _PyWstrList_Clear(_PyWstrList *list); +PyAPI_FUNC(int) _PyWstrList_Copy(_PyWstrList *list, + const _PyWstrList *list2); +PyAPI_FUNC(int) _PyWstrList_Append(_PyWstrList *list, + const wchar_t *item); +PyAPI_FUNC(PyObject*) _PyWstrList_AsList(const _PyWstrList *list); + /* --- _PyArgv ---------------------------------------------------- */ -PyAPI_FUNC(_PyInitError) _PyArgv_Decode(const _PyArgv *args, - wchar_t*** argv_p); +PyAPI_FUNC(_PyInitError) _PyArgv_AsWstrList(const _PyArgv *args, + _PyWstrList *list); + /* --- Py_GetArgcArgv() helpers ----------------------------------- */ PyAPI_FUNC(void) _Py_ClearArgcArgv(void); + /* --- _PyPreConfig ----------------------------------------------- */ PyAPI_FUNC(int) _Py_str_to_int( const char *str, int *result); PyAPI_FUNC(const wchar_t*) _Py_get_xoption( - int nxoption, - wchar_t * const *xoptions, + const _PyWstrList *xoptions, const wchar_t *name); PyAPI_FUNC(void) _PyPreConfig_Clear(_PyPreConfig *config); diff --git a/Include/internal/pycore_getopt.h b/Include/internal/pycore_getopt.h index 1d30f5b..0d1897c 100644 --- a/Include/internal/pycore_getopt.h +++ b/Include/internal/pycore_getopt.h @@ -6,8 +6,8 @@ #endif extern int _PyOS_opterr; -extern int _PyOS_optind; -extern wchar_t *_PyOS_optarg; +extern Py_ssize_t _PyOS_optind; +extern const wchar_t *_PyOS_optarg; extern void _PyOS_ResetGetOpt(void); @@ -17,6 +17,6 @@ typedef struct { int val; } _PyOS_LongOption; -extern int _PyOS_GetOpt(int argc, wchar_t **argv, int *longindex); +extern int _PyOS_GetOpt(Py_ssize_t argc, wchar_t **argv, int *longindex); #endif /* !Py_INTERNAL_PYGETOPT_H */ diff --git a/Include/internal/pycore_pathconfig.h b/Include/internal/pycore_pathconfig.h index fb6b1d7..d0938df 100644 --- a/Include/internal/pycore_pathconfig.h +++ b/Include/internal/pycore_pathconfig.h @@ -44,7 +44,7 @@ PyAPI_FUNC(_PyInitError) _PyPathConfig_SetGlobal( PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate_impl( _PyPathConfig *config, const _PyCoreConfig *core_config); -PyAPI_FUNC(PyObject*) _PyPathConfig_ComputeArgv0(int argc, wchar_t **argv); +PyAPI_FUNC(PyObject*) _PyPathConfig_ComputeArgv0(const _PyWstrList *argv); PyAPI_FUNC(int) _Py_FindEnvConfigValue( FILE *env_file, const wchar_t *key, diff --git a/Modules/main.c b/Modules/main.c index ae99901..5c7f7e4 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -84,15 +84,15 @@ error: static PyObject* mainconfig_create_xoptions_dict(const _PyCoreConfig *config) { - int nxoption = config->nxoption; - wchar_t **xoptions = config->xoptions; + Py_ssize_t nxoption = config->xoptions.length; + wchar_t * const * xoptions = config->xoptions.items; PyObject *dict = PyDict_New(); if (dict == NULL) { return NULL; } - for (int i=0; i < nxoption; i++) { - wchar_t *option = xoptions[i]; + for (Py_ssize_t i=0; i < nxoption; i++) { + const wchar_t *option = xoptions[i]; if (mainconfig_add_xoption(dict, option) < 0) { Py_DECREF(dict); return NULL; @@ -243,22 +243,18 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config, } \ } \ } while (0) -#define COPY_WSTRLIST(ATTR, LEN, LIST) \ +#define COPY_WSTRLIST(ATTR, LIST) \ do { \ if (ATTR == NULL) { \ - ATTR = _Py_wstrlist_as_pylist(LEN, LIST); \ + ATTR = _PyWstrList_AsList(LIST); \ if (ATTR == NULL) { \ return _Py_INIT_NO_MEMORY(); \ } \ } \ } while (0) - COPY_WSTRLIST(main_config->warnoptions, - config->nwarnoption, config->warnoptions); - if (config->argc >= 0) { - COPY_WSTRLIST(main_config->argv, - config->argc, config->argv); - } + COPY_WSTRLIST(main_config->warnoptions, &config->warnoptions); + COPY_WSTRLIST(main_config->argv, &config->argv); if (config->_install_importlib) { COPY_WSTR(executable); @@ -268,7 +264,7 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config, COPY_WSTR(base_exec_prefix); COPY_WSTRLIST(main_config->module_search_path, - config->nmodule_search_path, config->module_search_paths); + &config->module_search_paths); if (config->pycache_prefix != NULL) { COPY_WSTR(pycache_prefix); @@ -784,8 +780,7 @@ pymain_run_python(PyInterpreterState *interp, int *exitcode) } } else if (!config->preconfig.isolated) { - PyObject *path0 = _PyPathConfig_ComputeArgv0(config->argc, - config->argv); + PyObject *path0 = _PyPathConfig_ComputeArgv0(&config->argv); if (path0 == NULL) { err = _Py_INIT_NO_MEMORY(); goto done; diff --git a/Programs/_testembed.c b/Programs/_testembed.c index bba2510..7c143f1 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -479,8 +479,8 @@ static int test_init_from_config(void) L"-c", L"pass", }; - config.argc = Py_ARRAY_LENGTH(argv); - config.argv = argv; + config.argv.length = Py_ARRAY_LENGTH(argv); + config.argv.items = argv; config.program = L"conf_program"; @@ -489,15 +489,15 @@ static int test_init_from_config(void) L"core_xoption2=", L"core_xoption3", }; - config.nxoption = Py_ARRAY_LENGTH(xoptions); - config.xoptions = xoptions; + config.xoptions.length = Py_ARRAY_LENGTH(xoptions); + config.xoptions.items = xoptions; static wchar_t* warnoptions[2] = { L"default", L"error::ResourceWarning", }; - config.nwarnoption = Py_ARRAY_LENGTH(warnoptions); - config.warnoptions = warnoptions; + config.warnoptions.length = Py_ARRAY_LENGTH(warnoptions); + config.warnoptions.items = warnoptions; /* FIXME: test module_search_path_env */ /* FIXME: test home */ diff --git a/Python/coreconfig.c b/Python/coreconfig.c index 845e4c9..15107fa 100644 --- a/Python/coreconfig.c +++ b/Python/coreconfig.c @@ -202,81 +202,128 @@ fail: } -/* --- _Py_wstrlist ----------------------------------------------- */ +/* --- _PyWstrList ------------------------------------------------ */ + +#ifndef NDEBUG +int +_PyWstrList_CheckConsistency(const _PyWstrList *list) +{ + assert(list->length >= 0); + if (list->length != 0) { + assert(list->items != NULL); + } + for (Py_ssize_t i = 0; i < list->length; i++) { + assert(list->items[i] != NULL); + } + return 1; +} +#endif /* Py_DEBUG */ + void -_Py_wstrlist_clear(int len, wchar_t **list) +_PyWstrList_Clear(_PyWstrList *list) { - for (int i=0; i < len; i++) { - PyMem_RawFree(list[i]); + assert(_PyWstrList_CheckConsistency(list)); + for (Py_ssize_t i=0; i < list->length; i++) { + PyMem_RawFree(list->items[i]); } - PyMem_RawFree(list); + PyMem_RawFree(list->items); + list->length = 0; + list->items = NULL; } -wchar_t** -_Py_wstrlist_copy(int len, wchar_t * const *list) +int +_PyWstrList_Copy(_PyWstrList *list, const _PyWstrList *list2) { - assert((len > 0 && list != NULL) || len == 0); - size_t size = len * sizeof(list[0]); - wchar_t **list_copy = PyMem_RawMalloc(size); - if (list_copy == NULL) { - return NULL; + assert(_PyWstrList_CheckConsistency(list)); + assert(_PyWstrList_CheckConsistency(list2)); + + if (list2->length == 0) { + _PyWstrList_Clear(list); + return 0; } - for (int i=0; i < len; i++) { - wchar_t* arg = _PyMem_RawWcsdup(list[i]); - if (arg == NULL) { - _Py_wstrlist_clear(i, list_copy); - return NULL; + + _PyWstrList copy = _PyWstrList_INIT; + + size_t size = list2->length * sizeof(list2->items[0]); + copy.items = PyMem_RawMalloc(size); + if (copy.items == NULL) { + return -1; + } + + for (Py_ssize_t i=0; i < list2->length; i++) { + wchar_t *item = _PyMem_RawWcsdup(list2->items[i]); + if (item == NULL) { + _PyWstrList_Clear(©); + return -1; } - list_copy[i] = arg; + copy.items[i] = item; + copy.length = i + 1; } - return list_copy; + + _PyWstrList_Clear(list); + *list = copy; + return 0; } -_PyInitError -_Py_wstrlist_append(int *len, wchar_t ***list, const wchar_t *str) +int +_PyWstrList_Append(_PyWstrList *list, const wchar_t *item) { - if (*len == INT_MAX) { - /* len+1 would overflow */ - return _Py_INIT_NO_MEMORY(); + if (list->length == PY_SSIZE_T_MAX) { + /* lenght+1 would overflow */ + return -1; } - wchar_t *str2 = _PyMem_RawWcsdup(str); - if (str2 == NULL) { - return _Py_INIT_NO_MEMORY(); + + wchar_t *item2 = _PyMem_RawWcsdup(item); + if (item2 == NULL) { + return -1; } - size_t size = (*len + 1) * sizeof(list[0]); - wchar_t **list2 = (wchar_t **)PyMem_RawRealloc(*list, size); - if (list2 == NULL) { - PyMem_RawFree(str2); - return _Py_INIT_NO_MEMORY(); + size_t size = (list->length + 1) * sizeof(list->items[0]); + wchar_t **items2 = (wchar_t **)PyMem_RawRealloc(list->items, size); + if (items2 == NULL) { + PyMem_RawFree(item2); + return -1; } - list2[*len] = str2; - *list = list2; - (*len)++; - return _Py_INIT_OK(); + + items2[list->length] = item2; + list->items = items2; + list->length++; + return 0; +} + + +static int +_PyWstrList_Extend(_PyWstrList *list, const _PyWstrList *list2) +{ + for (Py_ssize_t i = 0; i < list2->length; i++) { + if (_PyWstrList_Append(list, list2->items[i])) { + return -1; + } + } + return 0; } PyObject* -_Py_wstrlist_as_pylist(int len, wchar_t **list) +_PyWstrList_AsList(const _PyWstrList *list) { - assert(list != NULL || len < 1); + assert(_PyWstrList_CheckConsistency(list)); - PyObject *pylist = PyList_New(len); + PyObject *pylist = PyList_New(list->length); if (pylist == NULL) { return NULL; } - for (int i = 0; i < len; i++) { - PyObject *v = PyUnicode_FromWideChar(list[i], -1); - if (v == NULL) { + for (Py_ssize_t i = 0; i < list->length; i++) { + PyObject *item = PyUnicode_FromWideChar(list->items[i], -1); + if (item == NULL) { Py_DECREF(pylist); return NULL; } - PyList_SET_ITEM(pylist, i, v); + PyList_SET_ITEM(pylist, i, item); } return pylist; } @@ -369,8 +416,7 @@ _Py_ClearStandardStreamEncoding(void) /* --- Py_GetArgcArgv() ------------------------------------------- */ /* For Py_GetArgcArgv(); set by _Py_SetArgcArgv() */ -static int orig_argc = 0; -static wchar_t **orig_argv = NULL; +static _PyWstrList orig_argv = {.length = 0, .items = NULL}; void @@ -379,32 +425,22 @@ _Py_ClearArgcArgv(void) PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - _Py_wstrlist_clear(orig_argc, orig_argv); - orig_argc = 0; - orig_argv = NULL; + _PyWstrList_Clear(&orig_argv); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); } static int -_Py_SetArgcArgv(int argc, wchar_t * const *argv) +_Py_SetArgcArgv(Py_ssize_t argc, wchar_t * const *argv) { + const _PyWstrList argv_list = {.length = argc, .items = (wchar_t **)argv}; int res; PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - wchar_t **argv_copy = _Py_wstrlist_copy(argc, argv); - if (argv_copy != NULL) { - _Py_ClearArgcArgv(); - orig_argc = argc; - orig_argv = argv_copy; - res = 0; - } - else { - res = -1; - } + res = _PyWstrList_Copy(&orig_argv, &argv_list); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); return res; @@ -416,8 +452,8 @@ _Py_SetArgcArgv(int argc, wchar_t * const *argv) void Py_GetArgcArgv(int *argc, wchar_t ***argv) { - *argc = orig_argc; - *argv = orig_argv; + *argc = (int)orig_argv.length; + *argv = orig_argv.items; } @@ -439,12 +475,6 @@ _PyCoreConfig_Clear(_PyCoreConfig *config) PyMem_RawFree(ATTR); \ ATTR = NULL; \ } while (0) -#define CLEAR_WSTRLIST(LEN, LIST) \ - do { \ - _Py_wstrlist_clear(LEN, LIST); \ - LEN = 0; \ - LIST = NULL; \ - } while (0) CLEAR(config->pycache_prefix); CLEAR(config->module_search_path_env); @@ -452,13 +482,11 @@ _PyCoreConfig_Clear(_PyCoreConfig *config) CLEAR(config->program_name); CLEAR(config->program); - CLEAR_WSTRLIST(config->argc, config->argv); - config->argc = -1; - - CLEAR_WSTRLIST(config->nwarnoption, config->warnoptions); - CLEAR_WSTRLIST(config->nxoption, config->xoptions); - CLEAR_WSTRLIST(config->nmodule_search_path, config->module_search_paths); - config->nmodule_search_path = -1; + _PyWstrList_Clear(&config->argv); + _PyWstrList_Clear(&config->warnoptions); + _PyWstrList_Clear(&config->xoptions); + _PyWstrList_Clear(&config->module_search_paths); + config->use_module_search_paths = 0; CLEAR(config->executable); CLEAR(config->prefix); @@ -477,7 +505,6 @@ _PyCoreConfig_Clear(_PyCoreConfig *config) CLEAR(config->run_module); CLEAR(config->run_filename); #undef CLEAR -#undef CLEAR_WSTRLIST } @@ -509,15 +536,11 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2) } \ } \ } while (0) -#define COPY_WSTRLIST(LEN, LIST) \ +#define COPY_WSTRLIST(LIST) \ do { \ - if (config2->LIST != NULL) { \ - config->LIST = _Py_wstrlist_copy(config2->LEN, config2->LIST); \ - if (config->LIST == NULL) { \ - return -1; \ - } \ + if (_PyWstrList_Copy(&config->LIST, &config2->LIST) < 0 ) { \ + return -1; \ } \ - config->LEN = config2->LEN; \ } while (0) COPY_ATTR(install_signal_handlers); @@ -538,10 +561,11 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2) COPY_WSTR_ATTR(program_name); COPY_WSTR_ATTR(program); - COPY_WSTRLIST(argc, argv); - COPY_WSTRLIST(nwarnoption, warnoptions); - COPY_WSTRLIST(nxoption, xoptions); - COPY_WSTRLIST(nmodule_search_path, module_search_paths); + COPY_WSTRLIST(argv); + COPY_WSTRLIST(warnoptions); + COPY_WSTRLIST(xoptions); + COPY_WSTRLIST(module_search_paths); + COPY_ATTR(use_module_search_paths); COPY_WSTR_ATTR(executable); COPY_WSTR_ATTR(prefix); @@ -817,7 +841,7 @@ config_init_executable(_PyCoreConfig *config) static const wchar_t* config_get_xoption(const _PyCoreConfig *config, wchar_t *name) { - return _Py_get_xoption(config->nxoption, config->xoptions, name); + return _Py_get_xoption(&config->xoptions, name); } @@ -1427,9 +1451,6 @@ _PyCoreConfig_Read(_PyCoreConfig *config, const _PyPreConfig *preconfig) if (config->tracemalloc < 0) { config->tracemalloc = 0; } - if (config->argc < 0) { - config->argc = 0; - } if (config->filesystem_encoding == NULL || config->filesystem_errors == NULL) { err = config_init_fs_encoding(config); @@ -1449,6 +1470,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config, const _PyPreConfig *preconfig) assert(config->stdio_encoding != NULL); assert(config->stdio_errors != NULL); assert(config->_check_hash_pycs_mode != NULL); + assert(_PyWstrList_CheckConsistency(&config->argv)); return _Py_INIT_OK(); } @@ -1546,8 +1568,8 @@ _PyCoreConfig_AsDict(const _PyCoreConfig *config) : (Py_INCREF(Py_None), Py_None)) #define SET_ITEM_WSTR(ATTR) \ SET_ITEM(#ATTR, FROM_WSTRING(config->ATTR)) -#define SET_ITEM_WSTRLIST(NOPTION, OPTIONS) \ - SET_ITEM(#OPTIONS, _Py_wstrlist_as_pylist(config->NOPTION, config->OPTIONS)) +#define SET_ITEM_WSTRLIST(LIST) \ + SET_ITEM(#LIST, _PyWstrList_AsList(&config->LIST)) SET_ITEM_INT(install_signal_handlers); SET_ITEM_INT(use_hash_seed); @@ -1563,13 +1585,13 @@ _PyCoreConfig_AsDict(const _PyCoreConfig *config) SET_ITEM_STR(filesystem_errors); SET_ITEM_WSTR(pycache_prefix); SET_ITEM_WSTR(program_name); - SET_ITEM_WSTRLIST(argc, argv); + SET_ITEM_WSTRLIST(argv); SET_ITEM_WSTR(program); - SET_ITEM_WSTRLIST(nxoption, xoptions); - SET_ITEM_WSTRLIST(nwarnoption, warnoptions); + SET_ITEM_WSTRLIST(xoptions); + SET_ITEM_WSTRLIST(warnoptions); SET_ITEM_WSTR(module_search_path_env); SET_ITEM_WSTR(home); - SET_ITEM_WSTRLIST(nmodule_search_path, module_search_paths); + SET_ITEM_WSTRLIST(module_search_paths); SET_ITEM_WSTR(executable); SET_ITEM_WSTR(prefix); SET_ITEM_WSTR(base_prefix); @@ -1622,13 +1644,9 @@ fail: /* --- _PyCmdline ------------------------------------------------- */ typedef struct { - const _PyArgv *args; - int argc; - wchar_t **argv; - int nwarnoption; /* Number of -W command line options */ - wchar_t **warnoptions; /* Command line -W options */ - int nenv_warnoption; /* Number of PYTHONWARNINGS environment variables */ - wchar_t **env_warnoptions; /* PYTHONWARNINGS environment variables */ + _PyWstrList argv; + _PyWstrList warnoptions; /* Command line -W options */ + _PyWstrList env_warnoptions; /* PYTHONWARNINGS environment variables */ int print_help; /* -h, -? options */ int print_version; /* -V option */ } _PyCmdline; @@ -1637,18 +1655,9 @@ typedef struct { static void cmdline_clear(_PyCmdline *cmdline) { - _Py_wstrlist_clear(cmdline->nwarnoption, cmdline->warnoptions); - cmdline->nwarnoption = 0; - cmdline->warnoptions = NULL; - - _Py_wstrlist_clear(cmdline->nenv_warnoption, cmdline->env_warnoptions); - cmdline->nenv_warnoption = 0; - cmdline->env_warnoptions = NULL; - - if (cmdline->args->use_bytes_argv && cmdline->argv != NULL) { - _Py_wstrlist_clear(cmdline->args->argc, cmdline->argv); - } - cmdline->argv = NULL; + _PyWstrList_Clear(&cmdline->warnoptions); + _PyWstrList_Clear(&cmdline->env_warnoptions); + _PyWstrList_Clear(&cmdline->argv); } @@ -1659,11 +1668,10 @@ static _PyInitError config_parse_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline, int *need_usage) { - _PyInitError err; _PyOS_ResetGetOpt(); do { int longindex = -1; - int c = _PyOS_GetOpt(cmdline->args->argc, cmdline->argv, &longindex); + int c = _PyOS_GetOpt(cmdline->argv.length, cmdline->argv.items, &longindex); if (c == EOF) { break; } @@ -1775,20 +1783,14 @@ config_parse_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline, break; case 'W': - err = _Py_wstrlist_append(&cmdline->nwarnoption, - &cmdline->warnoptions, - _PyOS_optarg); - if (_Py_INIT_FAILED(err)) { - return err; + if (_PyWstrList_Append(&cmdline->warnoptions, _PyOS_optarg) < 0) { + return _Py_INIT_NO_MEMORY(); } break; case 'X': - err = _Py_wstrlist_append(&config->nxoption, - &config->xoptions, - _PyOS_optarg); - if (_Py_INIT_FAILED(err)) { - return err; + if (_PyWstrList_Append(&config->xoptions, _PyOS_optarg) < 0) { + return _Py_INIT_NO_MEMORY(); } break; @@ -1810,10 +1812,10 @@ config_parse_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline, } while (1); if (config->run_command == NULL && config->run_module == NULL - && _PyOS_optind < cmdline->args->argc - && wcscmp(cmdline->argv[_PyOS_optind], L"-") != 0) + && _PyOS_optind < cmdline->argv.length + && wcscmp(cmdline->argv.items[_PyOS_optind], L"-") != 0) { - config->run_filename = _PyMem_RawWcsdup(cmdline->argv[_PyOS_optind]); + config->run_filename = _PyMem_RawWcsdup(cmdline->argv.items[_PyOS_optind]); if (config->run_filename == NULL) { return _Py_INIT_NO_MEMORY(); } @@ -1858,12 +1860,9 @@ cmdline_init_env_warnoptions(_PyCmdline *cmdline, const _PyCoreConfig *config) warning != NULL; warning = WCSTOK(NULL, L",", &context)) { - _PyInitError err = _Py_wstrlist_append(&cmdline->nenv_warnoption, - &cmdline->env_warnoptions, - warning); - if (_Py_INIT_FAILED(err)) { + if (_PyWstrList_Append(&cmdline->env_warnoptions, warning) < 0) { PyMem_RawFree(env); - return err; + return _Py_INIT_NO_MEMORY(); } } PyMem_RawFree(env); @@ -1875,8 +1874,8 @@ static _PyInitError config_init_program(_PyCoreConfig *config, const _PyCmdline *cmdline) { wchar_t *program; - if (cmdline->args->argc >= 1 && cmdline->argv != NULL) { - program = cmdline->argv[0]; + if (cmdline->argv.length >= 1) { + program = cmdline->argv.items[0]; } else { program = L""; @@ -1891,27 +1890,9 @@ config_init_program(_PyCoreConfig *config, const _PyCmdline *cmdline) static _PyInitError -config_add_warnings_optlist(_PyCoreConfig *config, - int len, wchar_t * const *options) -{ - for (int i = 0; i < len; i++) { - _PyInitError err = _Py_wstrlist_append(&config->nwarnoption, - &config->warnoptions, - options[i]); - if (_Py_INIT_FAILED(err)) { - return err; - } - } - return _Py_INIT_OK(); -} - - -static _PyInitError config_init_warnoptions(_PyCoreConfig *config, const _PyCmdline *cmdline) { - _PyInitError err; - - assert(config->nwarnoption == 0); + assert(config->warnoptions.length == 0); /* The priority order for warnings configuration is (highest precedence * first): @@ -1929,26 +1910,17 @@ config_init_warnoptions(_PyCoreConfig *config, const _PyCmdline *cmdline) */ if (config->preconfig.dev_mode) { - err = _Py_wstrlist_append(&config->nwarnoption, - &config->warnoptions, - L"default"); - if (_Py_INIT_FAILED(err)) { - return err; + if (_PyWstrList_Append(&config->warnoptions, L"default")) { + return _Py_INIT_NO_MEMORY(); } } - err = config_add_warnings_optlist(config, - cmdline->nenv_warnoption, - cmdline->env_warnoptions); - if (_Py_INIT_FAILED(err)) { - return err; + if (_PyWstrList_Extend(&config->warnoptions, &cmdline->env_warnoptions) < 0) { + return _Py_INIT_NO_MEMORY(); } - err = config_add_warnings_optlist(config, - cmdline->nwarnoption, - cmdline->warnoptions); - if (_Py_INIT_FAILED(err)) { - return err; + if (_PyWstrList_Extend(&config->warnoptions, &cmdline->warnoptions) < 0) { + return _Py_INIT_NO_MEMORY(); } /* If the bytes_warning_flag isn't set, bytesobject.c and bytearrayobject.c @@ -1956,18 +1928,15 @@ config_init_warnoptions(_PyCoreConfig *config, const _PyCmdline *cmdline) * case. */ if (config->bytes_warning) { - wchar_t *filter; + const wchar_t *filter; if (config->bytes_warning> 1) { filter = L"error::BytesWarning"; } else { filter = L"default::BytesWarning"; } - err = _Py_wstrlist_append(&config->nwarnoption, - &config->warnoptions, - filter); - if (_Py_INIT_FAILED(err)) { - return err; + if (_PyWstrList_Append(&config->warnoptions, filter)) { + return _Py_INIT_NO_MEMORY(); } } return _Py_INIT_OK(); @@ -1977,23 +1946,24 @@ config_init_warnoptions(_PyCoreConfig *config, const _PyCmdline *cmdline) static _PyInitError config_init_argv(_PyCoreConfig *config, const _PyCmdline *cmdline) { - /* Copy argv to be able to modify it (to force -c/-m) */ - int argc = cmdline->args->argc - _PyOS_optind; - wchar_t **argv; + _PyWstrList wargv = _PyWstrList_INIT; - if (argc <= 0 || cmdline->argv == NULL) { + /* Copy argv to be able to modify it (to force -c/-m) */ + if (cmdline->argv.length <= _PyOS_optind) { /* Ensure at least one (empty) argument is seen */ - static wchar_t *empty_argv[1] = {L""}; - argc = 1; - argv = _Py_wstrlist_copy(1, empty_argv); + if (_PyWstrList_Append(&wargv, L"") < 0) { + return _Py_INIT_NO_MEMORY(); + } } else { - argv = _Py_wstrlist_copy(argc, &cmdline->argv[_PyOS_optind]); - } - - if (argv == NULL) { - return _Py_INIT_NO_MEMORY(); + _PyWstrList slice; + slice.length = cmdline->argv.length - _PyOS_optind; + slice.items = &cmdline->argv.items[_PyOS_optind]; + if (_PyWstrList_Copy(&wargv, &slice) < 0) { + return _Py_INIT_NO_MEMORY(); + } } + assert(wargv.length >= 1); wchar_t *arg0 = NULL; if (config->run_command != NULL) { @@ -2007,17 +1977,16 @@ config_init_argv(_PyCoreConfig *config, const _PyCmdline *cmdline) if (arg0 != NULL) { arg0 = _PyMem_RawWcsdup(arg0); if (arg0 == NULL) { - _Py_wstrlist_clear(argc, argv); + _PyWstrList_Clear(&wargv); return _Py_INIT_NO_MEMORY(); } - assert(argc >= 1); - PyMem_RawFree(argv[0]); - argv[0] = arg0; + PyMem_RawFree(wargv.items[0]); + wargv.items[0] = arg0; } - config->argc = argc; - config->argv = argv; + _PyWstrList_Clear(&config->argv); + config->argv = wargv; return _Py_INIT_OK(); } @@ -2097,7 +2066,7 @@ config_from_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline, return err; } - if (_Py_SetArgcArgv(cmdline->args->argc, cmdline->argv) < 0) { + if (_Py_SetArgcArgv(cmdline->argv.length, cmdline->argv.items) < 0) { return _Py_INIT_NO_MEMORY(); } return _Py_INIT_OK(); @@ -2117,9 +2086,8 @@ _PyCoreConfig_ReadFromArgv(_PyCoreConfig *config, const _PyArgv *args, _PyCmdline cmdline; memset(&cmdline, 0, sizeof(cmdline)); - cmdline.args = args; - err = _PyArgv_Decode(cmdline.args, &cmdline.argv); + err = _PyArgv_AsWstrList(args, &cmdline.argv); if (_Py_INIT_FAILED(err)) { goto done; } diff --git a/Python/getopt.c b/Python/getopt.c index 1dc8720..10bd1d4 100644 --- a/Python/getopt.c +++ b/Python/getopt.c @@ -37,9 +37,9 @@ extern "C" { #endif -int _PyOS_opterr = 1; /* generate error messages */ -int _PyOS_optind = 1; /* index into argv array */ -wchar_t *_PyOS_optarg = NULL; /* optional argument */ +int _PyOS_opterr = 1; /* generate error messages */ +Py_ssize_t _PyOS_optind = 1; /* index into argv array */ +const wchar_t *_PyOS_optarg = NULL; /* optional argument */ static wchar_t *opt_ptr = L""; @@ -61,7 +61,7 @@ void _PyOS_ResetGetOpt(void) opt_ptr = L""; } -int _PyOS_GetOpt(int argc, wchar_t **argv, int *longindex) +int _PyOS_GetOpt(Py_ssize_t argc, wchar_t **argv, int *longindex) { wchar_t *ptr; wchar_t option; diff --git a/Python/pathconfig.c b/Python/pathconfig.c index 14dbba7..fb2d19e 100644 --- a/Python/pathconfig.c +++ b/Python/pathconfig.c @@ -154,14 +154,14 @@ _PyPathConfig_ClearGlobal(void) static wchar_t* -wstrlist_join(wchar_t sep, int count, wchar_t **list) +_PyWstrList_Join(const _PyWstrList *list, wchar_t sep) { size_t len = 1; /* NUL terminator */ - for (int i=0; i < count; i++) { + for (Py_ssize_t i=0; i < list->length; i++) { if (i != 0) { len++; } - len += wcslen(list[i]); + len += wcslen(list->items[i]); } wchar_t *text = PyMem_RawMalloc(len * sizeof(wchar_t)); @@ -169,8 +169,8 @@ wstrlist_join(wchar_t sep, int count, wchar_t **list) return NULL; } wchar_t *str = text; - for (int i=0; i < count; i++) { - wchar_t *path = list[i]; + for (Py_ssize_t i=0; i < list->length; i++) { + wchar_t *path = list->items[i]; if (i != 0) { *str++ = SEP; } @@ -194,9 +194,7 @@ _PyCoreConfig_SetPathConfig(const _PyCoreConfig *core_config) _PyInitError err; _PyPathConfig path_config = _PyPathConfig_INIT; - path_config.module_search_path = wstrlist_join(DELIM, - core_config->nmodule_search_path, - core_config->module_search_paths); + path_config.module_search_path = _PyWstrList_Join(&core_config->module_search_paths, DELIM); if (path_config.module_search_path == NULL) { goto no_memory; } @@ -244,10 +242,9 @@ static _PyInitError core_config_init_module_search_paths(_PyCoreConfig *config, _PyPathConfig *path_config) { - assert(config->module_search_paths == NULL); - assert(config->nmodule_search_path < 0); + assert(!config->use_module_search_paths); - config->nmodule_search_path = 0; + _PyWstrList_Clear(&config->module_search_paths); const wchar_t *sys_path = path_config->module_search_path; const wchar_t delim = DELIM; @@ -266,12 +263,10 @@ core_config_init_module_search_paths(_PyCoreConfig *config, memcpy(path, sys_path, path_len * sizeof(wchar_t)); path[path_len] = L'\0'; - _PyInitError err = _Py_wstrlist_append(&config->nmodule_search_path, - &config->module_search_paths, - path); + int res = _PyWstrList_Append(&config->module_search_paths, path); PyMem_RawFree(path); - if (_Py_INIT_FAILED(err)) { - return err; + if (res < 0) { + return _Py_INIT_NO_MEMORY(); } if (*p == '\0') { @@ -279,6 +274,7 @@ core_config_init_module_search_paths(_PyCoreConfig *config, } sys_path = p + 1; } + config->use_module_search_paths = 1; return _Py_INIT_OK(); } @@ -294,7 +290,7 @@ _PyCoreConfig_CalculatePathConfig(_PyCoreConfig *config) goto error; } - if (config->nmodule_search_path < 0) { + if (!config->use_module_search_paths) { err = core_config_init_module_search_paths(config, &path_config); if (_Py_INIT_FAILED(err)) { goto error; @@ -352,7 +348,7 @@ _PyInitError _PyCoreConfig_InitPathConfig(_PyCoreConfig *config) { /* Do we need to calculate the path? */ - if ((config->nmodule_search_path < 0) + if (!config->use_module_search_paths || (config->executable == NULL) || (config->prefix == NULL) #ifdef MS_WINDOWS @@ -567,8 +563,10 @@ Py_GetProgramName(void) /* Compute argv[0] which will be prepended to sys.argv */ PyObject* -_PyPathConfig_ComputeArgv0(int argc, wchar_t **argv) +_PyPathConfig_ComputeArgv0(const _PyWstrList *argv) { + assert(_PyWstrList_CheckConsistency(argv)); + wchar_t *argv0; wchar_t *p = NULL; Py_ssize_t n = 0; @@ -585,8 +583,8 @@ _PyPathConfig_ComputeArgv0(int argc, wchar_t **argv) wchar_t fullpath[MAX_PATH]; #endif - argv0 = argv[0]; - if (argc > 0 && argv0 != NULL) { + if (argv->length > 0) { + argv0 = argv->items[0]; have_module_arg = (wcscmp(argv0, L"-m") == 0); have_script_arg = !have_module_arg && (wcscmp(argv0, L"-c") != 0); } diff --git a/Python/preconfig.c b/Python/preconfig.c index 50d66b1..a86ece5 100644 --- a/Python/preconfig.c +++ b/Python/preconfig.c @@ -64,33 +64,38 @@ _Py_SetFileSystemEncoding(const char *encoding, const char *errors) /* --- _PyArgv ---------------------------------------------------- */ _PyInitError -_PyArgv_Decode(const _PyArgv *args, wchar_t*** argv_p) +_PyArgv_AsWstrList(const _PyArgv *args, _PyWstrList *list) { - wchar_t** argv; + _PyWstrList wargv = _PyWstrList_INIT; if (args->use_bytes_argv) { - /* +1 for a the NULL terminator */ - size_t size = sizeof(wchar_t*) * (args->argc + 1); - argv = (wchar_t **)PyMem_RawMalloc(size); - if (argv == NULL) { + size_t size = sizeof(wchar_t*) * args->argc; + wargv.items = (wchar_t **)PyMem_RawMalloc(size); + if (wargv.items == NULL) { return _Py_INIT_NO_MEMORY(); } - for (int i = 0; i < args->argc; i++) { + for (Py_ssize_t i = 0; i < args->argc; i++) { size_t len; wchar_t *arg = Py_DecodeLocale(args->bytes_argv[i], &len); if (arg == NULL) { - _Py_wstrlist_clear(i, argv); + _PyWstrList_Clear(&wargv); return DECODE_LOCALE_ERR("command line arguments", (Py_ssize_t)len); } - argv[i] = arg; + wargv.items[i] = arg; + wargv.length++; } - argv[args->argc] = NULL; + + _PyWstrList_Clear(list); + *list = wargv; } else { - argv = args->wchar_argv; + wargv.length = args->argc; + wargv.items = args->wchar_argv; + if (_PyWstrList_Copy(list, &wargv) < 0) { + return _Py_INIT_NO_MEMORY(); + } } - *argv_p = argv; return _Py_INIT_OK(); } @@ -98,25 +103,16 @@ _PyArgv_Decode(const _PyArgv *args, wchar_t*** argv_p) /* --- _PyPreCmdline ------------------------------------------------- */ typedef struct { - const _PyArgv *args; - int argc; - wchar_t **argv; - int nxoption; /* Number of -X options */ - wchar_t **xoptions; /* -X options */ + _PyWstrList argv; + _PyWstrList xoptions; /* -X options */ } _PyPreCmdline; static void precmdline_clear(_PyPreCmdline *cmdline) { - if (cmdline->args->use_bytes_argv && cmdline->argv != NULL) { - _Py_wstrlist_clear(cmdline->args->argc, cmdline->argv); - } - cmdline->argv = NULL; - - _Py_wstrlist_clear(cmdline->nxoption, cmdline->xoptions); - cmdline->nxoption = 0; - cmdline->xoptions = NULL; + _PyWstrList_Clear(&cmdline->argv); + _PyWstrList_Clear(&cmdline->xoptions); } @@ -267,10 +263,10 @@ _Py_get_env_flag(_PyPreConfig *config, int *flag, const char *name) const wchar_t* -_Py_get_xoption(int nxoption, wchar_t * const *xoptions, const wchar_t *name) +_Py_get_xoption(const _PyWstrList *xoptions, const wchar_t *name) { - for (int i=0; i < nxoption; i++) { - const wchar_t *option = xoptions[i]; + for (Py_ssize_t i=0; i < xoptions->length; i++) { + const wchar_t *option = xoptions->items[i]; size_t len; wchar_t *sep = wcschr(option, L'='); if (sep != NULL) { @@ -292,7 +288,7 @@ preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline) { const wchar_t *xopt; if (cmdline) { - xopt = _Py_get_xoption(cmdline->nxoption, cmdline->xoptions, L"utf8"); + xopt = _Py_get_xoption(&cmdline->xoptions, L"utf8"); } else { xopt = NULL; @@ -435,7 +431,7 @@ preconfig_read(_PyPreConfig *config, const _PyPreCmdline *cmdline) } /* dev_mode */ - if ((cmdline && _Py_get_xoption(cmdline->nxoption, cmdline->xoptions, L"dev")) + if ((cmdline && _Py_get_xoption(&cmdline->xoptions, L"dev")) || _PyPreConfig_GetEnv(config, "PYTHONDEVMODE")) { config->dev_mode = 1; @@ -579,7 +575,7 @@ preconfig_parse_cmdline(_PyPreConfig *config, _PyPreCmdline *cmdline) _PyOS_opterr = 0; do { int longindex = -1; - int c = _PyOS_GetOpt(cmdline->args->argc, cmdline->argv, &longindex); + int c = _PyOS_GetOpt(cmdline->argv.length, cmdline->argv.items, &longindex); if (c == EOF || c == 'c' || c == 'm') { break; @@ -596,12 +592,8 @@ preconfig_parse_cmdline(_PyPreConfig *config, _PyPreCmdline *cmdline) case 'X': { - _PyInitError err; - err = _Py_wstrlist_append(&cmdline->nxoption, - &cmdline->xoptions, - _PyOS_optarg); - if (_Py_INIT_FAILED(err)) { - return err; + if (_PyWstrList_Append(&cmdline->xoptions, _PyOS_optarg) < 0) { + return _Py_INIT_NO_MEMORY(); } break; } @@ -624,9 +616,8 @@ preconfig_from_argv(_PyPreConfig *config, const _PyArgv *args) _PyPreCmdline cmdline; memset(&cmdline, 0, sizeof(cmdline)); - cmdline.args = args; - err = _PyArgv_Decode(cmdline.args, &cmdline.argv); + err = _PyArgv_AsWstrList(args, &cmdline.argv); if (_Py_INIT_FAILED(err)) { goto done; } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 99fd460..b3330a01 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2739,35 +2739,35 @@ PySys_SetPath(const wchar_t *path) } static PyObject * -makeargvobject(int argc, wchar_t **argv) +make_sys_argv(int argc, wchar_t * const * argv) { - PyObject *av; - if (argc <= 0 || argv == NULL) { - /* Ensure at least one (empty) argument is seen */ - static wchar_t *empty_argv[1] = {L""}; - argv = empty_argv; - argc = 1; + PyObject *list = PyList_New(argc); + if (list == NULL) { + return NULL; } - av = PyList_New(argc); - if (av != NULL) { - int i; - for (i = 0; i < argc; i++) { - PyObject *v = PyUnicode_FromWideChar(argv[i], -1); - if (v == NULL) { - Py_DECREF(av); - av = NULL; - break; - } - PyList_SET_ITEM(av, i, v); + + for (Py_ssize_t i = 0; i < argc; i++) { + PyObject *v = PyUnicode_FromWideChar(argv[i], -1); + if (v == NULL) { + Py_DECREF(list); + return NULL; } + PyList_SET_ITEM(list, i, v); } - return av; + return list; } void PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath) { - PyObject *av = makeargvobject(argc, argv); + if (argc < 1 || argv == NULL) { + /* Ensure at least one (empty) argument is seen */ + wchar_t* empty_argv[1] = {L""}; + argv = empty_argv; + argc = 1; + } + + PyObject *av = make_sys_argv(argc, argv); if (av == NULL) { Py_FatalError("no mem for sys.argv"); } @@ -2780,7 +2780,8 @@ PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath) if (updatepath) { /* If argv[0] is not '-c' nor '-m', prepend argv[0] to sys.path. If argv[0] is a symlink, use the real path. */ - PyObject *argv0 = _PyPathConfig_ComputeArgv0(argc, argv); + const _PyWstrList argv_list = {.length = argc, .items = argv}; + PyObject *argv0 = _PyPathConfig_ComputeArgv0(&argv_list); if (argv0 == NULL) { Py_FatalError("can't compute path0 from argv"); } -- cgit v0.12