Skip to content

Commit f710627

Browse files
Revert last changes
1 parent f195b04 commit f710627

File tree

12 files changed

+35
-167
lines changed

12 files changed

+35
-167
lines changed

Doc/c-api/typeobj.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
12601260
This bit indicates that instances of the class have a :attr:`~object.__dict__`
12611261
attribute, and that the space for the dictionary is managed by the VM.
12621262

1263-
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` must also be set.
1263+
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set.
12641264

12651265
The type traverse function must call :c:func:`PyObject_VisitManagedDict`
12661266
and its clear function must call :c:func:`PyObject_ClearManagedDict`.
@@ -1278,7 +1278,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
12781278
This bit indicates that instances of the class should be weakly
12791279
referenceable.
12801280

1281-
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` must also be set.
1281+
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set.
12821282

12831283
.. versionadded:: 3.12
12841284

Doc/whatsnew/3.15.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,13 @@ New features
785785
(Contributed by Victor Stinner in :gh:`129813`.)
786786

787787

788+
Limited C API changes
789+
---------------------
790+
791+
* If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` and :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF`
792+
flags are set then :c:macro:`Py_TPFLAGS_HAVE_GC` should be set too.
793+
(Contributed by Sergey Miryanov in :gh:`134786`)
794+
788795

789796
Porting to Python 3.15
790797
----------------------

Include/internal/pycore_object.h

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -936,13 +936,9 @@ extern int _PyType_CacheInitForSpecialization(PyHeapTypeObject *type,
936936
#ifdef Py_GIL_DISABLED
937937
# define MANAGED_DICT_OFFSET (((Py_ssize_t)sizeof(PyObject *))*-1)
938938
# define MANAGED_WEAKREF_OFFSET (((Py_ssize_t)sizeof(PyObject *))*-2)
939-
# define MANAGED_DICT_OFFSET_NO_GC (((Py_ssize_t)sizeof(PyObject *))*-1)
940-
# define MANAGED_WEAKREF_OFFSET_NO_GC (((Py_ssize_t)sizeof(PyObject *))*-2)
941939
#else
942940
# define MANAGED_DICT_OFFSET (((Py_ssize_t)sizeof(PyObject *))*-3)
943941
# define MANAGED_WEAKREF_OFFSET (((Py_ssize_t)sizeof(PyObject *))*-4)
944-
# define MANAGED_DICT_OFFSET_NO_GC (((Py_ssize_t)sizeof(PyObject *))*-1)
945-
# define MANAGED_WEAKREF_OFFSET_NO_GC (((Py_ssize_t)sizeof(PyObject *))*-2)
946942
#endif
947943

948944
typedef union {
@@ -952,13 +948,8 @@ typedef union {
952948
static inline PyManagedDictPointer *
953949
_PyObject_ManagedDictPointer(PyObject *obj)
954950
{
955-
PyTypeObject *type = Py_TYPE(obj);
956-
assert(type->tp_flags & Py_TPFLAGS_MANAGED_DICT);
957-
Py_ssize_t offset = MANAGED_DICT_OFFSET;
958-
if (!_PyType_IS_GC(type)) {
959-
offset = MANAGED_DICT_OFFSET_NO_GC;
960-
}
961-
return (PyManagedDictPointer *)((char *)obj + offset);
951+
assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
952+
return (PyManagedDictPointer *)((char *)obj + MANAGED_DICT_OFFSET);
962953
}
963954

964955
static inline PyDictObject *

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: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from test.support import import_helper, Py_GIL_DISABLED, refleak_helper
22
import unittest
3-
import weakref
43

54
_testcapi = import_helper.import_module('_testcapi')
65

@@ -275,16 +274,3 @@ def test_extension_managed_dict_type(self):
275274
obj.__dict__ = {'bar': 3}
276275
self.assertEqual(obj.__dict__, {'bar': 3})
277276
self.assertEqual(obj.bar, 3)
278-
279-
def test_type_have_managed_weakref_and_no_gc(self):
280-
ManagedWeakrefNoGCType = _testcapi.ManagedWeakrefNoGCType
281-
obj = ManagedWeakrefNoGCType()
282-
wr = weakref.ref(obj)
283-
284-
del obj # shouldn't segfault
285-
del wr
286-
287-
def test_type_have_managed_dict_and_no_gc(self):
288-
ManagedDictNoGCType = _testcapi.ManagedDictNoGCType
289-
obj = ManagedDictNoGCType()
290-
del obj # shouldn't segfault
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
Fix segmentation fault when deallocating object of the type with
2-
:c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` or :c:macro:`Py_TPFLAGS_MANAGED_DICT`
3-
enabled but without :c:macro:`Py_TPFLAGS_HAVE_GC`.
1+
Force to use :c:macro:`Py_TPFLAGS_HAVE_GC` if
2+
:c:macro:`Py_TPFLAGS_MANAGED_DICT` or :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF`
3+
used.

Modules/_testcapimodule.c

Lines changed: 0 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -3227,74 +3227,12 @@ static PyType_Spec ManagedDict_spec = {
32273227
ManagedDict_slots
32283228
};
32293229

3230-
typedef struct {
3231-
PyObject_HEAD
3232-
} ManagedWeakrefNoGCObject;
3233-
3234-
static void
3235-
ManagedWeakrefNoGC_dealloc(PyObject *self)
3236-
{
3237-
PyObject_ClearWeakRefs(self);
3238-
PyTypeObject *tp = Py_TYPE(self);
3239-
tp->tp_free(self);
3240-
Py_DECREF(tp);
3241-
}
3242-
3243-
static PyType_Slot ManagedWeakrefNoGC_slots[] = {
3244-
{Py_tp_dealloc, ManagedWeakrefNoGC_dealloc},
3245-
{0, 0}
3246-
};
3247-
3248-
static PyType_Spec ManagedWeakrefNoGC_spec = {
3249-
.name = "_testcapi.ManagedWeakrefNoGCType",
3250-
.basicsize = sizeof(ManagedWeakrefNoGCObject),
3251-
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_MANAGED_WEAKREF),
3252-
.slots = ManagedWeakrefNoGC_slots,
3253-
};
3254-
3255-
typedef struct {
3256-
PyObject_HEAD
3257-
} ManagedDictNoGCObject;
3258-
3259-
static void
3260-
ManagedDictNoGC_dealloc(PyObject *self)
3261-
{
3262-
PyTypeObject *tp = Py_TYPE(self);
3263-
tp->tp_free(self);
3264-
Py_DECREF(tp);
3265-
}
3266-
3267-
static PyType_Slot ManagedDictNoGC_slots[] = {
3268-
{Py_tp_dealloc, ManagedDictNoGC_dealloc},
3269-
{0, 0}
3270-
};
3271-
3272-
static PyType_Spec ManagedDictNoGC_spec = {
3273-
.name = "_testcapi.ManagedDictNoGCType",
3274-
.basicsize = sizeof(ManagedDictNoGCObject),
3275-
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_MANAGED_DICT),
3276-
.slots = ManagedDictNoGC_slots,
3277-
};
3278-
3279-
32803230
static PyObject *
32813231
create_managed_dict_type(void)
32823232
{
32833233
return PyType_FromSpec(&ManagedDict_spec);
32843234
}
32853235

3286-
static PyObject *
3287-
create_managed_weakref_no_gc_type(void)
3288-
{
3289-
return PyType_FromSpec(&ManagedWeakrefNoGC_spec);
3290-
}
3291-
3292-
static PyObject *
3293-
create_managed_dict_no_gc_type(void)
3294-
{
3295-
return PyType_FromSpec(&ManagedDictNoGC_spec);
3296-
}
3297-
32983236
static int
32993237
_testcapi_exec(PyObject *m)
33003238
{
@@ -3424,22 +3362,6 @@ _testcapi_exec(PyObject *m)
34243362
return -1;
34253363
}
34263364

3427-
PyObject *managed_weakref_no_gc_type = create_managed_weakref_no_gc_type();
3428-
if (managed_weakref_no_gc_type == NULL) {
3429-
return -1;
3430-
}
3431-
if (PyModule_Add(m, "ManagedWeakrefNoGCType", managed_weakref_no_gc_type) < 0) {
3432-
return -1;
3433-
}
3434-
3435-
PyObject *managed_dict_no_gc_type = create_managed_dict_no_gc_type();
3436-
if (managed_dict_no_gc_type == NULL) {
3437-
return -1;
3438-
}
3439-
if (PyModule_Add(m, "ManagedDictNoGCType", managed_dict_no_gc_type) < 0) {
3440-
return -1;
3441-
}
3442-
34433365
/* Include tests from the _testcapi/ directory */
34443366
if (_PyTestCapi_Init_Vectorcall(m) < 0) {
34453367
return -1;

Objects/typeobject.c

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4655,12 +4655,7 @@ type_new_descriptors(const type_new_ctx *ctx, PyTypeObject *type, PyObject *dict
46554655
if (ctx->add_weak) {
46564656
assert((type->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF) == 0);
46574657
type_add_flags(type, Py_TPFLAGS_MANAGED_WEAKREF);
4658-
if (_PyType_IS_GC(type)) {
4659-
type->tp_weaklistoffset = MANAGED_WEAKREF_OFFSET;
4660-
}
4661-
else {
4662-
type->tp_weaklistoffset = MANAGED_WEAKREF_OFFSET_NO_GC;
4663-
}
4658+
type->tp_weaklistoffset = MANAGED_WEAKREF_OFFSET;
46644659
}
46654660
if (ctx->add_dict) {
46664661
assert((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0);
@@ -8505,13 +8500,6 @@ overrides_hash(PyTypeObject *type)
85058500
return r;
85068501
}
85078502

8508-
void
8509-
PyObject_NoGC_Preheader_Del(void *op)
8510-
{
8511-
size_t presize = _PyType_PreHeaderSize(Py_TYPE(op));
8512-
PyObject_Free(((char *)op) - presize);
8513-
}
8514-
85158503
static int
85168504
inherit_slots(PyTypeObject *type, PyTypeObject *base)
85178505
{
@@ -8689,21 +8677,7 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
86898677
if ((type->tp_flags & Py_TPFLAGS_HAVE_GC) ==
86908678
(base->tp_flags & Py_TPFLAGS_HAVE_GC)) {
86918679
/* They agree about gc. */
8692-
8693-
if ((type->tp_flags & Py_TPFLAGS_PREHEADER) &&
8694-
type->tp_free == NULL &&
8695-
base->tp_free == PyObject_Free) {
8696-
/* Because type has preheader fields, its
8697-
* objects will be allocated with those fields
8698-
* and it should be take in account when object
8699-
* is freed, so we use special tp_free.
8700-
*/
8701-
type->tp_free = PyObject_NoGC_Preheader_Del;
8702-
}
8703-
else {
8704-
COPYSLOT(tp_free);
8705-
}
8706-
8680+
COPYSLOT(tp_free);
87078681
}
87088682
else if ((type->tp_flags & Py_TPFLAGS_HAVE_GC) &&
87098683
type->tp_free == NULL &&
@@ -8919,6 +8893,13 @@ type_ready_preheader(PyTypeObject *type)
89198893
type->tp_name);
89208894
return -1;
89218895
}
8896+
if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC)) {
8897+
PyErr_Format(PyExc_SystemError,
8898+
"type %s has the Py_TPFLAGS_MANAGED_DICT flag "
8899+
"but not Py_TPFLAGS_HAVE_GC flag",
8900+
type->tp_name);
8901+
return -1;
8902+
}
89228903
type->tp_dictoffset = -1;
89238904
}
89248905
if (type->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF) {
@@ -8931,12 +8912,14 @@ type_ready_preheader(PyTypeObject *type)
89318912
type->tp_name);
89328913
return -1;
89338914
}
8934-
if (_PyType_IS_GC(type)) {
8935-
type->tp_weaklistoffset = MANAGED_WEAKREF_OFFSET;
8936-
}
8937-
else {
8938-
type->tp_weaklistoffset = MANAGED_WEAKREF_OFFSET_NO_GC;
8915+
if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC)) {
8916+
PyErr_Format(PyExc_SystemError,
8917+
"type %s has the Py_TPFLAGS_MANAGED_WEAKREF flag "
8918+
"but not Py_TPFLAGS_HAVE_GC flag",
8919+
type->tp_name);
8920+
return -1;
89398921
}
8922+
type->tp_weaklistoffset = MANAGED_WEAKREF_OFFSET;
89408923
}
89418924
return 0;
89428925
}

Python/bytecodes.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3638,13 +3638,7 @@ dummy_func(
36383638
_LOAD_ATTR_NONDESCRIPTOR_NO_DICT;
36393639

36403640
op(_CHECK_ATTR_METHOD_LAZY_DICT, (dictoffset/1, owner -- owner)) {
3641-
PyObject *borrowed = PyStackRef_AsPyObjectBorrow(owner);
3642-
Py_ssize_t offset = MANAGED_DICT_OFFSET;
3643-
if (!PyType_IS_GC(Py_TYPE(borrowed))) {
3644-
offset = MANAGED_DICT_OFFSET_NO_GC;
3645-
}
3646-
3647-
char *ptr = ((char *)borrowed) + offset + dictoffset;
3641+
char *ptr = ((char *)PyStackRef_AsPyObjectBorrow(owner)) + MANAGED_DICT_OFFSET + dictoffset;
36483642
PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*(PyObject **)ptr);
36493643
/* This object has a __dict__, just not yet created */
36503644
DEOPT_IF(dict != NULL);

Python/executor_cases.c.h

Lines changed: 1 addition & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)