@@ -3463,12 +3463,9 @@ batch_dict(PickleState *state, PicklerObject *self, PyObject *iter, PyObject *or
34633463 * Returns 0 on success, -1 on error.
34643464 *
34653465 * Note that this currently doesn't work for protocol 0.
3466-
3467- * gh-146452: Wrap the dict iteration in a critical sections to prevent
3468- * concurrent mutation from invalidating PyDict_Next() iteration state.
34693466 */
34703467static int
3471- batch_dict_exact (PickleState * state , PicklerObject * self , PyObject * obj )
3468+ batch_dict_exact_impl (PickleState * state , PicklerObject * self , PyObject * obj )
34723469{
34733470 PyObject * key = NULL , * value = NULL ;
34743471 int i ;
@@ -3482,24 +3479,15 @@ batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj)
34823479 assert (self -> proto > 0 );
34833480
34843481 dict_size = PyDict_GET_SIZE (obj );
3482+ assert (dict_size );
34853483
34863484 /* Write in batches of BATCHSIZE. */
34873485 Py_ssize_t total = 0 ;
34883486 do {
34893487 if (dict_size - total == 1 ) {
3490- int next ;
3491- Py_BEGIN_CRITICAL_SECTION (obj );
3492- next = PyDict_Next (obj , & ppos , & key , & value );
3493- if (next ) {
3494- Py_INCREF (key );
3495- Py_INCREF (value );
3496- }
3497- Py_END_CRITICAL_SECTION ();
3498- if (!next ) {
3499- PyErr_SetString (PyExc_RuntimeError ,
3500- "dictionary changed size during iteration" );
3501- goto error ;
3502- }
3488+ PyDict_Next (obj , & ppos , & key , & value );
3489+ Py_INCREF (key );
3490+ Py_INCREF (value );
35033491 if (save (state , self , key , 0 ) < 0 ) {
35043492 goto error ;
35053493 }
@@ -3517,18 +3505,9 @@ batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj)
35173505 i = 0 ;
35183506 if (_Pickler_Write (self , & mark_op , 1 ) < 0 )
35193507 return -1 ;
3520- int next ;
3521- while (1 ) {
3522- Py_BEGIN_CRITICAL_SECTION (obj );
3523- next = PyDict_Next (obj , & ppos , & key , & value );
3524- if (next ) {
3525- Py_INCREF (key );
3526- Py_INCREF (value );
3527- }
3528- Py_END_CRITICAL_SECTION ();
3529- if (!next ) {
3530- break ;
3531- }
3508+ while (PyDict_Next (obj , & ppos , & key , & value )) {
3509+ Py_INCREF (key );
3510+ Py_INCREF (value );
35323511 if (save (state , self , key , 0 ) < 0 ) {
35333512 goto error ;
35343513 }
@@ -3559,6 +3538,18 @@ batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj)
35593538 return -1 ;
35603539}
35613540
3541+ /* gh-146452: Wrap the dict iteration in a critical section to prevent
3542+ concurrent mutation from invalidating PyDict_Next() iteration state. */
3543+ static int
3544+ batch_dict_exact (PickleState * state , PicklerObject * self , PyObject * obj )
3545+ {
3546+ int ret ;
3547+ Py_BEGIN_CRITICAL_SECTION (obj );
3548+ ret = batch_dict_exact_impl (state , self , obj );
3549+ Py_END_CRITICAL_SECTION ();
3550+ return ret ;
3551+ }
3552+
35623553static int
35633554save_dict (PickleState * state , PicklerObject * self , PyObject * obj )
35643555{
0 commit comments