-
-
Notifications
You must be signed in to change notification settings - Fork 33.6k
Open
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtopic-IOtype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Description
What happened?
TextIOWrapper.close() queries the stream’s closed property. A user-defined RawIOBase.closed can re-enter and call wrapper.detach(), clearing self->buffer. The function then continues and calls self->buffer.close() on a NULL pointer, leading to a null-pointer dereference in _PyObject_GetMethod/_Py_TYPE.
Proof of Concept:
import io
class EvilBuffer(io.RawIOBase):
def __init__(self):
super().__init__()
self.wrapper = None
self.detached = False
@property
def closed(self):
if self.wrapper is not None and not self.detached:
self.detached = True
self.wrapper.detach()
return False
raw = EvilBuffer()
wrapper = io.TextIOWrapper(raw)
raw.wrapper = wrapper
wrapper.close()Affected Versions:
| Python Version | Status | Exit Code |
|---|---|---|
Python 3.9.24+ (heads/3.9:9c4638d, Oct 17 2025, 11:19:30) |
ASAN | 1 |
Python 3.10.19+ (heads/3.10:0142619, Oct 17 2025, 11:20:05) [GCC 13.3.0] |
ASAN | 1 |
Python 3.11.14+ (heads/3.11:88f3f5b, Oct 17 2025, 11:20:44) [GCC 13.3.0] |
ASAN | 1 |
Python 3.12.12+ (heads/3.12:8cb2092, Oct 17 2025, 11:21:35) [GCC 13.3.0] |
ASAN | 1 |
Python 3.13.9+ (heads/3.13:0760a57, Oct 17 2025, 11:22:25) [GCC 13.3.0] |
ASAN | 1 |
Python 3.14.0+ (heads/3.14:889e918, Oct 17 2025, 11:23:02) [GCC 13.3.0] |
ASAN | 1 |
Python 3.15.0a1+ (heads/main:fbf0843, Oct 17 2025, 11:23:37) [GCC 13.3.0] |
ASAN | 1 |
Related Code Snippet
/*[clinic input]
@critical_section
_io.TextIOWrapper.close
[clinic start generated code]*/
static PyObject *
_io_TextIOWrapper_close_impl(textio *self)
/*[clinic end generated code: output=056ccf8b4876e4f4 input=8e12d7079d5ac5c1]*/
{
PyObject *res;
int r;
CHECK_ATTACHED(self);
// Bug: Re-enter the closed property method which detached the textio buffer
res = _io_TextIOWrapper_closed_get_impl(self);
if (res == NULL)
return NULL;
r = PyObject_IsTrue(res);
Py_DECREF(res);
if (r < 0)
return NULL;
if (r > 0) {
Py_RETURN_NONE; /* stream already closed */
}
else {
PyObject *exc = NULL;
if (self->finalizing) {
res = PyObject_CallMethodOneArg(self->buffer, &_Py_ID(_dealloc_warn),
(PyObject *)self);
if (res) {
Py_DECREF(res);
}
else {
PyErr_Clear();
}
}
if (_PyFile_Flush((PyObject *)self) < 0) {
exc = PyErr_GetRaisedException();
}
// Crash: self->buffer=0x0 after detached.
res = PyObject_CallMethodNoArgs(self->buffer, &_Py_ID(close));
if (exc != NULL) {
_PyErr_ChainExceptions1(exc);
Py_CLEAR(res);
}
return res;
}
}Sanitizer Output:
=================================================================
==1558952==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x64c4d0fea39a bp 0x7ffe22fcb5f0 sp 0x7ffe22fcb530 T0)
==1558952==The signal is caused by a READ memory access.
==1558952==Hint: address points to the zero page.
#0 0x64c4d0fea39a in _Py_TYPE Include/object.h:277
#1 0x64c4d0fea39a in _PyObject_GetMethodStackRef Objects/object.c:1698
#2 0x64c4d0f2a796 in PyObject_VectorcallMethod Objects/call.c:840
#3 0x64c4d13e717d in PyObject_CallMethodNoArgs Include/cpython/abstract.h:65
#4 0x64c4d13e717d in _io_TextIOWrapper_close_impl Modules/_io/textio.c:3169
#5 0x64c4d13e7277 in _io_TextIOWrapper_close Modules/_io/clinic/textio.c.h:1160
#6 0x64c4d0f48571 in method_vectorcall_NOARGS Objects/descrobject.c:448
#7 0x64c4d0f28e7f in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
#8 0x64c4d0f28f72 in PyObject_Vectorcall Objects/call.c:327
#9 0x64c4d11a7056 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
#10 0x64c4d11eae54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#11 0x64c4d11eb148 in _PyEval_Vector Python/ceval.c:2001
#12 0x64c4d11eb3f8 in PyEval_EvalCode Python/ceval.c:884
#13 0x64c4d12e2507 in run_eval_code_obj Python/pythonrun.c:1365
#14 0x64c4d12e2723 in run_mod Python/pythonrun.c:1459
#15 0x64c4d12e357a in pyrun_file Python/pythonrun.c:1293
#16 0x64c4d12e6220 in _PyRun_SimpleFileObject Python/pythonrun.c:521
#17 0x64c4d12e64f6 in _PyRun_AnyFileObject Python/pythonrun.c:81
#18 0x64c4d133774d in pymain_run_file_obj Modules/main.c:410
#19 0x64c4d13379b4 in pymain_run_file Modules/main.c:429
#20 0x64c4d13391b2 in pymain_run_python Modules/main.c:691
#21 0x64c4d1339842 in Py_RunMain Modules/main.c:772
#22 0x64c4d1339a2e in pymain_main Modules/main.c:802
#23 0x64c4d1339db3 in Py_BytesMain Modules/main.c:826
#24 0x64c4d0dbd645 in main Programs/python.c:15
#25 0x7cb5cbe2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#26 0x7cb5cbe2a28a in __libc_start_main_impl ../csu/libc-start.c:360
#27 0x64c4d0dbd574 in _start (/home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-latest/targets/cpython/python+0x2dd574) (BuildId: ff3dc40ea460bd4beb2c3a72283cca525b319bf0)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV Include/object.h:277 in _Py_TYPE
==1558952==ABORTING
Metadata
Metadata
Assignees
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtopic-IOtype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump