Closed FrancisRussell closed 5 years ago
@FrancisRussell sorry for the delay. Do you have a minimal working example that reproduces this ?
Without having looked at what the current implementation does, an empty SliceDeque
is guaranteed to:
&[T]
whose length is 0
, that is, is_empty() == true
. &[T].as_ptr()
returns mem::align_of::<T>() as *[mut,const] T
which is a valid pointer to address a zero-sized allocation of a T
This is pretty much how all Rust's allocation mechanisms (GlobalAlloc
, Alloc
, Vec
, Box
, ...) work when passed a ZST.
If SliceDeque
does not currently work like this, then this is a bug that should be fixed.
If I pass this code a SliceDeque::new(), the write will fail with EFAULT (buf is outside the accessible address space), because SliceDeque returns a start pointer that is not mapped in the address space.
I suppose that you are calling write
with a length of zero. Is that correct? EDIT: that is, can you assert that the buffer being passed to <TcpStream as Write>::write(tcp_stream, &buf)
has a length of zero ?
I've written this to replicate (the issue also manifests under standard file IO):
extern crate slice_deque;
use slice_deque::SliceDeque;
use std::fs::File;
use std::io::Write;
fn main() {
let out_buffer = SliceDeque::new();
let mut out_file = File::create("/tmp/slice_deque_test").unwrap();
let res = out_file.write(&out_buffer[..]);
println!("Result was {:?}", res);
println!("Buffer size: {}", out_buffer.len());
println!("Address of buffer was: {:?}", out_buffer.as_ptr());
}
Running on x86-64 Debian testing under a 4.6.12 kernel and slice-deque 0.1.13 I get the following:
Result was Err(Os { code: 14, kind: Other, message: "Bad address" })
Buffer size: 0
Address of buffer was: 0xffffffffffffffff
I traced the issue to this line. I note that drop() specifically avoids doing a deallocation when the buffer is empty, however, it looks like removing this check will break things since deallocate_mirrored() expects a non-zero size.
Could you confirm that v0.1.14 fixes this?
I've been using SliceDeque with code that uses the write system call on Linux (via the standard Write trait on std::net::TcpStream). If I pass this code a SliceDeque::new(), the write will fail with EFAULT (buf is outside the accessible address space), because SliceDeque returns a start pointer that is not mapped in the address space.
I've not been able to find any documentation on the guarantees intended to be provided by slice, but it would seem to be good practice to have the zero length SliceDeque return a pointer inside the address space, such as null, for a zero-length slice since Linux system calls will check the pointer validity, even if the start address will not be deferenced.