@@ -5465,6 +5465,42 @@ _Py_type_getattro(PyObject *type, PyObject *name)
5465
5465
return _Py_type_getattro_impl ((PyTypeObject * )type , name , NULL );
5466
5466
}
5467
5467
5468
+ static int
5469
+ type_update_dict (PyTypeObject * type , PyDictObject * dict , PyObject * name ,
5470
+ PyObject * value , PyObject * * old_value )
5471
+ {
5472
+ // We don't want any re-entrancy between when we update the dict
5473
+ // and call type_modified_unlocked, including running the destructor
5474
+ // of the current value as it can observe the cache in an inconsistent
5475
+ // state. Because we have an exact unicode and our dict has exact
5476
+ // unicodes we know that this will all complete without releasing
5477
+ // the locks.
5478
+ if (_PyDict_GetItemRef_Unicode_LockHeld (dict , name , old_value ) < 0 ) {
5479
+ return -1 ;
5480
+ }
5481
+
5482
+ /* Clear the VALID_VERSION flag of 'type' and all its
5483
+ subclasses. This could possibly be unified with the
5484
+ update_subclasses() recursion in update_slot(), but carefully:
5485
+ they each have their own conditions on which to stop
5486
+ recursing into subclasses. */
5487
+ type_modified_unlocked (type );
5488
+
5489
+ if (_PyDict_SetItem_LockHeld (dict , name , value ) < 0 ) {
5490
+ PyErr_Format (PyExc_AttributeError ,
5491
+ "type object '%.50s' has no attribute '%U'" ,
5492
+ ((PyTypeObject * )type )-> tp_name , name );
5493
+ _PyObject_SetAttributeErrorContext ((PyObject * )type , name );
5494
+ return -1 ;
5495
+ }
5496
+
5497
+ if (is_dunder_name (name )) {
5498
+ return update_slot (type , name );
5499
+ }
5500
+
5501
+ return 0 ;
5502
+ }
5503
+
5468
5504
static int
5469
5505
type_setattro (PyObject * self , PyObject * name , PyObject * value )
5470
5506
{
@@ -5507,12 +5543,11 @@ type_setattro(PyObject *self, PyObject *name, PyObject *value)
5507
5543
assert (!_PyType_HasFeature (metatype , Py_TPFLAGS_INLINE_VALUES ));
5508
5544
assert (!_PyType_HasFeature (metatype , Py_TPFLAGS_MANAGED_DICT ));
5509
5545
5510
- PyObject * old_value ;
5546
+ PyObject * old_value = NULL ;
5511
5547
PyObject * descr = _PyType_LookupRef (metatype , name );
5512
5548
if (descr != NULL ) {
5513
5549
descrsetfunc f = Py_TYPE (descr )-> tp_descr_set ;
5514
5550
if (f != NULL ) {
5515
- old_value = NULL ;
5516
5551
res = f (descr , (PyObject * )type , value );
5517
5552
goto done ;
5518
5553
}
@@ -5528,47 +5563,16 @@ type_setattro(PyObject *self, PyObject *name, PyObject *value)
5528
5563
}
5529
5564
END_TYPE_LOCK ();
5530
5565
if (dict == NULL ) {
5531
- return -1 ;
5566
+ res = -1 ;
5567
+ goto done ;
5532
5568
}
5533
5569
}
5534
5570
5535
- // We don't want any re-entrancy between when we update the dict
5536
- // and call type_modified_unlocked, including running the destructor
5537
- // of the current value as it can observe the cache in an inconsistent
5538
- // state. Because we have an exact unicode and our dict has exact
5539
- // unicodes we know that this will all complete without releasing
5540
- // the locks.
5541
5571
BEGIN_TYPE_DICT_LOCK (dict );
5542
-
5543
- if (_PyDict_GetItemRef_Unicode_LockHeld ((PyDictObject * )dict , name , & old_value ) < 0 ) {
5544
- return -1 ;
5545
- }
5546
-
5547
- /* Clear the VALID_VERSION flag of 'type' and all its
5548
- subclasses. This could possibly be unified with the
5549
- update_subclasses() recursion in update_slot(), but carefully:
5550
- they each have their own conditions on which to stop
5551
- recursing into subclasses. */
5552
- type_modified_unlocked (type );
5553
-
5554
- res = _PyDict_SetItem_LockHeld ((PyDictObject * )dict , name , value );
5555
-
5556
- if (res == 0 ) {
5557
- if (is_dunder_name (name )) {
5558
- res = update_slot (type , name );
5559
- }
5560
- }
5561
- else if (PyErr_ExceptionMatches (PyExc_KeyError )) {
5562
- PyErr_Format (PyExc_AttributeError ,
5563
- "type object '%.50s' has no attribute '%U'" ,
5564
- ((PyTypeObject * )type )-> tp_name , name );
5565
-
5566
- _PyObject_SetAttributeErrorContext ((PyObject * )type , name );
5567
- }
5568
-
5572
+ res = type_update_dict (type , (PyDictObject * )dict , name , value , & old_value );
5569
5573
assert (_PyType_CheckConsistency (type ));
5570
-
5571
5574
END_TYPE_DICT_LOCK ();
5575
+
5572
5576
done :
5573
5577
Py_DECREF (name );
5574
5578
Py_XDECREF (descr );
0 commit comments