@@ -22,8 +22,8 @@ use crate::fluent_generated as fluent;
22
22
23
23
use super :: {
24
24
alloc_range, AllocBytes , AllocId , AllocMap , AllocRange , Allocation , CheckInAllocMsg ,
25
- GlobalAlloc , InterpCx , InterpResult , Machine , MayLeak , Pointer , PointerArithmetic , Provenance ,
26
- Scalar ,
25
+ GlobalAlloc , InterpCx , InterpResult , Machine , MayLeak , Misalignment , Pointer ,
26
+ PointerArithmetic , Provenance , Scalar ,
27
27
} ;
28
28
29
29
#[ derive( Debug , PartialEq , Copy , Clone ) ]
@@ -372,7 +372,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
372
372
self . check_and_deref_ptr (
373
373
ptr,
374
374
size,
375
- M :: enforce_alignment ( self ) . then_some ( align) ,
375
+ align,
376
376
CheckInAllocMsg :: MemoryAccessTest ,
377
377
|alloc_id, offset, prov| {
378
378
let ( size, align) = self
@@ -382,9 +382,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
382
382
)
383
383
}
384
384
385
- /// Check if the given pointer points to live memory of given `size` and `align`
386
- /// (ignoring `M::enforce_alignment`). The caller can control the error message for the
387
- /// out-of-bounds case.
385
+ /// Check if the given pointer points to live memory of given `size` and `align`.
386
+ /// The caller can control the error message for the out-of-bounds case.
388
387
#[ inline( always) ]
389
388
pub fn check_ptr_access_align (
390
389
& self ,
@@ -393,7 +392,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
393
392
align : Align ,
394
393
msg : CheckInAllocMsg ,
395
394
) -> InterpResult < ' tcx > {
396
- self . check_and_deref_ptr ( ptr, size, Some ( align) , msg, |alloc_id, _, _| {
395
+ self . check_and_deref_ptr ( ptr, size, align, msg, |alloc_id, _, _| {
397
396
let ( size, align) = self . get_live_alloc_size_and_align ( alloc_id, msg) ?;
398
397
Ok ( ( size, align, ( ) ) )
399
398
} ) ?;
@@ -402,15 +401,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
402
401
403
402
/// Low-level helper function to check if a ptr is in-bounds and potentially return a reference
404
403
/// to the allocation it points to. Supports both shared and mutable references, as the actual
405
- /// checking is offloaded to a helper closure. `align` defines whether and which alignment check
406
- /// is done.
404
+ /// checking is offloaded to a helper closure.
407
405
///
408
406
/// If this returns `None`, the size is 0; it can however return `Some` even for size 0.
409
407
fn check_and_deref_ptr < T > (
410
408
& self ,
411
409
ptr : Pointer < Option < M :: Provenance > > ,
412
410
size : Size ,
413
- align : Option < Align > ,
411
+ align : Align ,
414
412
msg : CheckInAllocMsg ,
415
413
alloc_size : impl FnOnce (
416
414
AllocId ,
@@ -426,9 +424,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
426
424
throw_ub ! ( DanglingIntPointer ( addr, msg) ) ;
427
425
}
428
426
// Must be aligned.
429
- if let Some ( align) = align {
430
- self . check_offset_align ( addr, align) ?;
431
- }
427
+ self . check_misalign ( Self :: offset_misalignment ( addr, align) ) ?;
432
428
None
433
429
}
434
430
Ok ( ( alloc_id, offset, prov) ) => {
@@ -450,18 +446,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
450
446
}
451
447
// Test align. Check this last; if both bounds and alignment are violated
452
448
// we want the error to be about the bounds.
453
- if let Some ( align) = align {
454
- if M :: use_addr_for_alignment_check ( self ) {
455
- // `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
456
- self . check_offset_align ( ptr. addr ( ) . bytes ( ) , align) ?;
457
- } else {
458
- // Check allocation alignment and offset alignment.
459
- if alloc_align. bytes ( ) < align. bytes ( ) {
460
- throw_ub ! ( AlignmentCheckFailed { has: alloc_align, required: align } ) ;
461
- }
462
- self . check_offset_align ( offset. bytes ( ) , align) ?;
463
- }
464
- }
449
+ self . check_misalign ( self . alloc_misalignment ( ptr, offset, align, alloc_align) ) ?;
465
450
466
451
// We can still be zero-sized in this branch, in which case we have to
467
452
// return `None`.
@@ -470,16 +455,59 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
470
455
} )
471
456
}
472
457
473
- fn check_offset_align ( & self , offset : u64 , align : Align ) -> InterpResult < ' tcx > {
458
+ #[ inline( always) ]
459
+ pub ( super ) fn check_misalign ( & self , misaligned : Option < Misalignment > ) -> InterpResult < ' tcx > {
460
+ if M :: enforce_alignment ( self ) {
461
+ if let Some ( misaligned) = misaligned {
462
+ throw_ub ! ( AlignmentCheckFailed ( misaligned) )
463
+ }
464
+ }
465
+ Ok ( ( ) )
466
+ }
467
+
468
+ #[ must_use]
469
+ fn offset_misalignment ( offset : u64 , align : Align ) -> Option < Misalignment > {
474
470
if offset % align. bytes ( ) == 0 {
475
- Ok ( ( ) )
471
+ None
476
472
} else {
477
473
// The biggest power of two through which `offset` is divisible.
478
474
let offset_pow2 = 1 << offset. trailing_zeros ( ) ;
479
- throw_ub ! ( AlignmentCheckFailed {
480
- has: Align :: from_bytes( offset_pow2) . unwrap( ) ,
481
- required: align
482
- } ) ;
475
+ Some ( Misalignment { has : Align :: from_bytes ( offset_pow2) . unwrap ( ) , required : align } )
476
+ }
477
+ }
478
+
479
+ #[ must_use]
480
+ fn alloc_misalignment (
481
+ & self ,
482
+ ptr : Pointer < Option < M :: Provenance > > ,
483
+ offset : Size ,
484
+ align : Align ,
485
+ alloc_align : Align ,
486
+ ) -> Option < Misalignment > {
487
+ if M :: use_addr_for_alignment_check ( self ) {
488
+ // `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
489
+ Self :: offset_misalignment ( ptr. addr ( ) . bytes ( ) , align)
490
+ } else {
491
+ // Check allocation alignment and offset alignment.
492
+ if alloc_align. bytes ( ) < align. bytes ( ) {
493
+ Some ( Misalignment { has : alloc_align, required : align } )
494
+ } else {
495
+ Self :: offset_misalignment ( offset. bytes ( ) , align)
496
+ }
497
+ }
498
+ }
499
+
500
+ pub ( super ) fn is_ptr_misaligned (
501
+ & self ,
502
+ ptr : Pointer < Option < M :: Provenance > > ,
503
+ align : Align ,
504
+ ) -> Option < Misalignment > {
505
+ match self . ptr_try_get_alloc_id ( ptr) {
506
+ Err ( addr) => Self :: offset_misalignment ( addr, align) ,
507
+ Ok ( ( alloc_id, offset, _prov) ) => {
508
+ let ( _size, alloc_align, _kind) = self . get_alloc_info ( alloc_id) ;
509
+ self . alloc_misalignment ( ptr, offset, align, alloc_align)
510
+ }
483
511
}
484
512
}
485
513
}
@@ -597,7 +625,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
597
625
let ptr_and_alloc = self . check_and_deref_ptr (
598
626
ptr,
599
627
size,
600
- M :: enforce_alignment ( self ) . then_some ( align) ,
628
+ align,
601
629
CheckInAllocMsg :: MemoryAccessTest ,
602
630
|alloc_id, offset, prov| {
603
631
let alloc = self . get_alloc_raw ( alloc_id) ?;
0 commit comments