summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-01-10 18:18:38 (GMT)
committerGitHub <noreply@github.com>2024-01-10 18:18:38 (GMT)
commit73ae2023a76f199ff854f8da14bd9ff8e93ee7fd (patch)
tree15945814e01279d22bcff6c49b149a4fb7872c3f
parent901a971e161e060bd95f3cf3aeebe8b48d6e6dac (diff)
downloadcpython-73ae2023a76f199ff854f8da14bd9ff8e93ee7fd.zip
cpython-73ae2023a76f199ff854f8da14bd9ff8e93ee7fd.tar.gz
cpython-73ae2023a76f199ff854f8da14bd9ff8e93ee7fd.tar.bz2
gh-113753: Clear finalized bit when putting PyAsyncGenASend back into free list (#113754)
-rw-r--r--Include/internal/pycore_gc.h4
-rw-r--r--Lib/test/test_asyncgen.py8
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-01-05-21-28-48.gh-issue-113753.2HNiuq.rst2
-rw-r--r--Objects/genobject.c2
4 files changed, 16 insertions, 0 deletions
diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h
index 2a0730e..753763a 100644
--- a/Include/internal/pycore_gc.h
+++ b/Include/internal/pycore_gc.h
@@ -122,6 +122,10 @@ static inline void _PyGC_SET_FINALIZED(PyObject *op) {
PyGC_Head *gc = _Py_AS_GC(op);
_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 */
diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py
index a496301..7fa0a85 100644
--- a/Lib/test/test_asyncgen.py
+++ b/Lib/test/test_asyncgen.py
@@ -1701,6 +1701,14 @@ class TestUnawaitedWarnings(unittest.TestCase):
async def gen():
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"
with self.assertWarnsRegex(RuntimeWarning, msg):
g = gen()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-01-05-21-28-48.gh-issue-113753.2HNiuq.rst b/Misc/NEWS.d/next/Core and Builtins/2024-01-05-21-28-48.gh-issue-113753.2HNiuq.rst
new file mode 100644
index 0000000..32cf2cb
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2024-01-05-21-28-48.gh-issue-113753.2HNiuq.rst
@@ -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.
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 9614713..f03919c 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -6,6 +6,7 @@
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_ceval.h" // _PyEval_EvalFrame()
#include "pycore_frame.h" // _PyInterpreterFrame
+#include "pycore_gc.h" // _PyGC_CLEAR_FINALIZED()
#include "pycore_genobject.h" // struct _Py_async_gen_state
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
@@ -1739,6 +1740,7 @@ async_gen_asend_dealloc(PyAsyncGenASend *o)
#endif
if (state->asend_numfree < _PyAsyncGen_MAXFREELIST) {
assert(PyAsyncGenASend_CheckExact(o));
+ _PyGC_CLEAR_FINALIZED((PyObject *)o);
state->asend_freelist[state->asend_numfree++] = o;
}
else