Issue #28387: Fixed possible crash in _io.TextIOWrapper deallocator when
the garbage collector is invoked in other thread.
Based on patch by Sebastian Cufre.
diff --git a/Misc/ACKS b/Misc/ACKS
index 46d6adf..fb3f299 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -315,6 +315,7 @@
 Felipe Cruz
 Drew Csillag
 Joaquin Cuenca Abela
+Sebastian Cufre
 John Cugini
 Tom Culliton
 Raúl Cumplido
diff --git a/Misc/NEWS b/Misc/NEWS
index af4eb31..5410c77 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -113,6 +113,10 @@
 Library
 -------
 
+- Issue #28387: Fixed possible crash in _io.TextIOWrapper deallocator when
+  the garbage collector is invoked in other thread.  Based on patch by
+  Sebastian Cufre.
+
 - Issue #27517: LZMA compressor and decompressor no longer raise exceptions if
   given empty data twice.  Patch by Benjamin Fogle.
 
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index 063caa6..5d7f9ab 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -1103,7 +1103,7 @@
 }
 
 static int
-_textiowrapper_clear(textio *self)
+textiowrapper_clear(textio *self)
 {
     self->ok = 0;
     Py_CLEAR(self->buffer);
@@ -1116,6 +1116,8 @@
     Py_CLEAR(self->snapshot);
     Py_CLEAR(self->errors);
     Py_CLEAR(self->raw);
+
+    Py_CLEAR(self->dict);
     return 0;
 }
 
@@ -1125,11 +1127,11 @@
     self->finalizing = 1;
     if (_PyIOBase_finalize((PyObject *) self) < 0)
         return;
-    _textiowrapper_clear(self);
+    self->ok = 0;
     _PyObject_GC_UNTRACK(self);
     if (self->weakreflist != NULL)
         PyObject_ClearWeakRefs((PyObject *)self);
-    Py_CLEAR(self->dict);
+    textiowrapper_clear(self);
     Py_TYPE(self)->tp_free((PyObject *)self);
 }
 
@@ -1151,15 +1153,6 @@
     return 0;
 }
 
-static int
-textiowrapper_clear(textio *self)
-{
-    if (_textiowrapper_clear(self) < 0)
-        return -1;
-    Py_CLEAR(self->dict);
-    return 0;
-}
-
 static PyObject *
 textiowrapper_closed_get(textio *self, void *context);