Fix Python SystemExit exceptions silently exiting

Any script that raised a SystemExit called by --python, --python-expr
command line args or by executing the text block would exit without
printing a message. This caused the error from T99966 to be hidden.

Add explicit handling for SystemExit to ensure the message is always
shown before exiting.

More details noted in code-comments.
This commit is contained in:
Campbell Barton 2022-07-26 12:23:41 +10:00
parent 37ad72ab23
commit 3ae85a0d8f
Notes: blender-bot 2023-06-07 10:31:13 +02:00
Referenced by issue #88449: Blender LTS: Maintenance Task 2.93
Referenced by issue #88449, Blender LTS: Maintenance Task 2.93
Referenced by issue #98661, 3.2: Potential candidates for corrective releases
1 changed files with 37 additions and 0 deletions

View File

@ -823,6 +823,36 @@ void PyC_Err_PrintWithFunc(PyObject *py_func)
/** \name Exception Buffer Access
* \{ */
static void pyc_exception_buffer_handle_system_exit(PyObject *error_type,
PyObject *error_value,
PyObject *error_traceback)
{
if (!PyErr_GivenExceptionMatches(error_type, PyExc_SystemExit)) {
return;
}
/* Inspecting, follow Python's logic in #_Py_HandleSystemExit & treat as a regular exception. */
if (_Py_GetConfig()->inspect) {
return;
}
/* NOTE(@campbellbarton): A `SystemExit` exception will exit immediately (unless inspecting).
* So print the error and exit now. This is necessary as the call to #PyErr_Print exits,
* the temporary `sys.stderr` assignment causes the output to be suppressed, failing silently.
* Instead, restore the error and print it. If Python changes it's behavior and doesn't exit in
* the future - continue to create the exception buffer, see: T99966.
*
* Arguably accessing a `SystemExit` exception as a buffer should be supported without exiting.
* (by temporarily enabling inspection for example) however - it's not obvious exactly when this
* should be enabled and complicates the Python API by introducing different kinds of execution.
* Since the rule of thumb is for Blender's embedded Python to match stand-alone Python,
* favor exiting when a `SystemExit` is raised.
* Especially since this exception more likely to be used for background/batch-processing
* utilities where exiting immediately makes sense, the possibility of this being called
* indirectly from python-drivers or modal-operators is less of a concern. */
PyErr_Restore(error_type, error_value, error_traceback);
PyErr_Print();
}
/* returns the exception string as a new PyUnicode object, depends on external traceback module */
# if 0
@ -873,6 +903,8 @@ PyObject *PyC_ExceptionBuffer(void)
PyErr_Fetch(&error_type, &error_value, &error_traceback);
pyc_exception_buffer_handle_system_exit(error_type, error_value, error_traceback);
/* import io
* string_io = io.StringIO()
*/
@ -944,6 +976,11 @@ PyObject *PyC_ExceptionBuffer_Simple(void)
PyErr_Fetch(&error_type, &error_value, &error_traceback);
/* Since #PyErr_Print is not called it's not essential that `SystemExit` exceptions are handled.
* Do this to match the behavior of #PyC_ExceptionBuffer since requesting a brief exception
* shouldn't result in completely different behavior. */
pyc_exception_buffer_handle_system_exit(error_type, error_value, error_traceback);
if (PyErr_GivenExceptionMatches(error_type, PyExc_SyntaxError)) {
/* Special exception for syntax errors,
* in these cases the full error is verbose and not very useful,