From 77d9f1e6d9aad637667264c16c83d255526cc1ba Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 19 Nov 2023 20:34:40 +0800 Subject: [PATCH] gh-111965: Using critical sections to make ``io.StringIO`` thread safe. (gh-112116) --- Modules/_io/clinic/stringio.c.h | 120 ++++++++++++++++++++++++++++++-- Modules/_io/stringio.c | 104 +++++++++++++++++++++------ 2 files changed, 194 insertions(+), 30 deletions(-) diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h index 571ec511714..8e5c687dc6a 100644 --- a/Modules/_io/clinic/stringio.c.h +++ b/Modules/_io/clinic/stringio.c.h @@ -7,6 +7,7 @@ preserve # include "pycore_runtime.h" // _Py_ID() #endif #include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t() +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_modsupport.h" // _PyArg_CheckPositional() PyDoc_STRVAR(_io_StringIO_getvalue__doc__, @@ -24,7 +25,13 @@ _io_StringIO_getvalue_impl(stringio *self); static PyObject * _io_StringIO_getvalue(stringio *self, PyObject *Py_UNUSED(ignored)) { - return _io_StringIO_getvalue_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_StringIO_getvalue_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_io_StringIO_tell__doc__, @@ -42,7 +49,13 @@ _io_StringIO_tell_impl(stringio *self); static PyObject * _io_StringIO_tell(stringio *self, PyObject *Py_UNUSED(ignored)) { - return _io_StringIO_tell_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_StringIO_tell_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_io_StringIO_read__doc__, @@ -76,7 +89,9 @@ _io_StringIO_read(stringio *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_StringIO_read_impl(self, size); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -112,7 +127,9 @@ _io_StringIO_readline(stringio *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_StringIO_readline_impl(self, size); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -150,7 +167,9 @@ _io_StringIO_truncate(stringio *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_StringIO_truncate_impl(self, size); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -204,7 +223,9 @@ _io_StringIO_seek(stringio *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_StringIO_seek_impl(self, pos, whence); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -222,6 +243,21 @@ PyDoc_STRVAR(_io_StringIO_write__doc__, #define _IO_STRINGIO_WRITE_METHODDEF \ {"write", (PyCFunction)_io_StringIO_write, METH_O, _io_StringIO_write__doc__}, +static PyObject * +_io_StringIO_write_impl(stringio *self, PyObject *obj); + +static PyObject * +_io_StringIO_write(stringio *self, PyObject *obj) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_StringIO_write_impl(self, obj); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + PyDoc_STRVAR(_io_StringIO_close__doc__, "close($self, /)\n" "--\n" @@ -242,7 +278,13 @@ _io_StringIO_close_impl(stringio *self); static PyObject * _io_StringIO_close(stringio *self, PyObject *Py_UNUSED(ignored)) { - return _io_StringIO_close_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_StringIO_close_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_io_StringIO___init____doc__, @@ -330,7 +372,13 @@ _io_StringIO_readable_impl(stringio *self); static PyObject * _io_StringIO_readable(stringio *self, PyObject *Py_UNUSED(ignored)) { - return _io_StringIO_readable_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_StringIO_readable_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_io_StringIO_writable__doc__, @@ -348,7 +396,13 @@ _io_StringIO_writable_impl(stringio *self); static PyObject * _io_StringIO_writable(stringio *self, PyObject *Py_UNUSED(ignored)) { - return _io_StringIO_writable_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_StringIO_writable_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_io_StringIO_seekable__doc__, @@ -366,6 +420,58 @@ _io_StringIO_seekable_impl(stringio *self); static PyObject * _io_StringIO_seekable(stringio *self, PyObject *Py_UNUSED(ignored)) { - return _io_StringIO_seekable_impl(self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_StringIO_seekable_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; } -/*[clinic end generated code: output=f56aa7f8a271acf6 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_io_StringIO___getstate____doc__, +"__getstate__($self, /)\n" +"--\n" +"\n"); + +#define _IO_STRINGIO___GETSTATE___METHODDEF \ + {"__getstate__", (PyCFunction)_io_StringIO___getstate__, METH_NOARGS, _io_StringIO___getstate____doc__}, + +static PyObject * +_io_StringIO___getstate___impl(stringio *self); + +static PyObject * +_io_StringIO___getstate__(stringio *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_StringIO___getstate___impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(_io_StringIO___setstate____doc__, +"__setstate__($self, state, /)\n" +"--\n" +"\n"); + +#define _IO_STRINGIO___SETSTATE___METHODDEF \ + {"__setstate__", (PyCFunction)_io_StringIO___setstate__, METH_O, _io_StringIO___setstate____doc__}, + +static PyObject * +_io_StringIO___setstate___impl(stringio *self, PyObject *state); + +static PyObject * +_io_StringIO___setstate__(stringio *self, PyObject *state) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_StringIO___setstate___impl(self, state); + Py_END_CRITICAL_SECTION(); + + return return_value; +} +/*[clinic end generated code: output=5c8d67f4408a1e6e input=a9049054013a1b77]*/ diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 1856b07108b..0aa5e34cd7c 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -45,6 +45,10 @@ typedef struct { _PyIO_State *module_state; } stringio; +#define clinic_state() (find_io_state_by_def(Py_TYPE(self))) +#include "clinic/stringio.c.h" +#undef clinic_state + static int _io_StringIO___init__(PyObject *self, PyObject *args, PyObject *kwargs); #define CHECK_INITIALIZED(self) \ @@ -263,6 +267,7 @@ fail: } /*[clinic input] +@critical_section _io.StringIO.getvalue Retrieve the entire contents of the object. @@ -270,7 +275,7 @@ Retrieve the entire contents of the object. static PyObject * _io_StringIO_getvalue_impl(stringio *self) -/*[clinic end generated code: output=27b6a7bfeaebce01 input=d23cb81d6791cf88]*/ +/*[clinic end generated code: output=27b6a7bfeaebce01 input=fb5dee06b8d467f3]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); @@ -281,6 +286,7 @@ _io_StringIO_getvalue_impl(stringio *self) } /*[clinic input] +@critical_section _io.StringIO.tell Tell the current file position. @@ -288,7 +294,7 @@ Tell the current file position. static PyObject * _io_StringIO_tell_impl(stringio *self) -/*[clinic end generated code: output=2e87ac67b116c77b input=ec866ebaff02f405]*/ +/*[clinic end generated code: output=2e87ac67b116c77b input=98a08f3e2dae3550]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); @@ -296,6 +302,7 @@ _io_StringIO_tell_impl(stringio *self) } /*[clinic input] +@critical_section _io.StringIO.read size: Py_ssize_t(accept={int, NoneType}) = -1 / @@ -308,7 +315,7 @@ is reached. Return an empty string at EOF. static PyObject * _io_StringIO_read_impl(stringio *self, Py_ssize_t size) -/*[clinic end generated code: output=ae8cf6002f71626c input=0921093383dfb92d]*/ +/*[clinic end generated code: output=ae8cf6002f71626c input=9fbef45d8aece8e7]*/ { Py_ssize_t n; Py_UCS4 *output; @@ -368,6 +375,7 @@ _stringio_readline(stringio *self, Py_ssize_t limit) } /*[clinic input] +@critical_section _io.StringIO.readline size: Py_ssize_t(accept={int, NoneType}) = -1 / @@ -379,7 +387,7 @@ Returns an empty string if EOF is hit immediately. static PyObject * _io_StringIO_readline_impl(stringio *self, Py_ssize_t size) -/*[clinic end generated code: output=cabd6452f1b7e85d input=a5bd70bf682aa276]*/ +/*[clinic end generated code: output=cabd6452f1b7e85d input=4d14b8495dea1d98]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); @@ -427,6 +435,7 @@ stringio_iternext(stringio *self) } /*[clinic input] +@critical_section _io.StringIO.truncate pos as size: Py_ssize_t(accept={int, NoneType}, c_default="self->pos") = None / @@ -440,7 +449,7 @@ Returns the new absolute position. static PyObject * _io_StringIO_truncate_impl(stringio *self, Py_ssize_t size) -/*[clinic end generated code: output=eb3aef8e06701365 input=5505cff90ca48b96]*/ +/*[clinic end generated code: output=eb3aef8e06701365 input=461b872dce238452]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); @@ -462,6 +471,7 @@ _io_StringIO_truncate_impl(stringio *self, Py_ssize_t size) } /*[clinic input] +@critical_section _io.StringIO.seek pos: Py_ssize_t whence: int = 0 @@ -478,7 +488,7 @@ Returns the new absolute position. static PyObject * _io_StringIO_seek_impl(stringio *self, Py_ssize_t pos, int whence) -/*[clinic end generated code: output=e9e0ac9a8ae71c25 input=e3855b24e7cae06a]*/ +/*[clinic end generated code: output=e9e0ac9a8ae71c25 input=c75ced09343a00d7]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); @@ -515,6 +525,7 @@ _io_StringIO_seek_impl(stringio *self, Py_ssize_t pos, int whence) } /*[clinic input] +@critical_section _io.StringIO.write s as obj: object / @@ -526,8 +537,8 @@ the length of the string. [clinic start generated code]*/ static PyObject * -_io_StringIO_write(stringio *self, PyObject *obj) -/*[clinic end generated code: output=0deaba91a15b94da input=cf96f3b16586e669]*/ +_io_StringIO_write_impl(stringio *self, PyObject *obj) +/*[clinic end generated code: output=d53b1d841d7db288 input=1561272c0da4651f]*/ { Py_ssize_t size; @@ -547,6 +558,7 @@ _io_StringIO_write(stringio *self, PyObject *obj) } /*[clinic input] +@critical_section _io.StringIO.close Close the IO object. @@ -559,7 +571,7 @@ This method has no effect if the file is already closed. static PyObject * _io_StringIO_close_impl(stringio *self) -/*[clinic end generated code: output=04399355cbe518f1 input=cbc10b45f35d6d46]*/ +/*[clinic end generated code: output=04399355cbe518f1 input=305d19aa29cc40b9]*/ { self->closed = 1; /* Free up some memory */ @@ -756,6 +768,7 @@ _io_StringIO___init___impl(stringio *self, PyObject *value, /* Properties and pseudo-properties */ /*[clinic input] +@critical_section _io.StringIO.readable Returns True if the IO object can be read. @@ -763,7 +776,7 @@ Returns True if the IO object can be read. static PyObject * _io_StringIO_readable_impl(stringio *self) -/*[clinic end generated code: output=b19d44dd8b1ceb99 input=39ce068b224c21ad]*/ +/*[clinic end generated code: output=b19d44dd8b1ceb99 input=6cd2ffd65a8e8763]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); @@ -771,6 +784,7 @@ _io_StringIO_readable_impl(stringio *self) } /*[clinic input] +@critical_section _io.StringIO.writable Returns True if the IO object can be written. @@ -778,7 +792,7 @@ Returns True if the IO object can be written. static PyObject * _io_StringIO_writable_impl(stringio *self) -/*[clinic end generated code: output=13e4dd77187074ca input=7a691353aac38835]*/ +/*[clinic end generated code: output=13e4dd77187074ca input=1b3c63dbaa761c69]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); @@ -786,6 +800,7 @@ _io_StringIO_writable_impl(stringio *self) } /*[clinic input] +@critical_section _io.StringIO.seekable Returns True if the IO object can be seeked. @@ -793,7 +808,7 @@ Returns True if the IO object can be seeked. static PyObject * _io_StringIO_seekable_impl(stringio *self) -/*[clinic end generated code: output=4d20b4641c756879 input=4c606d05b32952e6]*/ +/*[clinic end generated code: output=4d20b4641c756879 input=a820fad2cf085fc3]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); @@ -812,8 +827,15 @@ _io_StringIO_seekable_impl(stringio *self) supported. */ +/*[clinic input] +@critical_section +_io.StringIO.__getstate__ + +[clinic start generated code]*/ + static PyObject * -stringio_getstate(stringio *self, PyObject *Py_UNUSED(ignored)) +_io_StringIO___getstate___impl(stringio *self) +/*[clinic end generated code: output=780be4a996410199 input=76f27255ef83bb92]*/ { PyObject *initvalue = _io_StringIO_getvalue_impl(self); PyObject *dict; @@ -839,8 +861,17 @@ stringio_getstate(stringio *self, PyObject *Py_UNUSED(ignored)) return state; } +/*[clinic input] +@critical_section +_io.StringIO.__setstate__ + + state: object + / +[clinic start generated code]*/ + static PyObject * -stringio_setstate(stringio *self, PyObject *state) +_io_StringIO___setstate___impl(stringio *self, PyObject *state) +/*[clinic end generated code: output=cb3962bc6d5c5609 input=8a27784b11b82e47]*/ { PyObject *initarg; PyObject *position_obj; @@ -941,14 +972,24 @@ stringio_setstate(stringio *self, PyObject *state) static PyObject * -stringio_closed(stringio *self, void *context) +stringio_closed_impl(stringio *self, void *context) { CHECK_INITIALIZED(self); return PyBool_FromLong(self->closed); } static PyObject * -stringio_line_buffering(stringio *self, void *context) +stringio_closed(stringio *self, void *context) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(self); + result = stringio_closed_impl(self, context); + Py_END_CRITICAL_SECTION(); + return result; +} + +static PyObject * +stringio_line_buffering_impl(stringio *self, void *context) { CHECK_INITIALIZED(self); CHECK_CLOSED(self); @@ -956,18 +997,35 @@ stringio_line_buffering(stringio *self, void *context) } static PyObject * -stringio_newlines(stringio *self, void *context) +stringio_line_buffering(stringio *self, void *context) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(self); + result = stringio_line_buffering_impl(self, context); + Py_END_CRITICAL_SECTION(); + return result; +} + +static PyObject * +stringio_newlines_impl(stringio *self, void *context) { CHECK_INITIALIZED(self); CHECK_CLOSED(self); - if (self->decoder == NULL) + if (self->decoder == NULL) { Py_RETURN_NONE; + } return PyObject_GetAttr(self->decoder, &_Py_ID(newlines)); } -#define clinic_state() (find_io_state_by_def(Py_TYPE(self))) -#include "clinic/stringio.c.h" -#undef clinic_state +static PyObject * +stringio_newlines(stringio *self, void *context) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(self); + result = stringio_newlines_impl(self, context); + Py_END_CRITICAL_SECTION(); + return result; +} static struct PyMethodDef stringio_methods[] = { _IO_STRINGIO_CLOSE_METHODDEF @@ -983,8 +1041,8 @@ static struct PyMethodDef stringio_methods[] = { _IO_STRINGIO_READABLE_METHODDEF _IO_STRINGIO_WRITABLE_METHODDEF - {"__getstate__", (PyCFunction)stringio_getstate, METH_NOARGS}, - {"__setstate__", (PyCFunction)stringio_setstate, METH_O}, + _IO_STRINGIO___GETSTATE___METHODDEF + _IO_STRINGIO___SETSTATE___METHODDEF {NULL, NULL} /* sentinel */ };