gh-116738: Make `_csv` module thread-safe (#118344)

This commit is contained in:
AN Long 2024-10-12 01:55:36 +08:00 committed by GitHub
parent 08f6bf7171
commit a00221e5a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 11 additions and 9 deletions

View File

@ -14,6 +14,7 @@ module instead.
#endif #endif
#include "Python.h" #include "Python.h"
#include "pycore_pyatomic_ft_wrappers.h"
#include <stddef.h> // offsetof() #include <stddef.h> // offsetof()
#include <stdbool.h> #include <stdbool.h>
@ -34,7 +35,7 @@ typedef struct {
PyTypeObject *dialect_type; PyTypeObject *dialect_type;
PyTypeObject *reader_type; PyTypeObject *reader_type;
PyTypeObject *writer_type; PyTypeObject *writer_type;
long field_limit; /* max parsed field size */ Py_ssize_t field_limit; /* max parsed field size */
PyObject *str_write; PyObject *str_write;
} _csvstate; } _csvstate;
@ -706,10 +707,11 @@ parse_grow_buff(ReaderObj *self)
static int static int
parse_add_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c) parse_add_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c)
{ {
if (self->field_len >= module_state->field_limit) { Py_ssize_t field_limit = FT_ATOMIC_LOAD_SSIZE_RELAXED(module_state->field_limit);
if (self->field_len >= field_limit) {
PyErr_Format(module_state->error_obj, PyErr_Format(module_state->error_obj,
"field larger than field limit (%ld)", "field larger than field limit (%zd)",
module_state->field_limit); field_limit);
return -1; return -1;
} }
if (self->field_len == self->field_size && !parse_grow_buff(self)) if (self->field_len == self->field_size && !parse_grow_buff(self))
@ -1659,20 +1661,20 @@ _csv_field_size_limit_impl(PyObject *module, PyObject *new_limit)
/*[clinic end generated code: output=f2799ecd908e250b input=cec70e9226406435]*/ /*[clinic end generated code: output=f2799ecd908e250b input=cec70e9226406435]*/
{ {
_csvstate *module_state = get_csv_state(module); _csvstate *module_state = get_csv_state(module);
long old_limit = module_state->field_limit; Py_ssize_t old_limit = FT_ATOMIC_LOAD_SSIZE_RELAXED(module_state->field_limit);
if (new_limit != NULL) { if (new_limit != NULL) {
if (!PyLong_CheckExact(new_limit)) { if (!PyLong_CheckExact(new_limit)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"limit must be an integer"); "limit must be an integer");
return NULL; return NULL;
} }
module_state->field_limit = PyLong_AsLong(new_limit); Py_ssize_t new_limit_value = PyLong_AsSsize_t(new_limit);
if (module_state->field_limit == -1 && PyErr_Occurred()) { if (new_limit_value == -1 && PyErr_Occurred()) {
module_state->field_limit = old_limit;
return NULL; return NULL;
} }
FT_ATOMIC_STORE_SSIZE_RELAXED(module_state->field_limit, new_limit_value);
} }
return PyLong_FromLong(old_limit); return PyLong_FromSsize_t(old_limit);
} }
static PyType_Slot error_slots[] = { static PyType_Slot error_slots[] = {