mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Raise IndexError for oversized SQLite blob indices (#9048)
Use index-sized conversion, preserve __index__ exceptions, and bound native type names to the UTF-8-safe diagnostic limit. Include in-memory blob read and write regressions without changing callback ownership. Assisted-by: OpenAI Codex:model identifier unavailable
This commit is contained in:
1 parent
37fdf4d2d9
commit
4638b6a5f3
2 files changed
+79
-7
No files matched your search
@@ -2839,15 +2839,31 @@ mod _sqlite3 {
|
||||
}
|
||||
}
|
||||
|
||||
fn wrapped_index(index: PyIntRef, length: c_int, vm: &VirtualMachine) -> PyResult<c_int> {
|
||||
let mut index = index.try_to_primitive::<c_int>(vm)?;
|
||||
fn wrapped_index(
|
||||
index: PyIntRef,
|
||||
object: &PyObject,
|
||||
length: c_int,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<c_int> {
|
||||
let mut index = index.try_to_primitive::<isize>(vm).map_err(|_| {
|
||||
let class = object.class();
|
||||
let type_name = class.slot_name();
|
||||
let mut end = type_name.len().min(200);
|
||||
while !type_name.is_char_boundary(end) {
|
||||
end -= 1;
|
||||
}
|
||||
vm.new_index_error(format!(
|
||||
"cannot fit '{}' into an index-sized integer",
|
||||
&type_name[..end]
|
||||
))
|
||||
})?;
|
||||
if index < 0 {
|
||||
index += length;
|
||||
index += length as isize;
|
||||
}
|
||||
if index < 0 || index >= length {
|
||||
if index < 0 || index >= length as isize {
|
||||
Err(vm.new_index_error("Blob index out of range"))
|
||||
} else {
|
||||
Ok(index)
|
||||
Ok(index as c_int)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2874,7 +2890,7 @@ mod _sqlite3 {
|
||||
let inner = self.inner(vm)?;
|
||||
if let Some(index) = needle.try_index_opt(vm) {
|
||||
let blob_len = inner.blob.bytes();
|
||||
let index = Self::wrapped_index(index?, blob_len, vm)?;
|
||||
let index = Self::wrapped_index(index?, needle, blob_len, vm)?;
|
||||
let mut byte: u8 = 0;
|
||||
let ret = inner.blob.read_single(&mut byte, index);
|
||||
self.check(ret, vm).map(|_| vm.ctx.new_int(byte).into())
|
||||
@@ -2937,7 +2953,7 @@ mod _sqlite3 {
|
||||
)));
|
||||
};
|
||||
let blob_len = inner.blob.bytes();
|
||||
let index = Self::wrapped_index(index?, blob_len, vm)?;
|
||||
let index = Self::wrapped_index(index?, needle, blob_len, vm)?;
|
||||
// Mirror CPython ass_subscript_index: use PyLong_AsLong, treat any
|
||||
// overflow (e.g. 2**65) as -1, then validate the [0, 255] range.
|
||||
let val = int_val.as_bigint().to_i64().unwrap_or(-1);
|
||||
|
||||
@@ -306,3 +306,59 @@ for operation in (
|
||||
"replace_callback",
|
||||
):
|
||||
check_nested_aggregate_destructor(operation)
|
||||
|
||||
|
||||
class BlobIndex:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __index__(self):
|
||||
return self.value
|
||||
|
||||
|
||||
class BlobInt(int):
|
||||
pass
|
||||
|
||||
|
||||
class BrokenBlobIndex:
|
||||
def __index__(self):
|
||||
raise OverflowError("index conversion failed")
|
||||
|
||||
|
||||
cx.execute("CREATE TABLE blobindices(b BLOB)")
|
||||
cx.execute("INSERT INTO blobindices(b) VALUES (?)", (b"abc",))
|
||||
with cx.blobopen("blobindices", "b", 1) as blob:
|
||||
assert blob[BlobIndex(-1)] == ord("c")
|
||||
blob[BlobIndex(0)] = ord("A")
|
||||
assert blob[0] == ord("A")
|
||||
|
||||
test = unittest.TestCase()
|
||||
for index in (sys.maxsize, -sys.maxsize - 1):
|
||||
with test.assertRaisesRegex(IndexError, "^Blob index out of range$"):
|
||||
blob[index]
|
||||
with test.assertRaisesRegex(IndexError, "^Blob index out of range$"):
|
||||
blob[index] = 0
|
||||
|
||||
for value in (sys.maxsize + 1, -sys.maxsize - 2):
|
||||
for index in (value, BlobInt(value), BlobIndex(value)):
|
||||
message = (
|
||||
f"^cannot fit '{type(index).__name__}' into an index-sized integer$"
|
||||
)
|
||||
with test.assertRaisesRegex(IndexError, message):
|
||||
blob[index]
|
||||
with test.assertRaisesRegex(IndexError, message):
|
||||
blob[index] = 0
|
||||
|
||||
for name, bounded_name in (("X" * 250, "X" * 200), ("€" * 67, "€" * 66)):
|
||||
long_index = type(name, (), {"__index__": lambda self: sys.maxsize + 1})()
|
||||
message = f"^cannot fit '{bounded_name}' into an index-sized integer$"
|
||||
with test.assertRaisesRegex(IndexError, message):
|
||||
blob[long_index]
|
||||
with test.assertRaisesRegex(IndexError, message):
|
||||
blob[long_index] = 0
|
||||
|
||||
with test.assertRaisesRegex(OverflowError, "^index conversion failed$"):
|
||||
blob[BrokenBlobIndex()]
|
||||
with test.assertRaisesRegex(OverflowError, "^index conversion failed$"):
|
||||
blob[BrokenBlobIndex()] = 0
|
||||
assert blob[:] == b"Abc"
|
||||
Reference in new issue
Block a user