mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 15:03:34 +00:00
This makes breaking changes to add underscores to many non-standard function names provided by the c library. MODE=tiny is now tinier and we now use smaller locks that are better for tiny apps in this mode. Some headers have been renamed to be in the same folder as the build package, so it'll be easier to know which build dependency is needed. Certain old misguided interfaces have been removed. Intel intrinsics headers are now listed in libc/isystem (but not in the amalgamation) to help further improve open source compatibility. Header complexity has also been reduced. Lastly, more shell scripts are now available.
165 lines
5.2 KiB
C
165 lines
5.2 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/intrin/weaken.h"
|
|
#include "libc/log/log.h"
|
|
#include "libc/runtime/runtime.h"
|
|
#include "libc/stdio/stdio.h"
|
|
#include "third_party/python/Include/abstract.h"
|
|
#include "third_party/python/Include/pyerrors.h"
|
|
#include "third_party/python/Include/pylifecycle.h"
|
|
#include "third_party/python/Include/pythonrun.h"
|
|
#include "third_party/python/Include/sysmodule.h"
|
|
#include "third_party/python/Include/traceback.h"
|
|
/* clang-format off */
|
|
|
|
_Py_IDENTIFIER(flush);
|
|
_Py_IDENTIFIER(stdout);
|
|
_Py_IDENTIFIER(stderr);
|
|
|
|
/* Import the site module (not into __main__ though) */
|
|
|
|
static void
|
|
_Py_FatalError_DumpTracebacks(int fd)
|
|
{
|
|
fputc('\n', stderr);
|
|
fflush(stderr);
|
|
/* display the current Python stack */
|
|
_Py_DumpTracebackThreads(fd, NULL, NULL);
|
|
}
|
|
|
|
/* Print the current exception (if an exception is set) with its traceback,
|
|
or display the current Python stack.
|
|
|
|
Don't call PyErr_PrintEx() and the except hook, because Py_FatalError() is
|
|
called on catastrophic cases.
|
|
|
|
Return 1 if the traceback was displayed, 0 otherwise. */
|
|
|
|
static int
|
|
_Py_FatalError_PrintExc(int fd)
|
|
{
|
|
PyObject *ferr, *res;
|
|
PyObject *exception, *v, *tb;
|
|
int has_tb;
|
|
|
|
PyErr_Fetch(&exception, &v, &tb);
|
|
if (exception == NULL) {
|
|
/* No current exception */
|
|
return 0;
|
|
}
|
|
|
|
ferr = _PySys_GetObjectId(&PyId_stderr);
|
|
if (ferr == NULL || ferr == Py_None) {
|
|
/* sys.stderr is not set yet or set to None,
|
|
no need to try to display the exception */
|
|
return 0;
|
|
}
|
|
|
|
PyErr_NormalizeException(&exception, &v, &tb);
|
|
if (tb == NULL) {
|
|
tb = Py_None;
|
|
Py_INCREF(tb);
|
|
}
|
|
PyException_SetTraceback(v, tb);
|
|
if (exception == NULL) {
|
|
/* PyErr_NormalizeException() failed */
|
|
return 0;
|
|
}
|
|
|
|
has_tb = (tb != Py_None);
|
|
PyErr_Display(exception, v, tb);
|
|
Py_XDECREF(exception);
|
|
Py_XDECREF(v);
|
|
Py_XDECREF(tb);
|
|
|
|
/* sys.stderr may be buffered: call sys.stderr.flush() */
|
|
res = _PyObject_CallMethodId(ferr, &PyId_flush, NULL);
|
|
if (res == NULL)
|
|
PyErr_Clear();
|
|
else
|
|
Py_DECREF(res);
|
|
|
|
return has_tb;
|
|
}
|
|
|
|
/* Print fatal error message and abort */
|
|
|
|
void
|
|
Py_FatalError(const char *msg)
|
|
{
|
|
const int fd = fileno(stderr);
|
|
static int reentrant = 0;
|
|
#ifdef MS_WINDOWS
|
|
size_t len;
|
|
WCHAR* buffer;
|
|
size_t i;
|
|
#endif
|
|
|
|
if (reentrant) {
|
|
/* Py_FatalError() caused a second fatal error.
|
|
Example: _Py_FlushStdFiles() raises a recursion error. */
|
|
goto exit;
|
|
}
|
|
reentrant = 1;
|
|
|
|
fprintf(stderr, "Fatal Python error: %s\n", msg);
|
|
fflush(stderr); /* it helps in Windows debug build */
|
|
|
|
/* Check if the current thread has a Python thread state
|
|
and holds the GIL */
|
|
PyThreadState *tss_tstate = NULL; // PyGILState_GetThisThreadState();
|
|
if (tss_tstate != NULL) {
|
|
PyThreadState *tstate = PyThreadState_GET();
|
|
if (tss_tstate != tstate) {
|
|
/* The Python thread does not hold the GIL */
|
|
tss_tstate = NULL;
|
|
}
|
|
}
|
|
else {
|
|
/* Py_FatalError() has been called from a C thread
|
|
which has no Python thread state. */
|
|
}
|
|
int has_tstate_and_gil = (tss_tstate != NULL);
|
|
|
|
/* If an exception is set, print the exception with its traceback */
|
|
if (!_Py_FatalError_PrintExc(fd)) {
|
|
/* No exception is set, or an exception is set without traceback */
|
|
_Py_FatalError_DumpTracebacks(fd);
|
|
}
|
|
|
|
/* The main purpose of faulthandler is to display the traceback. We already
|
|
* did our best to display it. So faulthandler can now be disabled.
|
|
* (Don't trigger it on abort().) */
|
|
_PyFaulthandler_Fini();
|
|
|
|
/* Check if the current Python thread hold the GIL */
|
|
if (has_tstate_and_gil) {
|
|
/* Flush sys.stdout and sys.stderr */
|
|
_Py_FlushStdFiles();
|
|
}
|
|
|
|
#ifdef MS_WINDOWS
|
|
len = strlen(msg);
|
|
|
|
/* Convert the message to wchar_t. This uses a simple one-to-one
|
|
conversion, assuming that the this error message actually uses ASCII
|
|
only. If this ceases to be true, we will have to convert. */
|
|
buffer = alloca( (len+1) * (sizeof *buffer));
|
|
for( i=0; i<=len; ++i)
|
|
buffer[i] = msg[i];
|
|
OutputDebugStringW(L"Fatal Python error: ");
|
|
OutputDebugStringW(buffer);
|
|
OutputDebugStringW(L"\n");
|
|
#endif /* MS_WINDOWS */
|
|
|
|
exit:
|
|
#if defined(MS_WINDOWS) && defined(_DEBUG)
|
|
DebugBreak();
|
|
#endif
|
|
if (_weaken(__die)) _weaken(__die)();
|
|
abort();
|
|
}
|