File tree Expand file tree Collapse file tree 3 files changed +45
-1
lines changed
Expand file tree Collapse file tree 3 files changed +45
-1
lines changed Original file line number Diff line number Diff line change @@ -135,6 +135,40 @@ def func():
135135 finally :
136136 atexit .unregister (func )
137137
138+ def test_eq_unregister_clear (self ):
139+ # Issue #112127: callback's __eq__ may call unregister or _clear
140+ global cnt
141+ cnt = 0
142+ class Func :
143+ def __init__ (self , action , eq_ret_val ):
144+ self .action = action
145+ self .eq_ret_val = eq_ret_val
146+
147+ def __call__ (self ):
148+ return
149+
150+ def __eq__ (self , o ):
151+ global cnt
152+ cnt += 1
153+ if cnt == 1 :
154+ self .action (o )
155+ return self .eq_ret_val (o )
156+
157+ for action , eq_ret_val in (
158+ (lambda o : atexit .unregister (self ), lambda o : NotImplemented ),
159+ (lambda o : atexit .unregister (self ), lambda o : True ),
160+ (lambda o : atexit .unregister (o ), lambda o : NotImplemented ),
161+ (lambda o : atexit .unregister (o ), lambda o : True ),
162+ (lambda o : atexit ._clear (), lambda o : NotImplemented ),
163+ (lambda o : atexit ._clear (), lambda o : True ),
164+ ):
165+ cnt = 0
166+ f1 = Func (action , eq_ret_val )
167+ f2 = Func (action , eq_ret_val )
168+ atexit .register (f1 )
169+ atexit .register (f2 )
170+ atexit ._run_exitfuncs ()
171+
138172
139173if __name__ == "__main__" :
140174 unittest .main ()
Original file line number Diff line number Diff line change @@ -881,6 +881,7 @@ Jim Jewett
881881Pedro Diaz Jimenez
882882Orjan Johansen
883883Fredrik Johansson
884+ Benjamin Johnson
884885Gregory K. Johnson
885886Kent Johnson
886887Michael Johnson
Original file line number Diff line number Diff line change @@ -278,11 +278,20 @@ atexit_unregister(PyObject *module, PyObject *func)
278278 continue ;
279279 }
280280
281+ /*
282+ * Increment refcounts of func and cb->func because equality check may
283+ * unregister one or both
284+ */
285+ PyObject * cb_func = Py_NewRef (cb -> func );
286+ PyObject * cur_func = Py_NewRef (func );
281287 int eq = PyObject_RichCompareBool (cb -> func , func , Py_EQ );
288+ Py_DECREF (cb_func );
289+ Py_DECREF (cur_func );
282290 if (eq < 0 ) {
283291 return NULL ;
284292 }
285- if (eq ) {
293+ // Equality comparison might have already deleted this callback
294+ if (eq && state -> callbacks [i ] != NULL ) {
286295 atexit_delete_cb (state , i );
287296 }
288297 }
You can’t perform that action at this time.
0 commit comments