| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 5673748 commit 57a0e57
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Fix race condition when pickling dictionaries in free threaded builds. Also | ||
| 2 | + reduce critical section cover. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3450,9 +3450,12 @@ batch_dict(PickleState *state, PicklerObject *self, PyObject *iter, PyObject *or | |||
| 3450 | 3450 | * Returns 0 on success, -1 on error. | |
| 3451 | 3451 | * | |
| 3452 | 3452 | * Note that this currently doesn't work for protocol 0. | |
| 3453 | + | ||
| 3454 | + * gh-146452: Wrap the dict iteration in a critical sections to prevent | ||
| 3455 | + * concurrent mutation from invalidating PyDict_Next() iteration state. | ||
| 3453 | 3456 | */ | |
| 3454 | 3457 | static int | |
| 3455 | - batch_dict_exact_impl(PickleState *state, PicklerObject *self, PyObject *obj) | ||
| 3458 | + batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj) | ||
| 3456 | 3459 | { | |
| 3457 | 3460 | PyObject *key = NULL, *value = NULL; | |
| 3458 | 3461 | int i; | |
@@ -3466,15 +3469,24 @@ batch_dict_exact_impl(PickleState *state, PicklerObject *self, PyObject *obj) | |||
| 3466 | 3469 | assert(self->proto > 0); | |
| 3467 | 3470 | ||
| 3468 | 3471 | dict_size = PyDict_GET_SIZE(obj); | |
| 3469 | - assert(dict_size); | ||
| 3470 | 3472 | ||
| 3471 | 3473 | /* Write in batches of BATCHSIZE. */ | |
| 3472 | 3474 | Py_ssize_t total = 0; | |
| 3473 | 3475 | do { | |
| 3474 | 3476 | if (dict_size - total == 1) { | |
| 3475 | - PyDict_Next(obj, &ppos, &key, &value); | ||
| 3476 | - Py_INCREF(key); | ||
| 3477 | - Py_INCREF(value); | ||
| 3477 | + int next; | ||
| 3478 | + Py_BEGIN_CRITICAL_SECTION(obj); | ||
| 3479 | + next = PyDict_Next(obj, &ppos, &key, &value); | ||
| 3480 | + if (next) { | ||
| 3481 | + Py_INCREF(key); | ||
| 3482 | + Py_INCREF(value); | ||
| 3483 | + } | ||
| 3484 | + Py_END_CRITICAL_SECTION(); | ||
| 3485 | + if (!next) { | ||
| 3486 | + PyErr_SetString(PyExc_RuntimeError, | ||
| 3487 | + "dictionary changed size during iteration"); | ||
| 3488 | + goto error; | ||
| 3489 | + } | ||
| 3478 | 3490 | if (save(state, self, key, 0) < 0) { | |
| 3479 | 3491 | goto error; | |
| 3480 | 3492 | } | |
@@ -3492,9 +3504,18 @@ batch_dict_exact_impl(PickleState *state, PicklerObject *self, PyObject *obj) | |||
| 3492 | 3504 | i = 0; | |
| 3493 | 3505 | if (_Pickler_Write(self, &mark_op, 1) < 0) | |
| 3494 | 3506 | return -1; | |
| 3495 | - while (PyDict_Next(obj, &ppos, &key, &value)) { | ||
| 3496 | - Py_INCREF(key); | ||
| 3497 | - Py_INCREF(value); | ||
| 3507 | + int next; | ||
| 3508 | + while (1) { | ||
| 3509 | + Py_BEGIN_CRITICAL_SECTION(obj); | ||
| 3510 | + next = PyDict_Next(obj, &ppos, &key, &value); | ||
| 3511 | + if (next) { | ||
| 3512 | + Py_INCREF(key); | ||
| 3513 | + Py_INCREF(value); | ||
| 3514 | + } | ||
| 3515 | + Py_END_CRITICAL_SECTION(); | ||
| 3516 | + if (!next) { | ||
| 3517 | + break; | ||
| 3518 | + } | ||
| 3498 | 3519 | if (save(state, self, key, 0) < 0) { | |
| 3499 | 3520 | goto error; | |
| 3500 | 3521 | } | |
@@ -3525,18 +3546,6 @@ batch_dict_exact_impl(PickleState *state, PicklerObject *self, PyObject *obj) | |||
| 3525 | 3546 | return -1; | |
| 3526 | 3547 | } | |
| 3527 | 3548 | ||
| 3528 | - /* gh-146452: Wrap the dict iteration in a critical section to prevent | ||
| 3529 | - concurrent mutation from invalidating PyDict_Next() iteration state. */ | ||
| 3530 | - static int | ||
| 3531 | - batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj) | ||
| 3532 | - { | ||
| 3533 | - int ret; | ||
| 3534 | - Py_BEGIN_CRITICAL_SECTION(obj); | ||
| 3535 | - ret = batch_dict_exact_impl(state, self, obj); | ||
| 3536 | - Py_END_CRITICAL_SECTION(); | ||
| 3537 | - return ret; | ||
| 3538 | - } | ||
| 3539 | - | ||
| 3540 | 3549 | static int | |
| 3541 | 3550 | save_dict(PickleState *state, PicklerObject *self, PyObject *obj) | |
| 3542 | 3551 | { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments