From ca7fb82e0b9fb47e4addcee7b993993e7ce27fde Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 29 Jun 2014 09:38:07 -0700 Subject: [PATCH] rustuv: Don't zero-out data on clones When cloning a stream, the data is already guaranteed to be in a consistent state, so there's no need to perform a zeroing. This prevents segfaults as seen in #15231 Closes #15231 --- src/librustuv/net.rs | 4 ++-- src/librustuv/pipe.rs | 4 ++-- src/librustuv/stream.rs | 7 +++++-- src/librustuv/tty.rs | 2 +- src/libstd/io/net/tcp.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/libstd/task.rs | 2 +- 6 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index f1c37762129..cfed05bf5be 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -191,7 +191,7 @@ impl TcpWatcher { TcpWatcher { home: home, handle: handle, - stream: StreamWatcher::new(handle), + stream: StreamWatcher::new(handle, true), refcount: Refcount::new(), read_access: AccessTimeout::new(), write_access: AccessTimeout::new(), @@ -278,7 +278,7 @@ impl rtio::RtioTcpStream for TcpWatcher { fn clone(&self) -> Box { box TcpWatcher { handle: self.handle, - stream: StreamWatcher::new(self.handle), + stream: StreamWatcher::new(self.handle, false), home: self.home.clone(), refcount: self.refcount.clone(), read_access: self.read_access.clone(), diff --git a/src/librustuv/pipe.rs b/src/librustuv/pipe.rs index cff7e9d7738..1c53814ac24 100644 --- a/src/librustuv/pipe.rs +++ b/src/librustuv/pipe.rs @@ -67,7 +67,7 @@ impl PipeWatcher { handle }; PipeWatcher { - stream: StreamWatcher::new(handle), + stream: StreamWatcher::new(handle, true), home: home, defused: false, refcount: Refcount::new(), @@ -131,7 +131,7 @@ impl rtio::RtioPipe for PipeWatcher { fn clone(&self) -> Box { box PipeWatcher { - stream: StreamWatcher::new(self.stream.handle), + stream: StreamWatcher::new(self.stream.handle, false), defused: false, home: self.home.clone(), refcount: self.refcount.clone(), diff --git a/src/librustuv/stream.rs b/src/librustuv/stream.rs index f615e8287b3..f6b9226588c 100644 --- a/src/librustuv/stream.rs +++ b/src/librustuv/stream.rs @@ -59,8 +59,11 @@ impl StreamWatcher { // will be manipulated on each of the methods called on this watcher. // Wrappers should ensure to always reset the field to an appropriate value // if they rely on the field to perform an action. - pub fn new(stream: *mut uvll::uv_stream_t) -> StreamWatcher { - unsafe { uvll::set_data_for_uv_handle(stream, 0 as *mut int) } + pub fn new(stream: *mut uvll::uv_stream_t, + init: bool) -> StreamWatcher { + if init { + unsafe { uvll::set_data_for_uv_handle(stream, 0 as *mut int) } + } StreamWatcher { handle: stream, last_write_req: None, diff --git a/src/librustuv/tty.rs b/src/librustuv/tty.rs index 85ec0c75d53..70b17db8dcf 100644 --- a/src/librustuv/tty.rs +++ b/src/librustuv/tty.rs @@ -56,7 +56,7 @@ impl TtyWatcher { let handle = UvHandle::alloc(None::, uvll::UV_TTY); let mut watcher = TtyWatcher { tty: handle, - stream: StreamWatcher::new(handle), + stream: StreamWatcher::new(handle, true), home: io.make_handle(), fd: fd, }; diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index b79e831ff61..baf53251fbe 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -1360,4 +1360,44 @@ mod test { rx2.recv(); }) + + iotest!(fn clone_while_reading() { + let addr = next_test_ip6(); + let listen = TcpListener::bind(addr.ip.to_str().as_slice(), addr.port); + let mut accept = listen.listen().unwrap(); + + // Enqueue a task to write to a socket + let (tx, rx) = channel(); + let (txdone, rxdone) = channel(); + let txdone2 = txdone.clone(); + spawn(proc() { + let mut tcp = TcpStream::connect(addr.ip.to_str().as_slice(), + addr.port).unwrap(); + rx.recv(); + tcp.write_u8(0).unwrap(); + txdone2.send(()); + }); + + // Spawn off a reading clone + let tcp = accept.accept().unwrap(); + let tcp2 = tcp.clone(); + let txdone3 = txdone.clone(); + spawn(proc() { + let mut tcp2 = tcp2; + tcp2.read_u8().unwrap(); + txdone3.send(()); + }); + + // Try to ensure that the reading clone is indeed reading + for _ in range(0i, 50) { + ::task::deschedule(); + } + + // clone the handle again while it's reading, then let it finish the + // read. + let _ = tcp.clone(); + tx.send(()); + rxdone.recv(); + rxdone.recv(); + }) } diff --git a/src/libstd/task.rs b/src/libstd/task.rs index 21d19deb0c7..6492717d3ec 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -649,7 +649,7 @@ fn task_abort_no_kill_runtime() { use std::io::timer; use mem; - let mut tb = TaskBuilder::new(); + let tb = TaskBuilder::new(); let rx = tb.try_future(proc() {}); mem::drop(rx); timer::sleep(1000);