static void CHAIN_EXCEPTION( PyObject *exception_type, PyObject *exception_value ) { // Implicit chain of exception already existing. PyThreadState *thread_state = PyThreadState_GET(); // Normalize existing exception first. PyErr_NormalizeException( &thread_state->exc_type, &thread_state->exc_value, &thread_state->exc_traceback ); PyObject *old_exc_value = thread_state->exc_value; if ( old_exc_value != NULL && old_exc_value != Py_None && old_exc_value != exception_value ) { Py_INCREF( old_exc_value ); PyObject *o = old_exc_value, *context; while (( context = PyException_GetContext(o) )) { Py_DECREF( context ); if ( context == exception_value ) { PyException_SetContext( o, NULL ); break; } o = context; } PyException_SetContext( exception_value, old_exc_value ); PyException_SetTraceback( old_exc_value, thread_state->exc_traceback ); } }
static PyObject * _PyErr_FormatVFromCause(PyObject *exception, const char *format, va_list vargs) { PyObject *exc, *val, *val2, *tb; assert(PyErr_Occurred()); PyErr_Fetch(&exc, &val, &tb); PyErr_NormalizeException(&exc, &val, &tb); if (tb != NULL) { PyException_SetTraceback(val, tb); Py_DECREF(tb); } Py_DECREF(exc); assert(!PyErr_Occurred()); PyErr_FormatV(exception, format, vargs); PyErr_Fetch(&exc, &val2, &tb); PyErr_NormalizeException(&exc, &val2, &tb); Py_INCREF(val); PyException_SetCause(val2, val); PyException_SetContext(val2, val); PyErr_Restore(exc, val2, tb); return NULL; }
static void CHAIN_EXCEPTION( PyObject *exception_type, PyObject *exception_value ) { // Implicit chain of exception already existing. PyThreadState *thread_state = PyThreadState_GET(); // Normalize existing exception first. TODO: Will normally be done already. NORMALIZE_EXCEPTION( &thread_state->exc_type, &thread_state->exc_value, (PyTracebackObject **)&thread_state->exc_traceback ); PyObject *old_exc_value = thread_state->exc_value; if ( old_exc_value != NULL && old_exc_value != Py_None && old_exc_value != exception_value ) { PyObject *current = old_exc_value; while( true ) { PyObject *context = PyException_GetContext( current ); if (!context) break; CHECK_OBJECT( context ); Py_DECREF( context ); CHECK_OBJECT( context ); if ( context == exception_value ) { PyException_SetContext( current, NULL ); break; } current = context; } CHECK_OBJECT( old_exc_value ); Py_INCREF( old_exc_value ); PyException_SetContext( exception_value, old_exc_value ); CHECK_OBJECT( thread_state->exc_traceback ); PyException_SetTraceback( old_exc_value, thread_state->exc_traceback ); } }
// Attach the exception context if necessary. NUITKA_MAY_BE_UNUSED static inline void ADD_EXCEPTION_CONTEXT( PyObject **exception_type, PyObject **exception_value ) { PyThreadState *tstate = PyThreadState_GET(); PyObject *context = tstate->exc_value; if ( context != NULL ) { NORMALIZE_EXCEPTION( exception_type, exception_value, NULL ); Py_INCREF( context ); PyException_SetContext( *exception_value, context ); } }
static PyObject * do_safecall(PyObject *callable, PyObject *args) { int has_error = 0; PyObject *exctype = NULL, *excval = NULL, *exctb = NULL; PyObject *result; if (PyErr_Occurred()) { /* Calling from within handler */ has_error = 1; PyErr_Fetch(&exctype, &excval, &exctb); PyErr_Clear(); } result = PyObject_CallObject(callable, args); if (!has_error) { /* No special handling here... */ return result; } if (!result) { #if PY_MAJOR_VERSION == 3 PyObject *exctype2, *excval2, *exctb2; PyErr_NormalizeException(&exctype, &excval, &exctb); PyErr_Fetch(&exctype2, &excval2, &exctb2); PyErr_NormalizeException(&exctype2, &excval, &exctb2); /* Py3K has exception contexts we can use! */ PyException_SetContext(excval2, excval); excval = NULL; /* Since SetContext steals a reference */ PyErr_Restore(exctype2, excval2, exctb2); #else PyErr_PrintEx(0); #endif /* Clean up remaining variables */ Py_XDECREF(exctype); Py_XDECREF(excval); Py_XDECREF(exctb); } else { PyErr_Restore(exctype, excval, exctb); } return result; }
/* Like PyErr_Restore(), but if an exception is already set, set the context associated with it. */ void _PyErr_ChainExceptions(PyObject *exc, PyObject *val, PyObject *tb) { if (exc == NULL) return; if (PyErr_Occurred()) { PyObject *exc2, *val2, *tb2; PyErr_Fetch(&exc2, &val2, &tb2); PyErr_NormalizeException(&exc, &val, &tb); Py_DECREF(exc); Py_XDECREF(tb); PyErr_NormalizeException(&exc2, &val2, &tb2); PyException_SetContext(val2, val); PyErr_Restore(exc2, val2, tb2); } else { PyErr_Restore(exc, val, tb); } }
void PyErr_SetObject(PyObject *exception, PyObject *value) { PyThreadState *tstate = PyThreadState_GET(); PyObject *exc_value; PyObject *tb = NULL; if (exception != NULL && !PyExceptionClass_Check(exception)) { PyErr_Format(PyExc_SystemError, "exception %R not a BaseException subclass", exception); return; } Py_XINCREF(value); exc_value = tstate->exc_value; if (exc_value != NULL && exc_value != Py_None) { /* Implicit exception chaining */ Py_INCREF(exc_value); if (value == NULL || !PyExceptionInstance_Check(value)) { /* We must normalize the value right now */ PyObject *fixed_value; /* Issue #23571: functions must not be called with an exception set */ PyErr_Clear(); fixed_value = _PyErr_CreateException(exception, value); Py_XDECREF(value); if (fixed_value == NULL) { return; } value = fixed_value; } /* Avoid reference cycles through the context chain. This is O(chain length) but context chains are usually very short. Sensitive readers may try to inline the call to PyException_GetContext. */ if (exc_value != value) { PyObject *o = exc_value, *context; while ((context = PyException_GetContext(o))) { Py_DECREF(context); if (context == value) { PyException_SetContext(o, NULL); break; } o = context; } PyException_SetContext(value, exc_value); } else { Py_DECREF(exc_value); } } if (value != NULL && PyExceptionInstance_Check(value)) tb = PyException_GetTraceback(value); Py_XINCREF(exception); PyErr_Restore(exception, value, tb); }
static PyObject * gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) { PyThreadState *tstate = PyThreadState_GET(); PyFrameObject *f = gen->gi_frame; PyObject *result; if (gen->gi_running) { char *msg = "generator already executing"; if (PyCoro_CheckExact(gen)) msg = "coroutine already executing"; PyErr_SetString(PyExc_ValueError, msg); return NULL; } if (f == NULL || f->f_stacktop == NULL) { if (PyCoro_CheckExact(gen) && !closing) { /* `gen` is an exhausted coroutine: raise an error, except when called from gen_close(), which should always be a silent method. */ PyErr_SetString( PyExc_RuntimeError, "cannot reuse already awaited coroutine"); } else if (arg && !exc) { /* `gen` is an exhausted generator: only set exception if called from send(). */ PyErr_SetNone(PyExc_StopIteration); } return NULL; } if (f->f_lasti == -1) { if (arg && arg != Py_None) { char *msg = "can't send non-None value to a " "just-started generator"; if (PyCoro_CheckExact(gen)) msg = "can't send non-None value to a " "just-started coroutine"; PyErr_SetString(PyExc_TypeError, msg); return NULL; } } else { /* Push arg onto the frame's value stack */ result = arg ? arg : Py_None; Py_INCREF(result); *(f->f_stacktop++) = result; } /* Generators always return to their most recent caller, not * necessarily their creator. */ Py_XINCREF(tstate->frame); assert(f->f_back == NULL); f->f_back = tstate->frame; gen->gi_running = 1; result = PyEval_EvalFrameEx(f, exc); gen->gi_running = 0; /* Don't keep the reference to f_back any longer than necessary. It * may keep a chain of frames alive or it could create a reference * cycle. */ assert(f->f_back == tstate->frame); Py_CLEAR(f->f_back); /* If the generator just returned (as opposed to yielding), signal * that the generator is exhausted. */ if (result && f->f_stacktop == NULL) { if (result == Py_None) { /* Delay exception instantiation if we can */ PyErr_SetNone(PyExc_StopIteration); } else { PyObject *e = PyObject_CallFunctionObjArgs( PyExc_StopIteration, result, NULL); if (e != NULL) { PyErr_SetObject(PyExc_StopIteration, e); Py_DECREF(e); } } Py_CLEAR(result); } else if (!result && PyErr_ExceptionMatches(PyExc_StopIteration)) { /* Check for __future__ generator_stop and conditionally turn * a leaking StopIteration into RuntimeError (with its cause * set appropriately). */ if (((PyCodeObject *)gen->gi_code)->co_flags & (CO_FUTURE_GENERATOR_STOP | CO_COROUTINE | CO_ITERABLE_COROUTINE)) { PyObject *exc, *val, *val2, *tb; char *msg = "generator raised StopIteration"; if (PyCoro_CheckExact(gen)) msg = "coroutine raised StopIteration"; PyErr_Fetch(&exc, &val, &tb); PyErr_NormalizeException(&exc, &val, &tb); if (tb != NULL) PyException_SetTraceback(val, tb); Py_DECREF(exc); Py_XDECREF(tb); PyErr_SetString(PyExc_RuntimeError, msg); PyErr_Fetch(&exc, &val2, &tb); PyErr_NormalizeException(&exc, &val2, &tb); Py_INCREF(val); PyException_SetCause(val2, val); PyException_SetContext(val2, val); PyErr_Restore(exc, val2, tb); } else { PyObject *exc, *val, *tb; /* Pop the exception before issuing a warning. */ PyErr_Fetch(&exc, &val, &tb); if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, "generator '%.50S' raised StopIteration", gen->gi_qualname)) { /* Warning was converted to an error. */ Py_XDECREF(exc); Py_XDECREF(val); Py_XDECREF(tb); } else { PyErr_Restore(exc, val, tb); } } } if (!result || f->f_stacktop == NULL) { /* generator can't be rerun, so release the frame */ /* first clean reference cycle through stored exception traceback */ PyObject *t, *v, *tb; t = f->f_exc_type; v = f->f_exc_value; tb = f->f_exc_traceback; f->f_exc_type = NULL; f->f_exc_value = NULL; f->f_exc_traceback = NULL; Py_XDECREF(t); Py_XDECREF(v); Py_XDECREF(tb); gen->gi_frame->f_gen = NULL; gen->gi_frame = NULL; Py_DECREF(f); } return result; }
static PyObject *Nuitka_Generator_send( struct Nuitka_GeneratorObject *generator, PyObject *value ) { if ( generator->m_status == status_Unused && value != NULL && value != Py_None ) { PyErr_Format( PyExc_TypeError, "can't send non-None value to a just-started generator" ); return NULL; } if ( generator->m_status != status_Finished ) { PyThreadState *thread_state = PyThreadState_GET(); #if PYTHON_VERSION < 300 PyObject *saved_exception_type = thread_state->exc_type; Py_XINCREF( saved_exception_type ); PyObject *saved_exception_value = thread_state->exc_value; Py_XINCREF( saved_exception_value ); PyTracebackObject *saved_exception_traceback = (PyTracebackObject *)thread_state->exc_traceback; Py_XINCREF( saved_exception_traceback ); #endif if ( generator->m_running ) { PyErr_Format( PyExc_ValueError, "generator already executing" ); return NULL; } if ( generator->m_status == status_Unused ) { // Prepare the generator context to run. int res = prepareFiber( &generator->m_yielder_context, (void *)Nuitka_Generator_entry_point, (uintptr_t)generator ); if ( res != 0 ) { PyErr_Format( PyExc_MemoryError, "generator cannot be allocated" ); return NULL; } generator->m_status = status_Running; } generator->m_yielded = value; // Put the generator back on the frame stack. PyFrameObject *return_frame = thread_state->frame; #ifndef __NUITKA_NO_ASSERT__ if ( return_frame ) { assertFrameObject( return_frame ); } #endif if ( generator->m_frame ) { // It would be nice if our frame were still alive. Nobody had the // right to release it. assertFrameObject( generator->m_frame ); // It's not supposed to be on the top right now. assert( return_frame != generator->m_frame ); Py_XINCREF( return_frame ); generator->m_frame->f_back = return_frame; thread_state->frame = generator->m_frame; } // Continue the yielder function while preventing recursion. generator->m_running = true; swapFiber( &generator->m_caller_context, &generator->m_yielder_context ); generator->m_running = false; thread_state = PyThreadState_GET(); // Remove the generator from the frame stack. if ( generator->m_frame ) { assert( thread_state->frame == generator->m_frame ); assertFrameObject( generator->m_frame ); Py_CLEAR( generator->m_frame->f_back ); } thread_state->frame = return_frame; if ( generator->m_yielded == NULL ) { assert( ERROR_OCCURRED() ); generator->m_status = status_Finished; Py_XDECREF( generator->m_frame ); generator->m_frame = NULL; Nuitka_Generator_release_closure( generator ); assert( ERROR_OCCURRED() ); #if PYTHON_VERSION < 300 Py_XDECREF( saved_exception_type ); Py_XDECREF( saved_exception_value ); Py_XDECREF( saved_exception_traceback ); #endif #if PYTHON_VERSION >= 350 if ( generator->m_code_object->co_flags & CO_FUTURE_GENERATOR_STOP && GET_ERROR_OCCURRED() == PyExc_StopIteration ) { PyObject *saved_exception_type, *saved_exception_value; PyTracebackObject *saved_exception_tb; FETCH_ERROR_OCCURRED( &saved_exception_type, &saved_exception_value, &saved_exception_tb ); NORMALIZE_EXCEPTION( &saved_exception_type, &saved_exception_value, &saved_exception_tb ); PyErr_Format( PyExc_RuntimeError, "generator raised StopIteration" ); PyObject *exception_type, *exception_value; PyTracebackObject *exception_tb; FETCH_ERROR_OCCURRED( &exception_type, &exception_value, &exception_tb ); RAISE_EXCEPTION_WITH_CAUSE( &exception_type, &exception_value, &exception_tb, saved_exception_value ); CHECK_OBJECT( exception_value ); CHECK_OBJECT( saved_exception_value ); Py_INCREF( saved_exception_value ); PyException_SetContext( exception_value, saved_exception_value ); Py_DECREF( saved_exception_type ); Py_XDECREF( saved_exception_tb ); RESTORE_ERROR_OCCURRED( exception_type, exception_value, exception_tb ); } #endif return NULL; } else { #if PYTHON_VERSION < 300 SET_CURRENT_EXCEPTION( saved_exception_type, saved_exception_value, saved_exception_traceback ); #endif return generator->m_yielded; } } else { PyErr_SetObject( PyExc_StopIteration, (PyObject *)NULL ); return NULL; } }