summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/methodobject.h1
-rw-r--r--Lib/test/test_sys.py2
-rw-r--r--Lib/test/test_weakref.py12
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/_testcapimodule.c16
-rw-r--r--Objects/methodobject.c6
7 files changed, 39 insertions, 2 deletions
diff --git a/Include/methodobject.h b/Include/methodobject.h
index 3cc2ea9..0236228 100644
--- a/Include/methodobject.h
+++ b/Include/methodobject.h
@@ -77,6 +77,7 @@ typedef struct {
PyMethodDef *m_ml; /* Description of the C function to call */
PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */
PyObject *m_module; /* The __module__ attribute, can be anything */
+ PyObject *m_weakreflist; /* List of weak references */
} PyCFunctionObject;
#endif
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 854e786..c50b20b 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -784,7 +784,7 @@ class SizeofTest(unittest.TestCase):
# buffer
# XXX
# builtin_function_or_method
- check(len, size('3P')) # XXX check layout
+ check(len, size('4P')) # XXX check layout
# bytearray
samples = [b'', b'u'*100000]
for sample in samples:
diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py
index adb923f..7476273 100644
--- a/Lib/test/test_weakref.py
+++ b/Lib/test/test_weakref.py
@@ -92,6 +92,18 @@ class ReferencesTestCase(TestBase):
self.check_basic_callback(create_function)
self.check_basic_callback(create_bound_method)
+ @support.cpython_only
+ def test_cfunction(self):
+ import _testcapi
+ create_cfunction = _testcapi.create_cfunction
+ f = create_cfunction()
+ wr = weakref.ref(f)
+ self.assertIs(wr(), f)
+ del f
+ self.assertIsNone(wr())
+ self.check_basic_ref(create_cfunction)
+ self.check_basic_callback(create_cfunction)
+
def test_multiple_callbacks(self):
o = C()
ref1 = weakref.ref(o, self.callback)
diff --git a/Misc/ACKS b/Misc/ACKS
index 09b68d1..60d6f7f 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1484,6 +1484,7 @@ Gordon Worley
Darren Worrall
Thomas Wouters
Daniel Wozniak
+Wei Wu
Heiko Wundram
Doug Wyatt
Robert Xiao
diff --git a/Misc/NEWS b/Misc/NEWS
index 877384f..4a3ebd5 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ Release date: TBA
Core and Builtins
-----------------
+- Issue #22116: C functions and methods (of the 'builtin_function_or_method'
+ type) can now be weakref'ed. Patch by Wei Wu.
+
- Issue #22077: Improve index error messages for bytearrays, bytes, lists,
and tuples by adding 'or slices'. Added ', not <typename' for bytearrays.
Original patch by Claudiu Popa.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index ebbf88f..9f20abb 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2653,6 +2653,21 @@ with_tp_del(PyObject *self, PyObject *args)
return obj;
}
+static PyMethodDef ml;
+
+static PyObject *
+create_cfunction(PyObject *self, PyObject *args)
+{
+ return PyCFunction_NewEx(&ml, self, NULL);
+}
+
+static PyMethodDef ml = {
+ "create_cfunction",
+ create_cfunction,
+ METH_NOARGS,
+ NULL
+};
+
static PyObject *
_test_incref(PyObject *ob)
{
@@ -3186,6 +3201,7 @@ static PyMethodDef TestMethods[] = {
{"pytime_object_to_timeval", test_pytime_object_to_timeval, METH_VARARGS},
{"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS},
{"with_tp_del", with_tp_del, METH_VARARGS},
+ {"create_cfunction", create_cfunction, METH_NOARGS},
{"test_pymem_alloc0",
(PyCFunction)test_pymem_alloc0, METH_NOARGS},
{"test_pymem_setrawallocators",
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index f2616d4..686baf9 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -37,6 +37,7 @@ PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
if (op == NULL)
return NULL;
}
+ op->m_weakreflist = NULL;
op->m_ml = ml;
Py_XINCREF(self);
op->m_self = self;
@@ -147,6 +148,9 @@ static void
meth_dealloc(PyCFunctionObject *m)
{
_PyObject_GC_UNTRACK(m);
+ if (m->m_weakreflist != NULL) {
+ PyObject_ClearWeakRefs((PyObject*) m);
+ }
Py_XDECREF(m->m_self);
Py_XDECREF(m->m_module);
if (numfree < PyCFunction_MAXFREELIST) {
@@ -352,7 +356,7 @@ PyTypeObject PyCFunction_Type = {
(traverseproc)meth_traverse, /* tp_traverse */
0, /* tp_clear */
meth_richcompare, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
+ offsetof(PyCFunctionObject, m_weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
meth_methods, /* tp_methods */