diff --git a/tests/snippets/index_overflow.py b/tests/snippets/index_overflow.py new file mode 100644 index 000000000..fa0d80b9a --- /dev/null +++ b/tests/snippets/index_overflow.py @@ -0,0 +1,26 @@ +import sys + + +def expect_cannot_fit_index_error(s, index): + try: + s[index] + except IndexError: + pass + # TODO: Replace current except block with commented + # after solving https://github.com/RustPython/RustPython/issues/322 + # except IndexError as error: + # assert str(error) == "cannot fit 'int' into an index-sized integer" + else: + assert False + + +MAX_INDEX = sys.maxsize + 1 +MIN_INDEX = -(MAX_INDEX + 1) + +test_str = "test" +expect_cannot_fit_index_error(test_str, MIN_INDEX) +expect_cannot_fit_index_error(test_str, MAX_INDEX) + +test_list = [0, 1, 2, 3] +expect_cannot_fit_index_error(test_list, MIN_INDEX) +expect_cannot_fit_index_error(test_list, MAX_INDEX) diff --git a/vm/src/obj/objsequence.rs b/vm/src/obj/objsequence.rs index 4dbd0026f..ff3ed6a01 100644 --- a/vm/src/obj/objsequence.rs +++ b/vm/src/obj/objsequence.rs @@ -76,17 +76,20 @@ pub fn get_item( subscript: PyObjectRef, ) -> PyResult { match &(subscript.borrow()).payload { - PyObjectPayload::Integer { value } => { - let value = value.to_i32().unwrap(); - let pos_index = elements.to_vec().get_pos(value); - if pos_index < elements.len() { - let obj = elements[pos_index].clone(); - Ok(obj) - } else { - let index_error = vm.context().exceptions.index_error.clone(); - Err(vm.new_exception(index_error, "Index out of bounds!".to_string())) + PyObjectPayload::Integer { value } => match value.to_i32() { + Some(value) => { + let pos_index = elements.to_vec().get_pos(value); + if pos_index < elements.len() { + let obj = elements[pos_index].clone(); + Ok(obj) + } else { + Err(vm.new_index_error("Index out of bounds!".to_string())) + } } - } + None => { + Err(vm.new_index_error("cannot fit 'int' into an index-sized integer".to_string())) + } + }, PyObjectPayload::Slice { start: _, stop: _, diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index ce55bb940..a20e5b517 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -1015,13 +1015,19 @@ fn to_graphemes>(value: S) -> Vec { pub fn subscript(vm: &mut VirtualMachine, value: &str, b: PyObjectRef) -> PyResult { if objtype::isinstance(&b, &vm.ctx.int_type()) { - let pos = objint::get_value(&b).to_i32().unwrap(); - let graphemes = to_graphemes(value); - let idx = graphemes.get_pos(pos); - graphemes - .get(idx) - .map(|c| vm.new_str(c.to_string())) - .ok_or(vm.new_index_error("string index out of range".to_string())) + match objint::get_value(&b).to_i32() { + Some(pos) => { + let graphemes = to_graphemes(value); + let idx = graphemes.get_pos(pos); + graphemes + .get(idx) + .map(|c| vm.new_str(c.to_string())) + .ok_or(vm.new_index_error("string index out of range".to_string())) + } + None => { + Err(vm.new_index_error("cannot fit 'int' into an index-sized integer".to_string())) + } + } } else { match &(*b.borrow()).payload { &PyObjectPayload::Slice {