FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

sqlite3: fix Blob.__setitem__ negative-step slice write · RustPython/RustPython@6f3eae8 · GitHub

Repository navigation

Commit 6f3eae8

Browse files
committed
sqlite3: fix Blob.__setitem__ negative-step slice write
In the step != 1 branch of Blob.ass_subscript, the loop used i_in_temp += step as usize where step is isize. For negative steps (e.g. step = -2), (-2isize) as usize = 18446744073709551614 causing an out-of-bounds panic whenever slice_len >= 2. Fix: use SaturatedSliceIter (already used by the read path) to iterate over the correct absolute blob indices, then map each index back to a temp buffer offset via abs_idx - range_start. Also fix a Clippy lint: replace val < 0 || val > 255 with the idiomatic !(0..=255).contains(&val) Add a regression test in extra_tests/snippets/stdlib_sqlite.py that exercises blob[9:0:-2] (negative step, slice_len=5).
1 parent 95abd48 commit 6f3eae8

2 files changed

Lines changed: 18 additions & 7 deletions

File tree

‎crates/stdlib/src/_sqlite3.rs‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2571,7 +2571,7 @@ mod _sqlite3 {
25712571
// Mirror CPython ass_subscript_index: use PyLong_AsLong, treat any
25722572
// overflow (e.g. 2**65) as -1, then validate the [0, 255] range.
25732573
let val = int_val.as_bigint().to_i64().unwrap_or(-1);
2574-
if val < 0 || val > 255 {
2574+
if !(0..=255).contains(&val) {
25752575
return Err(vm.new_value_error("byte must be in range(0, 256)"));
25762576
}
25772577
let ret = inner.blob.write_single(val as u8, index);
@@ -2612,25 +2612,25 @@ mod _sqlite3 {
26122612
self.check(ret, vm)
26132613
} else {
26142614
let span_len = range.end - range.start;
2615+
let range_start = range.start;
26152616
let mut temp_buf = vec![0u8; span_len];
26162617

26172618
let ret = inner.blob.read(
26182619
temp_buf.as_mut_ptr().cast(),
26192620
span_len as c_int,
2620-
range.start as c_int,
2621+
range_start as c_int,
26212622
);
26222623
self.check(ret, vm)?;
26232624

2624-
let mut i_in_temp: usize = 0;
2625-
for i_in_src in 0..slice_len {
2626-
temp_buf[i_in_temp] = buf[i_in_src];
2627-
i_in_temp += step as usize;
2625+
let iter = SaturatedSliceIter::from_adjust_indices(range, step, slice_len);
2626+
for (i_in_src, abs_idx) in iter.enumerate() {
2627+
temp_buf[abs_idx - range_start] = buf[i_in_src];
26282628
}
26292629

26302630
let ret = inner.blob.write(
26312631
temp_buf.as_ptr().cast(),
26322632
span_len as c_int,
2633-
range.start as c_int,
2633+
range_start as c_int,
26342634
);
26352635
self.check(ret, vm)
26362636
}

‎extra_tests/snippets/stdlib_sqlite.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,14 @@ def finalize(self):
5353
cx.create_aggregate("aggtxt", 1, AggrText)
5454
cur.execute("select aggtxt(key) from foo")
5555
assert cur.fetchone()[0] == "341011"
56+
57+
# Blob extended-slice assignment with negative step
58+
cx.execute("CREATE TABLE blobtest(b BLOB)")
59+
data = b"this blob data string is exactly fifty bytes long!"
60+
cx.execute("INSERT INTO blobtest(b) VALUES (?)", (data,))
61+
blob = cx.blobopen("blobtest", "b", 1)
62+
blob[9:0:-2] = b"12345" # writes to indices 9, 7, 5, 3, 1
63+
actual = cx.execute("select b from blobtest").fetchone()[0]
64+
expected = b"t5i4 3l2b1" + data[10:]
65+
assert actual == expected, f"got {actual!r}, expected {expected!r}"
66+
blob.close()

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL