Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcae853e

Browse files
GH-125789: fixfut._callbacks to always return a copy of callbacks (#125922)
Fix `asyncio.Future._callbacks` to always return a copy of the internal list of callbacks to avoid mutation from user code affecting the internal state.
1 parentebcc578 commitcae853e

File tree

3 files changed

+44
-28
lines changed

3 files changed

+44
-28
lines changed

‎Lib/test/test_asyncio/test_futures.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,24 @@ def test_future_del_segfault(self):
697697
withself.assertRaises(AttributeError):
698698
delfut._log_traceback
699699

700+
deftest_callbacks_copy(self):
701+
# See https://github.com/python/cpython/issues/125789
702+
# In C implementation, the `_callbacks` attribute
703+
# always returns a new list to avoid mutations of internal state
704+
705+
fut=self._new_future(loop=self.loop)
706+
f1=lambda_:1
707+
f2=lambda_:2
708+
fut.add_done_callback(f1)
709+
fut.add_done_callback(f2)
710+
callbacks=fut._callbacks
711+
self.assertIsNot(callbacks,fut._callbacks)
712+
fut.remove_done_callback(f1)
713+
callbacks=fut._callbacks
714+
self.assertIsNot(callbacks,fut._callbacks)
715+
fut.remove_done_callback(f2)
716+
self.assertIsNone(fut._callbacks)
717+
700718

701719
@unittest.skipUnless(hasattr(futures,'_CFuture'),
702720
'requires the C _asyncio module')
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix possible crash when mutating list of callbacks returned by:attr:`!asyncio.Future._callbacks`. It now always returns a new copy in C implementation:mod:`!_asyncio`. Patch by Kumar Aditya.

‎Modules/_asynciomodule.c‎

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,52 +1265,49 @@ static PyObject *
12651265
FutureObj_get_callbacks(FutureObj*fut,void*Py_UNUSED(ignored))
12661266
{
12671267
asyncio_state*state=get_asyncio_state_by_def((PyObject*)fut);
1268-
Py_ssize_ti;
1269-
12701268
ENSURE_FUTURE_ALIVE(state,fut)
12711269

1272-
if (fut->fut_callback0==NULL) {
1273-
if (fut->fut_callbacks==NULL) {
1274-
Py_RETURN_NONE;
1275-
}
1276-
1277-
returnPy_NewRef(fut->fut_callbacks);
1270+
Py_ssize_tlen=0;
1271+
if (fut->fut_callback0!=NULL) {
1272+
len++;
12781273
}
1279-
1280-
Py_ssize_tlen=1;
12811274
if (fut->fut_callbacks!=NULL) {
12821275
len+=PyList_GET_SIZE(fut->fut_callbacks);
12831276
}
12841277

1285-
1286-
PyObject*new_list=PyList_New(len);
1287-
if (new_list==NULL) {
1288-
returnNULL;
1278+
if (len==0) {
1279+
Py_RETURN_NONE;
12891280
}
12901281

1291-
PyObject*tup0=PyTuple_New(2);
1292-
if (tup0==NULL) {
1293-
Py_DECREF(new_list);
1282+
PyObject*callbacks=PyList_New(len);
1283+
if (callbacks==NULL) {
12941284
returnNULL;
12951285
}
12961286

1297-
Py_INCREF(fut->fut_callback0);
1298-
PyTuple_SET_ITEM(tup0,0,fut->fut_callback0);
1299-
assert(fut->fut_context0!=NULL);
1300-
Py_INCREF(fut->fut_context0);
1301-
PyTuple_SET_ITEM(tup0,1, (PyObject*)fut->fut_context0);
1302-
1303-
PyList_SET_ITEM(new_list,0,tup0);
1287+
Py_ssize_ti=0;
1288+
if (fut->fut_callback0!=NULL) {
1289+
PyObject*tup0=PyTuple_New(2);
1290+
if (tup0==NULL) {
1291+
Py_DECREF(callbacks);
1292+
returnNULL;
1293+
}
1294+
PyTuple_SET_ITEM(tup0,0,Py_NewRef(fut->fut_callback0));
1295+
assert(fut->fut_context0!=NULL);
1296+
PyTuple_SET_ITEM(tup0,1,Py_NewRef(fut->fut_context0));
1297+
PyList_SET_ITEM(callbacks,i,tup0);
1298+
i++;
1299+
}
13041300

13051301
if (fut->fut_callbacks!=NULL) {
1306-
for (i=0;i<PyList_GET_SIZE(fut->fut_callbacks);i++) {
1307-
PyObject*cb=PyList_GET_ITEM(fut->fut_callbacks,i);
1302+
for (Py_ssize_tj=0;j<PyList_GET_SIZE(fut->fut_callbacks);j++) {
1303+
PyObject*cb=PyList_GET_ITEM(fut->fut_callbacks,j);
13081304
Py_INCREF(cb);
1309-
PyList_SET_ITEM(new_list,i+1,cb);
1305+
PyList_SET_ITEM(callbacks,i,cb);
1306+
i++;
13101307
}
13111308
}
13121309

1313-
returnnew_list;
1310+
returncallbacks;
13141311
}
13151312

13161313
staticPyObject*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp