@@ -14,10 +14,15 @@ use std::ptr;
1414
1515use rustc_ast:: Mutability ;
1616use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
17+ use rustc_hir:: CRATE_HIR_ID ;
1718use rustc_middle:: mir:: display_allocation;
19+ use rustc_middle:: mir:: interpret:: UndefinedBehaviorInfo ;
1820use rustc_middle:: ty:: { self , Instance , ParamEnv , Ty , TyCtxt } ;
21+ use rustc_session:: lint:: builtin:: INVALID_ALIGNMENT ;
1922use rustc_target:: abi:: { Align , HasDataLayout , Size } ;
2023
24+ use crate :: const_eval:: CheckAlignment ;
25+
2126use super :: {
2227 alloc_range, AllocId , AllocMap , AllocRange , Allocation , CheckInAllocMsg , GlobalAlloc , InterpCx ,
2328 InterpResult , Machine , MayLeak , Pointer , PointerArithmetic , Provenance , Scalar ,
@@ -377,7 +382,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
377382 ptr,
378383 size,
379384 align,
380- /* force_alignment_check */ true ,
385+ CheckAlignment :: Error ,
381386 msg,
382387 |alloc_id, _, _| {
383388 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> {
396401 ptr : Pointer < Option < M :: Provenance > > ,
397402 size : Size ,
398403 align : Align ,
399- force_alignment_check : bool ,
404+ check : CheckAlignment ,
400405 msg : CheckInAllocMsg ,
401406 alloc_size : impl FnOnce (
402407 AllocId ,
403408 Size ,
404409 M :: ProvenanceExtra ,
405410 ) -> InterpResult < ' tcx , ( Size , Align , T ) > ,
406411 ) -> 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-
420412 Ok ( match self . ptr_try_get_alloc_id ( ptr) {
421413 Err ( addr) => {
422414 // 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> {
425417 throw_ub ! ( DanglingIntPointer ( addr, msg) ) ;
426418 }
427419 // 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 ) ?;
430422 }
431423 None
432424 }
@@ -449,16 +441,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
449441 }
450442 // Test align. Check this last; if both bounds and alignment are violated
451443 // we want the error to be about the bounds.
452- if force_alignment_check {
444+ if check . should_check ( ) {
453445 if M :: use_addr_for_alignment_check ( self ) {
454446 // `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 ) ?;
456448 } else {
457449 // Check allocation alignment and offset alignment.
458450 if alloc_align. bytes ( ) < align. bytes ( ) {
459- throw_ub ! ( AlignmentCheckFailed { has : alloc_align, required : align } ) ;
451+ self . alignment_check_failed ( alloc_align, align, check ) ? ;
460452 }
461- check_offset_align ( offset. bytes ( ) , align) ?;
453+ self . check_offset_align ( offset. bytes ( ) , align, check ) ?;
462454 }
463455 }
464456
@@ -468,6 +460,55 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
468460 }
469461 } )
470462 }
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+ }
471512}
472513
473514/// Allocation accessors
0 commit comments