77#include "pycore_immutability.h"
88
99
10+ static PyObject *
11+ _destroy (PyObject * set , PyObject * objweakref )
12+ {
13+ Py_INCREF (set );
14+ if (PySet_Discard (set , objweakref ) < 0 ) {
15+ Py_DECREF (set );
16+ return NULL ;
17+ }
18+ Py_DECREF (set );
19+
20+ Py_RETURN_NONE ;
21+ }
22+
23+ static PyMethodDef _destroy_def = {
24+ "_destroy" , (PyCFunction ) _destroy , METH_O
25+ };
1026
11- static int init_state (struct _Py_immutability_state * state )
27+ static PyObject *
28+ type_weakref (struct _Py_immutability_state * state , PyObject * obj )
29+ {
30+ if (state -> destroy_cb == NULL ){
31+ state -> destroy_cb = PyCFunction_NewEx (& _destroy_def , state -> freezable_types , NULL );
32+ if (state -> destroy_cb == NULL ) {
33+ return NULL ;
34+ }
35+ }
36+
37+ return PyWeakref_NewRef (obj , state -> destroy_cb );
38+ }
39+
40+ static
41+ int init_state (struct _Py_immutability_state * state )
1242{
1343 PyObject * frozen_importlib = NULL ;
1444
@@ -40,6 +70,8 @@ static int init_state(struct _Py_immutability_state *state)
4070 return -1 ;
4171 }
4272
73+ Py_DECREF (frozen_importlib );
74+
4375 return 0 ;
4476}
4577
@@ -279,7 +311,8 @@ static int freeze_visit(PyObject* obj, void* frontier)
279311 return 0 ;
280312}
281313
282- static bool is_freezable_builtin (PyTypeObject * type )
314+ static bool
315+ is_freezable_builtin (PyTypeObject * type )
283316{
284317 if (type == & PyType_Type ||
285318 type == & PyBaseObject_Type ||
@@ -319,28 +352,51 @@ static bool is_freezable_builtin(PyTypeObject *type)
319352 return false;
320353}
321354
355+ static int
356+ is_explicitly_freezable (struct _Py_immutability_state * state , PyObject * obj )
357+ {
358+ int result = 0 ;
359+ PyObject * ref = type_weakref (state , (PyObject * )obj -> ob_type );
360+ if (ref == NULL ){
361+ return -1 ;
362+ }
363+
364+ result = PySet_Contains (state -> freezable_types , ref );
365+ Py_DECREF (ref );
366+ return result ;
367+ }
322368
323369typedef enum {
324370 VALID_BUILTIN ,
325371 VALID_EXPLICIT ,
326372 VALID_IMPLICIT ,
327373 INVALID_NOT_FREEZABLE ,
328- INVALID_C_EXTENSIONS
374+ INVALID_C_EXTENSIONS ,
375+ ERROR
329376} FreezableCheck ;
330377
331378
332- static FreezableCheck check_freezable (PyObject * obj , PyObject * freezable_types )
379+ static FreezableCheck check_freezable (struct _Py_immutability_state * state , PyObject * obj )
333380{
334- if (PyObject_IsInstance (obj , (PyObject * )& _PyNotFreezable_Type )){
381+ int result = 0 ;
382+
383+ result = PyObject_IsInstance (obj , (PyObject * )& _PyNotFreezable_Type );
384+ if (result == -1 ){
385+ return ERROR ;
386+ }
387+ else if (result == 1 ){
335388 return INVALID_NOT_FREEZABLE ;
336389 }
337390
338391 if (is_freezable_builtin (obj -> ob_type )){
339392 return VALID_BUILTIN ;
340393 }
341394
342- PyObject * type = (PyObject * )obj -> ob_type ;
343- if (PySet_Contains (freezable_types , type ) == 1 ){
395+ result = is_explicitly_freezable (state , obj );
396+ if (result == -1 ){
397+ return ERROR ;
398+ }
399+ else if (result == 1 ){
344400 return VALID_EXPLICIT ;
345401 }
346402
@@ -360,7 +416,7 @@ int _PyImmutability_IsFreezable(PyObject *obj)
360416 return 0 ;
361417 }
362418
363- switch (check_freezable (obj , state -> freezable_types ))
419+ switch (check_freezable (state , obj ))
364420 {
365421 case VALID_BUILTIN :
366422 case VALID_EXPLICIT :
@@ -369,6 +425,8 @@ int _PyImmutability_IsFreezable(PyObject *obj)
369425 case INVALID_NOT_FREEZABLE :
370426 case INVALID_C_EXTENSIONS :
371427 return 0 ;
428+ case ERROR :
429+ return -1 ;
372430 }
373431
374432 PyErr_SetString (PyExc_RuntimeError , "Unknown state" );
@@ -377,17 +435,22 @@ int _PyImmutability_IsFreezable(PyObject *obj)
377435
378436int _PyImmutability_RegisterFreezable (PyTypeObject * tp )
379437{
438+ PyObject * ref ;
439+ int result ;
380440 struct _Py_immutability_state * state = get_immutable_state ();
381441 if (state == NULL ){
382442 PyErr_SetString (PyExc_RuntimeError , "Failed to initialize immutability state" );
383443 return -1 ;
384444 }
385445
386- if (PySet_Add (state -> freezable_types , _PyObject_CAST (tp )) == -1 ){
446+ ref = type_weakref (state , (PyObject * )tp );
447+ if (ref == NULL ){
387448 return -1 ;
388449 }
389450
390- return 0 ;
451+ result = PySet_Add (state -> freezable_types , ref );
452+ Py_DECREF (ref );
453+ return result ;
391454}
392455
393456
@@ -424,7 +487,7 @@ int _PyImmutability_Freeze(PyObject* obj)
424487 continue ;
425488 }
426489
427- check = check_freezable (item , state -> freezable_types );
490+ check = check_freezable (state , item );
428491 switch (check ){
429492 case INVALID_NOT_FREEZABLE :
430493 PyErr_SetString (PyExc_TypeError , "Invalid freeze request: instance of NotFreezable" );
@@ -441,6 +504,9 @@ int _PyImmutability_Freeze(PyObject* obj)
441504 case VALID_EXPLICIT :
442505 case VALID_IMPLICIT :
443506 break ;
507+
508+ case ERROR :
509+ goto error ;
444510
445511 default :
446512 PyErr_SetString (PyExc_RuntimeError , "Unknown freezable check value" );
0 commit comments