Skip to content

Commit 5297865

Browse files
committed
gh-118473: Fix set_asyncgen_hooks not to allow partial setup
1 parent c1bf487 commit 5297865

File tree

5 files changed

+39
-22
lines changed

5 files changed

+39
-22
lines changed

Include/internal/pycore_ceval.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ extern PyObject* _PyEval_GetAsyncGenFirstiter(void);
7171
extern PyObject* _PyEval_GetAsyncGenFinalizer(void);
7272

7373
// Used by sys.set_asyncgen_hooks()
74-
extern int _PyEval_SetAsyncGenFirstiter(PyObject *);
75-
extern int _PyEval_SetAsyncGenFinalizer(PyObject *);
74+
extern void _PyEval_SetAsyncGenFirstiter(PyObject *);
75+
extern void _PyEval_SetAsyncGenFinalizer(PyObject *);
7676

7777
// Used by sys.get_coroutine_origin_tracking_depth()
7878
// and sys.set_coroutine_origin_tracking_depth()

Lib/test/test_sys.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1779,14 +1779,28 @@ def test_asyncgen_hooks(self):
17791779
self.assertIsNone(old.finalizer)
17801780

17811781
firstiter = lambda *a: None
1782+
finalizer = lambda *a: None
1783+
1784+
with self.assertRaises(TypeError):
1785+
sys.set_asyncgen_hooks(firstiter=firstiter, finalizer="invalid")
1786+
cur = sys.get_asyncgen_hooks()
1787+
self.assertIsNone(cur.firstiter)
1788+
self.assertIsNone(cur.finalizer)
1789+
1790+
# gh-118473
1791+
with self.assertRaises(TypeError):
1792+
sys.set_asyncgen_hooks(firstiter="invalid", finalizer=finalizer)
1793+
cur = sys.get_asyncgen_hooks()
1794+
self.assertIsNone(cur.firstiter)
1795+
self.assertIsNone(cur.finalizer)
1796+
17821797
sys.set_asyncgen_hooks(firstiter=firstiter)
17831798
hooks = sys.get_asyncgen_hooks()
17841799
self.assertIs(hooks.firstiter, firstiter)
17851800
self.assertIs(hooks[0], firstiter)
17861801
self.assertIs(hooks.finalizer, None)
17871802
self.assertIs(hooks[1], None)
17881803

1789-
finalizer = lambda *a: None
17901804
sys.set_asyncgen_hooks(finalizer=finalizer)
17911805
hooks = sys.get_asyncgen_hooks()
17921806
self.assertIs(hooks.firstiter, firstiter)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix set_asyncgen_hooks not to be partially set when raising TypeError

Python/ceval.c

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,17 +2366,12 @@ _PyEval_GetCoroutineOriginTrackingDepth(void)
23662366
return tstate->coroutine_origin_tracking_depth;
23672367
}
23682368

2369-
int
2369+
void
23702370
_PyEval_SetAsyncGenFirstiter(PyObject *firstiter)
23712371
{
23722372
PyThreadState *tstate = _PyThreadState_GET();
23732373

2374-
if (_PySys_Audit(tstate, "sys.set_asyncgen_hook_firstiter", NULL) < 0) {
2375-
return -1;
2376-
}
2377-
23782374
Py_XSETREF(tstate->async_gen_firstiter, Py_XNewRef(firstiter));
2379-
return 0;
23802375
}
23812376

23822377
PyObject *
@@ -2386,17 +2381,12 @@ _PyEval_GetAsyncGenFirstiter(void)
23862381
return tstate->async_gen_firstiter;
23872382
}
23882383

2389-
int
2384+
void
23902385
_PyEval_SetAsyncGenFinalizer(PyObject *finalizer)
23912386
{
23922387
PyThreadState *tstate = _PyThreadState_GET();
23932388

2394-
if (_PySys_Audit(tstate, "sys.set_asyncgen_hook_finalizer", NULL) < 0) {
2395-
return -1;
2396-
}
2397-
23982389
Py_XSETREF(tstate->async_gen_finalizer, Py_XNewRef(finalizer));
2399-
return 0;
24002390
}
24012391

24022392
PyObject *

Python/sysmodule.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,6 +1391,7 @@ static PyObject *
13911391
sys_set_asyncgen_hooks(PyObject *self, PyObject *args, PyObject *kw)
13921392
{
13931393
static char *keywords[] = {"firstiter", "finalizer", NULL};
1394+
PyThreadState *tstate = NULL;
13941395
PyObject *firstiter = NULL;
13951396
PyObject *finalizer = NULL;
13961397

@@ -1400,34 +1401,45 @@ sys_set_asyncgen_hooks(PyObject *self, PyObject *args, PyObject *kw)
14001401
return NULL;
14011402
}
14021403

1404+
tstate = _PyThreadState_GET();
1405+
14031406
if (finalizer && finalizer != Py_None) {
14041407
if (!PyCallable_Check(finalizer)) {
14051408
PyErr_Format(PyExc_TypeError,
14061409
"callable finalizer expected, got %.50s",
14071410
Py_TYPE(finalizer)->tp_name);
14081411
return NULL;
14091412
}
1410-
if (_PyEval_SetAsyncGenFinalizer(finalizer) < 0) {
1413+
if (_PySys_Audit(tstate, "sys.set_asyncgen_hook_finalizer", NULL) < 0) {
14111414
return NULL;
14121415
}
14131416
}
1414-
else if (finalizer == Py_None && _PyEval_SetAsyncGenFinalizer(NULL) < 0) {
1415-
return NULL;
1416-
}
14171417

14181418
if (firstiter && firstiter != Py_None) {
14191419
if (!PyCallable_Check(firstiter)) {
14201420
PyErr_Format(PyExc_TypeError,
14211421
"callable firstiter expected, got %.50s",
14221422
Py_TYPE(firstiter)->tp_name);
1423+
14231424
return NULL;
14241425
}
1425-
if (_PyEval_SetAsyncGenFirstiter(firstiter) < 0) {
1426+
if (_PySys_Audit(tstate, "sys.set_asyncgen_hook_firstiter", NULL) < 0) {
14261427
return NULL;
14271428
}
14281429
}
1429-
else if (firstiter == Py_None && _PyEval_SetAsyncGenFirstiter(NULL) < 0) {
1430-
return NULL;
1430+
1431+
if (finalizer && finalizer != Py_None) {
1432+
_PyEval_SetAsyncGenFinalizer(finalizer);
1433+
}
1434+
else if (finalizer == Py_None) {
1435+
_PyEval_SetAsyncGenFinalizer(NULL);
1436+
}
1437+
1438+
if (firstiter && firstiter != Py_None) {
1439+
_PyEval_SetAsyncGenFirstiter(firstiter);
1440+
}
1441+
else if (firstiter == Py_None) {
1442+
_PyEval_SetAsyncGenFirstiter(NULL);
14311443
}
14321444

14331445
Py_RETURN_NONE;

0 commit comments

Comments
 (0)