@@ -140,6 +140,7 @@ static PyObject* frozendict_new(PyTypeObject *type, PyObject *args,
140140 PyObject * kwds );
141141static PyObject * frozendict_new_untracked (PyTypeObject * type );
142142static PyObject * dict_new (PyTypeObject * type , PyObject * args , PyObject * kwds );
143+ static PyObject * dict_new_untracked (PyTypeObject * type );
143144static int dict_merge (PyObject * a , PyObject * b , int override , PyObject * * dupkey );
144145static int dict_contains (PyObject * op , PyObject * key );
145146static int dict_merge_from_seq2 (PyObject * d , PyObject * seq2 , int override );
@@ -3419,22 +3420,26 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
34193420 PyObject * d ;
34203421 int status ;
34213422
3423+ PyTypeObject * cls_type = _PyType_CAST (cls );
34223424 d = _PyObject_CallNoArgs (cls );
34233425 if (d == NULL ) {
34243426 return NULL ;
34253427 }
3428+ // The constructor returns a tracked object; keep it untracked while it is
3429+ // filled and GC-track it once complete (done:), so a half-built frozendict
3430+ // is never observable.
3431+ _PyObject_GC_UNTRACK (d );
34263432
34273433 // If cls is a dict or frozendict subclass with overridden constructor,
34283434 // copy the frozendict.
3429- PyTypeObject * cls_type = _PyType_CAST (cls );
34303435 if (PyFrozenDict_Check (d ) && cls_type -> tp_new != frozendict_new ) {
34313436 // Subclass-friendly copy
34323437 PyObject * copy ;
34333438 if (PyObject_IsSubclass (cls , (PyObject * )& PyFrozenDict_Type )) {
3434- copy = frozendict_new (cls_type , NULL , NULL );
3439+ copy = frozendict_new_untracked (cls_type );
34353440 }
34363441 else {
3437- copy = dict_new (cls_type , NULL , NULL );
3442+ copy = dict_new_untracked (cls_type );
34383443 }
34393444 if (copy == NULL ) {
34403445 Py_DECREF (d );
@@ -3456,23 +3461,23 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
34563461 Py_BEGIN_CRITICAL_SECTION2 (d , iterable );
34573462 d = (PyObject * )dict_dict_fromkeys (mp , iterable , value );
34583463 Py_END_CRITICAL_SECTION2 ();
3459- return d ;
3464+ goto done ;
34603465 }
34613466 else if (PyFrozenDict_CheckExact (iterable )) {
34623467 PyDictObject * mp = (PyDictObject * )d ;
34633468
34643469 Py_BEGIN_CRITICAL_SECTION (d );
34653470 d = (PyObject * )dict_dict_fromkeys (mp , iterable , value );
34663471 Py_END_CRITICAL_SECTION ();
3467- return d ;
3472+ goto done ;
34683473 }
34693474 else if (PyAnySet_CheckExact (iterable )) {
34703475 PyDictObject * mp = (PyDictObject * )d ;
34713476
34723477 Py_BEGIN_CRITICAL_SECTION2 (d , iterable );
34733478 d = (PyObject * )dict_set_fromkeys (mp , iterable , value );
34743479 Py_END_CRITICAL_SECTION2 ();
3475- return d ;
3480+ goto done ;
34763481 }
34773482 }
34783483 else if (PyFrozenDict_CheckExact (d )) {
@@ -3482,20 +3487,20 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
34823487 Py_BEGIN_CRITICAL_SECTION (iterable );
34833488 d = (PyObject * )dict_dict_fromkeys (mp , iterable , value );
34843489 Py_END_CRITICAL_SECTION ();
3485- return d ;
3490+ goto done ;
34863491 }
34873492 else if (PyFrozenDict_CheckExact (iterable )) {
34883493 PyDictObject * mp = (PyDictObject * )d ;
34893494 d = (PyObject * )dict_dict_fromkeys (mp , iterable , value );
3490- return d ;
3495+ goto done ;
34913496 }
34923497 else if (PyAnySet_CheckExact (iterable )) {
34933498 PyDictObject * mp = (PyDictObject * )d ;
34943499
34953500 Py_BEGIN_CRITICAL_SECTION (iterable );
34963501 d = (PyObject * )dict_set_fromkeys (mp , iterable , value );
34973502 Py_END_CRITICAL_SECTION ();
3498- return d ;
3503+ goto done ;
34993504 }
35003505 }
35013506
@@ -3541,12 +3546,20 @@ dict_iter_exit:;
35413546 if (PyErr_Occurred ())
35423547 goto Fail ;
35433548 Py_DECREF (it );
3544- return d ;
3549+ goto done ;
35453550
35463551Fail :
35473552 Py_DECREF (it );
35483553 Py_DECREF (d );
35493554 return NULL ;
3555+
3556+ done :
3557+ // Built untracked above; GC-track now that it is complete.
3558+ if (d != NULL ) {
3559+ assert (!_PyObject_GC_IS_TRACKED (d ));
3560+ _PyObject_GC_TRACK (d );
3561+ }
3562+ return d ;
35503563}
35513564
35523565/* Methods */
0 commit comments