Commit f7e5b56c authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

bpo-32030: Split Py_Main() into subfunctions (#4399)

* Don't use "Python runtime" anymore to parse command line options or
  to get environment variables: pymain_init() is now a strict
  separation.
* Use an error message rather than "crashing" directly with
  Py_FatalError(). Limit the number of calls to Py_FatalError(). It
  prepares the code to handle errors more nicely later.
* Warnings options (-W, PYTHONWARNINGS) and "XOptions" (-X) are now
  only added to the sys module once Python core is properly
  initialized.
* _PyMain is now the well identified owner of some important strings
  like: warnings options, XOptions, and the "program name". The
  program name string is now properly freed at exit.
  pymain_free() is now responsible to free the "command" string.
* Rename most methods in Modules/main.c to use a "pymain_" prefix to
  avoid conflits and ease debug.
* Replace _Py_CommandLineDetails_INIT with memset(0)
* Reorder a lot of code to fix the initialization ordering. For
  example, initializing standard streams now comes before parsing
  PYTHONWARNINGS.
* Py_Main() now handles errors when adding warnings options and
  XOptions.
* Add _PyMem_GetDefaultRawAllocator() private function.
* Cleanup _PyMem_Initialize(): remove useless global constants: move
  them into _PyMem_Initialize().
* Call _PyRuntime_Initialize() as soon as possible:
  _PyRuntime_Initialize() now returns an error message on failure.
* Add _PyInitError structure and following macros:

  * _Py_INIT_OK()
  * _Py_INIT_ERR(msg)
  * _Py_INIT_USER_ERR(msg): "user" error, don't abort() in that case
  * _Py_INIT_FAILED(err)
parent 43605e6b
......@@ -8,7 +8,7 @@ extern "C" {
#endif
#ifndef Py_LIMITED_API
PyAPI_FUNC(void) _PyImportZip_Init(void);
PyAPI_FUNC(_PyInitError) _PyImportZip_Init(void);
PyMODINIT_FUNC PyInit_imp(void);
#endif /* !Py_LIMITED_API */
......
......@@ -74,10 +74,16 @@ typedef struct pyruntimestate {
// XXX Consolidate globals found via the check-c-globals script.
} _PyRuntimeState;
#define _PyRuntimeState_INIT {.initialized = 0, .core_initialized = 0}
PyAPI_DATA(_PyRuntimeState) _PyRuntime;
PyAPI_FUNC(void) _PyRuntimeState_Init(_PyRuntimeState *);
PyAPI_FUNC(_PyInitError) _PyRuntimeState_Init(_PyRuntimeState *);
PyAPI_FUNC(void) _PyRuntimeState_Fini(_PyRuntimeState *);
/* Initialize _PyRuntimeState.
Return NULL on success, or return an error message on failure. */
PyAPI_FUNC(_PyInitError) _PyRuntime_Initialize(void);
#define _Py_CURRENTLY_FINALIZING(tstate) \
(_PyRuntime.finalizing == tstate)
......
......@@ -20,18 +20,44 @@ PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void);
PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding,
const char *errors);
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_FAILED(err) \
(err.msg != NULL)
/* PEP 432 Multi-phase initialization API (Private while provisional!) */
PyAPI_FUNC(void) _Py_InitializeCore(const _PyCoreConfig *);
PyAPI_FUNC(_PyInitError) _Py_InitializeCore(const _PyCoreConfig *);
PyAPI_FUNC(int) _Py_IsCoreInitialized(void);
PyAPI_FUNC(int) _Py_ReadMainInterpreterConfig(_PyMainInterpreterConfig *);
PyAPI_FUNC(int) _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *);
PyAPI_FUNC(_PyInitError) _Py_ReadMainInterpreterConfig(_PyMainInterpreterConfig *);
PyAPI_FUNC(_PyInitError) _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *);
#endif
/* Initialization and finalization */
PyAPI_FUNC(void) Py_Initialize(void);
PyAPI_FUNC(void) Py_InitializeEx(int);
#ifndef Py_LIMITED_API
PyAPI_FUNC(void) _Py_InitializeEx_Private(int, int);
PyAPI_FUNC(_PyInitError) _Py_InitializeEx_Private(int, int);
PyAPI_FUNC(void) _Py_FatalInitError(_PyInitError err) _Py_NO_RETURN;
#endif
PyAPI_FUNC(void) Py_Finalize(void);
PyAPI_FUNC(int) Py_FinalizeEx(void);
......@@ -50,7 +76,7 @@ PyAPI_FUNC(void) _Py_PyAtExit(void (*func)(void));
#endif
PyAPI_FUNC(int) Py_AtExit(void (*func)(void));
PyAPI_FUNC(void) Py_Exit(int);
PyAPI_FUNC(void) Py_Exit(int) _Py_NO_RETURN;
/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. */
#ifndef Py_LIMITED_API
......@@ -86,15 +112,15 @@ PyAPI_FUNC(const char *) _Py_gitversion(void);
/* Internal -- various one-time initializations */
#ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _PyBuiltin_Init(void);
PyAPI_FUNC(PyObject *) _PySys_BeginInit(void);
PyAPI_FUNC(_PyInitError) _PySys_BeginInit(PyObject **sysmod);
PyAPI_FUNC(int) _PySys_EndInit(PyObject *sysdict);
PyAPI_FUNC(void) _PyImport_Init(void);
PyAPI_FUNC(_PyInitError) _PyImport_Init(void);
PyAPI_FUNC(void) _PyExc_Init(PyObject * bltinmod);
PyAPI_FUNC(void) _PyImportHooks_Init(void);
PyAPI_FUNC(_PyInitError) _PyImportHooks_Init(void);
PyAPI_FUNC(int) _PyFrame_Init(void);
PyAPI_FUNC(int) _PyFloat_Init(void);
PyAPI_FUNC(int) PyByteArray_Init(void);
PyAPI_FUNC(void) _Py_HashRandomization_Init(_PyCoreConfig *core_config);
PyAPI_FUNC(_PyInitError) _Py_HashRandomization_Init(_PyCoreConfig *core_config);
#endif
/* Various internal finalizers */
......
......@@ -223,6 +223,10 @@ PyAPI_FUNC(void) PyMem_SetAllocator(PyMemAllocatorDomain domain,
PyAPI_FUNC(void) PyMem_SetupDebugHooks(void);
#endif
#ifdef Py_BUILD_CORE
PyAPI_FUNC(void) _PyMem_GetDefaultRawAllocator(PyMemAllocatorEx *alloc);
#endif
#ifdef __cplusplus
}
#endif
......
......@@ -37,6 +37,11 @@ PyAPI_FUNC(PyObject *) PySys_GetXOptions(void);
PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *);
#endif
#ifdef Py_BUILD_CORE
PyAPI_FUNC(int) _PySys_AddXOptionWithError(const wchar_t *s);
PyAPI_FUNC(int) _PySys_AddWarnOptionWithError(PyObject *option);
#endif
#ifdef __cplusplus
}
#endif
......
......@@ -1281,47 +1281,54 @@ PyInit_faulthandler(void)
return m;
}
/* Call faulthandler.enable() if the PYTHONFAULTHANDLER environment variable
is defined, or if sys._xoptions has a 'faulthandler' key. */
static int
faulthandler_env_options(void)
faulthandler_init_enable(void)
{
PyObject *xoptions, *key, *module, *res;
char *p;
PyObject *module = PyImport_ImportModule("faulthandler");
if (module == NULL) {
return -1;
}
if (!((p = Py_GETENV("PYTHONFAULTHANDLER")) && *p != '\0')) {
/* PYTHONFAULTHANDLER environment variable is missing
or an empty string */
int has_key;
PyObject *res = _PyObject_CallMethodId(module, &PyId_enable, NULL);
Py_DECREF(module);
if (res == NULL) {
return -1;
}
Py_DECREF(res);
xoptions = PySys_GetXOptions();
if (xoptions == NULL)
return -1;
return 0;
}
key = PyUnicode_FromString("faulthandler");
if (key == NULL)
return -1;
/* Call faulthandler.enable() if the PYTHONFAULTHANDLER environment variable
is defined, or if sys._xoptions has a 'faulthandler' key. */
has_key = PyDict_Contains(xoptions, key);
Py_DECREF(key);
if (has_key <= 0)
return has_key;
static int
faulthandler_init_parse(void)
{
char *p = Py_GETENV("PYTHONFAULTHANDLER");
if (p && *p != '\0') {
return 1;
}
module = PyImport_ImportModule("faulthandler");
if (module == NULL) {
/* PYTHONFAULTHANDLER environment variable is missing
or an empty string */
PyObject *xoptions = PySys_GetXOptions();
if (xoptions == NULL) {
return -1;
}
res = _PyObject_CallMethodId(module, &PyId_enable, NULL);
Py_DECREF(module);
if (res == NULL)
PyObject *key = PyUnicode_FromString("faulthandler");
if (key == NULL) {
return -1;
Py_DECREF(res);
return 0;
}
int has_key = PyDict_Contains(xoptions, key);
Py_DECREF(key);
return has_key;
}
int _PyFaulthandler_Init(void)
_PyInitError
_PyFaulthandler_Init(void)
{
#ifdef HAVE_SIGALTSTACK
int err;
......@@ -1345,14 +1352,22 @@ int _PyFaulthandler_Init(void)
thread.cancel_event = PyThread_allocate_lock();
thread.running = PyThread_allocate_lock();
if (!thread.cancel_event || !thread.running) {
PyErr_SetString(PyExc_RuntimeError,
"could not allocate locks for faulthandler");
return -1;
return _Py_INIT_ERR("failed to allocate locks for faulthandler");
}
PyThread_acquire_lock(thread.cancel_event, 1);
#endif
return faulthandler_env_options();
int enable = faulthandler_init_parse();
if (enable < 0) {
return _Py_INIT_ERR("failed to parse faulthandler env var and cmdline");
}
if (enable) {
if (faulthandler_init_enable() < 0) {
return _Py_INIT_ERR("failed to enable faulthandler");
}
}
return _Py_INIT_OK();
}
void _PyFaulthandler_Fini(void)
......
This diff is collapsed.
......@@ -182,31 +182,17 @@ static struct {
#define _PyMem_Raw _PyRuntime.mem.allocators.raw
static const PyMemAllocatorEx _pymem_raw = {
#ifdef Py_DEBUG
&_PyMem_Debug.raw, PYRAWDBG_FUNCS
#else
NULL, PYRAW_FUNCS
#endif
};
#define _PyMem _PyRuntime.mem.allocators.mem
static const PyMemAllocatorEx _pymem = {
#ifdef Py_DEBUG
&_PyMem_Debug.mem, PYDBG_FUNCS
#else
NULL, PYMEM_FUNCS
#endif
};
#define _PyObject _PyRuntime.mem.allocators.obj
static const PyMemAllocatorEx _pyobject = {
#ifdef Py_DEBUG
&_PyMem_Debug.obj, PYDBG_FUNCS
#else
NULL, PYOBJ_FUNCS
#endif
};
void
_PyMem_GetDefaultRawAllocator(PyMemAllocatorEx *alloc_p)
{
PyMemAllocatorEx alloc = {NULL, PYRAW_FUNCS};
*alloc_p = alloc;
}
int
_PyMem_SetupAllocators(const char *opt)
......@@ -267,34 +253,52 @@ _PyMem_SetupAllocators(const char *opt)
return 0;
}
#undef PYRAW_FUNCS
#undef PYMEM_FUNCS
#undef PYOBJ_FUNCS
#undef PYRAWDBG_FUNCS
#undef PYDBG_FUNCS
static const PyObjectArenaAllocator _PyObject_Arena = {NULL,
void
_PyObject_Initialize(struct _pyobj_runtime_state *state)
{
PyObjectArenaAllocator _PyObject_Arena = {NULL,
#ifdef MS_WINDOWS
_PyObject_ArenaVirtualAlloc, _PyObject_ArenaVirtualFree
_PyObject_ArenaVirtualAlloc, _PyObject_ArenaVirtualFree
#elif defined(ARENAS_USE_MMAP)
_PyObject_ArenaMmap, _PyObject_ArenaMunmap
_PyObject_ArenaMmap, _PyObject_ArenaMunmap
#else
_PyObject_ArenaMalloc, _PyObject_ArenaFree
_PyObject_ArenaMalloc, _PyObject_ArenaFree
#endif
};
void
_PyObject_Initialize(struct _pyobj_runtime_state *state)
{
state->allocator_arenas = _PyObject_Arena;
}
void
_PyMem_Initialize(struct _pymem_runtime_state *state)
{
state->allocators.raw = _pymem_raw;
state->allocators.mem = _pymem;
state->allocators.obj = _pyobject;
PyMemAllocatorEx pymem_raw = {
#ifdef Py_DEBUG
&_PyMem_Debug.raw, PYRAWDBG_FUNCS
#else
NULL, PYRAW_FUNCS
#endif
};
PyMemAllocatorEx pymem = {
#ifdef Py_DEBUG
&_PyMem_Debug.mem, PYDBG_FUNCS
#else
NULL, PYMEM_FUNCS
#endif
};
PyMemAllocatorEx pyobject = {
#ifdef Py_DEBUG
&_PyMem_Debug.obj, PYDBG_FUNCS
#else
NULL, PYOBJ_FUNCS
#endif
};
state->allocators.raw = pymem_raw;
state->allocators.mem = pymem;
state->allocators.obj = pyobject;
#ifdef WITH_PYMALLOC
Py_BUILD_ASSERT(NB_SMALL_SIZE_CLASSES == 64);
......@@ -311,6 +315,7 @@ _PyMem_Initialize(struct _pymem_runtime_state *state)
#endif /* WITH_PYMALLOC */
}
#ifdef WITH_PYMALLOC
static int
_PyMem_DebugEnabled(void)
......
......@@ -57,7 +57,7 @@
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>Py_BUILD_CORE;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
......@@ -113,4 +113,4 @@ $(_PGOPath)
</PropertyGroup>
<WriteLinesToFile File="$(PySourcePath)python.bat" Lines="$(_Content)" Overwrite="true" Condition="'$(_Content)' != '$(_ExistingContent)'" />
</Target>
</Project>
\ No newline at end of file
</Project>
......@@ -27,13 +27,11 @@
int Py_DebugFlag;
int Py_VerboseFlag;
int Py_IgnoreEnvironmentFlag;
_PyRuntimeState _PyRuntime = {0, 0};
_PyRuntimeState _PyRuntime = _PyRuntimeState_INIT;
/* Forward */
grammar *getgrammar(const char *filename);
void Py_Exit(int) _Py_NO_RETURN;
void
Py_Exit(int sts)
{
......
......@@ -81,7 +81,10 @@ main(int argc, char *argv[])
Py_SetProgramName(L"./_freeze_importlib");
/* Don't install importlib, since it could execute outdated bytecode. */
_Py_InitializeEx_Private(1, 0);
_PyInitError err = _Py_InitializeEx_Private(1, 0);
if (_Py_INIT_FAILED(err)) {
_Py_FatalInitError(err);
}
if (strstr(inpath, "_external") != NULL) {
is_bootstrap = 0;
......
/* Minimal main program -- everything is loaded from the library */
#include "Python.h"
#include "internal/pystate.h"
#include <locale.h>
#ifdef __FreeBSD__
......@@ -22,9 +23,16 @@ main(int argc, char **argv)
wchar_t **argv_copy;
/* We need a second copy, as Python might modify the first one. */
wchar_t **argv_copy2;
int i, res;
int i, status;
char *oldloc;
_PyInitError err = _PyRuntime_Initialize();
if (_Py_INIT_FAILED(err)) {
fprintf(stderr, "Fatal Python error: %s\n", err.msg);
fflush(stderr);
exit(1);
}
/* Force malloc() allocator to bootstrap Python */
#ifdef Py_DEBUG
(void)_PyMem_SetupAllocators("malloc_debug");
......@@ -88,7 +96,7 @@ main(int argc, char **argv)
setlocale(LC_ALL, oldloc);
PyMem_RawFree(oldloc);
res = Py_Main(argc, argv_copy);
status = Py_Main(argc, argv_copy);
/* Force again malloc() allocator to release memory blocks allocated
before Py_Main() */
......@@ -103,6 +111,6 @@ main(int argc, char **argv)
}
PyMem_RawFree(argv_copy);
PyMem_RawFree(argv_copy2);
return res;
return status;
}
#endif
......@@ -561,15 +561,16 @@ int Py_ReadHashSeed(char *seed_text,
return 0;
}
static void
static _PyInitError
init_hash_secret(int use_hash_seed,
unsigned long hash_seed)
{
void *secret = &_Py_HashSecret;
Py_ssize_t secret_size = sizeof(_Py_HashSecret_t);
if (_Py_HashSecret_Initialized)
return;
if (_Py_HashSecret_Initialized) {
return _Py_INIT_OK();
}
_Py_HashSecret_Initialized = 1;
if (use_hash_seed) {
......@@ -593,12 +594,14 @@ init_hash_secret(int use_hash_seed,
pyurandom() is non-blocking mode (blocking=0): see the PEP 524. */
res = pyurandom(secret, secret_size, 0, 0);
if (res < 0) {
Py_FatalError("failed to get random numbers to initialize Python");
return _Py_INIT_ERR("failed to get random numbers "
"to initialize Python");
}
}
return _Py_INIT_OK();
}
void
_PyInitError
_Py_HashRandomization_Init(_PyCoreConfig *core_config)
{
char *seed_text;
......@@ -608,13 +611,13 @@ _Py_HashRandomization_Init(_PyCoreConfig *core_config)
if (use_hash_seed < 0) {
seed_text = Py_GETENV("PYTHONHASHSEED");
if (Py_ReadHashSeed(seed_text, &use_hash_seed, &hash_seed) < 0) {
Py_FatalError("PYTHONHASHSEED must be \"random\" or an integer "
"in range [0; 4294967295]");
return _Py_INIT_USER_ERR("PYTHONHASHSEED must be \"random\" "
"or an integer in range [0; 4294967295]");
}
core_config->use_hash_seed = use_hash_seed;
core_config->hash_seed = hash_seed;
}
init_hash_secret(use_hash_seed, hash_seed);
return init_hash_secret(use_hash_seed, hash_seed);
}
void
......
......@@ -2,6 +2,7 @@
/* Python interpreter main program for frozen scripts */
#include "Python.h"
#include "internal/pystate.h"
#include <locale.h>
#ifdef MS_WINDOWS
......@@ -15,6 +16,13 @@ extern int PyInitFrozenExtensions(void);
int
Py_FrozenMain(int argc, char **argv)
{
_PyInitError err = _PyRuntime_Initialize();
if (_Py_INIT_FAILED(err)) {
fprintf(stderr, "Fatal Python error: %s\n", err.msg);
fflush(stderr);
exit(1);
}
char *p;
int i, n, sts = 1;
int inspect = 0;
......
......@@ -42,19 +42,23 @@ module _imp
/* Initialize things */
void
_PyInitError
_PyImport_Init(void)
{
PyInterpreterState *interp = PyThreadState_Get()->interp;
initstr = PyUnicode_InternFromString("__init__");
if (initstr == NULL)
Py_FatalError("Can't initialize import variables");
if (initstr == NULL) {
return _Py_INIT_ERR("Can't initialize import variables");
}
interp->builtins_copy = PyDict_Copy(interp->builtins);
if (interp->builtins_copy == NULL)
Py_FatalError("Can't backup builtins dict");
if (interp->builtins_copy == NULL) {
return _Py_INIT_ERR("Can't backup builtins dict");
}
return _Py_INIT_OK();
}
void
_PyInitError
_PyImportHooks_Init(void)
{
PyObject *v, *path_hooks = NULL;
......@@ -80,15 +84,18 @@ _PyImportHooks_Init(void)
goto error;
err = PySys_SetObject("path_hooks", path_hooks);
if (err) {
error:
PyErr_Print();
Py_FatalError("initializing sys.meta_path, sys.path_hooks, "
"or path_importer_cache failed");
goto error;
}
Py_DECREF(path_hooks);
return _Py_INIT_OK();
error:
PyErr_Print();
return _Py_INIT_ERR("initializing sys.meta_path, sys.path_hooks, "
"or path_importer_cache failed");
}
void
_PyInitError
_PyImportZip_Init(void)
{
PyObject *path_hooks, *zimpimport;
......@@ -133,11 +140,11 @@ _PyImportZip_Init(void)
}
}
return;
return _Py_INIT_OK();
error:
PyErr_Print();
Py_FatalError("initializing zipimport failed");
return _Py_INIT_ERR("initializing zipimport failed");
}
/* Locking primitives to prevent parallel imports of the same module
......
This diff is collapsed.
......@@ -35,7 +35,7 @@ to avoid the expense of doing their own locking).
extern "C" {
#endif
void
_PyInitError
_PyRuntimeState_Init(_PyRuntimeState *runtime)
{
memset(runtime, 0, sizeof(*runtime));
......@@ -46,17 +46,19 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
_PyEval_Initialize(&runtime->ceval);
runtime->gilstate.check_enabled = 1;
/* A TSS key must be initialized with Py_tss_NEEDS_INIT
in accordance with the specification. */
{
Py_tss_t initial = Py_tss_NEEDS_INIT;
runtime->gilstate.autoTSSkey = initial;
}
Py_tss_t initial = Py_tss_NEEDS_INIT;
runtime->gilstate.autoTSSkey = initial;
runtime->interpreters.mutex = PyThread_allocate_lock();
if (runtime->interpreters.mutex == NULL)
Py_FatalError("Can't initialize threads for interpreter");
if (runtime->interpreters.mutex == NULL) {
return _Py_INIT_ERR("Can't initialize threads for interpreter");
}
runtime->interpreters.next_id = -1;
return _Py_INIT_OK();
}
void
......
......@@ -1582,13 +1582,23 @@ PySys_ResetWarnOptions(void)
PyList_SetSlice(warnoptions, 0, PyList_GET_SIZE(warnoptions), NULL);
}
void
PySys_AddWarnOptionUnicode(PyObject *unicode)
int
_PySys_AddWarnOptionWithError(PyObject *option)
{
PyObject *warnoptions = get_warnoptions();
if (warnoptions == NULL)
return;
PyList_Append(warnoptions, unicode);
if (warnoptions == NULL) {
return -1;
}
if (PyList_Append(warnoptions, option)) {
return -1;
}
return 0;
}
void
PySys_AddWarnOptionUnicode(PyObject *option)
{
(void)_PySys_AddWarnOptionWithError(option);
}
void
......@@ -1627,18 +1637,17 @@ get_xoptions(void)
return xoptions;
}
void
PySys_AddXOption(const wchar_t *s)
int
_PySys_AddXOptionWithError(const wchar_t *s)
{
PyObject *opts;
PyObject *name = NULL, *value = NULL;
const wchar_t *name_end;
opts = get_xoptions();
if (opts == NULL)
PyObject *opts = get_xoptions();
if (opts == NULL) {
goto error;
}
name_end = wcschr(s, L'=');
const wchar_t *name_end = wcschr(s, L'=');
if (!name_end) {
name = PyUnicode_FromWideChar(s, -1);
value = Py_True;
......@@ -1648,19 +1657,30 @@ PySys_AddXOption(const wchar_t *s)
name = PyUnicode_FromWideChar(s, name_end - s);
value = PyUnicode_FromWideChar(name_end + 1, -1);
}
if (name == NULL || value == NULL)
if (name == NULL || value == NULL) {
goto error;
}
if (PyDict_SetItem(opts, name, value) < 0) {
goto error;
PyDict_SetItem(opts, name, value);
}
Py_DECREF(name);
Py_DECREF(value);
return;
return 0;
error:
Py_XDECREF(name);
Py_XDECREF(value);
/* No return value, therefore clear error state if possible */
if (_PyThreadState_UncheckedGet()) {
PyErr_Clear();
return -1;
}
void
PySys_AddXOption(const wchar_t *s)
{
if (_PySys_AddXOptionWithError(s) < 0) {
/* No return value, therefore clear error state if possible */
if (_PyThreadState_UncheckedGet()) {
PyErr_Clear();
}
}
}
......@@ -1999,50 +2019,52 @@ static struct PyModuleDef sysmodule = {
#define SET_SYS_FROM_STRING_BORROW(key, value) \
do { \
PyObject *v = (value); \
if (v == NULL) \
return NULL; \
if (v == NULL) { \
goto err_occurred; \
} \
res = PyDict_SetItemString(sysdict, key, v); \
if (res < 0) { \
return NULL; \
goto err_occurred; \
} \
} while (0)
#define SET_SYS_FROM_STRING(key, value) \
do { \
PyObject *v = (value); \
if (v == NULL) \
return NULL; \
if (v == NULL) { \
goto err_occurred; \
} \
res = PyDict_SetItemString(sysdict, key, v); \
Py_DECREF(v); \
if (res < 0) { \
return NULL; \
goto err_occurred; \
} \
} while (0)
PyObject *
_PySys_BeginInit(void)
_PyInitError
_PySys_BeginInit(PyObject **sysmod)
{
PyObject *m, *sysdict, *version_info;
int res;
m = _PyModule_CreateInitialized(&sysmodule, PYTHON_API_VERSION);
if (m == NULL)
return NULL;
if (m == NULL) {
return _Py_INIT_ERR("failed to create a module object");
}
sysdict = PyModule_GetDict(m);
/* Check that stdin is not a directory
Using shell redirection, you can redirect stdin to a directory,
crashing the Python interpreter. Catch this common mistake here
and output a useful error message. Note that under MS Windows,
the shell already prevents that. */
#if !defined(MS_WINDOWS)
Using shell redirection, you can redirect stdin to a directory,
crashing the Python interpreter. Catch this common mistake here
and output a useful error message. Note that under MS Windows,
the shell already prevents that. */
#ifndef MS_WINDOWS
{
struct _Py_stat_struct sb;
if (_Py_fstat_noraise(fileno(stdin), &sb) == 0 &&
S_ISDIR(sb.st_mode)) {
/* There's nothing more we can do. */
/* Py_FatalError() will core dump, so just exit. */
PySys_WriteStderr("Python error: <stdin> is a directory, cannot continue\n");
exit(EXIT_FAILURE);
return _Py_INIT_USER_ERR("<stdin> is a directory, "
"cannot continue");
}
}
#endif
......@@ -2078,8 +2100,9 @@ _PySys_BeginInit(void)
PyLong_GetInfo());
/* initialize hash_info */
if (Hash_InfoType.tp_name == NULL) {
if (PyStructSequence_InitType2(&Hash_InfoType, &hash_info_desc) < 0)
return NULL;
if (PyStructSequence_InitType2(&Hash_InfoType, &hash_info_desc) < 0) {
goto type_init_failed;
}
}
SET_SYS_FROM_STRING("hash_info",
get_hash_info());
......@@ -2109,8 +2132,9 @@ _PySys_BeginInit(void)
/* version_info */
if (VersionInfoType.tp_name == NULL) {
if (PyStructSequence_InitType2(&VersionInfoType,
&version_info_desc) < 0)
return NULL;
&version_info_desc) < 0) {
goto type_init_failed;
}
}
version_info = make_version_info();
SET_SYS_FROM_STRING("version_info", version_info);
......@@ -2126,8 +2150,9 @@ _PySys_BeginInit(void)
/* flags */
if (FlagsType.tp_name == 0) {
if (PyStructSequence_InitType2(&FlagsType, &flags_desc) < 0)
return NULL;
if (PyStructSequence_InitType2(&FlagsType, &flags_desc) < 0) {
goto type_init_failed;
}
}
/* Set flags to their default values */
SET_SYS_FROM_STRING("flags", make_flags());
......@@ -2136,14 +2161,17 @@ _PySys_BeginInit(void)
/* getwindowsversion */
if (WindowsVersionType.tp_name == 0)
if (PyStructSequence_InitType2(&WindowsVersionType,
&windows_version_desc) < 0)
return NULL;
&windows_version_desc) < 0) {
goto type_init_failed;
}
/* prevent user from creating new instances */
WindowsVersionType.tp_init = NULL;
WindowsVersionType.tp_new = NULL;
assert(!PyErr_Occurred());
res = PyDict_DelItemString(WindowsVersionType.tp_dict, "__new__");
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) {
PyErr_Clear();
}
#endif
/* float repr style: 0.03 (short) vs 0.029999999999999999 (legacy) */
......@@ -2161,13 +2189,22 @@ _PySys_BeginInit(void)
if (AsyncGenHooksType.tp_name == NULL) {
if (PyStructSequence_InitType2(
&AsyncGenHooksType, &asyncgen_hooks_desc) < 0) {
return NULL;
goto type_init_failed;
}
}
if (PyErr_Occurred())
return NULL;
return m;
if (PyErr_Occurred()) {
goto err_occurred;
}
*sysmod = m;
return _Py_INIT_OK();
type_init_failed:
return _Py_INIT_ERR("failed to initialize a type");
err_occurred:
return _Py_INIT_ERR("can't initialize sys module");
}
#undef SET_SYS_FROM_STRING
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment