@@ -7495,6 +7495,7 @@ store_instance_attr_dict(PyObject *obj, PyDictObject *dict, PyObject *name, PyOb
74957495int
74967496_PyObject_StoreInstanceAttribute (PyObject * obj , PyObject * name , PyObject * value )
74977497{
7498+ // Pyrona: This functions was checked and no further migration is needed
74987499 PyDictValues * values = _PyObject_InlineValues (obj );
74997500 if (!FT_ATOMIC_LOAD_UINT8 (values -> valid )) {
75007501 PyDictObject * dict = _PyObject_GetManagedDict (obj );
@@ -7578,6 +7579,7 @@ _PyObject_ManagedDictValidityCheck(PyObject *obj)
75787579bool
75797580_PyObject_TryGetInstanceAttribute (PyObject * obj , PyObject * name , PyObject * * attr )
75807581{
7582+ // Pyrona: This functions was checked and no further migration is needed
75817583 assert (PyUnicode_CheckExact (name ));
75827584 PyDictValues * values = _PyObject_InlineValues (obj );
75837585 if (!FT_ATOMIC_LOAD_UINT8 (values -> valid )) {
@@ -7724,17 +7726,25 @@ clear_inline_values(PyObject *dict, PyDictValues *values)
77247726 }
77257727}
77267728
7727- static void
7729+ static int
77287730set_dict_inline_values (PyObject * obj , PyDictObject * new_dict )
77297731{
7732+ // Pyrona: This functions was checked and no further migration is needed
77307733 _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (obj );
77317734
77327735 PyDictValues * values = _PyObject_InlineValues (obj );
77337736
7737+ // Regions: The given dictionary should always be in the local region or NULL.
7738+ // This call should always succeed. Since this is a private funciton we changed
7739+ // it to be failable to support other circumstances
7740+ if (PyRegion_AddRef (obj , new_dict )) {
7741+ return -1 ;
7742+ }
77347743 Py_XINCREF (new_dict );
77357744 FT_ATOMIC_STORE_PTR (_PyObject_ManagedDictPointer (obj )-> dict , new_dict );
77367745
77377746 clear_inline_values (obj , values );
7747+ return 0 ;
77387748}
77397749
77407750#ifdef Py_GIL_DISABLED
@@ -7815,6 +7825,7 @@ decref_maybe_delay(PyObject *obj, bool delay)
78157825int
78167826_PyObject_SetManagedDict (PyObject * obj , PyObject * new_dict )
78177827{
7828+ // Pyrona: This functions was checked and no further migration is needed
78187829 assert (Py_TYPE (obj )-> tp_flags & Py_TPFLAGS_MANAGED_DICT );
78197830#ifndef NDEBUG
78207831 Py_BEGIN_CRITICAL_SECTION (obj );
@@ -7863,17 +7874,27 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
78637874
78647875 return 0 ;
78657876#else
7877+ if (!(PyRegion_IsLocal (new_dict ) || PyRegion_SameRegion (obj , new_dict ) || new_dict == NULL )) {
7878+ PyErr_Format (PyExc_RuntimeError ,
7879+ "new dict must be local, in the same region as the object, or NULL, "
7880+ "got object=%R and new_dict=%R" , obj , new_dict );
7881+ return -1 ;
7882+ }
78667883 PyDictObject * dict = _PyObject_GetManagedDict (obj );
78677884 if (dict == NULL ) {
7868- set_dict_inline_values (obj , (PyDictObject * )new_dict );
7869- return 0 ;
7885+ return set_dict_inline_values (obj , (PyDictObject * )new_dict );
78707886 }
78717887 if (_PyDict_DetachFromObject (dict , obj ) == 0 ) {
7888+ // Regions: The function above moves all objects into `dict`. On failure,
7889+ // dict remains set. The failure should therefore not clear the fields
7890+ // but only move them into the managed dict.
7891+ // This should always succeed, due to the local or same region check above.
78727892 if (PyRegion_AddRef (obj , new_dict )) {
78737893 return -1 ;
78747894 }
78757895 _PyObject_ManagedDictPointer (obj )-> dict = (PyDictObject * )Py_XNewRef (new_dict );
78767896 PyRegion_RemoveRef (obj , dict );
7897+ Py_DECREF (dict );
78777898 return 0 ;
78787899 }
78797900 assert (new_dict == NULL );
@@ -7903,9 +7924,20 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
79037924static int
79047925detach_dict_from_object (PyDictObject * mp , PyObject * obj )
79057926{
7927+ // Pyrona: This functions was checked and no further migration is needed
79067928 assert (_PyObject_ManagedDictPointer (obj )-> dict == mp );
79077929 assert (_PyObject_InlineValuesConsistencyCheck (obj ));
79087930
7931+ // Immutability: During deallocation of immutable objects, the object is
7932+ // unfrozen. Here is can happen that the object itself is turned mutable
7933+ // while the dict stayed immutable. This case explicitly allows this.
7934+ if (!(PyRegion_SameRegion (mp , obj ) || (!_Py_IsImmutable (obj ) && _Py_IsImmutable (mp )))) {
7935+ PyErr_Format (PyExc_RuntimeError ,
7936+ "the instance dictionary has to be in the same region as the object"
7937+ "got object=%R and dict=%R" , obj , mp );
7938+ return -1 ;
7939+ }
7940+
79097941 if (FT_ATOMIC_LOAD_PTR_RELAXED (mp -> ma_values ) != _PyObject_InlineValues (obj )) {
79107942 return 0 ;
79117943 }
@@ -7980,6 +8012,7 @@ PyObject_ClearManagedDict(PyObject *obj)
79808012int
79818013_PyDict_DetachFromObject (PyDictObject * mp , PyObject * obj )
79828014{
8015+ // Pyrona: This functions was checked and no further migration is needed
79838016 ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED (obj );
79848017
79858018 return detach_dict_from_object (mp , obj );
@@ -8264,6 +8297,7 @@ _PyDict_SendEvent(int watcher_bits,
82648297static int
82658298_PyObject_InlineValuesConsistencyCheck (PyObject * obj )
82668299{
8300+ // Pyrona: This functions was checked and no further migration is needed
82678301 if ((Py_TYPE (obj )-> tp_flags & Py_TPFLAGS_INLINE_VALUES ) == 0 ) {
82688302 return 1 ;
82698303 }
0 commit comments