Skip to content

Commit 73ae202

Browse files
authored
gh-113753: Clear finalized bit when putting PyAsyncGenASend back into free list (#113754)
1 parent 901a971 commit 73ae202

File tree

4 files changed

+16
-0
lines changed

4 files changed

+16
-0
lines changed

Include/internal/pycore_gc.h

+4
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ static inline void _PyGC_SET_FINALIZED(PyObject *op) {
122122
PyGC_Head *gc = _Py_AS_GC(op);
123123
_PyGCHead_SET_FINALIZED(gc);
124124
}
125+
static inline void _PyGC_CLEAR_FINALIZED(PyObject *op) {
126+
PyGC_Head *gc = _Py_AS_GC(op);
127+
gc->_gc_prev &= ~_PyGC_PREV_MASK_FINALIZED;
128+
}
125129

126130

127131
/* GC runtime state */

Lib/test/test_asyncgen.py

+8
Original file line numberDiff line numberDiff line change
@@ -1701,6 +1701,14 @@ def test_asend(self):
17011701
async def gen():
17021702
yield 1
17031703

1704+
# gh-113753: asend objects allocated from a free-list should warn.
1705+
# Ensure there is a finalized 'asend' object ready to be reused.
1706+
try:
1707+
g = gen()
1708+
g.asend(None).send(None)
1709+
except StopIteration:
1710+
pass
1711+
17041712
msg = f"coroutine method 'asend' of '{gen.__qualname__}' was never awaited"
17051713
with self.assertWarnsRegex(RuntimeWarning, msg):
17061714
g = gen()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix an issue where the finalizer of ``PyAsyncGenASend`` objects might not be
2+
called if they were allocated from a free list.

Objects/genobject.c

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "pycore_call.h" // _PyObject_CallNoArgs()
77
#include "pycore_ceval.h" // _PyEval_EvalFrame()
88
#include "pycore_frame.h" // _PyInterpreterFrame
9+
#include "pycore_gc.h" // _PyGC_CLEAR_FINALIZED()
910
#include "pycore_genobject.h" // struct _Py_async_gen_state
1011
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
1112
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
@@ -1739,6 +1740,7 @@ async_gen_asend_dealloc(PyAsyncGenASend *o)
17391740
#endif
17401741
if (state->asend_numfree < _PyAsyncGen_MAXFREELIST) {
17411742
assert(PyAsyncGenASend_CheckExact(o));
1743+
_PyGC_CLEAR_FINALIZED((PyObject *)o);
17421744
state->asend_freelist[state->asend_numfree++] = o;
17431745
}
17441746
else

0 commit comments

Comments
 (0)