@@ -5656,6 +5656,42 @@ _Py_type_getattro(PyObject *type, PyObject *name)
5656
5656
return _Py_type_getattro_impl ((PyTypeObject * )type , name , NULL );
5657
5657
}
5658
5658
5659
+ static int
5660
+ type_update_dict (PyTypeObject * type , PyDictObject * dict , PyObject * name ,
5661
+ PyObject * value , PyObject * * old_value )
5662
+ {
5663
+ // We don't want any re-entrancy between when we update the dict
5664
+ // and call type_modified_unlocked, including running the destructor
5665
+ // of the current value as it can observe the cache in an inconsistent
5666
+ // state. Because we have an exact unicode and our dict has exact
5667
+ // unicodes we know that this will all complete without releasing
5668
+ // the locks.
5669
+ if (_PyDict_GetItemRef_Unicode_LockHeld (dict , name , old_value ) < 0 ) {
5670
+ return -1 ;
5671
+ }
5672
+
5673
+ /* Clear the VALID_VERSION flag of 'type' and all its
5674
+ subclasses. This could possibly be unified with the
5675
+ update_subclasses() recursion in update_slot(), but carefully:
5676
+ they each have their own conditions on which to stop
5677
+ recursing into subclasses. */
5678
+ type_modified_unlocked (type );
5679
+
5680
+ if (_PyDict_SetItem_LockHeld (dict , name , value ) < 0 ) {
5681
+ PyErr_Format (PyExc_AttributeError ,
5682
+ "type object '%.50s' has no attribute '%U'" ,
5683
+ ((PyTypeObject * )type )-> tp_name , name );
5684
+ _PyObject_SetAttributeErrorContext ((PyObject * )type , name );
5685
+ return -1 ;
5686
+ }
5687
+
5688
+ if (is_dunder_name (name )) {
5689
+ return update_slot (type , name );
5690
+ }
5691
+
5692
+ return 0 ;
5693
+ }
5694
+
5659
5695
static int
5660
5696
type_setattro (PyObject * self , PyObject * name , PyObject * value )
5661
5697
{
@@ -5698,12 +5734,11 @@ type_setattro(PyObject *self, PyObject *name, PyObject *value)
5698
5734
assert (!_PyType_HasFeature (metatype , Py_TPFLAGS_INLINE_VALUES ));
5699
5735
assert (!_PyType_HasFeature (metatype , Py_TPFLAGS_MANAGED_DICT ));
5700
5736
5701
- PyObject * old_value ;
5737
+ PyObject * old_value = NULL ;
5702
5738
PyObject * descr = _PyType_LookupRef (metatype , name );
5703
5739
if (descr != NULL ) {
5704
5740
descrsetfunc f = Py_TYPE (descr )-> tp_descr_set ;
5705
5741
if (f != NULL ) {
5706
- old_value = NULL ;
5707
5742
res = f (descr , (PyObject * )type , value );
5708
5743
goto done ;
5709
5744
}
@@ -5719,47 +5754,16 @@ type_setattro(PyObject *self, PyObject *name, PyObject *value)
5719
5754
}
5720
5755
END_TYPE_LOCK ();
5721
5756
if (dict == NULL ) {
5722
- return -1 ;
5757
+ res = -1 ;
5758
+ goto done ;
5723
5759
}
5724
5760
}
5725
5761
5726
- // We don't want any re-entrancy between when we update the dict
5727
- // and call type_modified_unlocked, including running the destructor
5728
- // of the current value as it can observe the cache in an inconsistent
5729
- // state. Because we have an exact unicode and our dict has exact
5730
- // unicodes we know that this will all complete without releasing
5731
- // the locks.
5732
5762
BEGIN_TYPE_DICT_LOCK (dict );
5733
-
5734
- if (_PyDict_GetItemRef_Unicode_LockHeld ((PyDictObject * )dict , name , & old_value ) < 0 ) {
5735
- return -1 ;
5736
- }
5737
-
5738
- /* Clear the VALID_VERSION flag of 'type' and all its
5739
- subclasses. This could possibly be unified with the
5740
- update_subclasses() recursion in update_slot(), but carefully:
5741
- they each have their own conditions on which to stop
5742
- recursing into subclasses. */
5743
- type_modified_unlocked (type );
5744
-
5745
- res = _PyDict_SetItem_LockHeld ((PyDictObject * )dict , name , value );
5746
-
5747
- if (res == 0 ) {
5748
- if (is_dunder_name (name )) {
5749
- res = update_slot (type , name );
5750
- }
5751
- }
5752
- else if (PyErr_ExceptionMatches (PyExc_KeyError )) {
5753
- PyErr_Format (PyExc_AttributeError ,
5754
- "type object '%.50s' has no attribute '%U'" ,
5755
- ((PyTypeObject * )type )-> tp_name , name );
5756
-
5757
- _PyObject_SetAttributeErrorContext ((PyObject * )type , name );
5758
- }
5759
-
5763
+ res = type_update_dict (type , (PyDictObject * )dict , name , value , & old_value );
5760
5764
assert (_PyType_CheckConsistency (type ));
5761
-
5762
5765
END_TYPE_DICT_LOCK ();
5766
+
5763
5767
done :
5764
5768
Py_DECREF (name );
5765
5769
Py_XDECREF (descr );
0 commit comments