@@ -287,18 +287,37 @@ impl fmt::Debug for Ipv6MembershipRequest {
287287 }
288288}
289289
290- /// Copy the in-memory representation of src into the byte slice dst,
291- /// updating the slice to point to the remainder of dst only. Unsafe
292- /// because it exposes all bytes in src, which may be UB if some of them
293- /// are uninitialized (including padding).
294- unsafe fn copy_bytes < ' a , ' b , T : ?Sized > ( src : & T , dst : & ' a mut & ' b mut [ u8 ] ) {
290+ /// Copy the in-memory representation of `src` into the byte slice `dst`.
291+ ///
292+ /// Returns the remainder of `dst`.
293+ ///
294+ /// Panics when `dst` is too small for `src` (more precisely, panics if
295+ /// `mem::size_of_val(src) >= dst.len()`).
296+ ///
297+ /// Unsafe because it transmutes `src` to raw bytes, which is only safe for some
298+ /// types `T`. Refer to the [Rustonomicon] for details.
299+ ///
300+ /// [Rustonomicon]: https://doc.rust-lang.org/nomicon/transmutes.html
301+ unsafe fn copy_bytes < ' a , T : ?Sized > ( src : & T , dst : & ' a mut [ u8 ] ) -> & ' a mut [ u8 ] {
295302 let srclen = mem:: size_of_val ( src) ;
296- let mut tmpdst = & mut [ ] [ ..] ;
297- mem:: swap ( & mut tmpdst, dst) ;
298- let ( target, mut remainder) = tmpdst. split_at_mut ( srclen) ;
299- // Safe because the mutable borrow of dst guarantees that src does not alias it.
300- ptr:: copy_nonoverlapping ( src as * const T as * const u8 , target. as_mut_ptr ( ) , srclen) ;
301- mem:: swap ( dst, & mut remainder) ;
303+ ptr:: copy_nonoverlapping (
304+ src as * const T as * const u8 ,
305+ dst[ ..srclen] . as_mut_ptr ( ) ,
306+ srclen
307+ ) ;
308+
309+ & mut dst[ srclen..]
310+ }
311+
312+ /// Fills `dst` with `len` zero bytes and returns the remainder of the slice.
313+ ///
314+ /// Panics when `len >= dst.len()`.
315+ fn pad_bytes ( len : usize , dst : & mut [ u8 ] ) -> & mut [ u8 ] {
316+ for pad in & mut dst[ ..len] {
317+ * pad = 0 ;
318+ }
319+
320+ & mut dst[ len..]
302321}
303322
304323cfg_if ! {
@@ -434,6 +453,11 @@ pub enum ControlMessage<'a> {
434453 ///
435454 /// See the description in the "Ancillary messages" section of the
436455 /// [unix(7) man page](http://man7.org/linux/man-pages/man7/unix.7.html).
456+ ///
457+ /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't recommended since it
458+ /// causes platform-dependent behaviour: It might swallow all but the first `ScmRights` message
459+ /// or fail with `EINVAL`. Instead, you can put all fds to be passed into a single `ScmRights`
460+ /// message.
437461 ScmRights ( & ' a [ RawFd ] ) ,
438462 /// A message of type `SCM_TIMESTAMP`, containing the time the
439463 /// packet was received by the kernel.
@@ -545,7 +569,7 @@ impl<'a> ControlMessage<'a> {
545569
546570 // Unsafe: start and end of buffer must be cmsg_align'd. Updates
547571 // the provided slice; panics if the buffer is too small.
548- unsafe fn encode_into < ' b > ( & self , buf : & mut & ' b mut [ u8 ] ) {
572+ unsafe fn encode_into ( & self , buf : & mut [ u8 ] ) {
549573 match * self {
550574 ControlMessage :: ScmRights ( fds) => {
551575 let cmsg = cmsghdr {
@@ -554,17 +578,16 @@ impl<'a> ControlMessage<'a> {
554578 cmsg_type : libc:: SCM_RIGHTS ,
555579 ..mem:: uninitialized ( )
556580 } ;
557- copy_bytes ( & cmsg, buf) ;
581+ let buf = copy_bytes ( & cmsg, buf) ;
558582
559583 let padlen = cmsg_align ( mem:: size_of_val ( & cmsg) ) -
560584 mem:: size_of_val ( & cmsg) ;
585+ let buf = pad_bytes ( padlen, buf) ;
561586
562- let mut tmpbuf = & mut [ ] [ ..] ;
563- mem:: swap ( & mut tmpbuf, buf) ;
564- let ( _padding, mut remainder) = tmpbuf. split_at_mut ( padlen) ;
565- mem:: swap ( buf, & mut remainder) ;
587+ let buf = copy_bytes ( fds, buf) ;
566588
567- copy_bytes ( fds, buf) ;
589+ let padlen = self . space ( ) - self . len ( ) ;
590+ pad_bytes ( padlen, buf) ;
568591 } ,
569592 ControlMessage :: ScmTimestamp ( t) => {
570593 let cmsg = cmsghdr {
@@ -573,21 +596,28 @@ impl<'a> ControlMessage<'a> {
573596 cmsg_type : libc:: SCM_TIMESTAMP ,
574597 ..mem:: uninitialized ( )
575598 } ;
576- copy_bytes ( & cmsg, buf) ;
599+ let buf = copy_bytes ( & cmsg, buf) ;
577600
578601 let padlen = cmsg_align ( mem:: size_of_val ( & cmsg) ) -
579602 mem:: size_of_val ( & cmsg) ;
603+ let buf = pad_bytes ( padlen, buf) ;
580604
581- let mut tmpbuf = & mut [ ] [ ..] ;
582- mem:: swap ( & mut tmpbuf, buf) ;
583- let ( _padding, mut remainder) = tmpbuf. split_at_mut ( padlen) ;
584- mem:: swap ( buf, & mut remainder) ;
605+ let buf = copy_bytes ( t, buf) ;
585606
586- copy_bytes ( t, buf) ;
607+ let padlen = self . space ( ) - self . len ( ) ;
608+ pad_bytes ( padlen, buf) ;
587609 } ,
588610 ControlMessage :: Unknown ( UnknownCmsg ( orig_cmsg, bytes) ) => {
589- copy_bytes ( orig_cmsg, buf) ;
590- copy_bytes ( bytes, buf) ;
611+ let buf = copy_bytes ( orig_cmsg, buf) ;
612+
613+ let padlen = cmsg_align ( mem:: size_of_val ( & orig_cmsg) ) -
614+ mem:: size_of_val ( & orig_cmsg) ;
615+ let buf = pad_bytes ( padlen, buf) ;
616+
617+ let buf = copy_bytes ( bytes, buf) ;
618+
619+ let padlen = self . space ( ) - self . len ( ) ;
620+ pad_bytes ( padlen, buf) ;
591621 }
592622 }
593623 }
@@ -600,23 +630,25 @@ impl<'a> ControlMessage<'a> {
600630///
601631/// Allocates if cmsgs is nonempty.
602632pub fn sendmsg < ' a > ( fd : RawFd , iov : & [ IoVec < & ' a [ u8 ] > ] , cmsgs : & [ ControlMessage < ' a > ] , flags : MsgFlags , addr : Option < & ' a SockAddr > ) -> Result < usize > {
603- let mut len = 0 ;
604633 let mut capacity = 0 ;
605634 for cmsg in cmsgs {
606- len += cmsg. len ( ) ;
607635 capacity += cmsg. space ( ) ;
608636 }
609637 // Note that the resulting vector claims to have length == capacity,
610638 // so it's presently uninitialized.
611639 let mut cmsg_buffer = unsafe {
612- let mut vec = Vec :: < u8 > :: with_capacity ( len ) ;
613- vec. set_len ( len ) ;
640+ let mut vec = Vec :: < u8 > :: with_capacity ( capacity ) ;
641+ vec. set_len ( capacity ) ;
614642 vec
615643 } ;
616644 {
617- let mut ptr = & mut cmsg_buffer [ .. ] ;
645+ let mut ofs = 0 ;
618646 for cmsg in cmsgs {
619- unsafe { cmsg. encode_into ( & mut ptr) } ;
647+ let mut ptr = & mut cmsg_buffer[ ofs..] ;
648+ unsafe {
649+ cmsg. encode_into ( ptr) ;
650+ }
651+ ofs += cmsg. space ( ) ;
620652 }
621653 }
622654
@@ -669,10 +701,23 @@ pub fn recvmsg<'a, T>(fd: RawFd, iov: &[IoVec<&mut [u8]>], cmsg_buffer: Option<&
669701 } ;
670702 let ret = unsafe { libc:: recvmsg ( fd, & mut mhdr, flags. bits ( ) ) } ;
671703
704+ let cmsg_buffer = if msg_controllen > 0 {
705+ // got control message(s)
706+ debug_assert ! ( !mhdr. msg_control. is_null( ) ) ;
707+ unsafe {
708+ // Safe: The pointer is not null and the length is correct as part of `recvmsg`s
709+ // contract.
710+ slice:: from_raw_parts ( mhdr. msg_control as * const u8 ,
711+ mhdr. msg_controllen as usize )
712+ }
713+ } else {
714+ // No control message, create an empty buffer to avoid creating a slice from a null pointer
715+ & [ ]
716+ } ;
717+
672718 Ok ( unsafe { RecvMsg {
673719 bytes : try!( Errno :: result ( ret) ) as usize ,
674- cmsg_buffer : slice:: from_raw_parts ( mhdr. msg_control as * const u8 ,
675- mhdr. msg_controllen as usize ) ,
720+ cmsg_buffer,
676721 address : sockaddr_storage_to_addr ( & address,
677722 mhdr. msg_namelen as usize ) . ok ( ) ,
678723 flags : MsgFlags :: from_bits_truncate ( mhdr. msg_flags ) ,
0 commit comments