Index: Include/pythonrun.h =================================================================== --- Include/pythonrun.h (revision 73674) +++ Include/pythonrun.h (working copy) @@ -25,6 +25,8 @@ PyAPI_FUNC(void) Py_SetPythonHome(char *); PyAPI_FUNC(char *) Py_GetPythonHome(void); +PyAPI_FUNC(void) Py_InitializeFatalHook(void (*func)(const char *)); + PyAPI_FUNC(void) Py_Initialize(void); PyAPI_FUNC(void) Py_InitializeEx(int); PyAPI_FUNC(void) Py_Finalize(void); Index: Python/pythonrun.c =================================================================== --- Python/pythonrun.c (revision 73674) +++ Python/pythonrun.c (working copy) @@ -156,6 +156,12 @@ return; initialized = 1; + /* Install the default hook for Py_FatalError. Only an embedding + application may have installed its own; in this case the + following call has no effect. + */ + Py_InitializeFatalHook(Py_FatalError); + if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '0円') Py_DebugFlag = add_flag(Py_DebugFlag, p); if ((p = Py_GETENV("PYTHONVERBOSE")) && *p != '0円') @@ -537,6 +543,16 @@ call_ll_exitfuncs(); } +static void (*fatalhook)(const char*) = NULL; + +void +Py_InitializeFatalHook(void (*func)(const char*)) +{ + /* Only set it if it is uninitialized. */ + if (fatalhook == NULL) + fatalhook = func; +} + /* Create and initialize a new interpreter and thread, and return the new thread. This requires that Py_Initialize() has been called first. @@ -1634,6 +1650,10 @@ void Py_FatalError(const char *msg) { + if (fatalhook != Py_FatalError && fatalhook != NULL) + fatalhook(msg); + /* If the hook fell through, finish the process anyways. */ + fprintf(stderr, "Fatal Python error: %s\n", msg); fflush(stderr); /* it helps in Windows debug build */ Index: Doc/c-api/init.rst =================================================================== --- Doc/c-api/init.rst (revision 73674) +++ Doc/c-api/init.rst (working copy) @@ -81,7 +81,22 @@ than once; this can happen if an application calls :cfunc:`Py_Initialize` and :cfunc:`Py_Finalize` more than once. + +.. cfunction:: void Py_InitializeFatalHook( void (*func)(const char *) ) + Force :cfunc:`Py_FatalError` to invoke the given function instead + of printing to standard error and aborting out of the process. + This is intended for use in embedded applications that want to + define their own route for handling fatal errors. This gives the + application the chance to log the error to a special destination, + and to do any appropriate cleanups before exiting. If the function + does not exit, the default behavior applies. + + If used, this *must* be called prior to :cfunc:`Py_Initialize`. + Otherwise, ``Py_Initialize`` will set the hook to the default, and + future attempts to ``Py_InitializeFatalHook`` will be ignored. + + .. cfunction:: PyThreadState* Py_NewInterpreter() .. index::