about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2013-04-22 19:20:31 -0700
committerBrian Anderson <banderson@mozilla.com>2013-04-22 19:20:31 -0700
commit8a2f9cae213d38b31e9372b9d8a7fee1263f1363 (patch)
tree4bccce3e1845aa4c046303d7302d828d9bc2d432
parenta292d5175091f61e92d0f393275e32ad2b05d584 (diff)
downloadrust-8a2f9cae213d38b31e9372b9d8a7fee1263f1363.tar.gz
rust-8a2f9cae213d38b31e9372b9d8a7fee1263f1363.zip
core::rt: Fix a use after free in uv 'write'
-rw-r--r--src/libcore/rt/uv/mod.rs6
-rw-r--r--src/libcore/rt/uv/net.rs16
-rw-r--r--src/libcore/rt/uvio.rs5
-rw-r--r--src/libcore/rt/uvll.rs6
4 files changed, 21 insertions, 12 deletions
diff --git a/src/libcore/rt/uv/mod.rs b/src/libcore/rt/uv/mod.rs
index 32757d6376e..4c4b2e03d3d 100644
--- a/src/libcore/rt/uv/mod.rs
+++ b/src/libcore/rt/uv/mod.rs
@@ -301,7 +301,8 @@ struct WatcherData {
     write_cb: Option<ConnectionCallback>,
     connect_cb: Option<ConnectionCallback>,
     close_cb: Option<NullCallback>,
-    alloc_cb: Option<AllocCallback>
+    alloc_cb: Option<AllocCallback>,
+    buf: Option<Buf>
 }
 
 pub fn install_watcher_data<H, W: Watcher + NativeHandle<*H>>(watcher: &mut W) {
@@ -311,7 +312,8 @@ pub fn install_watcher_data<H, W: Watcher + NativeHandle<*H>>(watcher: &mut W) {
             write_cb: None,
             connect_cb: None,
             close_cb: None,
-            alloc_cb: None
+            alloc_cb: None,
+            buf: None
         };
         let data = transmute::<~WatcherData, *c_void>(data);
         uvll::set_data_for_uv_handle(watcher.native_handle(), data);
diff --git a/src/libcore/rt/uv/net.rs b/src/libcore/rt/uv/net.rs
index 860c988b9c9..04b9008b067 100644
--- a/src/libcore/rt/uv/net.rs
+++ b/src/libcore/rt/uv/net.rs
@@ -107,21 +107,25 @@ pub impl StreamWatcher {
 
         let req = WriteRequest::new();
         let buf = vec_to_uv_buf(msg);
-        // XXX: Allocation
-        let bufs = ~[buf];
+        assert!(data.buf.is_none());
+        data.buf = Some(buf);
+        let bufs = [buf];
         unsafe {
             assert!(0 == uvll::write(req.native_handle(),
                                           self.native_handle(),
-                                          &bufs, write_cb));
+                                          bufs, write_cb));
         }
-        // XXX: Freeing immediately after write. Is this ok?
-        let _v = vec_from_uv_buf(buf);
 
         extern fn write_cb(req: *uvll::uv_write_t, status: c_int) {
             let write_request: WriteRequest = NativeHandle::from_native_handle(req);
             let mut stream_watcher = write_request.stream();
             write_request.delete();
-            let cb = get_watcher_data(&mut stream_watcher).write_cb.swap_unwrap();
+            let cb = {
+                let data = get_watcher_data(&mut stream_watcher);
+                let _vec = vec_from_uv_buf(data.buf.swap_unwrap());
+                let cb = data.write_cb.swap_unwrap();
+                cb
+            };
             let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status);
             cb(stream_watcher, status);
         }
diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs
index 2e9d0afa52f..e7b2880b74b 100644
--- a/src/libcore/rt/uvio.rs
+++ b/src/libcore/rt/uvio.rs
@@ -445,7 +445,7 @@ fn test_read_read_read() {
                 let io = local_sched::unsafe_borrow_io();
                 let mut listener = io.bind(addr).unwrap();
                 let mut stream = listener.listen().unwrap();
-                let mut buf = [0, .. 2048];
+                let mut buf = [1, .. 2048];
                 let mut total_bytes_written = 0;
                 while total_bytes_written < MAX {
                     stream.write(buf);
@@ -465,6 +465,9 @@ fn test_read_read_read() {
                 let nread = stream.read(buf).unwrap();
                 rtdebug!("read %u bytes", nread as uint);
                 total_bytes_read += nread;
+                for uint::range(0, nread) |i| {
+                    assert!(buf[i] == 1);
+                }
             }
             rtdebug!("read %u bytes total", total_bytes_read as uint);
             stream.close();
diff --git a/src/libcore/rt/uvll.rs b/src/libcore/rt/uvll.rs
index 640a69743ba..0f75ebb6090 100644
--- a/src/libcore/rt/uvll.rs
+++ b/src/libcore/rt/uvll.rs
@@ -219,9 +219,9 @@ pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int {
     return rust_uv_accept(server as *c_void, client as *c_void);
 }
 
-pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: *~[uv_buf_t], cb: *u8) -> c_int {
-    let buf_ptr = vec::raw::to_ptr(*buf_in);
-    let buf_cnt = vec::len(*buf_in) as i32;
+pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int {
+    let buf_ptr = vec::raw::to_ptr(buf_in);
+    let buf_cnt = vec::len(buf_in) as i32;
     return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb);
 }
 pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> c_int {