Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
gh-125789: fix side-effects inasyncio callback scheduling methods#125833
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
be7cac9ca61908640c799a05cde222b21ccf7b6730f72c393378fe09File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| Mitigate interpreter crashes and state corruption due to side-effects in | ||
| :meth:`asyncio.Future.remove_done_callback` or other callback scheduling | ||
| methods. Patch by Bénédikt Tran. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -441,8 +441,16 @@ future_schedule_callbacks(asyncio_state *state, FutureObj *fut) | ||
| return 0; | ||
| } | ||
| // Beware: An evil 'call_soon' could change fut_callbacks or its items | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Do you have a test case for an evil 'call_soon'? MemberAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. No, you're right. I didn't test but I think we can just call Contributor
| ||
| // (see https://github.com/python/cpython/issues/125789 for details). | ||
| for (i = 0; | ||
| fut->fut_callbacks != NULL && i < PyList_GET_SIZE(fut->fut_callbacks); | ||
| i++) { | ||
| PyObject *cb_tup = PyList_GET_ITEM(fut->fut_callbacks, i); | ||
| if (!PyTuple_CheckExact(cb_tup) || PyTuple_GET_SIZE(cb_tup) != 2) { | ||
| PyErr_SetString(PyExc_RuntimeError, "corrupted callback tuple"); | ||
| return -1; | ||
| } | ||
| PyObject *cb = PyTuple_GET_ITEM(cb_tup, 0); | ||
| PyObject *ctx = PyTuple_GET_ITEM(cb_tup, 1); | ||
| @@ -1017,7 +1025,13 @@ _asyncio_Future_remove_done_callback_impl(FutureObj *self, PyTypeObject *cls, | ||
| ENSURE_FUTURE_ALIVE(state, self) | ||
| if (self->fut_callback0 != NULL) { | ||
| // Beware: An evil PyObject_RichCompareBool could change fut_callback0 | ||
| // (see https://github.com/python/cpython/issues/125789 for details) | ||
| // In addition, the reference to self->fut_callback0 may be cleared, | ||
| // so we need to temporarily hold it explicitly. | ||
| PyObject *fut_callback0 = Py_NewRef(self->fut_callback0); | ||
| int cmp = PyObject_RichCompareBool(fut_callback0, fn, Py_EQ); | ||
| Py_DECREF(fut_callback0); | ||
| if (cmp == -1) { | ||
| return NULL; | ||
| } | ||
| @@ -1041,8 +1055,17 @@ _asyncio_Future_remove_done_callback_impl(FutureObj *self, PyTypeObject *cls, | ||
| if (len == 1) { | ||
| PyObject *cb_tup = PyList_GET_ITEM(self->fut_callbacks, 0); | ||
| // Beware: An evil PyObject_RichCompareBool could change fut_callbacks | ||
| // or its items (see https://github.com/python/cpython/issues/97592 or | ||
| // https://github.com/python/cpython/issues/125789 for details). | ||
| if (!PyTuple_CheckExact(cb_tup) || PyTuple_GET_SIZE(cb_tup) != 2) { | ||
| PyErr_SetString(PyExc_RuntimeError, "corrupted callback tuple"); | ||
| return NULL; | ||
| } | ||
| Py_INCREF(cb_tup); | ||
| PyObject *cb = PyTuple_GET_ITEM(cb_tup, 0); | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. A little nitpicky, but the incref should be on | ||
| int cmp = PyObject_RichCompareBool(cb, fn, Py_EQ); | ||
| Py_DECREF(cb_tup); | ||
| if (cmp == -1) { | ||
| return NULL; | ||
| } | ||
| @@ -1060,24 +1083,29 @@ _asyncio_Future_remove_done_callback_impl(FutureObj *self, PyTypeObject *cls, | ||
| return NULL; | ||
| } | ||
| // Beware: An evil PyObject_RichCompareBool could change fut_callbacks | ||
| // or its items (see https://github.com/python/cpython/issues/97592 or | ||
| // https://github.com/python/cpython/issues/125789 for details). | ||
| for (i = 0; | ||
| self->fut_callbacks != NULL && i < PyList_GET_SIZE(self->fut_callbacks); | ||
| i++) { | ||
| PyObject *cb_tup = PyList_GET_ITEM(self->fut_callbacks, i); | ||
| if (!PyTuple_CheckExact(cb_tup) || PyTuple_GET_SIZE(cb_tup) != 2) { | ||
| PyErr_SetString(PyExc_RuntimeError, "corrupted callback tuple"); | ||
| goto fail; | ||
| } | ||
| Py_INCREF(cb_tup); | ||
| PyObject *cb = PyTuple_GET_ITEM(cb_tup, 0); | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Same thing here, I don't think it's possible to delete | ||
| int ret = PyObject_RichCompareBool(cb, fn, Py_EQ); | ||
| if (ret == 0) { | ||
| if (j < len) { | ||
| PyList_SET_ITEM(newlist, j,cb_tup); | ||
| j++; | ||
| continue; | ||
| } | ||
| ret = PyList_Append(newlist,cb_tup); | ||
| } | ||
| Py_DECREF(cb_tup); | ||
| if (ret < 0) { | ||
| goto fail; | ||
| } | ||
Uh oh!
There was an error while loading.Please reload this page.