Skip to content

Commit dcd75ef

Browse files
committed
Validate TextIOWrapper chunk size
Match CPython for non-positive, oversized, and index-compatible values. Assisted-by: Codex:GPT-5
1 parent 492e41c commit dcd75ef

2 files changed

Lines changed: 46 additions & 11 deletions

File tree

crates/vm/src/stdlib/_io.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3206,19 +3206,27 @@ mod _io {
32063206
}
32073207

32083208
#[pygetset(setter, name = "_CHUNK_SIZE")]
3209-
fn set_chunksize(
3210-
&self,
3211-
chunk_size: PySetterValue<usize>,
3212-
vm: &VirtualMachine,
3213-
) -> PyResult<()> {
3214-
let mut textio = self.lock(vm)?;
3215-
match chunk_size {
3216-
PySetterValue::Assign(chunk_size) => textio.chunk_size = chunk_size,
3209+
fn set_chunksize(&self, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
3210+
let chunk_size: isize = match value {
3211+
PySetterValue::Assign(object_value) => {
3212+
let integer = object_value.try_index(vm)?;
3213+
3214+
integer.try_to_primitive::<isize>(vm).map_err(|_| {
3215+
vm.new_value_error("cannot fit 'int' into an index-sized integer")
3216+
})?
3217+
}
32173218
PySetterValue::Delete => Err(vm.new_attribute_error("cannot delete attribute"))?,
32183219
};
3219-
// TODO: RUSTPYTHON
3220-
// Change chunk_size type, validate it manually and throws ValueError if invalid.
3221-
// https://github.com/python/cpython/blob/2e9da8e3522764d09f1d6054a2be567e91a30812/Modules/_io/textio.c#L3124-L3143
3220+
3221+
if chunk_size <= 0 {
3222+
return Err(vm.new_value_error("a strictly positive integer is required"));
3223+
}
3224+
3225+
let chunk_size = usize::try_from(chunk_size)
3226+
.map_err(|_| vm.new_value_error("a strictly positive integer is required"))?;
3227+
3228+
let mut textio = self.lock(vm)?;
3229+
textio.chunk_size = chunk_size;
32223230
Ok(())
32233231
}
32243232

extra_tests/snippets/stdlib_io.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,30 @@ def write(self, data):
8484
raw.textio = textio
8585
with assert_raises(AttributeError):
8686
textio.writelines(["x"])
87+
88+
textio = TextIOWrapper(BytesIO())
89+
90+
for invalid_chunk_size in (0, -1, 2**100):
91+
try:
92+
textio._CHUNK_SIZE = invalid_chunk_size
93+
except ValueError:
94+
pass
95+
else:
96+
assert False, f"expected ValueError for {invalid_chunk_size!r}"
97+
98+
for invalid_chunk_size in (1.5, "4"):
99+
try:
100+
textio._CHUNK_SIZE = invalid_chunk_size
101+
except TypeError:
102+
pass
103+
else:
104+
assert False, f"expected TypeError for {invalid_chunk_size!r}"
105+
106+
107+
class ChunkSize:
108+
def __index__(self):
109+
return 16
110+
111+
112+
textio._CHUNK_SIZE = ChunkSize()
113+
assert textio._CHUNK_SIZE == 16

0 commit comments

Comments
 (0)