Bug report
Bug description:
_io_StringIO___init___impl resets the entire object state with no critical section,
|
self->ok = 0; |
|
|
|
PyUnicodeWriter_Discard(self->writer); |
|
self->writer = NULL; |
|
Py_CLEAR(self->readnl); |
|
Py_CLEAR(self->writenl); |
|
Py_CLEAR(self->decoder); |
|
|
|
assert((newline != NULL && newline_obj != Py_None) || |
|
(newline == NULL && newline_obj == Py_None)); |
|
|
|
if (newline) { |
|
self->readnl = PyUnicode_FromString(newline); |
|
if (self->readnl == NULL) |
|
return -1; |
|
} |
|
self->readuniversal = (newline == NULL || newline[0] == '\0'); |
|
self->readtranslate = (newline == NULL); |
|
/* If newline == "", we don't translate anything. |
|
If newline == "\n" or newline == None, we translate to "\n", which is |
|
a no-op. |
|
(for newline == None, TextIOWrapper translates to os.linesep, but it |
|
is pointless for StringIO) |
|
*/ |
|
if (newline != NULL && newline[0] == '\r') { |
|
self->writenl = Py_NewRef(self->readnl); |
|
} |
|
|
|
_PyIO_State *module_state = find_io_state_by_def(Py_TYPE(self)); |
|
if (self->readuniversal) { |
|
self->decoder = PyObject_CallFunctionObjArgs( |
|
(PyObject *)module_state->PyIncrementalNewlineDecoder_Type, |
|
Py_None, self->readtranslate ? Py_True : Py_False, NULL); |
|
if (self->decoder == NULL) |
|
return -1; |
|
} |
|
|
|
/* Now everything is set up, resize buffer to size of initial value, |
|
and copy it */ |
|
self->string_size = 0; |
|
if (value && value != Py_None) |
|
value_len = PyUnicode_GetLength(value); |
|
else |
|
value_len = 0; |
|
if (value_len > 0) { |
|
/* This is a heuristic, for newline translation might change |
|
the string length. */ |
|
if (resize_buffer(self, 0) < 0) |
|
return -1; |
|
self->state = STATE_REALIZED; |
|
self->pos = 0; |
|
if (write_str(self, value) < 0) |
|
return -1; |
|
} |
|
else { |
|
/* Empty stringio object, we can start by accumulating */ |
|
if (resize_buffer(self, 0) < 0) |
|
return -1; |
|
self->writer = PyUnicodeWriter_Create(0); |
|
if (self->writer == NULL) { |
|
return -1; |
|
} |
|
self->state = STATE_ACCUMULATING; |
|
} |
|
self->pos = 0; |
|
self->module_state = module_state; |
|
self->closed = 0; |
|
self->ok = 1; |
while _io_StringIO_truncate_impl reads/writes the same fields under critical section.
|
static PyObject * |
|
_io_StringIO_truncate_impl(stringio *self, PyObject *pos) |
|
/*[clinic end generated code: output=c76c43b5ecfaf4e2 input=d59fd2ee49757ae6]*/ |
|
{ |
|
CHECK_INITIALIZED(self); |
|
CHECK_CLOSED(self); |
|
|
|
Py_ssize_t size; |
|
if (pos == Py_None) { |
|
size = self->pos; |
|
} |
|
else { |
|
size = PyLong_AsLong(pos); |
|
if (size == -1 && PyErr_Occurred()) { |
|
return NULL; |
|
} |
|
if (size < 0) { |
|
PyErr_Format(PyExc_ValueError, |
|
"negative pos value %zd", size); |
|
return NULL; |
|
} |
|
} |
|
|
|
if (size < self->string_size) { |
|
ENSURE_REALIZED(self); |
|
if (resize_buffer(self, size) < 0) |
|
return NULL; |
|
self->string_size = size; |
|
} |
|
|
|
return PyLong_FromSsize_t(size); |
|
} |
If a thread inside __init__ and a thread inside truncate both reach PyMem_Realloc(self->buf, …) via resize_buffer() concurrently, it can corrupt the mimalloc heap and crashes with segfault in free-threading build.
Reproducer:
import io
from threading import Thread, Barrier
buf = io.StringIO('initial', newline='\n')
N_TRUNC = 7
ITERS = 10000
barrier = Barrier(1 + N_TRUNC)
def init_thread():
barrier.wait()
for i in range(ITERS):
if i & 1:
buf.__init__('data', None)
else:
buf.__init__('more', '\n')
def trunc_thread():
barrier.wait()
for i in range(ITERS):
try:
if i % 3 == 0:
buf.truncate(None)
else:
buf.truncate(i & 7)
except Exception:
pass
if __name__ == "__main__":
threads = [Thread(target=init_thread)]
threads += [Thread(target=trunc_thread) for _ in range(N_TRUNC)]
for t in threads: t.start()
for t in threads: t.join()
TSAN Report:
==================
==================
WARNING: ThreadSanitizer: data race (pid=658985)
Read of size 8 at 0x7fffb6331cf8 by thread T7:
#0 resize_buffer /cpython/./Modules/_io/stringio.c:85:26 (python3.16t+0x5ea66f)
#1 _io_StringIO_truncate_impl /cpython/./Modules/_io/stringio.c:483:13 (python3.16t+0x5ea66f)
#2 _io_StringIO_truncate /cpython/./Modules/_io/clinic/stringio.c.h:169:20 (python3.16t+0x5ea66f)
#3 _PyCallMethodDescriptorFast_StackRef /cpython/Python/ceval.c:860:11 (python3.16t+0x44273f)
#4 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:3910:35 (python3.16t+0x44273f)
#5 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#6 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#7 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#8 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#9 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#10 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#11 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x48ec15)
#12 context_run /cpython/Python/context.c:728:29 (python3.16t+0x48ec15)
#13 method_vectorcall_FASTCALL_KEYWORDS /cpython/Objects/descrobject.c:421:24 (python3.16t+0x22e84c)
#14 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x2149a8)
#15 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.16t+0x2149a8)
#16 _Py_VectorCallInstrumentation_StackRefSteal /cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8)
#17 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022)
#18 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#19 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#20 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#21 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#22 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#23 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#24 _PyVectorcall_Call /cpython/Objects/call.c:273:16 (python3.16t+0x214ca2)
#25 _PyObject_Call /cpython/Objects/call.c:348:16 (python3.16t+0x214ca2)
#26 PyObject_Call /cpython/Objects/call.c:373:12 (python3.16t+0x214d07)
#27 thread_run /cpython/./Modules/_threadmodule.c:388:21 (python3.16t+0x61a708)
#28 pythread_wrapper /cpython/Python/thread_pthread.h:234:5 (python3.16t+0x5473bb)
Previous write of size 8 at 0x7fffb6331cf8 by thread T1:
#0 resize_buffer /cpython/./Modules/_io/stringio.c:121:20 (python3.16t+0x5ec04b)
#1 write_str /cpython/./Modules/_io/stringio.c:237:13 (python3.16t+0x5ec04b)
#2 _io_StringIO___init___impl /cpython/./Modules/_io/stringio.c:772:13 (python3.16t+0x5e90b6)
#3 _io_StringIO___init__ /cpython/./Modules/_io/clinic/stringio.c.h:356:20 (python3.16t+0x5e90b6)
#4 wrap_init /cpython/Objects/typeobject.c:10392:9 (python3.16t+0x3506eb)
#5 wrapperdescr_raw_call /cpython/Objects/descrobject.c:523:16 (python3.16t+0x22dd94)
#6 wrapperdescr_call /cpython/Objects/descrobject.c:570:14 (python3.16t+0x22dd94)
#7 _PyObject_MakeTpCall /cpython/Objects/call.c:242:18 (python3.16t+0x213bfd)
#8 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:142:16 (python3.16t+0x214a70)
#9 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.16t+0x214a70)
#10 _Py_VectorCallInstrumentation_StackRefSteal /cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8)
#11 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022)
#12 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#13 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#14 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#15 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#16 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#17 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#18 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x48ec15)
#19 context_run /cpython/Python/context.c:728:29 (python3.16t+0x48ec15)
#20 method_vectorcall_FASTCALL_KEYWORDS /cpython/Objects/descrobject.c:421:24 (python3.16t+0x22e84c)
#21 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x2149a8)
#22 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.16t+0x2149a8)
#23 _Py_VectorCallInstrumentation_StackRefSteal /cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8)
#24 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022)
#25 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#26 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#27 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#28 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#29 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#30 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#31 _PyVectorcall_Call /cpython/Objects/call.c:273:16 (python3.16t+0x214ca2)
#32 _PyObject_Call /cpython/Objects/call.c:348:16 (python3.16t+0x214ca2)
#33 PyObject_Call /cpython/Objects/call.c:373:12 (python3.16t+0x214d07)
#34 thread_run /cpython/./Modules/_threadmodule.c:388:21 (python3.16t+0x61a708)
#35 pythread_wrapper /cpython/Python/thread_pthread.h:234:5 (python3.16t+0x5473bb)
...
WARNING: ThreadSanitizer: data race (pid=658985)
Read of size 4 at 0x7fffb800092c by thread T7:
#0 mi_slice_first /cpython/./Include/internal/mimalloc/mimalloc/internal.h:423:62 (python3.16t+0x2dd743)
#1 _mi_segment_page_of /cpython/./Include/internal/mimalloc/mimalloc/internal.h:438:23 (python3.16t+0x2dd743)
#2 _mi_usable_size /cpython/Objects/mimalloc/alloc.c:647:33 (python3.16t+0x2dd743)
#3 _mi_heap_realloc_zero /cpython/Objects/mimalloc/alloc.c:724:23 (python3.16t+0x2dd743)
#4 mi_heap_realloc /cpython/Objects/mimalloc/alloc.c:753:10 (python3.16t+0x2fa1c6)
#5 _PyMem_MiRealloc /cpython/Objects/obmalloc.c:289:12 (python3.16t+0x2fa1c6)
#6 PyMem_Realloc /cpython/Objects/obmalloc.c:1276:12 (python3.16t+0x2fc7d4)
#7 resize_buffer /cpython/./Modules/_io/stringio.c:116:26 (python3.16t+0x5ea7a7)
#8 _io_StringIO_truncate_impl /cpython/./Modules/_io/stringio.c:483:13 (python3.16t+0x5ea7a7)
#9 _io_StringIO_truncate /cpython/./Modules/_io/clinic/stringio.c.h:169:20 (python3.16t+0x5ea7a7)
#10 _PyCallMethodDescriptorFast_StackRef /cpython/Python/ceval.c:860:11 (python3.16t+0x44273f)
#11 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:3910:35 (python3.16t+0x44273f)
#12 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#13 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#14 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#15 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#16 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#17 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#18 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x48ec15)
#19 context_run /cpython/Python/context.c:728:29 (python3.16t+0x48ec15)
#20 method_vectorcall_FASTCALL_KEYWORDS /cpython/Objects/descrobject.c:421:24 (python3.16t+0x22e84c)
#21 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x2149a8)
#22 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.16t+0x2149a8)
#23 _Py_VectorCallInstrumentation_StackRefSteal /cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8)
#24 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022)
#25 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#26 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#27 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#28 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#29 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#30 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#31 _PyVectorcall_Call /cpython/Objects/call.c:273:16 (python3.16t+0x214ca2)
#32 _PyObject_Call /cpython/Objects/call.c:348:16 (python3.16t+0x214ca2)
#33 PyObject_Call /cpython/Objects/call.c:373:12 (python3.16t+0x214d07)
#34 thread_run /cpython/./Modules/_threadmodule.c:388:21 (python3.16t+0x61a708)
#35 pythread_wrapper /cpython/Python/thread_pthread.h:234:5 (python3.16t+0x5473bb)
Previous write of size 4 at 0x7fffb800092c by thread T1:
#0 mi_segment_span_allocate /cpython/Objects/mimalloc/segment.c:710:23 (python3.16t+0x306f1b)
#1 mi_segments_page_find_and_allocate /cpython/Objects/mimalloc/segment.c:777:29 (python3.16t+0x2f6f95)
#2 mi_segments_page_alloc /cpython/Objects/mimalloc/segment.c:1507:21 (python3.16t+0x2f6f95)
#3 _mi_segment_page_alloc /cpython/Objects/mimalloc/segment.c (python3.16t+0x2f66f5)
#4 mi_page_fresh_alloc /cpython/Objects/mimalloc/page.c:288:21 (python3.16t+0x3040ee)
#5 mi_page_fresh /cpython/Objects/mimalloc/page.c:309:21 (python3.16t+0x2f3116)
#6 mi_page_queue_find_free_ex /cpython/Objects/mimalloc/page.c:786:12 (python3.16t+0x2f3116)
#7 mi_find_free_page /cpython/Objects/mimalloc/page.c:825:10 (python3.16t+0x2f3116)
#8 mi_find_page /cpython/Objects/mimalloc/page.c:924:12 (python3.16t+0x2f3116)
#9 _mi_malloc_generic /cpython/Objects/mimalloc/page.c:950:21 (python3.16t+0x2db5e1)
#10 _mi_page_malloc /cpython/Objects/mimalloc/alloc.c:44:12 (python3.16t+0x2dd9c9)
#11 mi_heap_malloc_small_zero /cpython/Objects/mimalloc/alloc.c:127:19 (python3.16t+0x2dd9c9)
#12 _mi_heap_malloc_zero_ex /cpython/Objects/mimalloc/alloc.c:156:12 (python3.16t+0x2dd9c9)
#13 _mi_heap_malloc_zero /cpython/Objects/mimalloc/alloc.c:179:10 (python3.16t+0x2dd9c9)
#14 mi_heap_malloc /cpython/Objects/mimalloc/alloc.c:183:10 (python3.16t+0x2dd9c9)
#15 _mi_heap_realloc_zero /cpython/Objects/mimalloc/alloc.c:732:16 (python3.16t+0x2dd9c9)
#16 mi_heap_realloc /cpython/Objects/mimalloc/alloc.c:753:10 (python3.16t+0x2fa1c6)
#17 _PyMem_MiRealloc /cpython/Objects/obmalloc.c:289:12 (python3.16t+0x2fa1c6)
#18 PyMem_Realloc /cpython/Objects/obmalloc.c:1276:12 (python3.16t+0x2fc7d4)
#19 resize_buffer /cpython/./Modules/_io/stringio.c:116:26 (python3.16t+0x5ec02f)
#20 write_str /cpython/./Modules/_io/stringio.c:237:13 (python3.16t+0x5ec02f)
#21 _io_StringIO___init___impl /cpython/./Modules/_io/stringio.c:772:13 (python3.16t+0x5e90b6)
#22 _io_StringIO___init__ /cpython/./Modules/_io/clinic/stringio.c.h:356:20 (python3.16t+0x5e90b6)
#23 wrap_init /cpython/Objects/typeobject.c:10392:9 (python3.16t+0x3506eb)
#24 wrapperdescr_raw_call /cpython/Objects/descrobject.c:523:16 (python3.16t+0x22dd94)
#25 wrapperdescr_call /cpython/Objects/descrobject.c:570:14 (python3.16t+0x22dd94)
#26 _PyObject_MakeTpCall /cpython/Objects/call.c:242:18 (python3.16t+0x213bfd)
#27 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:142:16 (python3.16t+0x214a70)
#28 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.16t+0x214a70)
#29 _Py_VectorCallInstrumentation_StackRefSteal /cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8)
#30 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022)
#31 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#32 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#33 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#34 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#35 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#36 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#37 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x48ec15)
#38 context_run /cpython/Python/context.c:728:29 (python3.16t+0x48ec15)
#39 method_vectorcall_FASTCALL_KEYWORDS /cpython/Objects/descrobject.c:421:24 (python3.16t+0x22e84c)
#40 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x2149a8)
#41 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.16t+0x2149a8)
#42 _Py_VectorCallInstrumentation_StackRefSteal /cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8)
#43 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022)
#44 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#45 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#46 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#47 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#48 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#49 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#50 _PyVectorcall_Call /cpython/Objects/call.c:273:16 (python3.16t+0x214ca2)
#51 _PyObject_Call /cpython/Objects/call.c:348:16 (python3.16t+0x214ca2)
#52 PyObject_Call /cpython/Objects/call.c:373:12 (python3.16t+0x214d07)
#53 thread_run /cpython/./Modules/_threadmodule.c:388:21 (python3.16t+0x61a708)
#54 pythread_wrapper /cpython/Python/thread_pthread.h:234:5 (python3.16t+0x5473bb)
...
==================
ThreadSanitizer:DEADLYSIGNAL
==658985==ERROR: ThreadSanitizer: SEGV on unknown address 0x006100000064 (pc 0x5555556a0f64 bp 0x000000000000 sp 0x7fffb11fc4d0 T658987)
==658985==The signal is caused by a READ memory access.
#0 __tsan_atomic64_load <null> (python3.16t+0x14cf64)
#1 mi_block_nextx /cpython/./Include/internal/mimalloc/mimalloc/internal.h:640:23 (python3.16t+0x2dd830)
#2 mi_block_next /cpython/./Include/internal/mimalloc/mimalloc/internal.h:669:10 (python3.16t+0x2dd830)
#3 _mi_page_malloc /cpython/Objects/mimalloc/alloc.c:49:16 (python3.16t+0x2dd830)
#4 mi_heap_malloc_small_zero /cpython/Objects/mimalloc/alloc.c:127:19 (python3.16t+0x2dd830)
#5 _mi_heap_malloc_zero_ex /cpython/Objects/mimalloc/alloc.c:156:12 (python3.16t+0x2dd830)
#6 _mi_heap_malloc_zero /cpython/Objects/mimalloc/alloc.c:179:10 (python3.16t+0x2dd830)
#7 mi_heap_malloc /cpython/Objects/mimalloc/alloc.c:183:10 (python3.16t+0x2dd830)
#8 _mi_heap_realloc_zero /cpython/Objects/mimalloc/alloc.c:732:16 (python3.16t+0x2dd830)
#9 mi_heap_realloc /cpython/Objects/mimalloc/alloc.c:753:10 (python3.16t+0x2fa1c6)
#10 _PyMem_MiRealloc /cpython/Objects/obmalloc.c:289:12 (python3.16t+0x2fa1c6)
#11 PyMem_Realloc /cpython/Objects/obmalloc.c:1276:12 (python3.16t+0x2fc7d4)
#12 resize_buffer /cpython/./Modules/_io/stringio.c:116:26 (python3.16t+0x5ec02f)
#13 write_str /cpython/./Modules/_io/stringio.c:237:13 (python3.16t+0x5ec02f)
#14 _io_StringIO___init___impl /cpython/./Modules/_io/stringio.c:772:13 (python3.16t+0x5e90b6)
#15 _io_StringIO___init__ /cpython/./Modules/_io/clinic/stringio.c.h:356:20 (python3.16t+0x5e90b6)
#16 wrap_init /cpython/Objects/typeobject.c:10392:9 (python3.16t+0x3506eb)
#17 wrapperdescr_raw_call /cpython/Objects/descrobject.c:523:16 (python3.16t+0x22dd94)
#18 wrapperdescr_call /cpython/Objects/descrobject.c:570:14 (python3.16t+0x22dd94)
#19 _PyObject_MakeTpCall /cpython/Objects/call.c:242:18 (python3.16t+0x213bfd)
#20 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:142:16 (python3.16t+0x214a70)
#21 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.16t+0x214a70)
#22 _Py_VectorCall_StackRefSteal /cpython/Python/ceval.c:724:11 (python3.16t+0x4368e7)
#23 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:4362:35 (python3.16t+0x443779)
#24 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#25 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#26 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#27 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#28 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#29 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#30 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x48ec15)
#31 context_run /cpython/Python/context.c:728:29 (python3.16t+0x48ec15)
#32 method_vectorcall_FASTCALL_KEYWORDS /cpython/Objects/descrobject.c:421:24 (python3.16t+0x22e84c)
#33 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x2149a8)
#34 PyObject_Vectorcall /cpython/Objects/call.c:327:12 (python3.16t+0x2149a8)
#35 _Py_VectorCallInstrumentation_StackRefSteal /cpython/Python/ceval.c:766:11 (python3.16t+0x4370c8)
#36 _PyEval_EvalFrameDefault /cpython/Python/generated_cases.c.h:1846:35 (python3.16t+0x43d022)
#37 _PyEval_EvalFrame /cpython/./Include/internal/pycore_ceval.h:122:16 (python3.16t+0x436463)
#38 _PyEval_Vector /cpython/Python/ceval.c:2134:12 (python3.16t+0x436463)
#39 _PyFunction_Vectorcall /cpython/Objects/call.c (python3.16t+0x215013)
#40 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11 (python3.16t+0x216b11)
#41 _PyObject_VectorcallPrepend /cpython/Objects/call.c:855:20 (python3.16t+0x216b11)
#42 method_vectorcall /cpython/Objects/classobject.c:55:12 (python3.16t+0x21a132)
#43 _PyVectorcall_Call /cpython/Objects/call.c:273:16 (python3.16t+0x214ca2)
#44 _PyObject_Call /cpython/Objects/call.c:348:16 (python3.16t+0x214ca2)
#45 PyObject_Call /cpython/Objects/call.c:373:12 (python3.16t+0x214d07)
#46 thread_run /cpython/./Modules/_threadmodule.c:388:21 (python3.16t+0x61a708)
#47 pythread_wrapper /cpython/Python/thread_pthread.h:234:5 (python3.16t+0x5473bb)
#48 __tsan_thread_start_func <null> (python3.16t+0xf9182)
#49 start_thread nptl/pthread_create.c:447:8 (libc.so.6+0x9caa3)
#50 clone3 misc/../sysdeps/unix/sysv/linux/x86_64/clone3.S:78 (libc.so.6+0x129c6b)
ThreadSanitizer can not provide additional info.
SUMMARY: ThreadSanitizer: SEGV (/cpython/cpython-tsan/bin/python3.16t+0x14cf64) in __tsan_atomic64_load
==658985==ABORTING
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Bug report
Bug description:
_io_StringIO___init___implresets the entire object state with no critical section,cpython/Modules/_io/stringio.c
Lines 721 to 788 in 160dc74
while
_io_StringIO_truncate_implreads/writes the same fields under critical section.cpython/Modules/_io/stringio.c
Lines 458 to 489 in 160dc74
If a thread inside
__init__and a thread insidetruncateboth reachPyMem_Realloc(self->buf, …)viaresize_buffer()concurrently, it can corrupt the mimalloc heap and crashes with segfault in free-threading build.Reproducer:
TSAN Report:
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux