Skip to content

Commit f165f99

Browse files
committed
Validate mmap assignments against current storage
Use the existing mapping guard for bounds and writes after argument conversion, including empty assignments. Match the Python 3.14.8 ordering while preserving export guards and ownership APIs. Assisted-by: OpenAI Codex:model identifier unavailable
1 parent 399e5b0 commit f165f99

2 files changed

Lines changed: 63 additions & 33 deletions

File tree

‎crates/stdlib/src/mmap.rs‎

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,17 +1455,15 @@ mod mmap {
14551455
value: &PyObject,
14561456
vm: &VirtualMachine,
14571457
) -> PyResult<()> {
1458-
let i: usize = i
1459-
.wrapped_at(self.__len__())
1460-
.ok_or_else(|| vm.new_index_error("mmap index out of range"))?;
1461-
14621458
let b = value_from_object(vm, value)?;
14631459

14641460
self.try_writable(vm, |mmap| {
1461+
let i = i
1462+
.wrapped_at(mmap.len())
1463+
.ok_or_else(|| vm.new_index_error("mmap index out of range"))?;
14651464
mmap[i] = b;
1466-
})?;
1467-
1468-
Ok(())
1465+
Ok(())
1466+
})?
14691467
}
14701468

14711469
fn setitem_by_slice(
@@ -1474,43 +1472,37 @@ mod mmap {
14741472
value: &PyObject,
14751473
vm: &VirtualMachine,
14761474
) -> PyResult<()> {
1477-
let (range, step, slice_len) = slice.adjust_indices(self.__len__());
1478-
14791475
let bytes = bytes_from_object(vm, value)?;
14801476

1481-
if bytes.len() != slice_len {
1482-
return Err(vm.new_index_error("mmap slice assignment is wrong size"));
1483-
}
1477+
self.try_writable(vm, |mmap| {
1478+
let (range, step, slice_len) = slice.adjust_indices(mmap.len());
14841479

1485-
if slice_len == 0 {
1486-
// do nothing
1487-
Ok(())
1488-
} else if step == 1 {
1489-
self.try_writable(vm, |mmap| {
1480+
if bytes.len() != slice_len {
1481+
return Err(vm.new_index_error("mmap slice assignment is wrong size"));
1482+
}
1483+
1484+
if slice_len == 0 {
1485+
// do nothing
1486+
} else if step == 1 {
14901487
(&mut mmap[range])
14911488
.write(&bytes)
14921489
.map_err(|err| err.to_pyexception(vm))?;
1493-
Ok(())
1494-
})?
1495-
} else {
1496-
let mut bi = 0; // bytes index
1497-
if step.is_negative() {
1498-
for i in range.rev().step_by(step.unsigned_abs()) {
1499-
self.try_writable(vm, |mmap| {
1500-
mmap[i] = bytes[bi];
1501-
})?;
1502-
bi += 1;
1503-
}
15041490
} else {
1505-
for i in range.step_by(step.unsigned_abs()) {
1506-
self.try_writable(vm, |mmap| {
1491+
let mut bi = 0; // bytes index
1492+
if step.is_negative() {
1493+
for i in range.rev().step_by(step.unsigned_abs()) {
1494+
mmap[i] = bytes[bi];
1495+
bi += 1;
1496+
}
1497+
} else {
1498+
for i in range.step_by(step.unsigned_abs()) {
15071499
mmap[i] = bytes[bi];
1508-
})?;
1509-
bi += 1;
1500+
bi += 1;
1501+
}
15101502
}
15111503
}
15121504
Ok(())
1513-
}
1505+
})?
15141506
}
15151507
}
15161508

‎extra_tests/snippets/stdlib_mmap.py‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,41 @@
7777
with assert_raises(ValueError):
7878
mapped.resize(4)
7979
assert mapped.closed
80+
81+
82+
# Assignment validates current storage after argument conversion, even if empty.
83+
with mmap.mmap(-1, 4) as mapped:
84+
with assert_raises(ValueError):
85+
mapped[4] = 256
86+
mapped[0:0] = b""
87+
with assert_raises(ValueError):
88+
mapped[0:0] = b""
89+
90+
with mmap.mmap(-1, 4, access=mmap.ACCESS_READ) as mapped:
91+
with assert_raises(TypeError):
92+
mapped[0:0] = b""
93+
94+
95+
class CloseOnIndex:
96+
def __init__(self, mapped):
97+
self.mapped = mapped
98+
99+
def __index__(self):
100+
self.mapped.close()
101+
return 0
102+
103+
104+
for close_from in ("key", "value", "slice"):
105+
mapped = mmap.mmap(-1, 4)
106+
closer = CloseOnIndex(mapped)
107+
try:
108+
with assert_raises(ValueError):
109+
if close_from == "key":
110+
mapped[closer] = 0
111+
elif close_from == "value":
112+
mapped[0] = closer
113+
else:
114+
mapped[closer:0] = b""
115+
assert mapped.closed
116+
finally:
117+
mapped.close()

0 commit comments

Comments
 (0)