Skip to content

Commit

Permalink
gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternat…
Browse files Browse the repository at this point in the history
…ives (in Modules/) (#102196)
  • Loading branch information
iritkatriel authored Feb 24, 2023
1 parent 568fc0d commit 2db23d1
Show file tree
Hide file tree
Showing 18 changed files with 136 additions and 169 deletions.
69 changes: 22 additions & 47 deletions Modules/_asynciomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1422,7 +1422,6 @@ _asyncio_Future__make_cancelled_error_impl(FutureObj *self)
static void
FutureObj_finalize(FutureObj *fut)
{
PyObject *error_type, *error_value, *error_traceback;
PyObject *context;
PyObject *message = NULL;
PyObject *func;
Expand All @@ -1434,7 +1433,7 @@ FutureObj_finalize(FutureObj *fut)
fut->fut_log_tb = 0;

/* Save the current exception, if any. */
PyErr_Fetch(&error_type, &error_value, &error_traceback);
PyObject *exc = PyErr_GetRaisedException();

context = PyDict_New();
if (context == NULL) {
Expand Down Expand Up @@ -1476,7 +1475,7 @@ FutureObj_finalize(FutureObj *fut)
Py_XDECREF(message);

/* Restore the saved exception. */
PyErr_Restore(error_type, error_value, error_traceback);
PyErr_SetRaisedException(exc);
}

static PyMethodDef FutureType_methods[] = {
Expand Down Expand Up @@ -2491,14 +2490,13 @@ TaskObj_finalize(TaskObj *task)
PyObject *context;
PyObject *message = NULL;
PyObject *func;
PyObject *error_type, *error_value, *error_traceback;

if (task->task_state != STATE_PENDING || !task->task_log_destroy_pending) {
goto done;
}

/* Save the current exception, if any. */
PyErr_Fetch(&error_type, &error_value, &error_traceback);
PyObject *exc = PyErr_GetRaisedException();

context = PyDict_New();
if (context == NULL) {
Expand Down Expand Up @@ -2541,7 +2539,7 @@ TaskObj_finalize(TaskObj *task)
Py_XDECREF(message);

/* Restore the saved exception. */
PyErr_Restore(error_type, error_value, error_traceback);
PyErr_SetRaisedException(exc);

done:
FutureObj_finalize((FutureObj*)task);
Expand Down Expand Up @@ -2766,8 +2764,6 @@ task_step_impl(asyncio_state *state, TaskObj *task, PyObject *exc)
}

if (gen_status == PYGEN_RETURN || gen_status == PYGEN_ERROR) {
PyObject *et, *ev, *tb;

if (result != NULL) {
/* The error is StopIteration and that means that
the underlying coroutine has resolved */
Expand All @@ -2794,52 +2790,39 @@ task_step_impl(asyncio_state *state, TaskObj *task, PyObject *exc)

if (PyErr_ExceptionMatches(state->asyncio_CancelledError)) {
/* CancelledError */
PyErr_Fetch(&et, &ev, &tb);
assert(et);
PyErr_NormalizeException(&et, &ev, &tb);
if (tb != NULL) {
PyException_SetTraceback(ev, tb);
Py_DECREF(tb);
}
Py_XDECREF(et);

PyObject *exc = PyErr_GetRaisedException();
assert(exc);

FutureObj *fut = (FutureObj*)task;
/* transfer ownership */
fut->fut_cancelled_exc = ev;
fut->fut_cancelled_exc = exc;

return future_cancel(state, fut, NULL);
}

/* Some other exception; pop it and call Task.set_exception() */
PyErr_Fetch(&et, &ev, &tb);
assert(et);
PyErr_NormalizeException(&et, &ev, &tb);
if (tb != NULL) {
PyException_SetTraceback(ev, tb);
}
PyObject *exc = PyErr_GetRaisedException();
assert(exc);

o = future_set_exception(state, (FutureObj*)task, ev);
o = future_set_exception(state, (FutureObj*)task, exc);
if (!o) {
/* An exception in Task.set_exception() */
Py_DECREF(et);
Py_XDECREF(tb);
Py_XDECREF(ev);
Py_DECREF(exc);
goto fail;
}
assert(o == Py_None);
Py_DECREF(o);

if (PyErr_GivenExceptionMatches(et, PyExc_KeyboardInterrupt) ||
PyErr_GivenExceptionMatches(et, PyExc_SystemExit))
if (PyErr_GivenExceptionMatches(exc, PyExc_KeyboardInterrupt) ||
PyErr_GivenExceptionMatches(exc, PyExc_SystemExit))
{
/* We've got a KeyboardInterrupt or a SystemError; re-raise it */
PyErr_Restore(et, ev, tb);
PyErr_SetRaisedException(exc);
goto fail;
}

Py_DECREF(et);
Py_XDECREF(tb);
Py_XDECREF(ev);
Py_DECREF(exc);

Py_RETURN_NONE;
}
Expand Down Expand Up @@ -3059,10 +3042,9 @@ task_step(asyncio_state *state, TaskObj *task, PyObject *exc)
res = task_step_impl(state, task, exc);

if (res == NULL) {
PyObject *et, *ev, *tb;
PyErr_Fetch(&et, &ev, &tb);
PyObject *exc = PyErr_GetRaisedException();
leave_task(state, task->task_loop, (PyObject*)task);
_PyErr_ChainExceptions(et, ev, tb); /* Normalizes (et, ev, tb) */
_PyErr_ChainExceptions1(exc);
return NULL;
}
else {
Expand All @@ -3079,7 +3061,6 @@ task_step(asyncio_state *state, TaskObj *task, PyObject *exc)
static PyObject *
task_wakeup(TaskObj *task, PyObject *o)
{
PyObject *et, *ev, *tb;
PyObject *result;
assert(o);

Expand Down Expand Up @@ -3111,18 +3092,12 @@ task_wakeup(TaskObj *task, PyObject *o)
/* exception raised */
}

PyErr_Fetch(&et, &ev, &tb);
assert(et);
PyErr_NormalizeException(&et, &ev, &tb);
if (tb != NULL) {
PyException_SetTraceback(ev, tb);
}
PyObject *exc = PyErr_GetRaisedException();
assert(exc);

result = task_step(state, task, ev);
result = task_step(state, task, exc);

Py_DECREF(et);
Py_XDECREF(tb);
Py_XDECREF(ev);
Py_DECREF(exc);

return result;
}
Expand Down
7 changes: 3 additions & 4 deletions Modules/_io/_iomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -437,10 +437,9 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode,

error:
if (result != NULL) {
PyObject *exc, *val, *tb, *close_result;
PyErr_Fetch(&exc, &val, &tb);
close_result = PyObject_CallMethodNoArgs(result, &_Py_ID(close));
_PyErr_ChainExceptions(exc, val, tb);
PyObject *exc = PyErr_GetRaisedException();
PyObject *close_result = PyObject_CallMethodNoArgs(result, &_Py_ID(close));
_PyErr_ChainExceptions1(exc);
Py_XDECREF(close_result);
Py_DECREF(result);
}
Expand Down
60 changes: 30 additions & 30 deletions Modules/_io/bufferedio.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,12 +472,13 @@ buffered_closed_get(buffered *self, void *context)
static PyObject *
buffered_close(buffered *self, PyObject *args)
{
PyObject *res = NULL, *exc = NULL, *val, *tb;
PyObject *res = NULL;
int r;

CHECK_INITIALIZED(self)
if (!ENTER_BUFFERED(self))
if (!ENTER_BUFFERED(self)) {
return NULL;
}

r = buffered_closed(self);
if (r < 0)
Expand All @@ -497,12 +498,16 @@ buffered_close(buffered *self, PyObject *args)
/* flush() will most probably re-take the lock, so drop it first */
LEAVE_BUFFERED(self)
res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(flush));
if (!ENTER_BUFFERED(self))
if (!ENTER_BUFFERED(self)) {
return NULL;
if (res == NULL)
PyErr_Fetch(&exc, &val, &tb);
else
}
PyObject *exc = NULL;
if (res == NULL) {
exc = PyErr_GetRaisedException();
}
else {
Py_DECREF(res);
}

res = PyObject_CallMethodNoArgs(self->raw, &_Py_ID(close));

Expand All @@ -512,7 +517,7 @@ buffered_close(buffered *self, PyObject *args)
}

if (exc != NULL) {
_PyErr_ChainExceptions(exc, val, tb);
_PyErr_ChainExceptions1(exc);
Py_CLEAR(res);
}

Expand Down Expand Up @@ -637,17 +642,14 @@ _set_BlockingIOError(const char *msg, Py_ssize_t written)
static Py_ssize_t *
_buffered_check_blocking_error(void)
{
PyObject *t, *v, *tb;
PyOSErrorObject *err;

PyErr_Fetch(&t, &v, &tb);
if (v == NULL || !PyErr_GivenExceptionMatches(v, PyExc_BlockingIOError)) {
PyErr_Restore(t, v, tb);
PyObject *exc = PyErr_GetRaisedException();
if (exc == NULL || !PyErr_GivenExceptionMatches(exc, PyExc_BlockingIOError)) {
PyErr_SetRaisedException(exc);
return NULL;
}
err = (PyOSErrorObject *) v;
PyOSErrorObject *err = (PyOSErrorObject *)exc;
/* TODO: sanity check (err->written >= 0) */
PyErr_Restore(t, v, tb);
PyErr_SetRaisedException(exc);
return &err->written;
}

Expand Down Expand Up @@ -749,13 +751,11 @@ _buffered_init(buffered *self)
int
_PyIO_trap_eintr(void)
{
PyObject *typ, *val, *tb;
PyOSErrorObject *env_err;
if (!PyErr_ExceptionMatches(PyExc_OSError))
if (!PyErr_ExceptionMatches(PyExc_OSError)) {
return 0;
PyErr_Fetch(&typ, &val, &tb);
PyErr_NormalizeException(&typ, &val, &tb);
env_err = (PyOSErrorObject *) val;
}
PyObject *exc = PyErr_GetRaisedException();
PyOSErrorObject *env_err = (PyOSErrorObject *)exc;
assert(env_err != NULL);
if (env_err->myerrno != NULL) {
assert(EINTR > 0 && EINTR < INT_MAX);
Expand All @@ -764,14 +764,12 @@ _PyIO_trap_eintr(void)
int myerrno = PyLong_AsLongAndOverflow(env_err->myerrno, &overflow);
PyErr_Clear();
if (myerrno == EINTR) {
Py_DECREF(typ);
Py_DECREF(val);
Py_XDECREF(tb);
Py_DECREF(exc);
return 1;
}
}
/* This silences any error set by PyObject_RichCompareBool() */
PyErr_Restore(typ, val, tb);
PyErr_SetRaisedException(exc);
return 0;
}

Expand Down Expand Up @@ -2228,15 +2226,17 @@ bufferedrwpair_writable(rwpair *self, PyObject *Py_UNUSED(ignored))
static PyObject *
bufferedrwpair_close(rwpair *self, PyObject *Py_UNUSED(ignored))
{
PyObject *exc = NULL, *val, *tb;
PyObject *exc = NULL;
PyObject *ret = _forward_call(self->writer, &_Py_ID(close), NULL);
if (ret == NULL)
PyErr_Fetch(&exc, &val, &tb);
else
if (ret == NULL) {
exc = PyErr_GetRaisedException();
}
else {
Py_DECREF(ret);
}
ret = _forward_call(self->reader, &_Py_ID(close), NULL);
if (exc != NULL) {
_PyErr_ChainExceptions(exc, val, tb);
_PyErr_ChainExceptions1(exc);
Py_CLEAR(ret);
}
return ret;
Expand Down
31 changes: 17 additions & 14 deletions Modules/_io/fileio.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,13 @@ static PyObject *
fileio_dealloc_warn(fileio *self, PyObject *source)
{
if (self->fd >= 0 && self->closefd) {
PyObject *exc, *val, *tb;
PyErr_Fetch(&exc, &val, &tb);
PyObject *exc = PyErr_GetRaisedException();
if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) {
/* Spurious errors can appear at shutdown */
if (PyErr_ExceptionMatches(PyExc_Warning))
PyErr_WriteUnraisable((PyObject *) self);
}
PyErr_Restore(exc, val, tb);
PyErr_SetRaisedException(exc);
}
Py_RETURN_NONE;
}
Expand Down Expand Up @@ -140,28 +139,33 @@ _io_FileIO_close_impl(fileio *self)
/*[clinic end generated code: output=7737a319ef3bad0b input=f35231760d54a522]*/
{
PyObject *res;
PyObject *exc, *val, *tb;
PyObject *exc;
int rc;
res = PyObject_CallMethodOneArg((PyObject*)&PyRawIOBase_Type,
&_Py_ID(close), (PyObject *)self);
if (!self->closefd) {
self->fd = -1;
return res;
}
if (res == NULL)
PyErr_Fetch(&exc, &val, &tb);
if (res == NULL) {
exc = PyErr_GetRaisedException();
}
if (self->finalizing) {
PyObject *r = fileio_dealloc_warn(self, (PyObject *) self);
if (r)
if (r) {
Py_DECREF(r);
else
}
else {
PyErr_Clear();
}
}
rc = internal_close(self);
if (res == NULL)
_PyErr_ChainExceptions(exc, val, tb);
if (rc < 0)
if (res == NULL) {
_PyErr_ChainExceptions1(exc);
}
if (rc < 0) {
Py_CLEAR(res);
}
return res;
}

Expand Down Expand Up @@ -487,10 +491,9 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode,
if (!fd_is_own)
self->fd = -1;
if (self->fd >= 0) {
PyObject *exc, *val, *tb;
PyErr_Fetch(&exc, &val, &tb);
PyObject *exc = PyErr_GetRaisedException();
internal_close(self);
_PyErr_ChainExceptions(exc, val, tb);
_PyErr_ChainExceptions1(exc);
}

done:
Expand Down
Loading

0 comments on commit 2db23d1

Please sign in to comment.