From 9b822fa5a9cfb83157881e1dbc7426f88033f8ca Mon Sep 17 00:00:00 2001 From: Jeong YunWon <jeong@youknowone.org> Date: Tue, 14 Sep 2021 03:10:18 +0900 Subject: [PATCH 1/4] io buffers use PyMemoryView::release --- vm/src/builtins/memory.rs | 2 +- vm/src/stdlib/io.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index bd50cf28d6..fd798a23bf 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -37,7 +37,7 @@ pub struct PyMemoryViewNewArgs { #[derive(Debug)] pub struct PyMemoryView { buffer: PyBuffer, - pub(crate) released: AtomicCell<bool>, + released: AtomicCell<bool>, // start should always less or equal to the stop // start and stop pointing to the memory index not slice index // if length is not zero than [start, stop) diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 456160aa90..0d553318db 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -893,7 +893,7 @@ mod _io { // TODO: loop if write() raises an interrupt let res = vm.call_method(raw, "write", (memobj.clone(),)); - memobj.released.store(true); + memobj.release(); self.buffer = std::mem::take(&mut writebuf.data.lock()); res? @@ -1132,7 +1132,7 @@ mod _io { let res = vm.call_method(self.raw.as_ref().unwrap(), "readinto", (memobj.clone(),)); - memobj.released.store(true); + memobj.release(); std::mem::swap(v, &mut readbuf.data.lock()); res? From 9189de38172c5a21cc17986f74488cea77ad4a1b Mon Sep 17 00:00:00 2001 From: Jeong YunWon <jeong@youknowone.org> Date: Tue, 14 Sep 2021 03:22:57 +0900 Subject: [PATCH 2/4] clean up imports --- vm/src/builtins/memory.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index fd798a23bf..28aeeec890 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -1,9 +1,6 @@ use crate::buffer::{BufferOptions, PyBuffer, PyBufferInternal}; -use crate::builtins::bytes::{PyBytes, PyBytesRef}; -use crate::builtins::list::{PyList, PyListRef}; -use crate::builtins::pystr::{PyStr, PyStrRef}; -use crate::builtins::pytype::PyTypeRef; use crate::builtins::slice::PySliceRef; +use crate::builtins::{PyBytes, PyBytesRef, PyList, PyListRef, PyStr, PyStrRef, PyTypeRef}; use crate::bytesinner::bytes_to_hex; use crate::common::{ borrow::{BorrowedValue, BorrowedValueMut}, From 6a309cb8e4bdaeb4d667e4222b7f870369161410 Mon Sep 17 00:00:00 2001 From: Jeong YunWon <jeong@youknowone.org> Date: Sun, 12 Sep 2021 23:41:27 +0900 Subject: [PATCH 3/4] memoryview validation tool they will be only activated on debug build --- vm/src/builtins/memory.rs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index 28aeeec890..99d96be914 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -58,6 +58,24 @@ impl SlotConstructor for PyMemoryView { #[pyimpl(with(Hashable, Comparable, AsBuffer, SlotConstructor))] impl PyMemoryView { + #[cfg(debug_assertions)] + fn validate(self) -> Self { + let options = &self.buffer.options; + let bytes_len = options.len * options.itemsize; + let buffer_len = self.buffer.internal.obj_bytes().len(); + let t1 = self.stop - self.start == bytes_len; + let t2 = buffer_len >= self.stop; + let t3 = buffer_len >= self.start + bytes_len; + assert!(t1); + assert!(t2); + assert!(t3); + self + } + #[cfg(not(debug_assertions))] + fn validate(self) -> Self { + self + } + fn parse_format(format: &str, vm: &VirtualMachine) -> PyResult<FormatSpec> { FormatSpec::parse(format, vm) } @@ -77,7 +95,8 @@ impl PyMemoryView { step: 1, format_spec, hash: OnceCell::new(), - }) + } + .validate()) } pub fn from_buffer_range( @@ -96,7 +115,8 @@ impl PyMemoryView { step: 1, format_spec, hash: OnceCell::new(), - }) + } + .validate()) } fn as_contiguous(&self) -> Option<BorrowedValue<[u8]>> { @@ -270,6 +290,7 @@ impl PyMemoryView { format_spec, hash: OnceCell::new(), } + .validate() .into_object(vm)); } @@ -315,6 +336,7 @@ impl PyMemoryView { format_spec, hash: OnceCell::new(), } + .validate() .into_object(vm)); }; @@ -345,6 +367,7 @@ impl PyMemoryView { format_spec, hash: OnceCell::new(), } + .validate() .into_object(vm)) } @@ -538,6 +561,7 @@ impl PyMemoryView { hash: OnceCell::new(), ..*zelf } + .validate() .into_ref(vm)) } @@ -607,6 +631,7 @@ impl PyMemoryView { hash: OnceCell::new(), ..*zelf } + .validate() .into_ref(vm)) } From 5befe49cd988cf5dd8999c247d351bdd7392a0cc Mon Sep 17 00:00:00 2001 From: Jeong YunWon <jeong@youknowone.org> Date: Tue, 14 Sep 2021 06:07:19 +0900 Subject: [PATCH 4/4] PyMemoryView::getitem_slice reuse common convert_slice --- vm/src/builtins/memory.rs | 64 +++++++++++---------------------------- 1 file changed, 18 insertions(+), 46 deletions(-) diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index 99d96be914..ffe837d504 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -9,7 +9,7 @@ use crate::common::{ rc::PyRc, }; use crate::function::{FuncArgs, OptionalArg}; -use crate::sliceable::{convert_slice, saturate_range, wrap_index, SequenceIndex}; +use crate::sliceable::{convert_slice, wrap_index, SequenceIndex}; use crate::slots::{AsBuffer, Comparable, Hashable, PyComparisonOp, SlotConstructor}; use crate::stdlib::pystruct::_struct::FormatSpec; use crate::utils::Either; @@ -19,8 +19,7 @@ use crate::{ }; use crossbeam_utils::atomic::AtomicCell; use itertools::Itertools; -use num_bigint::BigInt; -use num_traits::{One, Signed, ToPrimitive, Zero}; +use num_traits::ToPrimitive; use std::fmt::Debug; use std::ops::Deref; @@ -255,25 +254,20 @@ impl PyMemoryView { fn getitem_by_slice(zelf: PyRef<Self>, slice: PySliceRef, vm: &VirtualMachine) -> PyResult { // slicing a memoryview return a new memoryview - let start = slice.start_index(vm)?; - let stop = slice.stop_index(vm)?; - let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one); - if step.is_zero() { - return Err(vm.new_value_error("slice step cannot be zero".to_owned())); - } - let newstep: BigInt = step.clone() * zelf.step; let len = zelf.buffer.options.len; + let (range, step, is_negative_step) = convert_slice(&slice, len, vm)?; + let abs_step = step.unwrap(); + let step = if is_negative_step { + -(abs_step as isize) + } else { + abs_step as isize + }; + let newstep = step * zelf.step; let itemsize = zelf.buffer.options.itemsize; let format_spec = zelf.format_spec.clone(); - if newstep == BigInt::one() { - let range = saturate_range(&start, &stop, len); - let range = if range.end < range.start { - range.start..range.start - } else { - range - }; + if newstep == 1 { let newlen = range.end - range.start; let start = zelf.start + range.start * itemsize; let stop = zelf.start + range.end * itemsize; @@ -294,35 +288,7 @@ impl PyMemoryView { .into_object(vm)); } - let (start, stop) = if step.is_negative() { - ( - stop.map(|x| { - if x == -BigInt::one() { - len + BigInt::one() - } else { - x + 1 - } - }), - start.map(|x| { - if x == -BigInt::one() { - BigInt::from(len) - } else { - x + 1 - } - }), - ) - } else { - (start, stop) - }; - - let range = saturate_range(&start, &stop, len); - let newlen = if range.end > range.start { - // overflow is not possible as dividing a positive integer - ((range.end - range.start - 1) / step.abs()) - .to_usize() - .unwrap() - + 1 - } else { + if range.start >= range.end { return Ok(PyMemoryView { buffer: zelf.buffer.clone_with_options(BufferOptions { len: 0, @@ -340,6 +306,12 @@ impl PyMemoryView { .into_object(vm)); }; + // overflow is not possible as dividing a positive integer + let newlen = ((range.end - range.start - 1) / abs_step) + .to_usize() + .unwrap() + + 1; + // newlen will be 0 if step is overflowed let newstep = newstep.to_isize().unwrap_or(-1);