gh-113753: Clear finalized bit when putting PyAsyncGenASend back into free list (#113754)

This commit is contained in:
Sam Gross 2024-01-10 13:18:38 -05:00 committed by GitHub
parent 901a971e16
commit 73ae2023a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 16 additions and 0 deletions

View File

@ -122,6 +122,10 @@ static inline void _PyGC_SET_FINALIZED(PyObject *op) {
PyGC_Head *gc = _Py_AS_GC(op); PyGC_Head *gc = _Py_AS_GC(op);
_PyGCHead_SET_FINALIZED(gc); _PyGCHead_SET_FINALIZED(gc);
} }
static inline void _PyGC_CLEAR_FINALIZED(PyObject *op) {
PyGC_Head *gc = _Py_AS_GC(op);
gc->_gc_prev &= ~_PyGC_PREV_MASK_FINALIZED;
}
/* GC runtime state */ /* GC runtime state */

View File

@ -1701,6 +1701,14 @@ class TestUnawaitedWarnings(unittest.TestCase):
async def gen(): async def gen():
yield 1 yield 1
# gh-113753: asend objects allocated from a free-list should warn.
# Ensure there is a finalized 'asend' object ready to be reused.
try:
g = gen()
g.asend(None).send(None)
except StopIteration:
pass
msg = f"coroutine method 'asend' of '{gen.__qualname__}' was never awaited" msg = f"coroutine method 'asend' of '{gen.__qualname__}' was never awaited"
with self.assertWarnsRegex(RuntimeWarning, msg): with self.assertWarnsRegex(RuntimeWarning, msg):
g = gen() g = gen()

View File

@ -0,0 +1,2 @@
Fix an issue where the finalizer of ``PyAsyncGenASend`` objects might not be
called if they were allocated from a free list.

View File

@ -6,6 +6,7 @@
#include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_ceval.h" // _PyEval_EvalFrame() #include "pycore_ceval.h" // _PyEval_EvalFrame()
#include "pycore_frame.h" // _PyInterpreterFrame #include "pycore_frame.h" // _PyInterpreterFrame
#include "pycore_gc.h" // _PyGC_CLEAR_FINALIZED()
#include "pycore_genobject.h" // struct _Py_async_gen_state #include "pycore_genobject.h" // struct _Py_async_gen_state
#include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_modsupport.h" // _PyArg_CheckPositional()
#include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_object.h" // _PyObject_GC_UNTRACK()
@ -1739,6 +1740,7 @@ async_gen_asend_dealloc(PyAsyncGenASend *o)
#endif #endif
if (state->asend_numfree < _PyAsyncGen_MAXFREELIST) { if (state->asend_numfree < _PyAsyncGen_MAXFREELIST) {
assert(PyAsyncGenASend_CheckExact(o)); assert(PyAsyncGenASend_CheckExact(o));
_PyGC_CLEAR_FINALIZED((PyObject *)o);
state->asend_freelist[state->asend_numfree++] = o; state->asend_freelist[state->asend_numfree++] = o;
} }
else else