gh-134786: raise error if `Py_TPFLAGS_MANAGED_WEAKREF` or `Py_TPFLAGS… · python/cpython@da65f38 · GitHub
Skip to content

Commit da65f38

Browse files
gh-134786: raise error if Py_TPFLAGS_MANAGED_WEAKREF or Py_TPFLAGS_MANAGED_DICT is used without Py_TPFLAGS_HAVE_GC set (#135863)
1 parent d12cbf2 commit da65f38

8 files changed

Lines changed: 72 additions & 2 deletions

File tree

Doc/c-api/typeobj.rst

Lines changed: 3 additions & 1 deletion

Doc/extending/newtypes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,8 @@ For an object to be weakly referenceable, the extension type must set the
560560
field. The legacy :c:member:`~PyTypeObject.tp_weaklistoffset` field should
561561
be left as zero.
562562

563+
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set.
564+
563565
Concretely, here is how the statically declared type object would look::
564566

565567
static PyTypeObject TrivialType = {

Doc/whatsnew/3.15.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,14 @@ New features
951951
(Contributed by Victor Stinner in :gh:`111489`.)
952952

953953

954+
Changed C APIs
955+
--------------
956+
957+
* If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` or :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF`
958+
flag is set then :c:macro:`Py_TPFLAGS_HAVE_GC` must be set too.
959+
(Contributed by Sergey Miryanov in :gh:`134786`)
960+
961+
954962
Porting to Python 3.15
955963
----------------------
956964

Include/object.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ given type object has a specified feature.
529529
#define Py_TPFLAGS_INLINE_VALUES (1 << 2)
530530

531531
/* Placement of weakref pointers are managed by the VM, not by the type.
532-
* The VM will automatically set tp_weaklistoffset.
532+
* The VM will automatically set tp_weaklistoffset. Implies Py_TPFLAGS_HAVE_GC.
533533
*/
534534
#define Py_TPFLAGS_MANAGED_WEAKREF (1 << 3)
535535

Lib/test/test_capi/test_type.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,3 +274,10 @@ def test_extension_managed_dict_type(self):
274274
obj.__dict__ = {'bar': 3}
275275
self.assertEqual(obj.__dict__, {'bar': 3})
276276
self.assertEqual(obj.bar, 3)
277+
278+
def test_extension_managed_weakref_nogc_type(self):
279+
msg = ("type _testcapi.ManagedWeakrefNoGCType "
280+
"has the Py_TPFLAGS_MANAGED_WEAKREF "
281+
"flag but not Py_TPFLAGS_HAVE_GC flag")
282+
with self.assertRaisesRegex(SystemError, msg):
283+
_testcapi.create_managed_weakref_nogc_type()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
If :c:macro:`Py_TPFLAGS_MANAGED_DICT` and :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF`
2+
are used, then :c:macro:`Py_TPFLAGS_HAVE_GC` must be used as well.

Modules/_testcapimodule.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2562,6 +2562,39 @@ toggle_reftrace_printer(PyObject *ob, PyObject *arg)
25622562
Py_RETURN_NONE;
25632563
}
25642564

2565+
2566+
typedef struct {
2567+
PyObject_HEAD
2568+
} ManagedWeakrefNoGCObject;
2569+
2570+
static void
2571+
ManagedWeakrefNoGC_dealloc(PyObject *self)
2572+
{
2573+
PyObject_ClearWeakRefs(self);
2574+
PyTypeObject *tp = Py_TYPE(self);
2575+
tp->tp_free(self);
2576+
Py_DECREF(tp);
2577+
}
2578+
2579+
static PyType_Slot ManagedWeakrefNoGC_slots[] = {
2580+
{Py_tp_dealloc, ManagedWeakrefNoGC_dealloc},
2581+
{0, 0}
2582+
};
2583+
2584+
static PyType_Spec ManagedWeakrefNoGC_spec = {
2585+
.name = "_testcapi.ManagedWeakrefNoGCType",
2586+
.basicsize = sizeof(ManagedWeakrefNoGCObject),
2587+
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_MANAGED_WEAKREF),
2588+
.slots = ManagedWeakrefNoGC_slots,
2589+
};
2590+
2591+
static PyObject *
2592+
create_managed_weakref_nogc_type(PyObject *self, PyObject *Py_UNUSED(args))
2593+
{
2594+
return PyType_FromSpec(&ManagedWeakrefNoGC_spec);
2595+
}
2596+
2597+
25652598
static PyMethodDef TestMethods[] = {
25662599
{"set_errno", set_errno, METH_VARARGS},
25672600
{"test_config", test_config, METH_NOARGS},
@@ -2656,6 +2689,8 @@ static PyMethodDef TestMethods[] = {
26562689
{"test_atexit", test_atexit, METH_NOARGS},
26572690
{"code_offset_to_line", _PyCFunction_CAST(code_offset_to_line), METH_FASTCALL},
26582691
{"toggle_reftrace_printer", toggle_reftrace_printer, METH_O},
2692+
{"create_managed_weakref_nogc_type",
2693+
create_managed_weakref_nogc_type, METH_NOARGS},
26592694
{NULL, NULL} /* sentinel */
26602695
};
26612696

Objects/typeobject.c

Lines changed: 14 additions & 0 deletions

0 commit comments

Comments
 (0)