Skip to content

Commit e1ff17b

Browse files
brijkapadiavstinner
authored andcommitted
gh-154523: Fix data-race in TextIOWrapper.detach() (#154565)
(cherry picked from commit 8440a6a)
1 parent d978860 commit e1ff17b

4 files changed

Lines changed: 62 additions & 2 deletions

File tree

‎Lib/test/test_free_threading/test_io.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,23 @@ def reset_worker():
198198
decoder.reset()
199199

200200
run_concurrently([decode_worker] * 2 + [reset_worker] * 2)
201+
202+
203+
class TextIOWrapperTest(TestCase):
204+
def test_buffer_detach_race(self):
205+
make = lambda: io.TextIOWrapper(io.BytesIO())
206+
slot = [make()]
207+
208+
def reader():
209+
for _ in range(1000):
210+
try:
211+
slot[0].buffer
212+
except ValueError:
213+
pass
214+
215+
def detacher():
216+
for _ in range(1000):
217+
slot[0] = make()
218+
slot[0].detach()
219+
220+
run_concurrently([reader, detacher])
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed data-race when calling :meth:`io.TextIOBase.detach` in
2+
:term:`free-threaded build`.

‎Modules/_io/clinic/textio.c.h‎

Lines changed: 26 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Modules/_io/textio.c‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3426,6 +3426,19 @@ _io_TextIOWrapper__CHUNK_SIZE_set_impl(textio *self, PyObject *value)
34263426
return 0;
34273427
}
34283428

3429+
/*[clinic input]
3430+
@critical_section
3431+
@getter
3432+
_io.TextIOWrapper.buffer
3433+
[clinic start generated code]*/
3434+
3435+
static PyObject *
3436+
_io_TextIOWrapper_buffer_get_impl(textio *self)
3437+
/*[clinic end generated code: output=d265a34555aa5d4b input=5951cfa148f7350a]*/
3438+
{
3439+
return Py_XNewRef(buffer_access_safe(self));
3440+
}
3441+
34293442
static PyMethodDef incrementalnewlinedecoder_methods[] = {
34303443
_IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF
34313444
_IO_INCREMENTALNEWLINEDECODER_GETSTATE_METHODDEF
@@ -3484,7 +3497,6 @@ static PyMethodDef textiowrapper_methods[] = {
34843497

34853498
static PyMemberDef textiowrapper_members[] = {
34863499
{"encoding", _Py_T_OBJECT, offsetof(textio, encoding), Py_READONLY},
3487-
{"buffer", _Py_T_OBJECT, offsetof(textio, buffer), Py_READONLY},
34883500
{"line_buffering", Py_T_BOOL, offsetof(textio, line_buffering), Py_READONLY},
34893501
{"write_through", Py_T_BOOL, offsetof(textio, write_through), Py_READONLY},
34903502
{"_finalizing", Py_T_BOOL, offsetof(textio, finalizing), 0},
@@ -3499,6 +3511,7 @@ static PyGetSetDef textiowrapper_getset[] = {
34993511
_IO_TEXTIOWRAPPER_NEWLINES_GETSETDEF
35003512
_IO_TEXTIOWRAPPER_ERRORS_GETSETDEF
35013513
_IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF
3514+
_IO_TEXTIOWRAPPER_BUFFER_GETSETDEF
35023515
{NULL}
35033516
};
35043517

0 commit comments

Comments
 (0)