@@ -287,18 +287,37 @@ impl fmt::Debug for Ipv6MembershipRequest {
287
287
}
288
288
}
289
289
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 ] {
295
302
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..]
302
321
}
303
322
304
323
cfg_if ! {
@@ -434,6 +453,11 @@ pub enum ControlMessage<'a> {
434
453
///
435
454
/// See the description in the "Ancillary messages" section of the
436
455
/// [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.
437
461
ScmRights ( & ' a [ RawFd ] ) ,
438
462
/// A message of type `SCM_TIMESTAMP`, containing the time the
439
463
/// packet was received by the kernel.
@@ -545,7 +569,7 @@ impl<'a> ControlMessage<'a> {
545
569
546
570
// Unsafe: start and end of buffer must be cmsg_align'd. Updates
547
571
// 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 ] ) {
549
573
match * self {
550
574
ControlMessage :: ScmRights ( fds) => {
551
575
let cmsg = cmsghdr {
@@ -554,17 +578,16 @@ impl<'a> ControlMessage<'a> {
554
578
cmsg_type : libc:: SCM_RIGHTS ,
555
579
..mem:: uninitialized ( )
556
580
} ;
557
- copy_bytes ( & cmsg, buf) ;
581
+ let buf = copy_bytes ( & cmsg, buf) ;
558
582
559
583
let padlen = cmsg_align ( mem:: size_of_val ( & cmsg) ) -
560
584
mem:: size_of_val ( & cmsg) ;
585
+ let buf = pad_bytes ( padlen, buf) ;
561
586
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) ;
566
588
567
- copy_bytes ( fds, buf) ;
589
+ let padlen = self . space ( ) - self . len ( ) ;
590
+ pad_bytes ( padlen, buf) ;
568
591
} ,
569
592
ControlMessage :: ScmTimestamp ( t) => {
570
593
let cmsg = cmsghdr {
@@ -573,21 +596,28 @@ impl<'a> ControlMessage<'a> {
573
596
cmsg_type : libc:: SCM_TIMESTAMP ,
574
597
..mem:: uninitialized ( )
575
598
} ;
576
- copy_bytes ( & cmsg, buf) ;
599
+ let buf = copy_bytes ( & cmsg, buf) ;
577
600
578
601
let padlen = cmsg_align ( mem:: size_of_val ( & cmsg) ) -
579
602
mem:: size_of_val ( & cmsg) ;
603
+ let buf = pad_bytes ( padlen, buf) ;
580
604
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) ;
585
606
586
- copy_bytes ( t, buf) ;
607
+ let padlen = self . space ( ) - self . len ( ) ;
608
+ pad_bytes ( padlen, buf) ;
587
609
} ,
588
610
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) ;
591
621
}
592
622
}
593
623
}
@@ -600,23 +630,25 @@ impl<'a> ControlMessage<'a> {
600
630
///
601
631
/// Allocates if cmsgs is nonempty.
602
632
pub 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 ;
604
633
let mut capacity = 0 ;
605
634
for cmsg in cmsgs {
606
- len += cmsg. len ( ) ;
607
635
capacity += cmsg. space ( ) ;
608
636
}
609
637
// Note that the resulting vector claims to have length == capacity,
610
638
// so it's presently uninitialized.
611
639
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 ) ;
614
642
vec
615
643
} ;
616
644
{
617
- let mut ptr = & mut cmsg_buffer [ .. ] ;
645
+ let mut ofs = 0 ;
618
646
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 ( ) ;
620
652
}
621
653
}
622
654
@@ -669,10 +701,23 @@ pub fn recvmsg<'a, T>(fd: RawFd, iov: &[IoVec<&mut [u8]>], cmsg_buffer: Option<&
669
701
} ;
670
702
let ret = unsafe { libc:: recvmsg ( fd, & mut mhdr, flags. bits ( ) ) } ;
671
703
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
+
672
718
Ok ( unsafe { RecvMsg {
673
719
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,
676
721
address : sockaddr_storage_to_addr ( & address,
677
722
mhdr. msg_namelen as usize ) . ok ( ) ,
678
723
flags : MsgFlags :: from_bits_truncate ( mhdr. msg_flags ) ,
0 commit comments