bpo-34170: Add Python/coreconfig.c for _PyCoreConfig (GH-8607)
https://github.com/python/cpython/commit/6c785c0ebdadc84d80a53d896c38fd7ada8... commit: 6c785c0ebdadc84d80a53d896c38fd7ada8ae1f6 branch: master author: Victor Stinner <vstinner@redhat.com> committer: GitHub <noreply@github.com> date: 2018-08-01T17:56:14+02:00 summary: bpo-34170: Add Python/coreconfig.c for _PyCoreConfig (GH-8607) * Add Include/coreconfig.h * Move config_*() and _PyCoreConfig_*() functions from Modules/main.c to a new Python/coreconfig.c file. * Inline _Py_ReadHashSeed() into config_init_hash_seed() * Move global configuration variables to coreconfig.c files: A Include/coreconfig.h A Python/coreconfig.c M Include/Python.h M Include/internal/pystate.h M Include/pylifecycle.h M Include/pystate.h M Makefile.pre.in M Modules/main.c M PCbuild/pythoncore.vcxproj M PCbuild/pythoncore.vcxproj.filters M Python/bltinmodule.c M Python/bootstrap_hash.c M Python/import.c M Python/pylifecycle.c diff --git a/Include/Python.h b/Include/Python.h index 1feb1531cc94..bf1ca6cfe98e 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -111,6 +111,7 @@ #include "codecs.h" #include "pyerrors.h" +#include "coreconfig.h" #include "pystate.h" #include "context.h" diff --git a/Include/coreconfig.h b/Include/coreconfig.h new file mode 100644 index 000000000000..4401729d76f7 --- /dev/null +++ b/Include/coreconfig.h @@ -0,0 +1,318 @@ +#ifndef Py_PYCORECONFIG_H +#define Py_PYCORECONFIG_H +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef Py_LIMITED_API +typedef struct { + const char *prefix; + const char *msg; + int user_err; +} _PyInitError; + +/* Almost all errors causing Python initialization to fail */ +#ifdef _MSC_VER + /* Visual Studio 2015 doesn't implement C99 __func__ in C */ +# define _Py_INIT_GET_FUNC() __FUNCTION__ +#else +# define _Py_INIT_GET_FUNC() __func__ +#endif + +#define _Py_INIT_OK() \ + (_PyInitError){.prefix = NULL, .msg = NULL, .user_err = 0} +#define _Py_INIT_ERR(MSG) \ + (_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 0} +/* Error that can be fixed by the user like invalid input parameter. + Don't abort() the process on such error. */ +#define _Py_INIT_USER_ERR(MSG) \ + (_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 1} +#define _Py_INIT_NO_MEMORY() _Py_INIT_USER_ERR("memory allocation failed") +#define _Py_INIT_FAILED(err) \ + (err.msg != NULL) + +#endif /* !defined(Py_LIMITED_API) */ + + +typedef struct { + /* Install signal handlers? Yes by default. */ + int install_signal_handlers; + + /* If greater than 0: use environment variables. + Set to 0 by -E command line option. If set to -1 (default), it is + set to !Py_IgnoreEnvironmentFlag. */ + int use_environment; + + int use_hash_seed; /* PYTHONHASHSEED=x */ + unsigned long hash_seed; + + const char *allocator; /* Memory allocator: PYTHONMALLOC */ + int dev_mode; /* PYTHONDEVMODE, -X dev */ + + /* Enable faulthandler? + Set to 1 by -X faulthandler and PYTHONFAULTHANDLER. -1 means unset. */ + int faulthandler; + + /* Enable tracemalloc? + Set by -X tracemalloc=N and PYTHONTRACEMALLOC. -1 means unset */ + int tracemalloc; + + int import_time; /* PYTHONPROFILEIMPORTTIME, -X importtime */ + int show_ref_count; /* -X showrefcount */ + int show_alloc_count; /* -X showalloccount */ + int dump_refs; /* PYTHONDUMPREFS */ + int malloc_stats; /* PYTHONMALLOCSTATS */ + int coerce_c_locale; /* PYTHONCOERCECLOCALE, -1 means unknown */ + int coerce_c_locale_warn; /* PYTHONCOERCECLOCALE=warn */ + + /* Enable UTF-8 mode? + Set by -X utf8 command line option and PYTHONUTF8 environment variable. + If set to -1 (default), inherit Py_UTF8Mode value. */ + int utf8_mode; + + 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 */ + + /* Path configuration inputs */ + wchar_t *module_search_path_env; /* PYTHONPATH environment variable */ + wchar_t *home; /* PYTHONHOME environment variable, + 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 */ + wchar_t *executable; /* sys.executable */ + wchar_t *prefix; /* sys.prefix */ + 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 + + /* If greater than 0, enable isolated mode: sys.path contains + neither the script's directory nor the user's site-packages directory. + + Set to 1 by the -I command line option. If set to -1 (default), inherit + Py_IsolatedFlag value. */ + int isolated; + + /* If equal to zero, disable the import of the module site and the + site-dependent manipulations of sys.path that it entails. Also disable + these manipulations if site is explicitly imported later (call + site.main() if you want them to be triggered). + + Set to 0 by the -S command line option. If set to -1 (default), it is + set to !Py_NoSiteFlag. */ + int site_import; + + /* Bytes warnings: + + * If equal to 1, issue a warning when comparing bytes or bytearray with + str or bytes with int. + * If equal or greater to 2, issue an error. + + Incremented by the -b command line option. If set to -1 (default), inherit + Py_BytesWarningFlag value. */ + int bytes_warning; + + /* If greater than 0, enable inspect: when a script is passed as first + argument or the -c option is used, enter interactive mode after + executing the script or the command, even when sys.stdin does not appear + to be a terminal. + + Incremented by the -i command line option. Set to 1 if the PYTHONINSPECT + environment variable is non-empty. If set to -1 (default), inherit + Py_InspectFlag value. */ + int inspect; + + /* If greater than 0: enable the interactive mode (REPL). + + Incremented by the -i command line option. If set to -1 (default), + inherit Py_InteractiveFlag value. */ + int interactive; + + /* Optimization level. + + Incremented by the -O command line option. Set by the PYTHONOPTIMIZE + environment variable. If set to -1 (default), inherit Py_OptimizeFlag + value. */ + int optimization_level; + + /* If greater than 0, enable the debug mode: turn on parser debugging + output (for expert only, depending on compilation options). + + Incremented by the -d command line option. Set by the PYTHONDEBUG + environment variable. If set to -1 (default), inherit Py_DebugFlag + value. */ + int parser_debug; + + /* If equal to 0, Python won't try to write ``.pyc`` files on the + import of source modules. + + Set to 0 by the -B command line option and the PYTHONDONTWRITEBYTECODE + environment variable. If set to -1 (default), it is set to + !Py_DontWriteBytecodeFlag. */ + int write_bytecode; + + /* If greater than 0, enable the verbose mode: print a message each time a + module is initialized, showing the place (filename or built-in module) + from which it is loaded. + + If greater or equal to 2, print a message for each file that is checked + for when searching for a module. Also provides information on module + cleanup at exit. + + Incremented by the -v option. Set by the PYTHONVERBOSE environment + variable. If set to -1 (default), inherit Py_VerboseFlag value. */ + int verbose; + + /* If greater than 0, enable the quiet mode: Don't display the copyright + and version messages even in interactive mode. + + Incremented by the -q option. If set to -1 (default), inherit + Py_QuietFlag value. */ + int quiet; + + /* If greater than 0, don't add the user site-packages directory to + sys.path. + + Set to 0 by the -s and -I command line options , and the PYTHONNOUSERSITE + environment variable. If set to -1 (default), it is set to + !Py_NoUserSiteDirectory. */ + int user_site_directory; + + /* If equal to 0, enable unbuffered mode: force the stdout and stderr + streams to be unbuffered. + + Set to 0 by the -u option. Set by the PYTHONUNBUFFERED environment + variable. + If set to -1 (default), it is set to !Py_UnbufferedStdioFlag. */ + int buffered_stdio; + +#ifdef MS_WINDOWS + /* If greater than 1, use the "mbcs" encoding instead of the UTF-8 + encoding for the filesystem encoding. + + Set to 1 if the PYTHONLEGACYWINDOWSFSENCODING environment variable is + set to a non-empty string. If set to -1 (default), inherit + Py_LegacyWindowsFSEncodingFlag value. + + See PEP 529 for more details. */ + int legacy_windows_fs_encoding; + + /* If greater than zero, use io.FileIO instead of WindowsConsoleIO for sys + standard streams. + + Set to 1 if the PYTHONLEGACYWINDOWSSTDIO environment variable is set to + a non-empty string. If set to -1 (default), inherit + Py_LegacyWindowsStdioFlag value. + + See PEP 528 for more details. */ + int legacy_windows_stdio; +#endif + + /* --- Private fields -------- */ + + /* Install importlib? If set to 0, importlib is not initialized at all. + Needed by freeze_importlib. */ + int _install_importlib; + + /* Value of the --check-hash-based-pycs configure option. Valid values: + + - "default" means the 'check_source' flag in hash-based pycs + determines invalidation + - "always" causes the interpreter to hash the source file for + invalidation regardless of value of 'check_source' bit + - "never" causes the interpreter to always assume hash-based pycs are + valid + + Set by the --check-hash-based-pycs command line option. + If set to NULL (default), inherit _Py_CheckHashBasedPycsMode value. + + See PEP 552 "Deterministic pycs" for more details. */ + const char *_check_hash_pycs_mode; + + /* If greater than 0, suppress _PyPathConfig_Calculate() warnings. + + If set to -1 (default), inherit Py_FrozenFlag value. */ + int _frozen; + +} _PyCoreConfig; + +#ifdef MS_WINDOWS +# define _PyCoreConfig_WINDOWS_INIT \ + .legacy_windows_fs_encoding = -1, \ + .legacy_windows_stdio = -1, +#else +# define _PyCoreConfig_WINDOWS_INIT +#endif + +#define _PyCoreConfig_INIT \ + (_PyCoreConfig){ \ + .install_signal_handlers = 1, \ + .use_environment = -1, \ + .use_hash_seed = -1, \ + .faulthandler = -1, \ + .tracemalloc = -1, \ + .coerce_c_locale = -1, \ + .utf8_mode = -1, \ + .argc = -1, \ + .nmodule_search_path = -1, \ + .isolated = -1, \ + .site_import = -1, \ + .bytes_warning = -1, \ + .inspect = -1, \ + .interactive = -1, \ + .optimization_level = -1, \ + .parser_debug= -1, \ + .write_bytecode = -1, \ + .verbose = -1, \ + .quiet = -1, \ + .user_site_directory = -1, \ + .buffered_stdio = -1, \ + _PyCoreConfig_WINDOWS_INIT \ + ._install_importlib = 1, \ + ._frozen = -1} +/* Note: _PyCoreConfig_INIT sets other fields to 0/NULL */ + + +#ifndef Py_LIMITED_API +PyAPI_FUNC(_PyInitError) _PyCoreConfig_Read(_PyCoreConfig *config); +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(void) _PyCoreConfig_GetGlobalConfig(_PyCoreConfig *config); +PyAPI_FUNC(void) _PyCoreConfig_SetGlobalConfig(const _PyCoreConfig *config); +PyAPI_FUNC(const char*) _PyCoreConfig_GetEnv( + const _PyCoreConfig *config, + const char *name); +PyAPI_FUNC(int) _PyCoreConfig_GetEnvDup( + const _PyCoreConfig *config, + wchar_t **dest, + wchar_t *wname, + char *name); +#endif + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYCORECONFIG_H */ diff --git a/Include/internal/pystate.h b/Include/internal/pystate.h index e041d3768467..ef83af59323e 100644 --- a/Include/internal/pystate.h +++ b/Include/internal/pystate.h @@ -72,6 +72,12 @@ PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate_impl( const _PyCoreConfig *core_config); PyAPI_FUNC(void) _PyPathConfig_ClearGlobal(void); +PyAPI_FUNC(void) _Py_wstrlist_clear( + int len, + wchar_t **list); +PyAPI_FUNC(wchar_t**) _Py_wstrlist_copy( + int len, + wchar_t **list); PyAPI_FUNC(_PyInitError) _Py_wstrlist_append( int *len, wchar_t ***list, diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h index c58c7ec95d9d..4965d7cbf06c 100644 --- a/Include/pylifecycle.h +++ b/Include/pylifecycle.h @@ -7,36 +7,6 @@ extern "C" { #endif -#ifndef Py_LIMITED_API -typedef struct { - const char *prefix; - const char *msg; - int user_err; -} _PyInitError; - -/* Almost all errors causing Python initialization to fail */ -#ifdef _MSC_VER - /* Visual Studio 2015 doesn't implement C99 __func__ in C */ -# define _Py_INIT_GET_FUNC() __FUNCTION__ -#else -# define _Py_INIT_GET_FUNC() __func__ -#endif - -#define _Py_INIT_OK() \ - (_PyInitError){.prefix = NULL, .msg = NULL, .user_err = 0} -#define _Py_INIT_ERR(MSG) \ - (_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 0} -/* Error that can be fixed by the user like invalid input parameter. - Don't abort() the process on such error. */ -#define _Py_INIT_USER_ERR(MSG) \ - (_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 1} -#define _Py_INIT_NO_MEMORY() _Py_INIT_USER_ERR("memory allocation failed") -#define _Py_INIT_FAILED(err) \ - (err.msg != NULL) - -#endif - - PyAPI_FUNC(void) Py_SetProgramName(const wchar_t *); PyAPI_FUNC(wchar_t *) Py_GetProgramName(void); @@ -56,16 +26,6 @@ PyAPI_FUNC(_PyInitError) _Py_InitializeCore( const _PyCoreConfig *); PyAPI_FUNC(int) _Py_IsCoreInitialized(void); -PyAPI_FUNC(_PyInitError) _PyCoreConfig_Read(_PyCoreConfig *config); -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(void) _PyCoreConfig_SetGlobalConfig(const _PyCoreConfig *config); - PyAPI_FUNC(_PyInitError) _PyMainInterpreterConfig_Read( _PyMainInterpreterConfig *config, @@ -165,12 +125,6 @@ PyAPI_FUNC(int) _PyFloat_Init(void); PyAPI_FUNC(int) PyByteArray_Init(void); PyAPI_FUNC(_PyInitError) _Py_HashRandomization_Init(const _PyCoreConfig *); #endif -#ifdef Py_BUILD_CORE -PyAPI_FUNC(int) _Py_ReadHashSeed( - const char *seed_text, - int *use_hash_seed, - unsigned long *hash_seed); -#endif /* Various internal finalizers */ diff --git a/Include/pystate.h b/Include/pystate.h index b90084321141..bbeea9d51b82 100644 --- a/Include/pystate.h +++ b/Include/pystate.h @@ -8,6 +8,7 @@ extern "C" { #endif #include "pythread.h" +#include "coreconfig.h" /* This limitation is for performance and simplicity. If needed it can be removed (with effort). */ @@ -24,261 +25,6 @@ typedef struct _is PyInterpreterState; #else typedef PyObject* (*_PyFrameEvalFunction)(struct _frame *, int); - -typedef struct { - /* Install signal handlers? Yes by default. */ - int install_signal_handlers; - - /* If greater than 0: use environment variables. - Set to 0 by -E command line option. If set to -1 (default), it is - set to !Py_IgnoreEnvironmentFlag. */ - int use_environment; - - int use_hash_seed; /* PYTHONHASHSEED=x */ - unsigned long hash_seed; - - const char *allocator; /* Memory allocator: PYTHONMALLOC */ - int dev_mode; /* PYTHONDEVMODE, -X dev */ - - /* Enable faulthandler? - Set to 1 by -X faulthandler and PYTHONFAULTHANDLER. -1 means unset. */ - int faulthandler; - - /* Enable tracemalloc? - Set by -X tracemalloc=N and PYTHONTRACEMALLOC. -1 means unset */ - int tracemalloc; - - int import_time; /* PYTHONPROFILEIMPORTTIME, -X importtime */ - int show_ref_count; /* -X showrefcount */ - int show_alloc_count; /* -X showalloccount */ - int dump_refs; /* PYTHONDUMPREFS */ - int malloc_stats; /* PYTHONMALLOCSTATS */ - int coerce_c_locale; /* PYTHONCOERCECLOCALE, -1 means unknown */ - int coerce_c_locale_warn; /* PYTHONCOERCECLOCALE=warn */ - - /* Enable UTF-8 mode? - Set by -X utf8 command line option and PYTHONUTF8 environment variable. - If set to -1 (default), inherit Py_UTF8Mode value. */ - int utf8_mode; - - 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 */ - - /* Path configuration inputs */ - wchar_t *module_search_path_env; /* PYTHONPATH environment variable */ - wchar_t *home; /* PYTHONHOME environment variable, - 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 */ - wchar_t *executable; /* sys.executable */ - wchar_t *prefix; /* sys.prefix */ - 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 - - /* If greater than 0, enable isolated mode: sys.path contains - neither the script's directory nor the user's site-packages directory. - - Set to 1 by the -I command line option. If set to -1 (default), inherit - Py_IsolatedFlag value. */ - int isolated; - - /* If equal to zero, disable the import of the module site and the - site-dependent manipulations of sys.path that it entails. Also disable - these manipulations if site is explicitly imported later (call - site.main() if you want them to be triggered). - - Set to 0 by the -S command line option. If set to -1 (default), it is - set to !Py_NoSiteFlag. */ - int site_import; - - /* Bytes warnings: - - * If equal to 1, issue a warning when comparing bytes or bytearray with - str or bytes with int. - * If equal or greater to 2, issue an error. - - Incremented by the -b command line option. If set to -1 (default), inherit - Py_BytesWarningFlag value. */ - int bytes_warning; - - /* If greater than 0, enable inspect: when a script is passed as first - argument or the -c option is used, enter interactive mode after - executing the script or the command, even when sys.stdin does not appear - to be a terminal. - - Incremented by the -i command line option. Set to 1 if the PYTHONINSPECT - environment variable is non-empty. If set to -1 (default), inherit - Py_InspectFlag value. */ - int inspect; - - /* If greater than 0: enable the interactive mode (REPL). - - Incremented by the -i command line option. If set to -1 (default), - inherit Py_InteractiveFlag value. */ - int interactive; - - /* Optimization level. - - Incremented by the -O command line option. Set by the PYTHONOPTIMIZE - environment variable. If set to -1 (default), inherit Py_OptimizeFlag - value. */ - int optimization_level; - - /* If greater than 0, enable the debug mode: turn on parser debugging - output (for expert only, depending on compilation options). - - Incremented by the -d command line option. Set by the PYTHONDEBUG - environment variable. If set to -1 (default), inherit Py_DebugFlag - value. */ - int parser_debug; - - /* If equal to 0, Python won't try to write ``.pyc`` files on the - import of source modules. - - Set to 0 by the -B command line option and the PYTHONDONTWRITEBYTECODE - environment variable. If set to -1 (default), it is set to - !Py_DontWriteBytecodeFlag. */ - int write_bytecode; - - /* If greater than 0, enable the verbose mode: print a message each time a - module is initialized, showing the place (filename or built-in module) - from which it is loaded. - - If greater or equal to 2, print a message for each file that is checked - for when searching for a module. Also provides information on module - cleanup at exit. - - Incremented by the -v option. Set by the PYTHONVERBOSE environment - variable. If set to -1 (default), inherit Py_VerboseFlag value. */ - int verbose; - - /* If greater than 0, enable the quiet mode: Don't display the copyright - and version messages even in interactive mode. - - Incremented by the -q option. If set to -1 (default), inherit - Py_QuietFlag value. */ - int quiet; - - /* If greater than 0, don't add the user site-packages directory to - sys.path. - - Set to 0 by the -s and -I command line options , and the PYTHONNOUSERSITE - environment variable. If set to -1 (default), it is set to - !Py_NoUserSiteDirectory. */ - int user_site_directory; - - /* If equal to 0, enable unbuffered mode: force the stdout and stderr - streams to be unbuffered. - - Set to 0 by the -u option. Set by the PYTHONUNBUFFERED environment - variable. - If set to -1 (default), it is set to !Py_UnbufferedStdioFlag. */ - int buffered_stdio; - -#ifdef MS_WINDOWS - /* If greater than 1, use the "mbcs" encoding instead of the UTF-8 - encoding for the filesystem encoding. - - Set to 1 if the PYTHONLEGACYWINDOWSFSENCODING environment variable is - set to a non-empty string. If set to -1 (default), inherit - Py_LegacyWindowsFSEncodingFlag value. - - See PEP 529 for more details. */ - int legacy_windows_fs_encoding; - - /* If greater than zero, use io.FileIO instead of WindowsConsoleIO for sys - standard streams. - - Set to 1 if the PYTHONLEGACYWINDOWSSTDIO environment variable is set to - a non-empty string. If set to -1 (default), inherit - Py_LegacyWindowsStdioFlag value. - - See PEP 528 for more details. */ - int legacy_windows_stdio; -#endif - - /* --- Private fields -------- */ - - /* Install importlib? If set to 0, importlib is not initialized at all. - Needed by freeze_importlib. */ - int _install_importlib; - - /* Value of the --check-hash-based-pycs configure option. Valid values: - - - "default" means the 'check_source' flag in hash-based pycs - determines invalidation - - "always" causes the interpreter to hash the source file for - invalidation regardless of value of 'check_source' bit - - "never" causes the interpreter to always assume hash-based pycs are - valid - - Set by the --check-hash-based-pycs command line option. - If set to NULL (default), inherit _Py_CheckHashBasedPycsMode value. - - See PEP 552 "Deterministic pycs" for more details. */ - const char *_check_hash_pycs_mode; - - /* If greater than 0, suppress _PyPathConfig_Calculate() warnings. - - If set to -1 (default), inherit Py_FrozenFlag value. */ - int _frozen; - -} _PyCoreConfig; - -#ifdef MS_WINDOWS -# define _PyCoreConfig_WINDOWS_INIT \ - .legacy_windows_fs_encoding = -1, \ - .legacy_windows_stdio = -1, -#else -# define _PyCoreConfig_WINDOWS_INIT -#endif - -#define _PyCoreConfig_INIT \ - (_PyCoreConfig){ \ - .install_signal_handlers = 1, \ - .use_environment = -1, \ - .use_hash_seed = -1, \ - .faulthandler = -1, \ - .tracemalloc = -1, \ - .coerce_c_locale = -1, \ - .utf8_mode = -1, \ - .argc = -1, \ - .nmodule_search_path = -1, \ - .isolated = -1, \ - .site_import = -1, \ - .bytes_warning = -1, \ - .inspect = -1, \ - .interactive = -1, \ - .optimization_level = -1, \ - .parser_debug= -1, \ - .write_bytecode = -1, \ - .verbose = -1, \ - .quiet = -1, \ - .user_site_directory = -1, \ - .buffered_stdio = -1, \ - _PyCoreConfig_WINDOWS_INIT \ - ._install_importlib = 1, \ - ._frozen = -1} -/* Note: _PyCoreConfig_INIT sets other fields to 0/NULL */ - /* Placeholders while working on the new configuration API * * See PEP 432 for final anticipated contents diff --git a/Makefile.pre.in b/Makefile.pre.in index 51cf2fdb009b..d60d48e5f9bb 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -329,8 +329,9 @@ PYTHON_OBJS= \ Python/ast_unparse.o \ Python/bltinmodule.o \ Python/ceval.o \ - Python/compile.o \ Python/codecs.o \ + Python/compile.o \ + Python/coreconfig.o \ Python/dynamic_annotations.o \ Python/errors.o \ Python/frozenmain.o \ @@ -944,6 +945,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/codecs.h \ $(srcdir)/Include/compile.h \ $(srcdir)/Include/complexobject.h \ + $(srcdir)/Include/coreconfig.h \ $(srcdir)/Include/descrobject.h \ $(srcdir)/Include/dictobject.h \ $(srcdir)/Include/dtoa.h \ diff --git a/Modules/main.c b/Modules/main.c index 34069e1b2d31..f99ff86b749d 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -2,7 +2,6 @@ #include "Python.h" #include "osdefs.h" -#include "internal/import.h" #include "internal/pygetopt.h" #include "internal/pystate.h" @@ -46,16 +45,6 @@ extern "C" { : _Py_INIT_NO_MEMORY()) -#define SET_DECODE_ERROR(NAME, LEN) \ - do { \ - if ((LEN) == (size_t)-2) { \ - pymain->err = _Py_INIT_USER_ERR("cannot decode " NAME); \ - } \ - else { \ - pymain->err = _Py_INIT_NO_MEMORY(); \ - } \ - } while (0) - #ifdef MS_WINDOWS #define WCSTOK wcstok_s #else @@ -168,71 +157,6 @@ pymain_usage(int error, const wchar_t* program) } -static const char* -config_get_env_var(const _PyCoreConfig *config, const char *name) -{ - assert(config->use_environment >= 0); - - if (!config->use_environment) { - return NULL; - } - - const char *var = getenv(name); - if (var && var[0] != '\0') { - return var; - } - else { - return NULL; - } -} - - -static int -config_get_env_var_dup(const _PyCoreConfig *config, wchar_t **dest, wchar_t *wname, char *name) -{ - assert(config->use_environment >= 0); - - if (!config->use_environment) { - *dest = NULL; - return 0; - } - -#ifdef MS_WINDOWS - const wchar_t *var = _wgetenv(wname); - if (!var || var[0] == '\0') { - *dest = NULL; - return 0; - } - - wchar_t *copy = _PyMem_RawWcsdup(var); - if (copy == NULL) { - return -1; - } - - *dest = copy; -#else - const char *var = getenv(name); - if (!var || var[0] == '\0') { - *dest = NULL; - return 0; - } - - size_t len; - wchar_t *wvar = Py_DecodeLocale(var, &len); - if (!wvar) { - if (len == (size_t)-2) { - return -2; - } - else { - return -1; - } - } - *dest = wvar; -#endif - return 0; -} - - static void pymain_run_interactive_hook(void) { @@ -457,34 +381,6 @@ typedef struct { || pymain->module != NULL) -static void -clear_wstrlist(int len, wchar_t **list) -{ - for (int i=0; i < len; i++) { - PyMem_RawFree(list[i]); - } - PyMem_RawFree(list); -} - - -static wchar_t** -copy_wstrlist(int len, wchar_t **list) -{ - assert((len > 0 && list != NULL) || len == 0); - size_t size = len * sizeof(list[0]); - wchar_t **list_copy = PyMem_RawMalloc(size); - for (int i=0; i < len; i++) { - wchar_t* arg = _PyMem_RawWcsdup(list[i]); - if (arg == NULL) { - clear_wstrlist(i, list); - return NULL; - } - list_copy[i] = arg; - } - return list_copy; -} - - static wchar_t* pymain_wstrdup(_PyMain *pymain, const wchar_t *str) { @@ -516,7 +412,7 @@ pymain_init_cmdline_argv(_PyMain *pymain, _PyCoreConfig *config, size_t len; wchar_t *arg = Py_DecodeLocale(pymain->bytes_argv[i], &len); if (arg == NULL) { - clear_wstrlist(i, argv); + _Py_wstrlist_clear(i, argv); pymain->err = DECODE_LOCALE_ERR("command line arguments", (Py_ssize_t)len); return -1; @@ -547,244 +443,22 @@ pymain_init_cmdline_argv(_PyMain *pymain, _PyCoreConfig *config, } -static void -_PyCoreConfig_GetGlobalConfig(_PyCoreConfig *config) -{ -#define COPY_FLAG(ATTR, VALUE) \ - if (config->ATTR == -1) { \ - config->ATTR = VALUE; \ - } -#define COPY_NOT_FLAG(ATTR, VALUE) \ - if (config->ATTR == -1) { \ - config->ATTR = !(VALUE); \ - } - - COPY_FLAG(utf8_mode, Py_UTF8Mode); - COPY_FLAG(isolated, Py_IsolatedFlag); - COPY_FLAG(bytes_warning, Py_BytesWarningFlag); - COPY_FLAG(inspect, Py_InspectFlag); - COPY_FLAG(interactive, Py_InteractiveFlag); - COPY_FLAG(optimization_level, Py_OptimizeFlag); - COPY_FLAG(parser_debug, Py_DebugFlag); - COPY_FLAG(verbose, Py_VerboseFlag); - COPY_FLAG(quiet, Py_QuietFlag); -#ifdef MS_WINDOWS - COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag); - COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag); -#endif - COPY_FLAG(_frozen, Py_FrozenFlag); - - COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag); - COPY_NOT_FLAG(buffered_stdio, Py_UnbufferedStdioFlag); - COPY_NOT_FLAG(site_import, Py_NoSiteFlag); - COPY_NOT_FLAG(write_bytecode, Py_DontWriteBytecodeFlag); - COPY_NOT_FLAG(user_site_directory, Py_NoUserSiteDirectory); - - if (config->_check_hash_pycs_mode == NULL) { - config->_check_hash_pycs_mode = _Py_CheckHashBasedPycsMode; - } - -#undef COPY_FLAG -#undef COPY_NOT_FLAG -} - - -/* Set Py_xxx global configuration variables from 'config' configuration. */ -void -_PyCoreConfig_SetGlobalConfig(const _PyCoreConfig *config) -{ -#define COPY_FLAG(ATTR, VAR) \ - if (config->ATTR != -1) { \ - VAR = config->ATTR; \ - } -#define COPY_NOT_FLAG(ATTR, VAR) \ - if (config->ATTR != -1) { \ - VAR = !config->ATTR; \ - } - - COPY_FLAG(utf8_mode, Py_UTF8Mode); - COPY_FLAG(isolated, Py_IsolatedFlag); - COPY_FLAG(bytes_warning, Py_BytesWarningFlag); - COPY_FLAG(inspect, Py_InspectFlag); - COPY_FLAG(interactive, Py_InteractiveFlag); - COPY_FLAG(optimization_level, Py_OptimizeFlag); - COPY_FLAG(parser_debug, Py_DebugFlag); - COPY_FLAG(verbose, Py_VerboseFlag); - COPY_FLAG(quiet, Py_QuietFlag); -#ifdef MS_WINDOWS - COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag); - COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag); -#endif - - COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag); - COPY_NOT_FLAG(buffered_stdio, Py_UnbufferedStdioFlag); - COPY_NOT_FLAG(site_import, Py_NoSiteFlag); - COPY_NOT_FLAG(write_bytecode, Py_DontWriteBytecodeFlag); - COPY_NOT_FLAG(user_site_directory, Py_NoUserSiteDirectory); - - if (config->_check_hash_pycs_mode != NULL) { - _Py_CheckHashBasedPycsMode = config->_check_hash_pycs_mode; - } - - /* Random or non-zero hash seed */ - Py_HashRandomizationFlag = (config->use_hash_seed == 0 || - config->hash_seed != 0); - -#undef COPY_FLAG -#undef COPY_NOT_FLAG -} - - -/* Free memory allocated in config, but don't clear all attributes */ -void -_PyCoreConfig_Clear(_PyCoreConfig *config) -{ -#define CLEAR(ATTR) \ - do { \ - PyMem_RawFree(ATTR); \ - ATTR = NULL; \ - } while (0) -#define CLEAR_WSTRLIST(LEN, LIST) \ - do { \ - clear_wstrlist(LEN, LIST); \ - LEN = 0; \ - LIST = NULL; \ - } while (0) - - CLEAR(config->pycache_prefix); - CLEAR(config->module_search_path_env); - CLEAR(config->home); - 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; - - CLEAR(config->executable); - 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 -} - - -int -_PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2) -{ - _PyCoreConfig_Clear(config); - -#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR -#define COPY_STR_ATTR(ATTR) \ - do { \ - if (config2->ATTR != NULL) { \ - config->ATTR = _PyMem_RawWcsdup(config2->ATTR); \ - if (config->ATTR == NULL) { \ - return -1; \ - } \ - } \ - } while (0) -#define COPY_WSTRLIST(LEN, LIST) \ - do { \ - if (config2->LIST != NULL) { \ - config->LIST = copy_wstrlist(config2->LEN, config2->LIST); \ - if (config->LIST == NULL) { \ - return -1; \ - } \ - } \ - config->LEN = config2->LEN; \ - } while (0) - - COPY_ATTR(install_signal_handlers); - COPY_ATTR(use_environment); - COPY_ATTR(use_hash_seed); - COPY_ATTR(hash_seed); - COPY_ATTR(_install_importlib); - COPY_ATTR(allocator); - COPY_ATTR(dev_mode); - COPY_ATTR(faulthandler); - COPY_ATTR(tracemalloc); - COPY_ATTR(import_time); - COPY_ATTR(show_ref_count); - COPY_ATTR(show_alloc_count); - COPY_ATTR(dump_refs); - COPY_ATTR(malloc_stats); - - COPY_ATTR(coerce_c_locale); - COPY_ATTR(coerce_c_locale_warn); - COPY_ATTR(utf8_mode); - - COPY_STR_ATTR(pycache_prefix); - COPY_STR_ATTR(module_search_path_env); - COPY_STR_ATTR(home); - COPY_STR_ATTR(program_name); - COPY_STR_ATTR(program); - - COPY_WSTRLIST(argc, argv); - COPY_WSTRLIST(nwarnoption, warnoptions); - COPY_WSTRLIST(nxoption, xoptions); - COPY_WSTRLIST(nmodule_search_path, module_search_paths); - - COPY_STR_ATTR(executable); - 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); - - COPY_ATTR(isolated); - COPY_ATTR(site_import); - COPY_ATTR(bytes_warning); - COPY_ATTR(inspect); - COPY_ATTR(interactive); - COPY_ATTR(optimization_level); - COPY_ATTR(parser_debug); - COPY_ATTR(write_bytecode); - COPY_ATTR(verbose); - COPY_ATTR(quiet); - COPY_ATTR(user_site_directory); - COPY_ATTR(buffered_stdio); -#ifdef MS_WINDOWS - COPY_ATTR(legacy_windows_fs_encoding); - COPY_ATTR(legacy_windows_stdio); -#endif - COPY_ATTR(_check_hash_pycs_mode); - COPY_ATTR(_frozen); - -#undef COPY_ATTR -#undef COPY_STR_ATTR -#undef COPY_WSTRLIST - return 0; -} - - static void pymain_clear_cmdline(_PyMain *pymain, _PyCmdline *cmdline) { PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - clear_wstrlist(cmdline->nwarnoption, cmdline->warnoptions); + _Py_wstrlist_clear(cmdline->nwarnoption, cmdline->warnoptions); cmdline->nwarnoption = 0; cmdline->warnoptions = NULL; - clear_wstrlist(cmdline->nenv_warnoption, cmdline->env_warnoptions); + _Py_wstrlist_clear(cmdline->nenv_warnoption, cmdline->env_warnoptions); cmdline->nenv_warnoption = 0; cmdline->env_warnoptions = NULL; if (pymain->use_bytes_argv && cmdline->argv != NULL) { - clear_wstrlist(pymain->argc, cmdline->argv); + _Py_wstrlist_clear(pymain->argc, cmdline->argv); } cmdline->argv = NULL; @@ -838,7 +512,7 @@ pymain_free(_PyMain *pymain) pymain_clear_pymain(pymain); - clear_wstrlist(orig_argc, orig_argv); + _Py_wstrlist_clear(orig_argc, orig_argv); orig_argc = 0; orig_argv = NULL; @@ -1245,8 +919,8 @@ cmdline_init_env_warnoptions(_PyMain *pymain, const _PyCoreConfig *config, _PyCmdline *cmdline) { wchar_t *env; - int res = config_get_env_var_dup(config, &env, - L"PYTHONWARNINGS", "PYTHONWARNINGS"); + int res = _PyCoreConfig_GetEnvDup(config, &env, + L"PYTHONWARNINGS", "PYTHONWARNINGS"); if (res < 0) { return DECODE_LOCALE_ERR("PYTHONWARNINGS", res); } @@ -1314,85 +988,6 @@ pymain_init_stdio(_PyMain *pymain, _PyCoreConfig *config) } -/* Get the program name: use PYTHONEXECUTABLE and __PYVENV_LAUNCHER__ - environment variables on macOS if available. */ -static _PyInitError -config_init_program_name(_PyCoreConfig *config) -{ - /* If Py_SetProgramName() was called, use its value */ - const wchar_t *program_name = _Py_path_config.program_name; - if (program_name != NULL) { - config->program_name = _PyMem_RawWcsdup(program_name); - if (config->program_name == NULL) { - return _Py_INIT_NO_MEMORY(); - } - return _Py_INIT_OK(); - } - -#ifdef __APPLE__ - /* On MacOS X, when the Python interpreter is embedded in an - application bundle, it gets executed by a bootstrapping script - that does os.execve() with an argv[0] that's different from the - actual Python executable. This is needed to keep the Finder happy, - or rather, to work around Apple's overly strict requirements of - the process name. However, we still need a usable sys.executable, - so the actual executable path is passed in an environment variable. - See Lib/plat-mac/bundlebuiler.py for details about the bootstrap - script. */ - const char *p = config_get_env_var(config, "PYTHONEXECUTABLE"); - if (p != NULL) { - size_t len; - wchar_t* program_name = Py_DecodeLocale(p, &len); - if (program_name == NULL) { - return DECODE_LOCALE_ERR("PYTHONEXECUTABLE environment " - "variable", (Py_ssize_t)len); - } - config->program_name = program_name; - return _Py_INIT_OK(); - } -#ifdef WITH_NEXT_FRAMEWORK - else { - const char* pyvenv_launcher = getenv("__PYVENV_LAUNCHER__"); - if (pyvenv_launcher && *pyvenv_launcher) { - /* Used by Mac/Tools/pythonw.c to forward - * the argv0 of the stub executable - */ - size_t len; - wchar_t* program_name = Py_DecodeLocale(pyvenv_launcher, &len); - if (program_name == NULL) { - return DECODE_LOCALE_ERR("__PYVENV_LAUNCHER__ environment " - "variable", (Py_ssize_t)len); - } - config->program_name = program_name; - return _Py_INIT_OK(); - } - } -#endif /* WITH_NEXT_FRAMEWORK */ -#endif /* __APPLE__ */ - - /* Use argv[0] by default, if available */ - if (config->program != NULL) { - config->program_name = _PyMem_RawWcsdup(config->program); - if (config->program_name == NULL) { - return _Py_INIT_NO_MEMORY(); - } - return _Py_INIT_OK(); - } - - /* Last fall back: hardcoded string */ -#ifdef MS_WINDOWS - const wchar_t *default_program_name = L"python"; -#else - const wchar_t *default_program_name = L"python3"; -#endif - config->program_name = _PyMem_RawWcsdup(default_program_name); - if (config->program_name == NULL) { - return _Py_INIT_NO_MEMORY(); - } - return _Py_INIT_OK(); -} - - static void pymain_header(_PyMain *pymain) { @@ -1422,10 +1017,10 @@ pymain_init_core_argv(_PyMain *pymain, _PyCoreConfig *config, _PyCmdline *cmdlin /* Ensure at least one (empty) argument is seen */ static wchar_t *empty_argv[1] = {L""}; argc = 1; - argv = copy_wstrlist(1, empty_argv); + argv = _Py_wstrlist_copy(1, empty_argv); } else { - argv = copy_wstrlist(argc, &cmdline->argv[_PyOS_optind]); + argv = _Py_wstrlist_copy(argc, &cmdline->argv[_PyOS_optind]); } if (argv == NULL) { @@ -1445,7 +1040,7 @@ pymain_init_core_argv(_PyMain *pymain, _PyCoreConfig *config, _PyCmdline *cmdlin if (arg0 != NULL) { arg0 = _PyMem_RawWcsdup(arg0); if (arg0 == NULL) { - clear_wstrlist(argc, argv); + _Py_wstrlist_clear(argc, argv); pymain->err = _Py_INIT_NO_MEMORY(); return -1; } @@ -1558,7 +1153,7 @@ pymain_open_filename(_PyMain *pymain, _PyCoreConfig *config) static void pymain_run_startup(_PyMain *pymain, _PyCoreConfig *config, PyCompilerFlags *cf) { - const char *startup = config_get_env_var(config, "PYTHONSTARTUP"); + const char *startup = _PyCoreConfig_GetEnv(config, "PYTHONSTARTUP"); if (startup == NULL) { return; } @@ -1613,7 +1208,7 @@ pymain_repl(_PyMain *pymain, _PyCoreConfig *config, PyCompilerFlags *cf) { /* Check this environment variable at the end, to give programs the opportunity to set it from Python. */ - if (!Py_InspectFlag && config_get_env_var(config, "PYTHONINSPECT")) { + if (!Py_InspectFlag && _PyCoreConfig_GetEnv(config, "PYTHONINSPECT")) { Py_InspectFlag = 1; config->inspect = 1; } @@ -1660,359 +1255,6 @@ pymain_parse_cmdline(_PyMain *pymain, _PyCoreConfig *config, } -static const wchar_t* -config_get_xoption(_PyCoreConfig *config, wchar_t *name) -{ - int nxoption = config->nxoption; - wchar_t **xoptions = config->xoptions; - for (int i=0; i < nxoption; i++) { - wchar_t *option = xoptions[i]; - size_t len; - wchar_t *sep = wcschr(option, L'='); - if (sep != NULL) { - len = (sep - option); - } - else { - len = wcslen(option); - } - if (wcsncmp(option, name, len) == 0 && name[len] == L'\0') { - return option; - } - } - return NULL; -} - - -static int -pymain_str_to_int(const char *str, int *result) -{ - errno = 0; - const char *endptr = str; - long value = strtol(str, (char **)&endptr, 10); - if (*endptr != '\0' || errno == ERANGE) { - return -1; - } - if (value < INT_MIN || value > INT_MAX) { - return -1; - } - - *result = (int)value; - return 0; -} - - -static int -pymain_wstr_to_int(const wchar_t *wstr, int *result) -{ - errno = 0; - const wchar_t *endptr = wstr; - long value = wcstol(wstr, (wchar_t **)&endptr, 10); - if (*endptr != '\0' || errno == ERANGE) { - return -1; - } - if (value < INT_MIN || value > INT_MAX) { - return -1; - } - - *result = (int)value; - return 0; -} - - -static _PyInitError -pymain_init_tracemalloc(_PyCoreConfig *config) -{ - int nframe; - int valid; - - const char *env = config_get_env_var(config, "PYTHONTRACEMALLOC"); - if (env) { - if (!pymain_str_to_int(env, &nframe)) { - valid = (nframe >= 0); - } - else { - valid = 0; - } - if (!valid) { - return _Py_INIT_USER_ERR("PYTHONTRACEMALLOC: invalid number " - "of frames"); - } - config->tracemalloc = nframe; - } - - const wchar_t *xoption = config_get_xoption(config, L"tracemalloc"); - if (xoption) { - const wchar_t *sep = wcschr(xoption, L'='); - if (sep) { - if (!pymain_wstr_to_int(sep + 1, &nframe)) { - valid = (nframe >= 0); - } - else { - valid = 0; - } - if (!valid) { - return _Py_INIT_USER_ERR("-X tracemalloc=NFRAME: " - "invalid number of frames"); - } - } - else { - /* -X tracemalloc behaves as -X tracemalloc=1 */ - nframe = 1; - } - config->tracemalloc = nframe; - } - return _Py_INIT_OK(); -} - - -static _PyInitError -pymain_init_pycache_prefix(_PyCoreConfig *config) -{ - const wchar_t *xoption = config_get_xoption(config, L"pycache_prefix"); - if (xoption) { - const wchar_t *sep = wcschr(xoption, L'='); - if (sep && wcslen(sep) > 1) { - config->pycache_prefix = _PyMem_RawWcsdup(sep + 1); - if (config->pycache_prefix == NULL) { - return _Py_INIT_NO_MEMORY(); - } - } else { - // -X pycache_prefix= can cancel the env var - config->pycache_prefix = NULL; - } - return _Py_INIT_OK(); - } - - wchar_t *env; - int res = config_get_env_var_dup(config, &env, - L"PYTHONPYCACHEPREFIX", "PYTHONPYCACHEPREFIX"); - if (res < 0) { - return DECODE_LOCALE_ERR("PYTHONPYCACHEPREFIX", res); - } else if (env) { - config->pycache_prefix = env; - } - - return _Py_INIT_OK(); -} - - -static void -get_env_flag(_PyCoreConfig *config, int *flag, const char *name) -{ - const char *var = config_get_env_var(config, name); - if (!var) { - return; - } - int value; - if (pymain_str_to_int(var, &value) < 0 || value < 0) { - /* PYTHONDEBUG=text and PYTHONDEBUG=-2 behave as PYTHONDEBUG=1 */ - value = 1; - } - if (*flag < value) { - *flag = value; - } -} - - -static _PyInitError -config_init_home(_PyCoreConfig *config) -{ - wchar_t *home; - - /* If Py_SetPythonHome() was called, use its value */ - home = _Py_path_config.home; - if (home) { - config->home = _PyMem_RawWcsdup(home); - if (config->home == NULL) { - return _Py_INIT_NO_MEMORY(); - } - return _Py_INIT_OK(); - } - - int res = config_get_env_var_dup(config, &home, L"PYTHONHOME", "PYTHONHOME"); - if (res < 0) { - return DECODE_LOCALE_ERR("PYTHONHOME", res); - } - config->home = home; - return _Py_INIT_OK(); -} - - -static _PyInitError -config_init_hash_seed(_PyCoreConfig *config) -{ - if (config->use_hash_seed < 0) { - const char *seed_text = config_get_env_var(config, "PYTHONHASHSEED"); - int use_hash_seed; - unsigned long hash_seed; - if (_Py_ReadHashSeed(seed_text, &use_hash_seed, &hash_seed) < 0) { - return _Py_INIT_USER_ERR("PYTHONHASHSEED must be \"random\" " - "or an integer in range [0; 4294967295]"); - } - config->use_hash_seed = use_hash_seed; - config->hash_seed = hash_seed; - } - return _Py_INIT_OK(); -} - - -static _PyInitError -config_init_utf8_mode(_PyCoreConfig *config) -{ - const wchar_t *xopt = config_get_xoption(config, L"utf8"); - if (xopt) { - wchar_t *sep = wcschr(xopt, L'='); - if (sep) { - xopt = sep + 1; - if (wcscmp(xopt, L"1") == 0) { - config->utf8_mode = 1; - } - else if (wcscmp(xopt, L"0") == 0) { - config->utf8_mode = 0; - } - else { - return _Py_INIT_USER_ERR("invalid -X utf8 option value"); - } - } - else { - config->utf8_mode = 1; - } - return _Py_INIT_OK(); - } - - const char *opt = config_get_env_var(config, "PYTHONUTF8"); - if (opt) { - if (strcmp(opt, "1") == 0) { - config->utf8_mode = 1; - } - else if (strcmp(opt, "0") == 0) { - config->utf8_mode = 0; - } - else { - return _Py_INIT_USER_ERR("invalid PYTHONUTF8 environment " - "variable value"); - } - return _Py_INIT_OK(); - } - - return _Py_INIT_OK(); -} - - -static _PyInitError -config_read_env_vars(_PyCoreConfig *config) -{ - assert(config->use_environment > 0); - - /* Get environment variables */ - get_env_flag(config, &config->parser_debug, "PYTHONDEBUG"); - get_env_flag(config, &config->verbose, "PYTHONVERBOSE"); - get_env_flag(config, &config->optimization_level, "PYTHONOPTIMIZE"); - get_env_flag(config, &config->inspect, "PYTHONINSPECT"); - - int dont_write_bytecode = 0; - get_env_flag(config, &dont_write_bytecode, "PYTHONDONTWRITEBYTECODE"); - if (dont_write_bytecode) { - config->write_bytecode = 0; - } - - int no_user_site_directory = 0; - get_env_flag(config, &no_user_site_directory, "PYTHONNOUSERSITE"); - if (no_user_site_directory) { - config->user_site_directory = 0; - } - - int unbuffered_stdio = 0; - get_env_flag(config, &unbuffered_stdio, "PYTHONUNBUFFERED"); - if (unbuffered_stdio) { - config->buffered_stdio = 0; - } - -#ifdef MS_WINDOWS - get_env_flag(config, &config->legacy_windows_fs_encoding, - "PYTHONLEGACYWINDOWSFSENCODING"); - get_env_flag(config, &config->legacy_windows_stdio, - "PYTHONLEGACYWINDOWSSTDIO"); -#endif - - if (config->allocator == NULL) { - config->allocator = config_get_env_var(config, "PYTHONMALLOC"); - } - - if (config_get_env_var(config, "PYTHONDUMPREFS")) { - config->dump_refs = 1; - } - if (config_get_env_var(config, "PYTHONMALLOCSTATS")) { - config->malloc_stats = 1; - } - - const char *env = config_get_env_var(config, "PYTHONCOERCECLOCALE"); - if (env) { - if (strcmp(env, "0") == 0) { - config->coerce_c_locale = 0; - } - else if (strcmp(env, "warn") == 0) { - config->coerce_c_locale_warn = 1; - } - else { - config->coerce_c_locale = 1; - } - } - - wchar_t *path; - int res = config_get_env_var_dup(config, &path, L"PYTHONPATH", "PYTHONPATH"); - if (res < 0) { - return DECODE_LOCALE_ERR("PYTHONPATH", res); - } - config->module_search_path_env = path; - - _PyInitError err = config_init_hash_seed(config); - if (_Py_INIT_FAILED(err)) { - return err; - } - - return _Py_INIT_OK(); -} - - -static _PyInitError -config_read_complex_options(_PyCoreConfig *config) -{ - /* More complex options configured by env var and -X option */ - if (config->faulthandler < 0) { - if (config_get_env_var(config, "PYTHONFAULTHANDLER") - || config_get_xoption(config, L"faulthandler")) { - config->faulthandler = 1; - } - } - if (config_get_env_var(config, "PYTHONPROFILEIMPORTTIME") - || config_get_xoption(config, L"importtime")) { - config->import_time = 1; - } - if (config_get_xoption(config, L"dev" ) || - config_get_env_var(config, "PYTHONDEVMODE")) - { - config->dev_mode = 1; - } - - _PyInitError err; - if (config->tracemalloc < 0) { - err = pymain_init_tracemalloc(config); - if (_Py_INIT_FAILED(err)) { - return err; - } - } - - if (config->pycache_prefix == NULL) { - err = pymain_init_pycache_prefix(config); - if (_Py_INIT_FAILED(err)) { - return err; - } - } - return _Py_INIT_OK(); -} - - /* Parse command line options and environment variables. This code must not use Python runtime apart PyMem_Raw memory allocator. @@ -2165,143 +1407,6 @@ pymain_read_conf(_PyMain *pymain, _PyCoreConfig *config, } -static void -config_init_locale(_PyCoreConfig *config) -{ - if (config->utf8_mode >= 0 && config->coerce_c_locale >= 0) { - return; - } - - if (_Py_LegacyLocaleDetected()) { - /* POSIX locale: enable C locale coercion and UTF-8 Mode */ - if (config->utf8_mode < 0) { - config->utf8_mode = 1; - } - if (config->coerce_c_locale < 0) { - config->coerce_c_locale = 1; - } - return; - } -} - - -/* Read configuration settings from standard locations - * - * This function doesn't make any changes to the interpreter state - it - * merely populates any missing configuration settings. This allows an - * embedding application to completely override a config option by - * setting it before calling this function, or else modify the default - * setting before passing the fully populated config to Py_EndInitialization. - * - * More advanced selective initialization tricks are possible by calling - * this function multiple times with various preconfigured settings. - */ - -_PyInitError -_PyCoreConfig_Read(_PyCoreConfig *config) -{ - _PyInitError err; - - _PyCoreConfig_GetGlobalConfig(config); - - if (config->isolated > 0) { - config->use_environment = 0; - config->user_site_directory = 0; - } - -#ifdef MS_WINDOWS - if (config->legacy_windows_fs_encoding) { - config->utf8_mode = 0; - } -#endif - - assert(config->use_environment >= 0); - if (config->use_environment) { - err = config_read_env_vars(config); - if (_Py_INIT_FAILED(err)) { - return err; - } - } - - /* -X options */ - if (config_get_xoption(config, L"showrefcount")) { - config->show_ref_count = 1; - } - if (config_get_xoption(config, L"showalloccount")) { - config->show_alloc_count = 1; - } - - err = config_read_complex_options(config); - if (_Py_INIT_FAILED(err)) { - return err; - } - - if (config->utf8_mode < 0) { - err = config_init_utf8_mode(config); - if (_Py_INIT_FAILED(err)) { - return err; - } - } - - if (config->home == NULL) { - err = config_init_home(config); - if (_Py_INIT_FAILED(err)) { - return err; - } - } - - if (config->program_name == NULL) { - err = config_init_program_name(config); - if (_Py_INIT_FAILED(err)) { - return err; - } - } - - config_init_locale(config); - - if (config->_install_importlib) { - err = _PyCoreConfig_InitPathConfig(config); - if (_Py_INIT_FAILED(err)) { - return err; - } - } - - /* default values */ - if (config->dev_mode) { - if (config->faulthandler < 0) { - config->faulthandler = 1; - } - if (config->allocator == NULL) { - config->allocator = "debug"; - } - } - if (config->use_hash_seed < 0) { - config->use_hash_seed = 0; - config->hash_seed = 0; - } - if (config->faulthandler < 0) { - config->faulthandler = 0; - } - if (config->tracemalloc < 0) { - config->tracemalloc = 0; - } - if (config->coerce_c_locale < 0) { - config->coerce_c_locale = 0; - } - if (config->utf8_mode < 0) { - config->utf8_mode = 0; - } - if (config->_frozen < 0) { - config->_frozen = 0; - } - if (config->argc < 0) { - config->argc = 0; - } - - return _Py_INIT_OK(); -} - - void _PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *config) { @@ -2373,8 +1478,6 @@ _PyMainInterpreterConfig_Copy(_PyMainInterpreterConfig *config, } - - _PyInitError _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config, const _PyCoreConfig *config) @@ -2557,7 +1660,7 @@ pymain_cmdline_impl(_PyMain *pymain, _PyCoreConfig *config, } /* For Py_GetArgcArgv(). Cleared by pymain_free(). */ - orig_argv = copy_wstrlist(pymain->argc, cmdline->argv); + orig_argv = _Py_wstrlist_copy(pymain->argc, cmdline->argv); if (orig_argv == NULL) { pymain->err = _Py_INIT_NO_MEMORY(); return -1; diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 90330faa0cf2..42455f5c7da6 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -95,6 +95,7 @@ <ClInclude Include="..\Include\compile.h" /> <ClInclude Include="..\Include\complexobject.h" /> <ClInclude Include="..\Include\context.h" /> + <ClInclude Include="..\Include\coreconfig.h" /> <ClInclude Include="..\Include\datetime.h" /> <ClInclude Include="..\Include\descrobject.h" /> <ClInclude Include="..\Include\dictobject.h" /> @@ -367,6 +368,7 @@ <ClCompile Include="..\Python\codecs.c" /> <ClCompile Include="..\Python\compile.c" /> <ClCompile Include="..\Python\context.c" /> + <ClCompile Include="..\Python\coreconfig.c" /> <ClCompile Include="..\Python\dynamic_annotations.c" /> <ClCompile Include="..\Python\dynload_win.c" /> <ClCompile Include="..\Python\errors.c" /> diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index b51fd54f8b4d..582114f6f475 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -84,6 +84,9 @@ <ClInclude Include="..\Include\context.h"> <Filter>Include</Filter> </ClInclude> + <ClInclude Include="..\Include\coreconfig.h"> + <Filter>Include</Filter> + </ClInclude> <ClInclude Include="..\Include\datetime.h"> <Filter>Include</Filter> </ClInclude> @@ -857,6 +860,9 @@ <ClCompile Include="..\Python\compile.c"> <Filter>Python</Filter> </ClCompile> + <ClCompile Include="..\Python\coreconfig.c"> + <Filter>Python</Filter> + </ClCompile> <ClCompile Include="..\Python\context.h"> <Filter>Python</Filter> </ClCompile> diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 7bb5687d9ae0..4b12048f9d56 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -11,29 +11,6 @@ #include <ctype.h> -/* The default encoding used by the platform file system APIs - Can remain NULL for all platforms that don't have such a concept - - Don't forget to modify PyUnicode_DecodeFSDefault() if you touch any of the - values for Py_FileSystemDefaultEncoding! -*/ -#if defined(__APPLE__) -const char *Py_FileSystemDefaultEncoding = "utf-8"; -int Py_HasFileSystemDefaultEncoding = 1; -#elif defined(MS_WINDOWS) -/* may be changed by initfsencoding(), but should never be free()d */ -const char *Py_FileSystemDefaultEncoding = "utf-8"; -int Py_HasFileSystemDefaultEncoding = 1; -#else -const char *Py_FileSystemDefaultEncoding = NULL; /* set by initfsencoding() */ -int Py_HasFileSystemDefaultEncoding = 0; -#endif -const char *Py_FileSystemDefaultEncodeErrors = "surrogateescape"; -/* UTF-8 mode (PEP 540): if equals to 1, use the UTF-8 encoding, and change - stdin and stdout error handler to "surrogateescape". It is equal to - -1 by default: unknown, will be set by Py_Main() */ -int Py_UTF8Mode = -1; - _Py_IDENTIFIER(__builtins__); _Py_IDENTIFIER(__dict__); _Py_IDENTIFIER(__prepare__); diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c index 073b2ea8dbda..7b187f18877f 100644 --- a/Python/bootstrap_hash.c +++ b/Python/bootstrap_hash.c @@ -538,35 +538,6 @@ _PyOS_URandomNonblock(void *buffer, Py_ssize_t size) return pyurandom(buffer, size, 0, 1); } -int -_Py_ReadHashSeed(const char *seed_text, - int *use_hash_seed, - unsigned long *hash_seed) -{ - Py_BUILD_ASSERT(sizeof(_Py_HashSecret_t) == sizeof(_Py_HashSecret.uc)); - /* Convert a text seed to a numeric one */ - if (seed_text && *seed_text != '\0' && strcmp(seed_text, "random") != 0) { - const char *endptr = seed_text; - unsigned long seed; - seed = strtoul(seed_text, (char **)&endptr, 10); - if (*endptr != '\0' - || seed > 4294967295UL - || (errno == ERANGE && seed == ULONG_MAX)) - { - return -1; - } - /* Use a specific hash */ - *use_hash_seed = 1; - *hash_seed = seed; - } - else { - /* Use a random hash */ - *use_hash_seed = 0; - *hash_seed = 0; - } - return 0; -} - _PyInitError _Py_HashRandomization_Init(const _PyCoreConfig *config) diff --git a/Python/coreconfig.c b/Python/coreconfig.c new file mode 100644 index 000000000000..7dabe5f96447 --- /dev/null +++ b/Python/coreconfig.c @@ -0,0 +1,964 @@ +#include "Python.h" +#include "internal/import.h" +#include "internal/pystate.h" + + +#define DECODE_LOCALE_ERR(NAME, LEN) \ + (((LEN) == -2) \ + ? _Py_INIT_USER_ERR("cannot decode " NAME) \ + : _Py_INIT_NO_MEMORY()) + + +/* Global configuration variables */ + +/* The default encoding used by the platform file system APIs + Can remain NULL for all platforms that don't have such a concept + + Don't forget to modify PyUnicode_DecodeFSDefault() if you touch any of the + values for Py_FileSystemDefaultEncoding! +*/ +#if defined(__APPLE__) +const char *Py_FileSystemDefaultEncoding = "utf-8"; +int Py_HasFileSystemDefaultEncoding = 1; +#elif defined(MS_WINDOWS) +/* may be changed by initfsencoding(), but should never be free()d */ +const char *Py_FileSystemDefaultEncoding = "utf-8"; +int Py_HasFileSystemDefaultEncoding = 1; +#else +const char *Py_FileSystemDefaultEncoding = NULL; /* set by initfsencoding() */ +int Py_HasFileSystemDefaultEncoding = 0; +#endif +const char *Py_FileSystemDefaultEncodeErrors = "surrogateescape"; +/* UTF-8 mode (PEP 540): if equals to 1, use the UTF-8 encoding, and change + stdin and stdout error handler to "surrogateescape". It is equal to + -1 by default: unknown, will be set by Py_Main() */ +int Py_UTF8Mode = -1; +int Py_DebugFlag = 0; /* Needed by parser.c */ +int Py_VerboseFlag = 0; /* Needed by import.c */ +int Py_QuietFlag = 0; /* Needed by sysmodule.c */ +int Py_InteractiveFlag = 0; /* Needed by Py_FdIsInteractive() below */ +int Py_InspectFlag = 0; /* Needed to determine whether to exit at SystemExit */ +int Py_OptimizeFlag = 0; /* Needed by compile.c */ +int Py_NoSiteFlag = 0; /* Suppress 'import site' */ +int Py_BytesWarningFlag = 0; /* Warn on str(bytes) and str(buffer) */ +int Py_FrozenFlag = 0; /* Needed by getpath.c */ +int Py_IgnoreEnvironmentFlag = 0; /* e.g. PYTHONPATH, PYTHONHOME */ +int Py_DontWriteBytecodeFlag = 0; /* Suppress writing bytecode files (*.pyc) */ +int Py_NoUserSiteDirectory = 0; /* for -s and site.py */ +int Py_UnbufferedStdioFlag = 0; /* Unbuffered binary std{in,out,err} */ +int Py_HashRandomizationFlag = 0; /* for -R and PYTHONHASHSEED */ +int Py_IsolatedFlag = 0; /* for -I, isolate from user's env */ +#ifdef MS_WINDOWS +int Py_LegacyWindowsFSEncodingFlag = 0; /* Uses mbcs instead of utf-8 */ +int Py_LegacyWindowsStdioFlag = 0; /* Uses FileIO instead of WindowsConsoleIO */ +#endif +const char *_Py_CheckHashBasedPycsMode = "default"; + + +void +_Py_wstrlist_clear(int len, wchar_t **list) +{ + for (int i=0; i < len; i++) { + PyMem_RawFree(list[i]); + } + PyMem_RawFree(list); +} + + +wchar_t** +_Py_wstrlist_copy(int len, wchar_t **list) +{ + assert((len > 0 && list != NULL) || len == 0); + size_t size = len * sizeof(list[0]); + wchar_t **list_copy = PyMem_RawMalloc(size); + for (int i=0; i < len; i++) { + wchar_t* arg = _PyMem_RawWcsdup(list[i]); + if (arg == NULL) { + _Py_wstrlist_clear(i, list); + return NULL; + } + list_copy[i] = arg; + } + return list_copy; +} + + +/* Free memory allocated in config, but don't clear all attributes */ +void +_PyCoreConfig_Clear(_PyCoreConfig *config) +{ +#define CLEAR(ATTR) \ + do { \ + 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); + CLEAR(config->home); + 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; + + CLEAR(config->executable); + 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 +} + + +int +_PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2) +{ + _PyCoreConfig_Clear(config); + +#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR +#define COPY_STR_ATTR(ATTR) \ + do { \ + if (config2->ATTR != NULL) { \ + config->ATTR = _PyMem_RawWcsdup(config2->ATTR); \ + if (config->ATTR == NULL) { \ + return -1; \ + } \ + } \ + } while (0) +#define COPY_WSTRLIST(LEN, LIST) \ + do { \ + if (config2->LIST != NULL) { \ + config->LIST = _Py_wstrlist_copy(config2->LEN, config2->LIST); \ + if (config->LIST == NULL) { \ + return -1; \ + } \ + } \ + config->LEN = config2->LEN; \ + } while (0) + + COPY_ATTR(install_signal_handlers); + COPY_ATTR(use_environment); + COPY_ATTR(use_hash_seed); + COPY_ATTR(hash_seed); + COPY_ATTR(_install_importlib); + COPY_ATTR(allocator); + COPY_ATTR(dev_mode); + COPY_ATTR(faulthandler); + COPY_ATTR(tracemalloc); + COPY_ATTR(import_time); + COPY_ATTR(show_ref_count); + COPY_ATTR(show_alloc_count); + COPY_ATTR(dump_refs); + COPY_ATTR(malloc_stats); + + COPY_ATTR(coerce_c_locale); + COPY_ATTR(coerce_c_locale_warn); + COPY_ATTR(utf8_mode); + + COPY_STR_ATTR(pycache_prefix); + COPY_STR_ATTR(module_search_path_env); + COPY_STR_ATTR(home); + COPY_STR_ATTR(program_name); + COPY_STR_ATTR(program); + + COPY_WSTRLIST(argc, argv); + COPY_WSTRLIST(nwarnoption, warnoptions); + COPY_WSTRLIST(nxoption, xoptions); + COPY_WSTRLIST(nmodule_search_path, module_search_paths); + + COPY_STR_ATTR(executable); + 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); + + COPY_ATTR(isolated); + COPY_ATTR(site_import); + COPY_ATTR(bytes_warning); + COPY_ATTR(inspect); + COPY_ATTR(interactive); + COPY_ATTR(optimization_level); + COPY_ATTR(parser_debug); + COPY_ATTR(write_bytecode); + COPY_ATTR(verbose); + COPY_ATTR(quiet); + COPY_ATTR(user_site_directory); + COPY_ATTR(buffered_stdio); +#ifdef MS_WINDOWS + COPY_ATTR(legacy_windows_fs_encoding); + COPY_ATTR(legacy_windows_stdio); +#endif + COPY_ATTR(_check_hash_pycs_mode); + COPY_ATTR(_frozen); + +#undef COPY_ATTR +#undef COPY_STR_ATTR +#undef COPY_WSTRLIST + return 0; +} + + +const char* +_PyCoreConfig_GetEnv(const _PyCoreConfig *config, const char *name) +{ + assert(config->use_environment >= 0); + + if (!config->use_environment) { + return NULL; + } + + const char *var = getenv(name); + if (var && var[0] != '\0') { + return var; + } + else { + return NULL; + } +} + + +int +_PyCoreConfig_GetEnvDup(const _PyCoreConfig *config, + wchar_t **dest, + wchar_t *wname, char *name) +{ + assert(config->use_environment >= 0); + + if (!config->use_environment) { + *dest = NULL; + return 0; + } + +#ifdef MS_WINDOWS + const wchar_t *var = _wgetenv(wname); + if (!var || var[0] == '\0') { + *dest = NULL; + return 0; + } + + wchar_t *copy = _PyMem_RawWcsdup(var); + if (copy == NULL) { + return -1; + } + + *dest = copy; +#else + const char *var = getenv(name); + if (!var || var[0] == '\0') { + *dest = NULL; + return 0; + } + + size_t len; + wchar_t *wvar = Py_DecodeLocale(var, &len); + if (!wvar) { + if (len == (size_t)-2) { + return -2; + } + else { + return -1; + } + } + *dest = wvar; +#endif + return 0; +} + + +void +_PyCoreConfig_GetGlobalConfig(_PyCoreConfig *config) +{ +#define COPY_FLAG(ATTR, VALUE) \ + if (config->ATTR == -1) { \ + config->ATTR = VALUE; \ + } +#define COPY_NOT_FLAG(ATTR, VALUE) \ + if (config->ATTR == -1) { \ + config->ATTR = !(VALUE); \ + } + + COPY_FLAG(utf8_mode, Py_UTF8Mode); + COPY_FLAG(isolated, Py_IsolatedFlag); + COPY_FLAG(bytes_warning, Py_BytesWarningFlag); + COPY_FLAG(inspect, Py_InspectFlag); + COPY_FLAG(interactive, Py_InteractiveFlag); + COPY_FLAG(optimization_level, Py_OptimizeFlag); + COPY_FLAG(parser_debug, Py_DebugFlag); + COPY_FLAG(verbose, Py_VerboseFlag); + COPY_FLAG(quiet, Py_QuietFlag); +#ifdef MS_WINDOWS + COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag); + COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag); +#endif + COPY_FLAG(_frozen, Py_FrozenFlag); + + COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag); + COPY_NOT_FLAG(buffered_stdio, Py_UnbufferedStdioFlag); + COPY_NOT_FLAG(site_import, Py_NoSiteFlag); + COPY_NOT_FLAG(write_bytecode, Py_DontWriteBytecodeFlag); + COPY_NOT_FLAG(user_site_directory, Py_NoUserSiteDirectory); + + if (config->_check_hash_pycs_mode == NULL) { + config->_check_hash_pycs_mode = _Py_CheckHashBasedPycsMode; + } + +#undef COPY_FLAG +#undef COPY_NOT_FLAG +} + + +/* Set Py_xxx global configuration variables from 'config' configuration. */ +void +_PyCoreConfig_SetGlobalConfig(const _PyCoreConfig *config) +{ +#define COPY_FLAG(ATTR, VAR) \ + if (config->ATTR != -1) { \ + VAR = config->ATTR; \ + } +#define COPY_NOT_FLAG(ATTR, VAR) \ + if (config->ATTR != -1) { \ + VAR = !config->ATTR; \ + } + + COPY_FLAG(utf8_mode, Py_UTF8Mode); + COPY_FLAG(isolated, Py_IsolatedFlag); + COPY_FLAG(bytes_warning, Py_BytesWarningFlag); + COPY_FLAG(inspect, Py_InspectFlag); + COPY_FLAG(interactive, Py_InteractiveFlag); + COPY_FLAG(optimization_level, Py_OptimizeFlag); + COPY_FLAG(parser_debug, Py_DebugFlag); + COPY_FLAG(verbose, Py_VerboseFlag); + COPY_FLAG(quiet, Py_QuietFlag); +#ifdef MS_WINDOWS + COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag); + COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag); +#endif + + COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag); + COPY_NOT_FLAG(buffered_stdio, Py_UnbufferedStdioFlag); + COPY_NOT_FLAG(site_import, Py_NoSiteFlag); + COPY_NOT_FLAG(write_bytecode, Py_DontWriteBytecodeFlag); + COPY_NOT_FLAG(user_site_directory, Py_NoUserSiteDirectory); + + if (config->_check_hash_pycs_mode != NULL) { + _Py_CheckHashBasedPycsMode = config->_check_hash_pycs_mode; + } + + /* Random or non-zero hash seed */ + Py_HashRandomizationFlag = (config->use_hash_seed == 0 || + config->hash_seed != 0); + +#undef COPY_FLAG +#undef COPY_NOT_FLAG +} + + +/* Get the program name: use PYTHONEXECUTABLE and __PYVENV_LAUNCHER__ + environment variables on macOS if available. */ +static _PyInitError +config_init_program_name(_PyCoreConfig *config) +{ + /* If Py_SetProgramName() was called, use its value */ + const wchar_t *program_name = _Py_path_config.program_name; + if (program_name != NULL) { + config->program_name = _PyMem_RawWcsdup(program_name); + if (config->program_name == NULL) { + return _Py_INIT_NO_MEMORY(); + } + return _Py_INIT_OK(); + } + +#ifdef __APPLE__ + /* On MacOS X, when the Python interpreter is embedded in an + application bundle, it gets executed by a bootstrapping script + that does os.execve() with an argv[0] that's different from the + actual Python executable. This is needed to keep the Finder happy, + or rather, to work around Apple's overly strict requirements of + the process name. However, we still need a usable sys.executable, + so the actual executable path is passed in an environment variable. + See Lib/plat-mac/bundlebuiler.py for details about the bootstrap + script. */ + const char *p = _PyCoreConfig_GetEnv(config, "PYTHONEXECUTABLE"); + if (p != NULL) { + size_t len; + wchar_t* program_name = Py_DecodeLocale(p, &len); + if (program_name == NULL) { + return DECODE_LOCALE_ERR("PYTHONEXECUTABLE environment " + "variable", (Py_ssize_t)len); + } + config->program_name = program_name; + return _Py_INIT_OK(); + } +#ifdef WITH_NEXT_FRAMEWORK + else { + const char* pyvenv_launcher = getenv("__PYVENV_LAUNCHER__"); + if (pyvenv_launcher && *pyvenv_launcher) { + /* Used by Mac/Tools/pythonw.c to forward + * the argv0 of the stub executable + */ + size_t len; + wchar_t* program_name = Py_DecodeLocale(pyvenv_launcher, &len); + if (program_name == NULL) { + return DECODE_LOCALE_ERR("__PYVENV_LAUNCHER__ environment " + "variable", (Py_ssize_t)len); + } + config->program_name = program_name; + return _Py_INIT_OK(); + } + } +#endif /* WITH_NEXT_FRAMEWORK */ +#endif /* __APPLE__ */ + + /* Use argv[0] by default, if available */ + if (config->program != NULL) { + config->program_name = _PyMem_RawWcsdup(config->program); + if (config->program_name == NULL) { + return _Py_INIT_NO_MEMORY(); + } + return _Py_INIT_OK(); + } + + /* Last fall back: hardcoded string */ +#ifdef MS_WINDOWS + const wchar_t *default_program_name = L"python"; +#else + const wchar_t *default_program_name = L"python3"; +#endif + config->program_name = _PyMem_RawWcsdup(default_program_name); + if (config->program_name == NULL) { + return _Py_INIT_NO_MEMORY(); + } + return _Py_INIT_OK(); +} + + +static const wchar_t* +config_get_xoption(const _PyCoreConfig *config, wchar_t *name) +{ + int nxoption = config->nxoption; + wchar_t **xoptions = config->xoptions; + for (int i=0; i < nxoption; i++) { + wchar_t *option = xoptions[i]; + size_t len; + wchar_t *sep = wcschr(option, L'='); + if (sep != NULL) { + len = (sep - option); + } + else { + len = wcslen(option); + } + if (wcsncmp(option, name, len) == 0 && name[len] == L'\0') { + return option; + } + } + return NULL; +} + + +static _PyInitError +config_init_home(_PyCoreConfig *config) +{ + wchar_t *home; + + /* If Py_SetPythonHome() was called, use its value */ + home = _Py_path_config.home; + if (home) { + config->home = _PyMem_RawWcsdup(home); + if (config->home == NULL) { + return _Py_INIT_NO_MEMORY(); + } + return _Py_INIT_OK(); + } + + int res = _PyCoreConfig_GetEnvDup(config, &home, + L"PYTHONHOME", "PYTHONHOME"); + if (res < 0) { + return DECODE_LOCALE_ERR("PYTHONHOME", res); + } + config->home = home; + return _Py_INIT_OK(); +} + + +static _PyInitError +config_init_hash_seed(_PyCoreConfig *config) +{ + const char *seed_text = _PyCoreConfig_GetEnv(config, "PYTHONHASHSEED"); + + Py_BUILD_ASSERT(sizeof(_Py_HashSecret_t) == sizeof(_Py_HashSecret.uc)); + /* Convert a text seed to a numeric one */ + if (seed_text && strcmp(seed_text, "random") != 0) { + const char *endptr = seed_text; + unsigned long seed; + errno = 0; + seed = strtoul(seed_text, (char **)&endptr, 10); + if (*endptr != '\0' + || seed > 4294967295UL + || (errno == ERANGE && seed == ULONG_MAX)) + { + return _Py_INIT_USER_ERR("PYTHONHASHSEED must be \"random\" " + "or an integer in range [0; 4294967295]"); + } + /* Use a specific hash */ + config->use_hash_seed = 1; + config->hash_seed = seed; + } + else { + /* Use a random hash */ + config->use_hash_seed = 0; + config->hash_seed = 0; + } + return _Py_INIT_OK(); +} + + +static _PyInitError +config_init_utf8_mode(_PyCoreConfig *config) +{ + const wchar_t *xopt = config_get_xoption(config, L"utf8"); + if (xopt) { + wchar_t *sep = wcschr(xopt, L'='); + if (sep) { + xopt = sep + 1; + if (wcscmp(xopt, L"1") == 0) { + config->utf8_mode = 1; + } + else if (wcscmp(xopt, L"0") == 0) { + config->utf8_mode = 0; + } + else { + return _Py_INIT_USER_ERR("invalid -X utf8 option value"); + } + } + else { + config->utf8_mode = 1; + } + return _Py_INIT_OK(); + } + + const char *opt = _PyCoreConfig_GetEnv(config, "PYTHONUTF8"); + if (opt) { + if (strcmp(opt, "1") == 0) { + config->utf8_mode = 1; + } + else if (strcmp(opt, "0") == 0) { + config->utf8_mode = 0; + } + else { + return _Py_INIT_USER_ERR("invalid PYTHONUTF8 environment " + "variable value"); + } + return _Py_INIT_OK(); + } + + return _Py_INIT_OK(); +} + + +static int +config_str_to_int(const char *str, int *result) +{ + const char *endptr = str; + errno = 0; + long value = strtol(str, (char **)&endptr, 10); + if (*endptr != '\0' || errno == ERANGE) { + return -1; + } + if (value < INT_MIN || value > INT_MAX) { + return -1; + } + + *result = (int)value; + return 0; +} + + +static int +config_wstr_to_int(const wchar_t *wstr, int *result) +{ + const wchar_t *endptr = wstr; + errno = 0; + long value = wcstol(wstr, (wchar_t **)&endptr, 10); + if (*endptr != '\0' || errno == ERANGE) { + return -1; + } + if (value < INT_MIN || value > INT_MAX) { + return -1; + } + + *result = (int)value; + return 0; +} + + +static void +get_env_flag(_PyCoreConfig *config, int *flag, const char *name) +{ + const char *var = _PyCoreConfig_GetEnv(config, name); + if (!var) { + return; + } + int value; + if (config_str_to_int(var, &value) < 0 || value < 0) { + /* PYTHONDEBUG=text and PYTHONDEBUG=-2 behave as PYTHONDEBUG=1 */ + value = 1; + } + if (*flag < value) { + *flag = value; + } +} + + +static _PyInitError +config_read_env_vars(_PyCoreConfig *config) +{ + assert(config->use_environment > 0); + + /* Get environment variables */ + get_env_flag(config, &config->parser_debug, "PYTHONDEBUG"); + get_env_flag(config, &config->verbose, "PYTHONVERBOSE"); + get_env_flag(config, &config->optimization_level, "PYTHONOPTIMIZE"); + get_env_flag(config, &config->inspect, "PYTHONINSPECT"); + + int dont_write_bytecode = 0; + get_env_flag(config, &dont_write_bytecode, "PYTHONDONTWRITEBYTECODE"); + if (dont_write_bytecode) { + config->write_bytecode = 0; + } + + int no_user_site_directory = 0; + get_env_flag(config, &no_user_site_directory, "PYTHONNOUSERSITE"); + if (no_user_site_directory) { + config->user_site_directory = 0; + } + + int unbuffered_stdio = 0; + get_env_flag(config, &unbuffered_stdio, "PYTHONUNBUFFERED"); + if (unbuffered_stdio) { + config->buffered_stdio = 0; + } + +#ifdef MS_WINDOWS + get_env_flag(config, &config->legacy_windows_fs_encoding, + "PYTHONLEGACYWINDOWSFSENCODING"); + get_env_flag(config, &config->legacy_windows_stdio, + "PYTHONLEGACYWINDOWSSTDIO"); +#endif + + if (config->allocator == NULL) { + config->allocator = _PyCoreConfig_GetEnv(config, "PYTHONMALLOC"); + } + + if (_PyCoreConfig_GetEnv(config, "PYTHONDUMPREFS")) { + config->dump_refs = 1; + } + if (_PyCoreConfig_GetEnv(config, "PYTHONMALLOCSTATS")) { + config->malloc_stats = 1; + } + + const char *env = _PyCoreConfig_GetEnv(config, "PYTHONCOERCECLOCALE"); + if (env) { + if (strcmp(env, "0") == 0) { + config->coerce_c_locale = 0; + } + else if (strcmp(env, "warn") == 0) { + config->coerce_c_locale_warn = 1; + } + else { + config->coerce_c_locale = 1; + } + } + + wchar_t *path; + int res = _PyCoreConfig_GetEnvDup(config, &path, + L"PYTHONPATH", "PYTHONPATH"); + if (res < 0) { + return DECODE_LOCALE_ERR("PYTHONPATH", res); + } + config->module_search_path_env = path; + + if (config->use_hash_seed < 0) { + _PyInitError err = config_init_hash_seed(config); + if (_Py_INIT_FAILED(err)) { + return err; + } + } + + return _Py_INIT_OK(); +} + + +static _PyInitError +config_init_tracemalloc(_PyCoreConfig *config) +{ + int nframe; + int valid; + + const char *env = _PyCoreConfig_GetEnv(config, "PYTHONTRACEMALLOC"); + if (env) { + if (!config_str_to_int(env, &nframe)) { + valid = (nframe >= 0); + } + else { + valid = 0; + } + if (!valid) { + return _Py_INIT_USER_ERR("PYTHONTRACEMALLOC: invalid number " + "of frames"); + } + config->tracemalloc = nframe; + } + + const wchar_t *xoption = config_get_xoption(config, L"tracemalloc"); + if (xoption) { + const wchar_t *sep = wcschr(xoption, L'='); + if (sep) { + if (!config_wstr_to_int(sep + 1, &nframe)) { + valid = (nframe >= 0); + } + else { + valid = 0; + } + if (!valid) { + return _Py_INIT_USER_ERR("-X tracemalloc=NFRAME: " + "invalid number of frames"); + } + } + else { + /* -X tracemalloc behaves as -X tracemalloc=1 */ + nframe = 1; + } + config->tracemalloc = nframe; + } + return _Py_INIT_OK(); +} + + +static _PyInitError +config_init_pycache_prefix(_PyCoreConfig *config) +{ + assert(config->pycache_prefix == NULL); + + const wchar_t *xoption = config_get_xoption(config, L"pycache_prefix"); + if (xoption) { + const wchar_t *sep = wcschr(xoption, L'='); + if (sep && wcslen(sep) > 1) { + config->pycache_prefix = _PyMem_RawWcsdup(sep + 1); + if (config->pycache_prefix == NULL) { + return _Py_INIT_NO_MEMORY(); + } + } + else { + // -X pycache_prefix= can cancel the env var + config->pycache_prefix = NULL; + } + } + else { + wchar_t *env; + int res = _PyCoreConfig_GetEnvDup(config, &env, + L"PYTHONPYCACHEPREFIX", + "PYTHONPYCACHEPREFIX"); + if (res < 0) { + return DECODE_LOCALE_ERR("PYTHONPYCACHEPREFIX", res); + } + + if (env) { + config->pycache_prefix = env; + } + } + return _Py_INIT_OK(); +} + + +static _PyInitError +config_read_complex_options(_PyCoreConfig *config) +{ + /* More complex options configured by env var and -X option */ + if (config->faulthandler < 0) { + if (_PyCoreConfig_GetEnv(config, "PYTHONFAULTHANDLER") + || config_get_xoption(config, L"faulthandler")) { + config->faulthandler = 1; + } + } + if (_PyCoreConfig_GetEnv(config, "PYTHONPROFILEIMPORTTIME") + || config_get_xoption(config, L"importtime")) { + config->import_time = 1; + } + if (config_get_xoption(config, L"dev" ) || + _PyCoreConfig_GetEnv(config, "PYTHONDEVMODE")) + { + config->dev_mode = 1; + } + + _PyInitError err; + if (config->tracemalloc < 0) { + err = config_init_tracemalloc(config); + if (_Py_INIT_FAILED(err)) { + return err; + } + } + + if (config->pycache_prefix == NULL) { + err = config_init_pycache_prefix(config); + if (_Py_INIT_FAILED(err)) { + return err; + } + } + return _Py_INIT_OK(); +} + + +static void +config_init_locale(_PyCoreConfig *config) +{ + if (config->utf8_mode >= 0 && config->coerce_c_locale >= 0) { + return; + } + + if (_Py_LegacyLocaleDetected()) { + /* POSIX locale: enable C locale coercion and UTF-8 Mode */ + if (config->utf8_mode < 0) { + config->utf8_mode = 1; + } + if (config->coerce_c_locale < 0) { + config->coerce_c_locale = 1; + } + return; + } +} + + +/* Read configuration settings from standard locations + * + * This function doesn't make any changes to the interpreter state - it + * merely populates any missing configuration settings. This allows an + * embedding application to completely override a config option by + * setting it before calling this function, or else modify the default + * setting before passing the fully populated config to Py_EndInitialization. + * + * More advanced selective initialization tricks are possible by calling + * this function multiple times with various preconfigured settings. + */ + +_PyInitError +_PyCoreConfig_Read(_PyCoreConfig *config) +{ + _PyInitError err; + + _PyCoreConfig_GetGlobalConfig(config); + + if (config->isolated > 0) { + config->use_environment = 0; + config->user_site_directory = 0; + } + +#ifdef MS_WINDOWS + if (config->legacy_windows_fs_encoding) { + config->utf8_mode = 0; + } +#endif + + assert(config->use_environment >= 0); + if (config->use_environment) { + err = config_read_env_vars(config); + if (_Py_INIT_FAILED(err)) { + return err; + } + } + + /* -X options */ + if (config_get_xoption(config, L"showrefcount")) { + config->show_ref_count = 1; + } + if (config_get_xoption(config, L"showalloccount")) { + config->show_alloc_count = 1; + } + + err = config_read_complex_options(config); + if (_Py_INIT_FAILED(err)) { + return err; + } + + if (config->utf8_mode < 0) { + err = config_init_utf8_mode(config); + if (_Py_INIT_FAILED(err)) { + return err; + } + } + + if (config->home == NULL) { + err = config_init_home(config); + if (_Py_INIT_FAILED(err)) { + return err; + } + } + + if (config->program_name == NULL) { + err = config_init_program_name(config); + if (_Py_INIT_FAILED(err)) { + return err; + } + } + + config_init_locale(config); + + if (config->_install_importlib) { + err = _PyCoreConfig_InitPathConfig(config); + if (_Py_INIT_FAILED(err)) { + return err; + } + } + + /* default values */ + if (config->dev_mode) { + if (config->faulthandler < 0) { + config->faulthandler = 1; + } + if (config->allocator == NULL) { + config->allocator = "debug"; + } + } + if (config->use_hash_seed < 0) { + config->use_hash_seed = 0; + config->hash_seed = 0; + } + if (config->faulthandler < 0) { + config->faulthandler = 0; + } + if (config->tracemalloc < 0) { + config->tracemalloc = 0; + } + if (config->coerce_c_locale < 0) { + config->coerce_c_locale = 0; + } + if (config->utf8_mode < 0) { + config->utf8_mode = 0; + } + if (config->_frozen < 0) { + config->_frozen = 0; + } + if (config->argc < 0) { + config->argc = 0; + } + + return _Py_INIT_OK(); +} diff --git a/Python/import.c b/Python/import.c index 3a591836654b..de132a347e05 100644 --- a/Python/import.c +++ b/Python/import.c @@ -2279,8 +2279,6 @@ static struct PyModuleDef impmodule = { NULL }; -const char *_Py_CheckHashBasedPycsMode = "default"; - PyMODINIT_FUNC PyInit__imp(void) { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 63f461ab0432..95fb8616b52d 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -108,28 +108,6 @@ _Py_IsFinalizing(void) return _PyRuntime.finalizing != NULL; } -/* Global configuration variable declarations are in pydebug.h */ -/* XXX (ncoghlan): move those declarations to pylifecycle.h? */ -int Py_DebugFlag = 0; /* Needed by parser.c */ -int Py_VerboseFlag = 0; /* Needed by import.c */ -int Py_QuietFlag = 0; /* Needed by sysmodule.c */ -int Py_InteractiveFlag = 0; /* Needed by Py_FdIsInteractive() below */ -int Py_InspectFlag = 0; /* Needed to determine whether to exit at SystemExit */ -int Py_OptimizeFlag = 0; /* Needed by compile.c */ -int Py_NoSiteFlag = 0; /* Suppress 'import site' */ -int Py_BytesWarningFlag = 0; /* Warn on str(bytes) and str(buffer) */ -int Py_FrozenFlag = 0; /* Needed by getpath.c */ -int Py_IgnoreEnvironmentFlag = 0; /* e.g. PYTHONPATH, PYTHONHOME */ -int Py_DontWriteBytecodeFlag = 0; /* Suppress writing bytecode files (*.pyc) */ -int Py_NoUserSiteDirectory = 0; /* for -s and site.py */ -int Py_UnbufferedStdioFlag = 0; /* Unbuffered binary std{in,out,err} */ -int Py_HashRandomizationFlag = 0; /* for -R and PYTHONHASHSEED */ -int Py_IsolatedFlag = 0; /* for -I, isolate from user's env */ -#ifdef MS_WINDOWS -int Py_LegacyWindowsFSEncodingFlag = 0; /* Uses mbcs instead of utf-8 */ -int Py_LegacyWindowsStdioFlag = 0; /* Uses FileIO instead of WindowsConsoleIO */ -#endif - /* Hack to force loading of object files */ int (*_PyOS_mystrnicmp_hack)(const char *, const char *, Py_ssize_t) = \ PyOS_mystrnicmp; /* Python/pystrcmp.o */
participants (1)
-
Victor Stinner