-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Closed
Description
What happened?
_IOBase.writelines calls TextIOWrapper.write, which flushes buffered data by calling the user-provided raw write while the wrapper’s mutex is held. If that raw write re-enters TextIOWrapper.reconfigure (e.g., by calling textio.reconfigure), the inner call attempts self.data.lock().unwrap() on an already-held mutex and panics instead of rejecting the reentrant call or raising a Python exception.
Proof of Concept:
import io
class Raw:
def __init__(self):
self.textio = None
self.closed = False
def writable(self): return True
def readable(self): return False
def seekable(self): return False
def write(self, data):
self.textio.reconfigure(encoding="utf-8")
return len(data)
raw = Raw()
textio = io.TextIOWrapper(raw, encoding="utf-8", write_through=True)
raw.textio = textio
textio.writelines(["x"])Affected Versions
| RustPython Version | Status | Exit Code |
|---|---|---|
Python 3.13.0alpha (heads/main-dirty:21300f689, Dec 13 2025, 22:16:49) [RustPython 0.4.0 with rustc 1.90.0-nightly (11ad40bb8 2025-06-28)] |
Panic | 101 |
Vulnerable Code
fn writelines(instance: PyObjectRef, lines: ArgIterable, vm: &VirtualMachine) -> PyResult<()> {
check_closed(&instance, vm)?;
for line in lines.iter(vm)? {
vm.call_method(&instance, "write", (line?,))?; // Re-enters TextIOWrapper.write while wrapper lock is held
}
Ok(())
}
impl TextIOData {
fn write_pending(&mut self, vm: &VirtualMachine) -> PyResult<()> {
if self.pending.num_bytes == 0 {
return Ok(());
}
let data = self.pending.take(vm);
vm.call_method(&self.buffer, "write", (data,))?; // Calls raw write. User code can call textio.reconfigure reentrantly
Ok(())
}
}
#[pymethod]
fn reconfigure(&self, args: TextIOWrapperArgs, vm: &VirtualMachine) -> PyResult<()> {
let mut data = self.data.lock().unwrap(); // Reentrant lock returns None; unwrap panics instead of raising a Python error
if let Some(data) = data.as_mut() {
// ...
}
Ok(())
}Rust Output
thread 'main' panicked at crates/vm/src/stdlib/io.rs:2514:45:
called `Option::unwrap()` on a `None` value
stack backtrace:
0: __rustc::rust_begin_unwind
at /rustc/11ad40bb839ca16f74784b4ab72596ad85587298/library/std/src/panicking.rs:697:5
1: core::panicking::panic_fmt
at /rustc/11ad40bb839ca16f74784b4ab72596ad85587298/library/core/src/panicking.rs:75:14
2: core::panicking::panic
at /rustc/11ad40bb839ca16f74784b4ab72596ad85587298/library/core/src/panicking.rs:145:5
3: core::option::unwrap_failed
at /rustc/11ad40bb839ca16f74784b4ab72596ad85587298/library/core/src/option.rs:2072:5
4: core::option::Option<T>::unwrap
at /home/jackfromeast/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:1005:21
5: rustpython_vm::stdlib::io::_io::TextIOWrapper::reconfigure
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/stdlib/io.rs:2514:45
6: core::ops::function::Fn::call
at /home/jackfromeast/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:79:5
7: rustpython_vm::function::builtin::<impl rustpython_vm::function::builtin::sealed::PyNativeFnInternal<(rustpython_vm::function::builtin::RefParam<S>,rustpython_vm::function::builtin::OwnedParam<T1>),R,rustpython_vm::vm::VirtualMachine> for F>::call_
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/function/builtin.rs:154:17
8: <F as rustpython_vm::function::builtin::IntoPyNativeFn<(T,R,VM)>>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/function/builtin.rs:92:14
9: rustpython_vm::function::builtin::into_func::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/function/builtin.rs:50:40
10: <rustpython_vm::builtins::builtin_func::PyNativeMethod as rustpython_vm::types::slot::Callable>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/builtins/builtin_func.rs:234:9
11: rustpython_vm::types::slot::Callable::slot_call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/types/slot.rs:1028:9
12: rustpython_vm::protocol::callable::PyCallable::invoke
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:52:22
13: rustpython_vm::protocol::callable::<impl rustpython_vm::object::core::PyObject>::call_with_args
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:33:18
14: rustpython_vm::protocol::callable::<impl rustpython_vm::object::core::PyObject>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:22:14
15: rustpython_vm::frame::ExecutingFrame::execute_method_call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/frame.rs:1903:26
16: rustpython_vm::frame::ExecutingFrame::execute_instruction
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/frame.rs:688:22
17: rustpython_vm::frame::ExecutingFrame::run
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/frame.rs:372:31
18: rustpython_vm::frame::<impl rustpython_vm::object::core::Py<rustpython_vm::frame::Frame>>::run::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/frame.rs:247:40
19: rustpython_vm::frame::<impl rustpython_vm::object::core::Py<rustpython_vm::frame::Frame>>::with_exec
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/frame.rs:242:9
20: rustpython_vm::frame::<impl rustpython_vm::object::core::Py<rustpython_vm::frame::Frame>>::run
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/frame.rs:247:14
21: rustpython_vm::vm::VirtualMachine::run_frame::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/mod.rs:467:44
22: rustpython_vm::vm::VirtualMachine::with_frame::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/mod.rs:495:26
23: rustpython_vm::vm::VirtualMachine::with_recursion
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/mod.rs:483:22
24: rustpython_vm::vm::VirtualMachine::with_frame
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/mod.rs:493:14
25: rustpython_vm::vm::VirtualMachine::run_frame
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/mod.rs:467:20
26: rustpython_vm::builtins::function::<impl rustpython_vm::object::core::Py<rustpython_vm::builtins::function::PyFunction>>::invoke_with_locals
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/builtins/function.rs:437:34
27: rustpython_vm::builtins::function::<impl rustpython_vm::object::core::Py<rustpython_vm::builtins::function::PyFunction>>::invoke
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/builtins/function.rs:443:14
28: <rustpython_vm::builtins::function::PyFunction as rustpython_vm::types::slot::Callable>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/builtins/function.rs:645:14
29: rustpython_vm::types::slot::Callable::slot_call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/types/slot.rs:1028:9
30: rustpython_vm::protocol::callable::PyCallable::invoke
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:52:22
31: rustpython_vm::protocol::callable::<impl rustpython_vm::object::core::PyObject>::call_with_args
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:33:18
32: rustpython_vm::protocol::callable::<impl rustpython_vm::object::core::PyObject>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:22:14
33: <rustpython_vm::builtins::function::PyBoundMethod as rustpython_vm::types::slot::Callable>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/builtins/function.rs:735:23
34: rustpython_vm::types::slot::Callable::slot_call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/types/slot.rs:1028:9
35: rustpython_vm::protocol::callable::PyCallable::invoke
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:52:22
36: rustpython_vm::protocol::callable::<impl rustpython_vm::object::core::PyObject>::call_with_args
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:33:18
37: rustpython_vm::protocol::callable::<impl rustpython_vm::object::core::PyObject>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:22:14
38: rustpython_vm::vm::method::PyMethod::invoke
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/method.rs:127:14
39: rustpython_vm::vm::vm_object::<impl rustpython_vm::vm::VirtualMachine>::call_method
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/vm_object.rs:130:52
40: rustpython_vm::stdlib::io::_io::TextIOData::write_pending
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/stdlib/io.rs:3246:16
41: rustpython_vm::stdlib::io::_io::TextIOWrapper::write
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/stdlib/io.rs:2982:24
42: core::ops::function::Fn::call
at /home/jackfromeast/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:79:5
43: rustpython_vm::function::builtin::<impl rustpython_vm::function::builtin::sealed::PyNativeFnInternal<(rustpython_vm::function::builtin::RefParam<S>,rustpython_vm::function::builtin::OwnedParam<T1>),R,rustpython_vm::vm::VirtualMachine> for F>::call_
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/function/builtin.rs:154:17
44: <F as rustpython_vm::function::builtin::IntoPyNativeFn<(T,R,VM)>>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/function/builtin.rs:92:14
45: rustpython_vm::function::builtin::into_func::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/function/builtin.rs:50:40
46: <rustpython_vm::builtins::descriptor::PyMethodDescriptor as rustpython_vm::types::slot::Callable>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/builtins/descriptor.rs:97:9
47: rustpython_vm::types::slot::Callable::slot_call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/types/slot.rs:1028:9
48: rustpython_vm::protocol::callable::PyCallable::invoke
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:52:22
49: rustpython_vm::protocol::callable::<impl rustpython_vm::object::core::PyObject>::call_with_args
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:33:18
50: rustpython_vm::protocol::callable::<impl rustpython_vm::object::core::PyObject>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:22:14
51: rustpython_vm::vm::method::PyMethod::invoke
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/method.rs:127:14
52: rustpython_vm::vm::vm_object::<impl rustpython_vm::vm::VirtualMachine>::call_method
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/vm_object.rs:130:52
53: rustpython_vm::stdlib::io::_io::_IOBase::writelines
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/stdlib/io.rs:567:20
54: core::ops::function::Fn::call
at /home/jackfromeast/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:79:5
55: rustpython_vm::function::builtin::<impl rustpython_vm::function::builtin::sealed::PyNativeFnInternal<(rustpython_vm::function::builtin::OwnedParam<T1>,rustpython_vm::function::builtin::OwnedParam<T2>),R,rustpython_vm::vm::VirtualMachine> for F>::call_
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/function/builtin.rs:126:17
56: <F as rustpython_vm::function::builtin::IntoPyNativeFn<(T,R,VM)>>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/function/builtin.rs:92:14
57: rustpython_vm::function::builtin::into_func::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/function/builtin.rs:50:40
58: <rustpython_vm::builtins::builtin_func::PyNativeMethod as rustpython_vm::types::slot::Callable>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/builtins/builtin_func.rs:234:9
59: rustpython_vm::types::slot::Callable::slot_call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/types/slot.rs:1028:9
60: rustpython_vm::protocol::callable::PyCallable::invoke
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:52:22
61: rustpython_vm::protocol::callable::<impl rustpython_vm::object::core::PyObject>::call_with_args
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:33:18
62: rustpython_vm::protocol::callable::<impl rustpython_vm::object::core::PyObject>::call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/protocol/callable.rs:22:14
63: rustpython_vm::frame::ExecutingFrame::execute_method_call
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/frame.rs:1903:26
64: rustpython_vm::frame::ExecutingFrame::execute_instruction
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/frame.rs:692:22
65: rustpython_vm::frame::ExecutingFrame::run
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/frame.rs:372:31
66: rustpython_vm::frame::<impl rustpython_vm::object::core::Py<rustpython_vm::frame::Frame>>::run::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/frame.rs:247:40
67: rustpython_vm::frame::<impl rustpython_vm::object::core::Py<rustpython_vm::frame::Frame>>::with_exec
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/frame.rs:242:9
68: rustpython_vm::frame::<impl rustpython_vm::object::core::Py<rustpython_vm::frame::Frame>>::run
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/frame.rs:247:14
69: rustpython_vm::vm::VirtualMachine::run_frame::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/mod.rs:467:44
70: rustpython_vm::vm::VirtualMachine::with_frame::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/mod.rs:495:26
71: rustpython_vm::vm::VirtualMachine::with_recursion
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/mod.rs:483:22
72: rustpython_vm::vm::VirtualMachine::with_frame
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/mod.rs:493:14
73: rustpython_vm::vm::VirtualMachine::run_frame
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/mod.rs:467:20
74: rustpython_vm::vm::VirtualMachine::run_code_obj
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/mod.rs:442:14
75: rustpython_vm::vm::compile::<impl rustpython_vm::vm::VirtualMachine>::run_simple_file
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/compile.rs:93:26
76: rustpython_vm::vm::compile::<impl rustpython_vm::vm::VirtualMachine>::run_any_file
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/compile.rs:57:14
77: rustpython_vm::vm::compile::<impl rustpython_vm::vm::VirtualMachine>::run_script
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/compile.rs:50:14
78: rustpython::run_rustpython
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/src/lib.rs:231:16
79: rustpython::run::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/src/lib.rs:112:41
80: rustpython_vm::vm::interpreter::Interpreter::run::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/interpreter.rs:103:35
81: rustpython_vm::vm::interpreter::Interpreter::enter::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/interpreter.rs:72:39
82: scoped_tls::ScopedKey<T>::set
at /home/jackfromeast/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/scoped-tls-1.0.1/src/lib.rs:137:9
83: rustpython_vm::vm::thread::enter_vm::{{closure}}
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/thread.rs:30:20
84: std::thread::local::LocalKey<T>::try_with
at /home/jackfromeast/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:315:12
85: std::thread::local::LocalKey<T>::with
at /home/jackfromeast/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:279:20
86: rustpython_vm::vm::thread::enter_vm
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/thread.rs:27:14
87: rustpython_vm::vm::interpreter::Interpreter::enter
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/interpreter.rs:72:9
88: rustpython_vm::vm::interpreter::Interpreter::run
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/crates/vm/src/vm/interpreter.rs:103:24
89: rustpython::run
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/src/lib.rs:112:27
90: rustpython::main
at /home/jackfromeast/Desktop/entropy/targets/rustpython/RustPython/src/main.rs:2:5
91: core::ops::function::FnOnce::call_once
at /home/jackfromeast/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
CPython Output
Traceback (most recent call last):
File "<string>", line 17, in <module>
File "<string>", line 11, in write
AttributeError: 'Raw' object has no attribute 'flush'
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels