]> git.lizzy.rs Git - rust.git/commitdiff
Change everything returning `libc::sockaddr_storage` to use an &mut out-ptr instead
authorAndrew Poelstra <apoelstra@wpsoftware.net>
Mon, 4 Aug 2014 16:46:15 +0000 (09:46 -0700)
committerAndrew Poelstra <apoelstra@wpsoftware.net>
Mon, 4 Aug 2014 19:52:58 +0000 (12:52 -0700)
The BSD socket code does some cast tricks with the `libc::sockaddr*`
structs, which causes useful data to be stored in struct padding.
Since Load/Store instructions do not copy struct padding, this makes
these structures dangerous to pass or return by value.

In particular, https://github.com/rust-lang/rust/issues/15763 changes
return semantics so that a Load instruction is used, breaking the TCP
code. Once this PR is merged, that one should merge without error.

src/libnative/io/net.rs
src/libnative/io/pipe_unix.rs
src/librustuv/net.rs

index cf2d6e7fb45ae18ab1f5fb62502f34a612bf477c..a5332c8d077154ccdc9416b63ffb3b8316860327 100644 (file)
@@ -66,26 +66,27 @@ fn ip_to_inaddr(ip: rtio::IpAddr) -> InAddr {
     }
 }
 
-fn addr_to_sockaddr(addr: rtio::SocketAddr) -> (libc::sockaddr_storage, uint) {
+fn addr_to_sockaddr(addr: rtio::SocketAddr,
+                    storage: &mut libc::sockaddr_storage)
+                    -> libc::socklen_t {
     unsafe {
-        let storage: libc::sockaddr_storage = mem::zeroed();
         let len = match ip_to_inaddr(addr.ip) {
             InAddr(inaddr) => {
-                let storage: *mut libc::sockaddr_in = mem::transmute(&storage);
+                let storage = storage as *mut _ as *mut libc::sockaddr_in;
                 (*storage).sin_family = libc::AF_INET as libc::sa_family_t;
                 (*storage).sin_port = htons(addr.port);
                 (*storage).sin_addr = inaddr;
                 mem::size_of::<libc::sockaddr_in>()
             }
             In6Addr(inaddr) => {
-                let storage: *mut libc::sockaddr_in6 = mem::transmute(&storage);
+                let storage = storage as *mut _ as *mut libc::sockaddr_in6;
                 (*storage).sin6_family = libc::AF_INET6 as libc::sa_family_t;
                 (*storage).sin6_port = htons(addr.port);
                 (*storage).sin6_addr = inaddr;
                 mem::size_of::<libc::sockaddr_in6>()
             }
         };
-        return (storage, len);
+        return len as libc::socklen_t;
     }
 }
 
@@ -277,9 +278,9 @@ pub fn connect(addr: rtio::SocketAddr,
         let fd = try!(socket(addr, libc::SOCK_STREAM));
         let ret = TcpStream::new(Inner::new(fd));
 
-        let (addr, len) = addr_to_sockaddr(addr);
-        let addrp = &addr as *const _ as *const libc::sockaddr;
-        let len = len as libc::socklen_t;
+        let mut storage = unsafe { mem::zeroed() };
+        let len = addr_to_sockaddr(addr, &mut storage);
+        let addrp = &storage as *const _ as *const libc::sockaddr;
 
         match timeout {
             Some(timeout) => {
@@ -457,9 +458,9 @@ pub fn bind(addr: rtio::SocketAddr) -> IoResult<TcpListener> {
         let fd = try!(socket(addr, libc::SOCK_STREAM));
         let ret = TcpListener { inner: Inner::new(fd) };
 
-        let (addr, len) = addr_to_sockaddr(addr);
-        let addrp = &addr as *const _ as *const libc::sockaddr;
-        let len = len as libc::socklen_t;
+        let mut storage = unsafe { mem::zeroed() };
+        let len = addr_to_sockaddr(addr, &mut storage);
+        let addrp = &storage as *const _ as *const libc::sockaddr;
 
         // On platforms with Berkeley-derived sockets, this allows
         // to quickly rebind a socket, without needing to wait for
@@ -566,9 +567,9 @@ pub fn bind(addr: rtio::SocketAddr) -> IoResult<UdpSocket> {
             write_deadline: 0,
         };
 
-        let (addr, len) = addr_to_sockaddr(addr);
-        let addrp = &addr as *const _ as *const libc::sockaddr;
-        let len = len as libc::socklen_t;
+        let mut storage = unsafe { mem::zeroed() };
+        let len = addr_to_sockaddr(addr, &mut storage);
+        let addrp = &storage as *const _ as *const libc::sockaddr;
 
         match unsafe { libc::bind(fd, addrp, len) } {
             -1 => Err(last_error()),
@@ -656,9 +657,9 @@ fn recv_from(&mut self, buf: &mut [u8]) -> IoResult<(uint, rtio::SocketAddr)> {
     }
 
     fn send_to(&mut self, buf: &[u8], dst: rtio::SocketAddr) -> IoResult<()> {
-        let (dst, dstlen) = addr_to_sockaddr(dst);
-        let dstp = &dst as *const _ as *const libc::sockaddr;
-        let dstlen = dstlen as libc::socklen_t;
+        let mut storage = unsafe { mem::zeroed() };
+        let dstlen = addr_to_sockaddr(dst, &mut storage);
+        let dstp = &storage as *const _ as *const libc::sockaddr;
 
         let fd = self.fd();
         let dolock = || self.lock_nonblocking();
index 075ca769d073e919a46f31415195cce75205e13d..bc3f917a3dcc358f49a793a0f02a561b2cef1209 100644 (file)
@@ -29,12 +29,13 @@ fn unix_socket(ty: libc::c_int) -> IoResult<fd_t> {
     }
 }
 
-fn addr_to_sockaddr_un(addr: &CString) -> IoResult<(libc::sockaddr_storage, uint)> {
+fn addr_to_sockaddr_un(addr: &CString,
+                       storage: &mut libc::sockaddr_storage)
+                       -> IoResult<libc::socklen_t> {
     // the sun_path length is limited to SUN_LEN (with null)
     assert!(mem::size_of::<libc::sockaddr_storage>() >=
             mem::size_of::<libc::sockaddr_un>());
-    let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
-    let s: &mut libc::sockaddr_un = unsafe { mem::transmute(&mut storage) };
+    let s = unsafe { &mut *(storage as *mut _ as *mut libc::sockaddr_un) };
 
     let len = addr.len();
     if len > s.sun_path.len() - 1 {
@@ -53,7 +54,7 @@ fn addr_to_sockaddr_un(addr: &CString) -> IoResult<(libc::sockaddr_storage, uint
 
     // count the null terminator
     let len = mem::size_of::<libc::sa_family_t>() + len + 1;
-    return Ok((storage, len));
+    return Ok(len as libc::socklen_t);
 }
 
 struct Inner {
@@ -76,10 +77,10 @@ impl Drop for Inner {
 
 fn connect(addr: &CString, ty: libc::c_int,
            timeout: Option<u64>) -> IoResult<Inner> {
-    let (addr, len) = try!(addr_to_sockaddr_un(addr));
+    let mut storage = unsafe { mem::zeroed() };
+    let len = try!(addr_to_sockaddr_un(addr, &mut storage));
     let inner = Inner::new(try!(unix_socket(ty)));
-    let addrp = &addr as *const _ as *const libc::sockaddr;
-    let len = len as libc::socklen_t;
+    let addrp = &storage as *const _ as *const libc::sockaddr;
 
     match timeout {
         None => {
@@ -96,11 +97,12 @@ fn connect(addr: &CString, ty: libc::c_int,
 }
 
 fn bind(addr: &CString, ty: libc::c_int) -> IoResult<Inner> {
-    let (addr, len) = try!(addr_to_sockaddr_un(addr));
+    let mut storage = unsafe { mem::zeroed() };
+    let len = try!(addr_to_sockaddr_un(addr, &mut storage));
     let inner = Inner::new(try!(unix_socket(ty)));
-    let addrp = &addr as *const _;
+    let addrp = &storage as *const _ as *const libc::sockaddr;
     match unsafe {
-        libc::bind(inner.fd, addrp as *const _, len as libc::socklen_t)
+        libc::bind(inner.fd, addrp, len)
     } {
         -1 => Err(super::last_error()),
         _  => Ok(inner)
index 3cc10ae3823ac56a545d4e6fa4e014ebeccba299..16451f7edd9abbd75dac839790cc1ec6da807bfd 100644 (file)
@@ -75,17 +75,17 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
     }
 }
 
-fn addr_to_sockaddr(addr: rtio::SocketAddr) -> (libc::sockaddr_storage, uint) {
+fn addr_to_sockaddr(addr: rtio::SocketAddr,
+                    storage: &mut libc::sockaddr_storage)
+                    -> libc::socklen_t {
     unsafe {
-        let mut storage: libc::sockaddr_storage = mem::zeroed();
         let len = match addr.ip {
             rtio::Ipv4Addr(a, b, c, d) => {
                 let ip = (a as u32 << 24) |
                          (b as u32 << 16) |
                          (c as u32 <<  8) |
                          (d as u32 <<  0);
-                let storage: &mut libc::sockaddr_in =
-                    mem::transmute(&mut storage);
+                let storage = storage as *mut _ as *mut libc::sockaddr_in;
                 (*storage).sin_family = libc::AF_INET as libc::sa_family_t;
                 (*storage).sin_port = htons(addr.port);
                 (*storage).sin_addr = libc::in_addr {
@@ -95,11 +95,10 @@ fn addr_to_sockaddr(addr: rtio::SocketAddr) -> (libc::sockaddr_storage, uint) {
                 mem::size_of::<libc::sockaddr_in>()
             }
             rtio::Ipv6Addr(a, b, c, d, e, f, g, h) => {
-                let storage: &mut libc::sockaddr_in6 =
-                    mem::transmute(&mut storage);
-                storage.sin6_family = libc::AF_INET6 as libc::sa_family_t;
-                storage.sin6_port = htons(addr.port);
-                storage.sin6_addr = libc::in6_addr {
+                let storage = storage as *mut _ as *mut libc::sockaddr_in6;
+                (*storage).sin6_family = libc::AF_INET6 as libc::sa_family_t;
+                (*storage).sin6_port = htons(addr.port);
+                (*storage).sin6_addr = libc::in6_addr {
                     s6_addr: [
                         htons(a),
                         htons(b),
@@ -114,7 +113,7 @@ fn addr_to_sockaddr(addr: rtio::SocketAddr) -> (libc::sockaddr_storage, uint) {
                 mem::size_of::<libc::sockaddr_in6>()
             }
         };
-        return (storage, len);
+        return len as libc::socklen_t
     }
 }
 
@@ -203,8 +202,9 @@ pub fn connect(io: &mut UvIoFactory,
                    timeout: Option<u64>) -> Result<TcpWatcher, UvError> {
         let tcp = TcpWatcher::new(io);
         let cx = ConnectCtx { status: -1, task: None, timer: None };
-        let (addr, _len) = addr_to_sockaddr(address);
-        let addr_p = &addr as *const _ as *const libc::sockaddr;
+        let mut storage = unsafe { mem::zeroed() };
+        let _len = addr_to_sockaddr(address, &mut storage);
+        let addr_p = &storage as *const _ as *const libc::sockaddr;
         cx.connect(tcp, timeout, io, |req, tcp, cb| {
             unsafe { uvll::uv_tcp_connect(req.handle, tcp.handle, addr_p, cb) }
         })
@@ -361,10 +361,11 @@ pub fn bind(io: &mut UvIoFactory, address: rtio::SocketAddr)
             outgoing: tx,
             incoming: rx,
         };
-        let (addr, _len) = addr_to_sockaddr(address);
+        let mut storage = unsafe { mem::zeroed() };
+        let _len = addr_to_sockaddr(address, &mut storage);
         let res = unsafe {
-            let addr_p = &addr as *const libc::sockaddr_storage;
-            uvll::uv_tcp_bind(l.handle, addr_p as *const libc::sockaddr)
+            let addr_p = &storage as *const _ as *const libc::sockaddr;
+            uvll::uv_tcp_bind(l.handle, addr_p)
         };
         return match res {
             0 => Ok(l.install()),
@@ -513,10 +514,11 @@ pub fn bind(io: &mut UvIoFactory, address: rtio::SocketAddr)
         assert_eq!(unsafe {
             uvll::uv_udp_init(io.uv_loop(), udp.handle)
         }, 0);
-        let (addr, _len) = addr_to_sockaddr(address);
+        let mut storage = unsafe { mem::zeroed() };
+        let _len = addr_to_sockaddr(address, &mut storage);
         let result = unsafe {
-            let addr_p = &addr as *const libc::sockaddr_storage;
-            uvll::uv_udp_bind(udp.handle, addr_p as *const libc::sockaddr, 0u32)
+            let addr_p = &storage as *const _ as *const libc::sockaddr;
+            uvll::uv_udp_bind(udp.handle, addr_p, 0u32)
         };
         return match result {
             0 => Ok(udp),
@@ -614,8 +616,9 @@ fn send_to(&mut self, buf: &[u8], dst: rtio::SocketAddr) -> Result<(), IoError>
         let guard = try!(self.write_access.grant(m));
 
         let mut req = Request::new(uvll::UV_UDP_SEND);
-        let (addr, _len) = addr_to_sockaddr(dst);
-        let addr_p = &addr as *const _ as *const libc::sockaddr;
+        let mut storage = unsafe { mem::zeroed() };
+        let _len = addr_to_sockaddr(dst, &mut storage);
+        let addr_p = &storage as *const _ as *const libc::sockaddr;
 
         // see comments in StreamWatcher::write for why we may allocate a buffer
         // here.