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);