@@ -387,7 +387,7 @@ impl<'a, B: BitmapSlice> VolatileSlice<'a, B> {
387
387
// memory of the original slice.
388
388
unsafe {
389
389
Ok ( VolatileSlice :: with_bitmap (
390
- new_addr as * mut u8 ,
390
+ self . addr . add ( count ) ,
391
391
new_size,
392
392
self . bitmap . slice_at ( count) ,
393
393
) )
@@ -424,12 +424,16 @@ impl<'a, B: BitmapSlice> VolatileSlice<'a, B> {
424
424
{
425
425
// A fast path for u8/i8
426
426
if size_of :: < T > ( ) == 1 {
427
- // SAFETY: It is safe because the pointers are range-checked when the slices are
428
- // created, and they never escape the VolatileSlices.
429
- let source = unsafe { self . as_slice ( ) } ;
430
- // SAFETY: Safe because `T` is a one-byte data structure.
431
- let dst = unsafe { from_raw_parts_mut ( buf. as_mut_ptr ( ) as * mut u8 , buf. len ( ) ) } ;
432
- copy_slice ( dst, source)
427
+ let total = buf. len ( ) . min ( self . len ( ) ) ;
428
+
429
+ // SAFETY:
430
+ // - dst is valid for writes of at least `total`, since total <= buf.len()
431
+ // - src is valid for reads of at least `total` as total <= self.len()
432
+ // - The regions are non-overlapping as `src` points to guest memory and `buf` is
433
+ // a slice and thus has to live outside of guest memory (there can be more slices to
434
+ // guest memory without violating rust's aliasing rules)
435
+ // - size is always a multiple of alignment, so treating *mut T as *mut u8 is fine
436
+ unsafe { copy_slice ( buf. as_mut_ptr ( ) as * mut u8 , self . as_ptr ( ) , total) }
433
437
} else {
434
438
let count = self . size / size_of :: < T > ( ) ;
435
439
let source = self . get_array_ref :: < T > ( 0 , count) . unwrap ( ) ;
@@ -504,12 +508,16 @@ impl<'a, B: BitmapSlice> VolatileSlice<'a, B> {
504
508
{
505
509
// A fast path for u8/i8
506
510
if size_of :: < T > ( ) == 1 {
507
- // SAFETY: It is safe because the pointers are range-checked when the slices are created,
508
- // and they never escape the VolatileSlices.
509
- let dst = unsafe { self . as_mut_slice ( ) } ;
510
- // SAFETY: Safe because `T` is a one-byte data structure.
511
- let src = unsafe { from_raw_parts ( buf. as_ptr ( ) as * const u8 , buf. len ( ) ) } ;
512
- let count = copy_slice ( dst, src) ;
511
+ let total = buf. len ( ) . min ( self . len ( ) ) ;
512
+ // SAFETY:
513
+ // - dst is valid for writes of at least `total`, since total <= self.len()
514
+ // - src is valid for reads of at least `total` as total <= buf.len()
515
+ // - The regions are non-overlapping as `dst` points to guest memory and `buf` is
516
+ // a slice and thus has to live outside of guest memory (there can be more slices to
517
+ // guest memory without violating rust's aliasing rules)
518
+ // - size is always a multiple of alignment, so treating *mut T as *mut u8 is fine
519
+ let count = unsafe { copy_slice ( self . as_ptr ( ) , buf. as_ptr ( ) as * const u8 , total) } ;
520
+
513
521
self . bitmap . mark_dirty ( 0 , count * size_of :: < T > ( ) ) ;
514
522
} else {
515
523
let count = self . size / size_of :: < T > ( ) ;
@@ -587,12 +595,21 @@ impl<B: BitmapSlice> Bytes<usize> for VolatileSlice<'_, B> {
587
595
return Err ( Error :: OutOfBounds { addr } ) ;
588
596
}
589
597
590
- // SAFETY: Guest memory can't strictly be modeled as a slice because it is
591
- // volatile. Writing to it with what is essentially a fancy memcpy
592
- // won't hurt anything as long as we get the bounds checks right.
593
- let slice = unsafe { self . as_mut_slice ( ) } . split_at_mut ( addr) . 1 ;
598
+ let total = buf. len ( ) . min ( self . len ( ) - addr) ;
599
+
600
+ // SAFETY:
601
+ // We check above that `addr` is a valid offset within this volatile slice, and by
602
+ // the invariants of `VolatileSlice::new`, this volatile slice points to contiguous
603
+ // memory of length self.len(). Furthermore, both src and dst of the call to copy_slice
604
+ // are valid for reads and writes respectively of length `total` since total is the minimum
605
+ // of lengths of the memory areas pointed to. The areas do not overlap, since `dst` is
606
+ // inside guest memory, and buf is a slice (no slices to guest memory are possible without
607
+ // violating rust's aliasing rules).
608
+ let count = unsafe {
609
+ let dst = self . as_ptr ( ) . add ( addr) ;
610
+ copy_slice ( dst, buf. as_ptr ( ) , total)
611
+ } ;
594
612
595
- let count = copy_slice ( slice, buf) ;
596
613
self . bitmap . mark_dirty ( addr, count) ;
597
614
Ok ( count)
598
615
}
@@ -621,11 +638,20 @@ impl<B: BitmapSlice> Bytes<usize> for VolatileSlice<'_, B> {
621
638
return Err ( Error :: OutOfBounds { addr } ) ;
622
639
}
623
640
624
- // SAFETY: Guest memory can't strictly be modeled as a slice because it is
625
- // volatile. Writing to it with what is essentially a fancy memcpy
626
- // won't hurt anything as long as we get the bounds checks right.
627
- let slice = unsafe { self . as_slice ( ) } . split_at ( addr) . 1 ;
628
- Ok ( copy_slice ( buf, slice) )
641
+ let total = buf. len ( ) . min ( self . len ( ) - addr) ;
642
+
643
+ // SAFETY:
644
+ // We check above that `addr` is a valid offset within this volatile slice, and by
645
+ // the invariants of `VolatileSlice::new`, this volatile slice points to contiguous
646
+ // memory of length self.len(). Furthermore, both src and dst of the call to copy_slice
647
+ // are valid for reads and writes respectively of length `total` since total is the minimum
648
+ // of lengths of the memory areas pointed to. The areas do not overlap, since `dst` is
649
+ // inside guest memory, and buf is a slice (no slices to guest memory are possible without
650
+ // violating rust's aliasing rules).
651
+ unsafe {
652
+ let src = self . as_ptr ( ) . add ( addr) ;
653
+ Ok ( copy_slice ( buf. as_mut_ptr ( ) , src, total) )
654
+ }
629
655
}
630
656
631
657
/// # Examples
@@ -1190,12 +1216,16 @@ where
1190
1216
// A fast path for u8/i8
1191
1217
if size_of :: < T > ( ) == 1 {
1192
1218
let source = self . to_slice ( ) ;
1193
- // SAFETY: It is safe because the pointers are range-checked when the slices are
1194
- // created, and they never escape the VolatileSlices.
1195
- let src = unsafe { source. as_slice ( ) } ;
1196
- // SAFETY: Safe because `T` is a one-byte data structure.
1197
- let dst = unsafe { from_raw_parts_mut ( buf. as_mut_ptr ( ) as * mut u8 , buf. len ( ) ) } ;
1198
- return copy_slice ( dst, src) ;
1219
+ let total = buf. len ( ) . min ( source. len ( ) ) ;
1220
+
1221
+ // SAFETY:
1222
+ // - dst is valid for writes of at least `total`, since total <= buf.len()
1223
+ // - src is valid for reads of at least `total` as total <= source.len()
1224
+ // - The regions are non-overlapping as `src` points to guest memory and `buf` is
1225
+ // a slice and thus has to live outside of guest memory (there can be more slices to
1226
+ // guest memory without violating rust's aliasing rules)
1227
+ // - size is always a multiple of alignment, so treating *mut T as *mut u8 is fine
1228
+ return unsafe { copy_slice ( buf. as_mut_ptr ( ) as * mut u8 , source. as_ptr ( ) , total) } ;
1199
1229
}
1200
1230
1201
1231
let mut addr = self . addr ;
@@ -1269,12 +1299,18 @@ where
1269
1299
// A fast path for u8/i8
1270
1300
if size_of :: < T > ( ) == 1 {
1271
1301
let destination = self . to_slice ( ) ;
1272
- // SAFETY: It is safe because the pointers are range-checked when the slices are
1273
- // created, and they never escape the VolatileSlices.
1274
- let dst = unsafe { destination. as_mut_slice ( ) } ;
1275
- // SAFETY: Safe because `T` is a one-byte data structure.
1276
- let src = unsafe { from_raw_parts ( buf. as_ptr ( ) as * const u8 , buf. len ( ) ) } ;
1277
- let count = copy_slice ( dst, src) ;
1302
+ let total = buf. len ( ) . min ( destination. len ( ) ) ;
1303
+
1304
+ // absurd formatting brought to you by clippy
1305
+ let count =
1306
+ // SAFETY:
1307
+ // - dst is valid for writes of at least `total`, since total <= destination.len()
1308
+ // - src is valid for reads of at least `total` as total <= buf.len()
1309
+ // - The regions are non-overlapping as `dst` points to guest memory and `buf` is
1310
+ // a slice and thus has to live outside of guest memory (there can be more slices to
1311
+ // guest memory without violating rust's aliasing rules)
1312
+ // - size is always a multiple of alignment, so treating *const T as *const u8 is fine
1313
+ unsafe { copy_slice ( destination. as_ptr ( ) , buf. as_ptr ( ) as * const u8 , total) } ;
1278
1314
self . bitmap . mark_dirty ( 0 , count) ;
1279
1315
} else {
1280
1316
let mut addr = self . addr ;
@@ -1380,14 +1416,25 @@ mod copy_slice_impl {
1380
1416
total
1381
1417
}
1382
1418
1383
- pub ( super ) fn copy_slice ( dst : & mut [ u8 ] , src : & [ u8 ] ) -> usize {
1384
- let total = min ( src. len ( ) , dst. len ( ) ) ;
1419
+ /// Copies `total` bytes from `src` to `dst`
1420
+ ///
1421
+ /// SAFETY: `src` and `dst` must be point to a contiguously allocated memory region of at least
1422
+ /// length `total`. The regions must not overlap
1423
+ pub ( super ) unsafe fn copy_slice ( dst : * mut u8 , src : * const u8 , total : usize ) -> usize {
1385
1424
if total <= size_of :: < usize > ( ) {
1386
- // SAFETY: we take pointers to slices, which are assured to reference contiguously
1387
- // allocated memory of length total (as total is the minimum of the lengths of the slices)
1388
- unsafe { copy_slice_volatile ( dst. as_mut_ptr ( ) , src. as_ptr ( ) , total) } ;
1425
+ // SAFETY: Invariants of copy_slice_volatile are the same as invariants of copy_slice
1426
+ unsafe {
1427
+ copy_slice_volatile ( dst, src, total) ;
1428
+ } ;
1389
1429
} else {
1390
- dst[ ..total] . copy_from_slice ( & src[ ..total] ) ;
1430
+ // SAFETY:
1431
+ // - Both src and dst are allocated for reads/writes of length `total` by function
1432
+ // invariant
1433
+ // - src and dst are properly aligned, as any alignment is valid for u8
1434
+ // - The regions are not overlapping by function invariant
1435
+ unsafe {
1436
+ std:: ptr:: copy_nonoverlapping ( src, dst, total) ;
1437
+ }
1391
1438
}
1392
1439
1393
1440
total
0 commit comments