@@ -14,10 +14,15 @@ use std::ptr;
14
14
15
15
use rustc_ast:: Mutability ;
16
16
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
17
+ use rustc_hir:: CRATE_HIR_ID ;
17
18
use rustc_middle:: mir:: display_allocation;
19
+ use rustc_middle:: mir:: interpret:: UndefinedBehaviorInfo ;
18
20
use rustc_middle:: ty:: { self , Instance , ParamEnv , Ty , TyCtxt } ;
21
+ use rustc_session:: lint:: builtin:: INVALID_ALIGNMENT ;
19
22
use rustc_target:: abi:: { Align , HasDataLayout , Size } ;
20
23
24
+ use crate :: const_eval:: CheckAlignment ;
25
+
21
26
use super :: {
22
27
alloc_range, AllocId , AllocMap , AllocRange , Allocation , CheckInAllocMsg , GlobalAlloc , InterpCx ,
23
28
InterpResult , Machine , MayLeak , Pointer , PointerArithmetic , Provenance , Scalar ,
@@ -377,7 +382,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
377
382
ptr,
378
383
size,
379
384
align,
380
- /* force_alignment_check */ true ,
385
+ CheckAlignment :: Error ,
381
386
msg,
382
387
|alloc_id, _, _| {
383
388
let ( size, align) = self . get_live_alloc_size_and_align ( alloc_id) ?;
@@ -396,27 +401,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
396
401
ptr : Pointer < Option < M :: Provenance > > ,
397
402
size : Size ,
398
403
align : Align ,
399
- force_alignment_check : bool ,
404
+ check : CheckAlignment ,
400
405
msg : CheckInAllocMsg ,
401
406
alloc_size : impl FnOnce (
402
407
AllocId ,
403
408
Size ,
404
409
M :: ProvenanceExtra ,
405
410
) -> InterpResult < ' tcx , ( Size , Align , T ) > ,
406
411
) -> InterpResult < ' tcx , Option < T > > {
407
- fn check_offset_align < ' tcx > ( offset : u64 , align : Align ) -> InterpResult < ' tcx > {
408
- if offset % align. bytes ( ) == 0 {
409
- Ok ( ( ) )
410
- } else {
411
- // The biggest power of two through which `offset` is divisible.
412
- let offset_pow2 = 1 << offset. trailing_zeros ( ) ;
413
- throw_ub ! ( AlignmentCheckFailed {
414
- has: Align :: from_bytes( offset_pow2) . unwrap( ) ,
415
- required: align,
416
- } )
417
- }
418
- }
419
-
420
412
Ok ( match self . ptr_try_get_alloc_id ( ptr) {
421
413
Err ( addr) => {
422
414
// We couldn't get a proper allocation. This is only okay if the access size is 0,
@@ -425,8 +417,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
425
417
throw_ub ! ( DanglingIntPointer ( addr, msg) ) ;
426
418
}
427
419
// Must be aligned.
428
- if force_alignment_check {
429
- check_offset_align ( addr, align) ?;
420
+ if check . should_check ( ) {
421
+ self . check_offset_align ( addr, align, check ) ?;
430
422
}
431
423
None
432
424
}
@@ -449,16 +441,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
449
441
}
450
442
// Test align. Check this last; if both bounds and alignment are violated
451
443
// we want the error to be about the bounds.
452
- if force_alignment_check {
444
+ if check . should_check ( ) {
453
445
if M :: use_addr_for_alignment_check ( self ) {
454
446
// `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
455
- check_offset_align ( ptr. addr ( ) . bytes ( ) , align) ?;
447
+ self . check_offset_align ( ptr. addr ( ) . bytes ( ) , align, check ) ?;
456
448
} else {
457
449
// Check allocation alignment and offset alignment.
458
450
if alloc_align. bytes ( ) < align. bytes ( ) {
459
- throw_ub ! ( AlignmentCheckFailed { has : alloc_align, required : align } ) ;
451
+ self . alignment_check_failed ( alloc_align, align, check ) ? ;
460
452
}
461
- check_offset_align ( offset. bytes ( ) , align) ?;
453
+ self . check_offset_align ( offset. bytes ( ) , align, check ) ?;
462
454
}
463
455
}
464
456
@@ -468,6 +460,55 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
468
460
}
469
461
} )
470
462
}
463
+
464
+ fn check_offset_align (
465
+ & self ,
466
+ offset : u64 ,
467
+ align : Align ,
468
+ check : CheckAlignment ,
469
+ ) -> InterpResult < ' tcx > {
470
+ if offset % align. bytes ( ) == 0 {
471
+ Ok ( ( ) )
472
+ } else {
473
+ // The biggest power of two through which `offset` is divisible.
474
+ let offset_pow2 = 1 << offset. trailing_zeros ( ) ;
475
+ self . alignment_check_failed ( Align :: from_bytes ( offset_pow2) . unwrap ( ) , align, check)
476
+ }
477
+ }
478
+
479
+ fn alignment_check_failed (
480
+ & self ,
481
+ has : Align ,
482
+ required : Align ,
483
+ check : CheckAlignment ,
484
+ ) -> InterpResult < ' tcx , ( ) > {
485
+ match check {
486
+ CheckAlignment :: Error => {
487
+ throw_ub ! ( AlignmentCheckFailed { has, required } )
488
+ }
489
+ CheckAlignment :: No => span_bug ! (
490
+ self . cur_span( ) ,
491
+ "`alignment_check_failed` called when no alignment check requested"
492
+ ) ,
493
+ CheckAlignment :: FutureIncompat => self . tcx . struct_span_lint_hir (
494
+ INVALID_ALIGNMENT ,
495
+ self . stack ( ) . iter ( ) . find_map ( |frame| frame. lint_root ( ) ) . unwrap_or ( CRATE_HIR_ID ) ,
496
+ self . cur_span ( ) ,
497
+ UndefinedBehaviorInfo :: AlignmentCheckFailed { has, required } . to_string ( ) ,
498
+ |db| {
499
+ let mut stacktrace = self . generate_stacktrace ( ) ;
500
+ // Filter out `requires_caller_location` frames.
501
+ stacktrace
502
+ . retain ( |frame| !frame. instance . def . requires_caller_location ( * self . tcx ) ) ;
503
+ for frame in stacktrace {
504
+ db. span_label ( frame. span , format ! ( "inside `{}`" , frame. instance) ) ;
505
+ }
506
+ db
507
+ } ,
508
+ ) ,
509
+ }
510
+ Ok ( ( ) )
511
+ }
471
512
}
472
513
473
514
/// Allocation accessors
0 commit comments