mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 19:43:32 +00:00
57f0eed382
We remove (i.e. hide behind a debug ifdef) the recursion checking methods, and the memory hooks and memory allocator methods. ASAN mode has no PYMALLOC, so we need a macro. Fix build break with des.c stack allocation.
505 lines
16 KiB
C
505 lines
16 KiB
C
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│
|
|
│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Python 3 │
|
|
│ https://docs.python.org/3/license.html │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/assert.h"
|
|
#include "libc/calls/calls.h"
|
|
#include "libc/calls/internal.h"
|
|
#include "libc/calls/sigbits.h"
|
|
#include "libc/dce.h"
|
|
#include "libc/fmt/conv.h"
|
|
#include "libc/log/check.h"
|
|
#include "libc/log/log.h"
|
|
#include "libc/runtime/runtime.h"
|
|
#include "libc/stdio/stdio.h"
|
|
#include "libc/sysv/consts/sig.h"
|
|
#include "libc/unicode/locale.h"
|
|
#include "third_party/python/Include/Python-ast.h"
|
|
#include "third_party/python/Include/abstract.h"
|
|
#include "third_party/python/Include/ast.h"
|
|
#include "third_party/python/Include/boolobject.h"
|
|
#include "third_party/python/Include/code.h"
|
|
#include "third_party/python/Include/codecs.h"
|
|
#include "third_party/python/Include/cosmo.h"
|
|
#include "third_party/python/Include/dictobject.h"
|
|
#include "third_party/python/Include/errcode.h"
|
|
#include "third_party/python/Include/fileobject.h"
|
|
#include "third_party/python/Include/grammar.h"
|
|
#include "third_party/python/Include/import.h"
|
|
#include "third_party/python/Include/intrcheck.h"
|
|
#include "third_party/python/Include/marshal.h"
|
|
#include "third_party/python/Include/modsupport.h"
|
|
#include "third_party/python/Include/node.h"
|
|
#include "third_party/python/Include/objimpl.h"
|
|
#include "third_party/python/Include/osdefs.h"
|
|
#include "third_party/python/Include/parsetok.h"
|
|
#include "third_party/python/Include/pydebug.h"
|
|
#include "third_party/python/Include/pyerrors.h"
|
|
#include "third_party/python/Include/pylifecycle.h"
|
|
#include "third_party/python/Include/pymem.h"
|
|
#include "third_party/python/Include/pystrcmp.h"
|
|
#include "third_party/python/Include/pytime.h"
|
|
#include "third_party/python/Include/symtable.h"
|
|
#include "third_party/python/Include/sysmodule.h"
|
|
#include "third_party/python/Include/token.h"
|
|
#include "third_party/python/Include/traceback.h"
|
|
#include "third_party/python/Include/unicodeobject.h"
|
|
#include "third_party/python/Include/warnings.h"
|
|
#include "third_party/python/Include/yoink.h"
|
|
#include "third_party/python/pyconfig.h"
|
|
/* clang-format off */
|
|
|
|
/* Python interpreter top-level routines, including init/exit */
|
|
|
|
_Py_IDENTIFIER(name);
|
|
_Py_IDENTIFIER(flush);
|
|
_Py_IDENTIFIER(stdout);
|
|
_Py_IDENTIFIER(stderr);
|
|
|
|
/* Forward */
|
|
static void wait_for_thread_shutdown(void);
|
|
#ifdef WITH_THREAD
|
|
extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *);
|
|
extern void _PyGILState_Fini(void);
|
|
#endif /* WITH_THREAD */
|
|
|
|
/* Hack to force loading of object files */
|
|
int (*_PyOS_mystrnicmp_hack)(const char *, const char *, Py_ssize_t) = \
|
|
PyOS_mystrnicmp; /* Python/pystrcmp.o */
|
|
|
|
/* Helper to allow an embedding application to override the normal
|
|
* mechanism that attempts to figure out an appropriate IO encoding
|
|
*/
|
|
|
|
int
|
|
Py_SetStandardStreamEncoding(const char *encoding, const char *errors)
|
|
{
|
|
if (Py_IsInitialized()) {
|
|
/* This is too late to have any effect */
|
|
return -1;
|
|
}
|
|
/* Can't call PyErr_NoMemory() on errors, as Python hasn't been
|
|
* initialised yet.
|
|
*
|
|
* However, the raw memory allocators are initialised appropriately
|
|
* as C static variables, so _PyMem_RawStrdup is OK even though
|
|
* Py_Initialize hasn't been called yet.
|
|
*/
|
|
if (encoding) {
|
|
_Py_StandardStreamEncoding = _PyMem_RawStrdup(encoding);
|
|
if (!_Py_StandardStreamEncoding) {
|
|
return -2;
|
|
}
|
|
}
|
|
if (errors) {
|
|
_Py_StandardStreamErrors = _PyMem_RawStrdup(errors);
|
|
if (!_Py_StandardStreamErrors) {
|
|
if (_Py_StandardStreamEncoding) {
|
|
PyMem_RawFree(_Py_StandardStreamEncoding);
|
|
}
|
|
return -3;
|
|
}
|
|
}
|
|
#ifdef MS_WINDOWS
|
|
if (_Py_StandardStreamEncoding) {
|
|
/* Overriding the stream encoding implies legacy streams */
|
|
Py_LegacyWindowsStdioFlag = 1;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/* Global initializations. Can be undone by Py_FinalizeEx(). Don't
|
|
call this twice without an intervening Py_FinalizeEx() call. When
|
|
initializations fail, a fatal error is issued and the function does
|
|
not return. On return, the first thread and interpreter state have
|
|
been created.
|
|
|
|
Locking: you must hold the interpreter lock while calling this.
|
|
(If the lock has not yet been initialized, that's equivalent to
|
|
having the lock, but you cannot use multiple threads.)
|
|
|
|
*/
|
|
|
|
static int
|
|
add_flag(int flag, const char *envs)
|
|
{
|
|
int env = atoi(envs);
|
|
if (flag < env)
|
|
flag = env;
|
|
if (flag < 1)
|
|
flag = 1;
|
|
return flag;
|
|
}
|
|
|
|
void
|
|
_Py_InitializeEx_Private(int install_sigs, int install_importlib)
|
|
{
|
|
PyInterpreterState *interp;
|
|
PyThreadState *tstate;
|
|
PyObject *bimod, *sysmod, *pstderr;
|
|
char *p;
|
|
|
|
if (_Py_initialized)
|
|
return;
|
|
_Py_initialized = 1;
|
|
_Py_Finalizing = NULL;
|
|
|
|
#ifdef HAVE_SETLOCALE
|
|
/* Set up the LC_CTYPE locale, so we can obtain
|
|
the locale's charset without having to switch
|
|
locales. */
|
|
setlocale(LC_CTYPE, "");
|
|
#endif
|
|
|
|
if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '\0')
|
|
Py_DebugFlag = add_flag(Py_DebugFlag, p);
|
|
if ((p = Py_GETENV("PYTHONVERBOSE")) && *p != '\0')
|
|
Py_VerboseFlag = add_flag(Py_VerboseFlag, p);
|
|
if ((p = Py_GETENV("PYTHONOPTIMIZE")) && *p != '\0')
|
|
Py_OptimizeFlag = add_flag(Py_OptimizeFlag, p);
|
|
if ((p = Py_GETENV("PYTHONDONTWRITEBYTECODE")) && *p != '\0')
|
|
Py_DontWriteBytecodeFlag = add_flag(Py_DontWriteBytecodeFlag, p);
|
|
#ifdef MS_WINDOWS
|
|
if ((p = Py_GETENV("PYTHONLEGACYWINDOWSFSENCODING")) && *p != '\0')
|
|
Py_LegacyWindowsFSEncodingFlag = add_flag(Py_LegacyWindowsFSEncodingFlag, p);
|
|
if ((p = Py_GETENV("PYTHONLEGACYWINDOWSSTDIO")) && *p != '\0')
|
|
Py_LegacyWindowsStdioFlag = add_flag(Py_LegacyWindowsStdioFlag, p);
|
|
#endif
|
|
|
|
_PyRandom_Init();
|
|
|
|
interp = PyInterpreterState_New();
|
|
if (interp == NULL)
|
|
Py_FatalError("Py_Initialize: can't make first interpreter");
|
|
|
|
tstate = PyThreadState_New(interp);
|
|
if (tstate == NULL)
|
|
Py_FatalError("Py_Initialize: can't make first thread");
|
|
(void) PyThreadState_Swap(tstate);
|
|
|
|
#ifdef WITH_THREAD
|
|
/* We can't call _PyEval_FiniThreads() in Py_FinalizeEx because
|
|
destroying the GIL might fail when it is being referenced from
|
|
another running thread (see issue #9901).
|
|
Instead we destroy the previously created GIL here, which ensures
|
|
that we can call Py_Initialize / Py_FinalizeEx multiple times. */
|
|
_PyEval_FiniThreads();
|
|
|
|
/* Auto-thread-state API */
|
|
_PyGILState_Init(interp, tstate);
|
|
#endif /* WITH_THREAD */
|
|
|
|
_Py_ReadyTypes();
|
|
|
|
if (!_PyFrame_Init())
|
|
Py_FatalError("Py_Initialize: can't init frames");
|
|
|
|
if (!_PyLong_Init())
|
|
Py_FatalError("Py_Initialize: can't init longs");
|
|
|
|
if (!PyByteArray_Init())
|
|
Py_FatalError("Py_Initialize: can't init bytearray");
|
|
|
|
if (!_PyFloat_Init())
|
|
Py_FatalError("Py_Initialize: can't init float");
|
|
|
|
interp->modules = PyDict_New();
|
|
if (interp->modules == NULL)
|
|
Py_FatalError("Py_Initialize: can't make modules dictionary");
|
|
|
|
/* Init Unicode implementation; relies on the codec registry */
|
|
if (_PyUnicode_Init() < 0)
|
|
Py_FatalError("Py_Initialize: can't initialize unicode");
|
|
if (_PyStructSequence_Init() < 0)
|
|
Py_FatalError("Py_Initialize: can't initialize structseq");
|
|
|
|
bimod = _PyBuiltin_Init();
|
|
if (bimod == NULL)
|
|
Py_FatalError("Py_Initialize: can't initialize builtins modules");
|
|
_PyImport_FixupBuiltin(bimod, "builtins");
|
|
interp->builtins = PyModule_GetDict(bimod);
|
|
if (interp->builtins == NULL)
|
|
Py_FatalError("Py_Initialize: can't initialize builtins dict");
|
|
Py_INCREF(interp->builtins);
|
|
|
|
/* initialize builtin exceptions */
|
|
_PyExc_Init(bimod);
|
|
|
|
sysmod = _PySys_Init();
|
|
if (sysmod == NULL)
|
|
Py_FatalError("Py_Initialize: can't initialize sys");
|
|
interp->sysdict = PyModule_GetDict(sysmod);
|
|
if (interp->sysdict == NULL)
|
|
Py_FatalError("Py_Initialize: can't initialize sys dict");
|
|
Py_INCREF(interp->sysdict);
|
|
_PyImport_FixupBuiltin(sysmod, "sys");
|
|
PySys_SetPath(Py_GetPath());
|
|
PyDict_SetItemString(interp->sysdict, "modules",
|
|
interp->modules);
|
|
|
|
/* Set up a preliminary stderr printer until we have enough
|
|
infrastructure for the io module in place. */
|
|
pstderr = PyFile_NewStdPrinter(fileno(stderr));
|
|
if (pstderr == NULL)
|
|
Py_FatalError("Py_Initialize: can't set preliminary stderr");
|
|
_PySys_SetObjectId(&PyId_stderr, pstderr);
|
|
PySys_SetObject("__stderr__", pstderr);
|
|
Py_DECREF(pstderr);
|
|
|
|
_PyImport_Init();
|
|
|
|
_PyImportHooks_Init();
|
|
|
|
/* Initialize _warnings. */
|
|
_PyWarnings_Init();
|
|
|
|
if (!install_importlib)
|
|
return;
|
|
|
|
if (_PyTime_Init() < 0)
|
|
Py_FatalError("Py_Initialize: can't initialize time");
|
|
|
|
_Py_InitImport(interp, sysmod);
|
|
|
|
/* initialize the faulthandler module */
|
|
if (_PyFaulthandler_Init())
|
|
Py_FatalError("Py_Initialize: can't initialize faulthandler");
|
|
|
|
if (_Py_InitFsEncoding(interp) < 0)
|
|
Py_FatalError("Py_Initialize: unable to load the file system codec");
|
|
|
|
if (install_sigs)
|
|
_Py_InitSigs(); /* Signal handling stuff, including initintr() */
|
|
|
|
#if IsModeDbg()
|
|
if (_PyTraceMalloc_Init() < 0)
|
|
Py_FatalError("Py_Initialize: can't initialize tracemalloc");
|
|
#endif
|
|
|
|
_Py_InitMain(interp); /* Module __main__ */
|
|
if (_Py_InitStdio() < 0) {
|
|
Py_FatalError(
|
|
"Py_Initialize: can't initialize sys standard streams");
|
|
}
|
|
|
|
/* Initialize warnings. */
|
|
if (PySys_HasWarnOptions()) {
|
|
PyObject *warnings_module = PyImport_ImportModule("warnings");
|
|
if (warnings_module == NULL) {
|
|
fputs("'import warnings' failed; traceback:\n", stderr);
|
|
PyErr_Print();
|
|
}
|
|
Py_XDECREF(warnings_module);
|
|
}
|
|
|
|
_PyImportZip_Init();
|
|
|
|
if (!Py_NoSiteFlag)
|
|
_Py_InitSite(); /* Module site */
|
|
}
|
|
|
|
void
|
|
Py_InitializeEx(int install_sigs)
|
|
{
|
|
_Py_InitializeEx_Private(install_sigs, 1);
|
|
}
|
|
|
|
void
|
|
Py_Initialize(void)
|
|
{
|
|
Py_InitializeEx(1);
|
|
}
|
|
|
|
|
|
#ifdef COUNT_ALLOCS
|
|
extern void dump_counts(FILE*);
|
|
#endif
|
|
|
|
/* Create and initialize a new interpreter and thread, and return the
|
|
new thread. This requires that Py_Initialize() has been called
|
|
first.
|
|
|
|
Unsuccessful initialization yields a NULL pointer. Note that *no*
|
|
exception information is available even in this case -- the
|
|
exception information is held in the thread, and there is no
|
|
thread.
|
|
|
|
Locking: as above.
|
|
|
|
*/
|
|
|
|
PyThreadState *
|
|
Py_NewInterpreter(void)
|
|
{
|
|
PyInterpreterState *interp;
|
|
PyThreadState *tstate, *save_tstate;
|
|
PyObject *bimod, *sysmod;
|
|
|
|
if (!_Py_initialized)
|
|
Py_FatalError("Py_NewInterpreter: call Py_Initialize first");
|
|
|
|
#ifdef WITH_THREAD
|
|
/* Issue #10915, #15751: The GIL API doesn't work with multiple
|
|
interpreters: disable PyGILState_Check(). */
|
|
_PyGILState_check_enabled = 0;
|
|
#endif
|
|
|
|
interp = PyInterpreterState_New();
|
|
if (interp == NULL)
|
|
return NULL;
|
|
|
|
tstate = PyThreadState_New(interp);
|
|
if (tstate == NULL) {
|
|
PyInterpreterState_Delete(interp);
|
|
return NULL;
|
|
}
|
|
|
|
save_tstate = PyThreadState_Swap(tstate);
|
|
|
|
/* XXX The following is lax in error checking */
|
|
|
|
interp->modules = PyDict_New();
|
|
|
|
bimod = _PyImport_FindBuiltin("builtins");
|
|
if (bimod != NULL) {
|
|
interp->builtins = PyModule_GetDict(bimod);
|
|
if (interp->builtins == NULL)
|
|
goto handle_error;
|
|
Py_INCREF(interp->builtins);
|
|
}
|
|
else if (PyErr_Occurred()) {
|
|
goto handle_error;
|
|
}
|
|
|
|
/* initialize builtin exceptions */
|
|
_PyExc_Init(bimod);
|
|
|
|
sysmod = _PyImport_FindBuiltin("sys");
|
|
if (bimod != NULL && sysmod != NULL) {
|
|
PyObject *pstderr;
|
|
|
|
interp->sysdict = PyModule_GetDict(sysmod);
|
|
if (interp->sysdict == NULL)
|
|
goto handle_error;
|
|
Py_INCREF(interp->sysdict);
|
|
PySys_SetPath(Py_GetPath());
|
|
PyDict_SetItemString(interp->sysdict, "modules",
|
|
interp->modules);
|
|
/* Set up a preliminary stderr printer until we have enough
|
|
infrastructure for the io module in place. */
|
|
pstderr = PyFile_NewStdPrinter(fileno(stderr));
|
|
if (pstderr == NULL)
|
|
Py_FatalError("Py_Initialize: can't set preliminary stderr");
|
|
_PySys_SetObjectId(&PyId_stderr, pstderr);
|
|
PySys_SetObject("__stderr__", pstderr);
|
|
Py_DECREF(pstderr);
|
|
|
|
_PyImportHooks_Init();
|
|
|
|
_Py_InitImport(interp, sysmod);
|
|
|
|
if (_Py_InitFsEncoding(interp) < 0)
|
|
goto handle_error;
|
|
|
|
if (_Py_InitStdio() < 0)
|
|
Py_FatalError(
|
|
"Py_Initialize: can't initialize sys standard streams");
|
|
_Py_InitMain(interp);
|
|
if (!Py_NoSiteFlag)
|
|
_Py_InitSite();
|
|
}
|
|
|
|
if (!PyErr_Occurred())
|
|
return tstate;
|
|
|
|
handle_error:
|
|
/* Oops, it didn't work. Undo it all. */
|
|
|
|
PyErr_PrintEx(0);
|
|
PyThreadState_Clear(tstate);
|
|
PyThreadState_Swap(save_tstate);
|
|
PyThreadState_Delete(tstate);
|
|
PyInterpreterState_Delete(interp);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Delete an interpreter and its last thread. This requires that the
|
|
given thread state is current, that the thread has no remaining
|
|
frames, and that it is its interpreter's only remaining thread.
|
|
It is a fatal error to violate these constraints.
|
|
|
|
(Py_FinalizeEx() doesn't have these constraints -- it zaps
|
|
everything, regardless.)
|
|
|
|
Locking: as above.
|
|
|
|
*/
|
|
|
|
void
|
|
Py_EndInterpreter(PyThreadState *tstate)
|
|
{
|
|
PyInterpreterState *interp = tstate->interp;
|
|
|
|
if (tstate != PyThreadState_GET())
|
|
Py_FatalError("Py_EndInterpreter: thread is not current");
|
|
if (tstate->frame != NULL)
|
|
Py_FatalError("Py_EndInterpreter: thread still has a frame");
|
|
|
|
wait_for_thread_shutdown();
|
|
|
|
if (tstate != interp->tstate_head || tstate->next != NULL)
|
|
Py_FatalError("Py_EndInterpreter: not the last thread");
|
|
|
|
PyImport_Cleanup();
|
|
PyInterpreterState_Clear(interp);
|
|
PyThreadState_Swap(NULL);
|
|
PyInterpreterState_Delete(interp);
|
|
}
|
|
|
|
/* Clean up and exit */
|
|
|
|
#ifdef WITH_THREAD
|
|
#include "third_party/python/Include/pythread.h"
|
|
#endif
|
|
|
|
/* Wait until threading._shutdown completes, provided
|
|
the threading module was imported in the first place.
|
|
The shutdown routine will wait until all non-daemon
|
|
"threading" threads have completed. */
|
|
static void
|
|
wait_for_thread_shutdown(void)
|
|
{
|
|
#ifdef WITH_THREAD
|
|
_Py_IDENTIFIER(_shutdown);
|
|
PyObject *result;
|
|
PyThreadState *tstate = PyThreadState_GET();
|
|
PyObject *threading = PyMapping_GetItemString(tstate->interp->modules,
|
|
"threading");
|
|
if (threading == NULL) {
|
|
/* threading not imported */
|
|
PyErr_Clear();
|
|
return;
|
|
}
|
|
result = _PyObject_CallMethodId(threading, &PyId__shutdown, NULL);
|
|
if (result == NULL) {
|
|
PyErr_WriteUnraisable(threading);
|
|
}
|
|
else {
|
|
Py_DECREF(result);
|
|
}
|
|
Py_DECREF(threading);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
Py_Exit(int sts)
|
|
{
|
|
if (Py_FinalizeEx() < 0) {
|
|
sts = 120;
|
|
}
|
|
exit(sts);
|
|
}
|