Repository: tokio-rs/tokio-uring (Rust)

Issue:
[Bug] Wrong `Slice::deref/deref_mut` implementation
Here's a minimal reproducible example:
```rust
let v = Vec::with_capacity(32);
let slice = v.slice(..);
let x = &*slice;
// raise error 'range end index 32 out of range for slice of length 0'
```

The reason is that `Slice` creation uses `bytes_total()`, `Slice::deref` uses `bytes_init()`.
The module level `deref/deref_mut` or the `Slice::deref/deref_mut` implementation, I'm not sure which one should be modified.

https://github.com/tokio-rs/tokio-uring/blob/2c9fbeab9694b74a21588ff398767ee8b5619032/src/buf/io_buf.rs#L79-L83
https://github.com/tokio-rs/tokio-uring/blob/2c9fbeab9694b74a21588ff398767ee8b5619032/src/buf/mod.rs#L16-L20
https://github.com/tokio-rs/tokio-uring/blob/2c9fbeab9694b74a21588ff398767ee8b5619032/src/buf/slice.rs#L126-L132


Discussion:
#52 fixes this; the `Deref`/`DerefMut` impls should not try to extend the slice past the initialized part of the buffer. The helpers at the root of the `buf` module do the right thing.



Patch:
diff --git a/src/buf/slice.rs b/src/buf/slice.rs
index 28e2e87e..a76a7825 100644
--- a/src/buf/slice.rs
+++ b/src/buf/slice.rs
@@ -1,5 +1,6 @@
 use crate::buf::{IoBuf, IoBufMut};
 
+use std::cmp;
 use std::ops;
 
 /// An owned view into a contiguous sequence of bytes.
@@ -127,19 +128,23 @@ impl<T: IoBuf> ops::Deref for Slice<T> {
     type Target = [u8];
 
     fn deref(&self) -> &[u8] {
-        &super::deref(&self.buf)[self.begin..self.end]
+        let buf_bytes = super::deref(&self.buf);
+        let end = cmp::min(self.end, buf_bytes.len());
+        &buf_bytes[self.begin..end]
     }
 }
 
 impl<T: IoBufMut> ops::DerefMut for Slice<T> {
     fn deref_mut(&mut self) -> &mut [u8] {
-        &mut super::deref_mut(&mut self.buf)[self.begin..self.end]
+        let buf_bytes = super::deref_mut(&mut self.buf);
+        let end = cmp::min(self.end, buf_bytes.len());
+        &mut buf_bytes[self.begin..end]
     }
 }
 
 unsafe impl<T: IoBuf> IoBuf for Slice<T> {
     fn stable_ptr(&self) -> *const u8 {
-        ops::Deref::deref(self).as_ptr()
+        super::deref(&self.buf)[self.begin..].as_ptr()
     }
 
     fn bytes_init(&self) -> usize {
@@ -153,7 +158,7 @@ unsafe impl<T: IoBuf> IoBuf for Slice<T> {
 
 unsafe impl<T: IoBufMut> IoBufMut for Slice<T> {
     fn stable_mut_ptr(&mut self) -> *mut u8 {
-        ops::DerefMut::deref_mut(self).as_mut_ptr()
+        super::deref_mut(&mut self.buf)[self.begin..].as_mut_ptr()
     }
 
     unsafe fn set_init(&mut self, pos: usize) {


Test patch:
diff --git a/tests/buf.rs b/tests/buf.rs
index 2f69773c..958fc3be 100644
--- a/tests/buf.rs
+++ b/tests/buf.rs
@@ -1,5 +1,7 @@
 use tokio_uring::buf::{IoBuf, IoBufMut};
 
+use std::mem;
+
 #[test]
 fn test_vec() {
     let mut v = vec![];
@@ -117,3 +119,22 @@ test_slice! {
     vec => Vec::from(DATA);
     slice => DATA;
 }
+
+#[test]
+fn can_deref_slice_into_uninit_buf() {
+    let buf = Vec::with_capacity(10).slice(..);
+    let _ = buf.stable_ptr();
+    assert_eq!(buf.bytes_init(), 0);
+    assert_eq!(buf.bytes_total(), 10);
+    assert!(buf[..].is_empty());
+
+    let mut v = Vec::with_capacity(10);
+    v.push(42);
+    let mut buf = v.slice(..);
+    let _ = buf.stable_mut_ptr();
+    assert_eq!(buf.bytes_init(), 1);
+    assert_eq!(buf.bytes_total(), 10);
+    assert_eq!(mem::replace(&mut buf[0], 0), 42);
+    buf.copy_from_slice(&[43]);
+    assert_eq!(&buf[..], &[43]);
+}