@@ -46,38 +46,54 @@ new_weakref(PyObject *ob, PyObject *callback)
46
46
}
47
47
48
48
49
- /* This function clears the passed-in reference and removes it from the
50
- * list of weak references for the referent. This is the only code that
51
- * removes an item from the doubly-linked list of weak references for an
52
- * object; it is also responsible for clearing the callback slot.
49
+ /* This function is responsible for clearing the callback slot. When using this
50
+ * It must be called before calling remove_weakref, otherwise a segmentation fault will
51
+ * occur at build time.
53
52
*/
54
53
static void
55
54
clear_weakref (PyWeakReference * self )
56
55
{
57
56
PyObject * callback = self -> wr_callback ;
58
-
59
- if (self -> wr_object != Py_None ) {
60
- PyWeakReference * * list = GET_WEAKREFS_LISTPTR (self -> wr_object );
61
-
62
- if (* list == self )
63
- /* If 'self' is the end of the list (and thus self->wr_next == NULL)
64
- then the weakref list itself (and thus the value of *list) will
65
- end up being set to NULL. */
66
- * list = self -> wr_next ;
67
- self -> wr_object = Py_None ;
68
- if (self -> wr_prev != NULL )
69
- self -> wr_prev -> wr_next = self -> wr_next ;
70
- if (self -> wr_next != NULL )
71
- self -> wr_next -> wr_prev = self -> wr_prev ;
72
- self -> wr_prev = NULL ;
73
- self -> wr_next = NULL ;
74
- }
75
57
if (callback != NULL ) {
76
58
Py_DECREF (callback );
77
59
self -> wr_callback = NULL ;
78
60
}
79
61
}
80
62
63
+ /* This function removes the pass in reference from the list of weak references
64
+ * for the referent. This should be called from remove_weakref_fromt_referent
65
+ * as it will pass the required list argument.
66
+ */
67
+ static void
68
+ remove_weakref (PyWeakReference * self , PyWeakReference * * list )
69
+ {
70
+ if (* list == self )
71
+ /* If 'self' is the end of the list (and thus self->wr_next == NULL)
72
+ then the weakref list itself (and thus the value of *list) will
73
+ end up being set to NULL. */
74
+ * list = self -> wr_next ;
75
+ self -> wr_object = Py_None ;
76
+ if (self -> wr_prev != NULL )
77
+ self -> wr_prev -> wr_next = self -> wr_next ;
78
+ if (self -> wr_next != NULL )
79
+ self -> wr_next -> wr_prev = self -> wr_prev ;
80
+ self -> wr_prev = NULL ;
81
+ self -> wr_next = NULL ;
82
+ }
83
+
84
+ /* This function removes the pass in reference from the list of weak references
85
+ * for the referent. This should be called after clear_weakref, otherwise a
86
+ * segmentation fault will occur at build time.
87
+ */
88
+ static void
89
+ remove_weakref_from_referent (PyWeakReference * self )
90
+ {
91
+ if (self -> wr_object != Py_None ) {
92
+ PyWeakReference * * list = GET_WEAKREFS_LISTPTR (self -> wr_object );
93
+ remove_weakref (self , list );
94
+ }
95
+ }
96
+
81
97
/* Cyclic gc uses this to *just* clear the passed-in reference, leaving
82
98
* the callback intact and uncalled. It must be possible to call self's
83
99
* tp_dealloc() after calling this, so self has to be left in a sane enough
@@ -100,6 +116,7 @@ _PyWeakref_ClearRef(PyWeakReference *self)
100
116
callback = self -> wr_callback ;
101
117
self -> wr_callback = NULL ;
102
118
clear_weakref (self );
119
+ remove_weakref_from_referent (self );
103
120
self -> wr_callback = callback ;
104
121
}
105
122
@@ -108,6 +125,7 @@ weakref_dealloc(PyObject *self)
108
125
{
109
126
PyObject_GC_UnTrack (self );
110
127
clear_weakref ((PyWeakReference * ) self );
128
+ remove_weakref_from_referent ((PyWeakReference * ) self );
111
129
Py_TYPE (self )-> tp_free (self );
112
130
}
113
131
@@ -124,6 +142,7 @@ static int
124
142
gc_clear (PyWeakReference * self )
125
143
{
126
144
clear_weakref (self );
145
+ remove_weakref_from_referent (self );
127
146
return 0 ;
128
147
}
129
148
@@ -562,6 +581,7 @@ proxy_dealloc(PyWeakReference *self)
562
581
if (self -> wr_callback != NULL )
563
582
PyObject_GC_UnTrack ((PyObject * )self );
564
583
clear_weakref (self );
584
+ remove_weakref_from_referent (self );
565
585
PyObject_GC_Del (self );
566
586
}
567
587
@@ -958,8 +978,11 @@ PyObject_ClearWeakRefs(PyObject *object)
958
978
/* Remove the callback-less basic and proxy references */
959
979
if (* list != NULL && (* list )-> wr_callback == NULL ) {
960
980
clear_weakref (* list );
961
- if (* list != NULL && (* list )-> wr_callback == NULL )
981
+ remove_weakref_from_referent (* list );
982
+ if (* list != NULL && (* list )-> wr_callback == NULL ) {
962
983
clear_weakref (* list );
984
+ remove_weakref_from_referent (* list );
985
+ }
963
986
}
964
987
if (* list != NULL ) {
965
988
PyWeakReference * current = * list ;
@@ -972,6 +995,7 @@ PyObject_ClearWeakRefs(PyObject *object)
972
995
973
996
current -> wr_callback = NULL ;
974
997
clear_weakref (current );
998
+ remove_weakref_from_referent (current );
975
999
if (callback != NULL ) {
976
1000
if (Py_REFCNT ((PyObject * )current ) > 0 ) {
977
1001
handle_callback (current , callback );
@@ -1002,6 +1026,7 @@ PyObject_ClearWeakRefs(PyObject *object)
1002
1026
}
1003
1027
current -> wr_callback = NULL ;
1004
1028
clear_weakref (current );
1029
+ remove_weakref_from_referent (current );
1005
1030
current = next ;
1006
1031
}
1007
1032
for (i = 0 ; i < count ; ++ i ) {
@@ -1036,5 +1061,6 @@ _PyStaticType_ClearWeakRefs(PyTypeObject *type)
1036
1061
weaklist before clearing its wr_object and wr_callback.
1037
1062
That is how we're able to loop over the list. */
1038
1063
clear_weakref ((PyWeakReference * )* list );
1064
+ remove_weakref_from_referent ((PyWeakReference * )* list );
1039
1065
}
1040
1066
}
0 commit comments