77use std:: borrow:: Cow ;
88use std:: fmt:: Write ;
99use std:: hash:: Hash ;
10+ use std:: mem;
1011use std:: num:: NonZero ;
1112
1213use either:: { Left , Right } ;
@@ -288,6 +289,8 @@ struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> {
288289 /// If this is `Some`, then `reset_provenance_and_padding` must be true (but not vice versa:
289290 /// we might not track data vs padding bytes if the operand isn't stored in memory anyway).
290291 data_bytes : Option < RangeSet > ,
292+ /// True if we are inside of `MaybeDangling`. This disables pointer access checks.
293+ may_dangle : bool ,
291294}
292295
293296impl < ' rt , ' tcx , M : Machine < ' tcx > > ValidityVisitor < ' rt , ' tcx , M > {
@@ -489,7 +492,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
489492 if place. layout . is_unsized ( ) {
490493 self . check_wide_ptr_meta ( place. meta ( ) , place. layout ) ?;
491494 }
492- // Make sure this is dereferenceable and all.
495+
496+ // Determine size and alignment of pointee.
493497 let size_and_align = try_validation ! (
494498 self . ecx. size_and_align_of_val( & place) ,
495499 self . path,
@@ -503,27 +507,33 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
503507 // alignment and size determined by the layout (size will be 0,
504508 // alignment should take attributes into account).
505509 . unwrap_or_else ( || ( place. layout . size , place. layout . align . abi ) ) ;
506- // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
507- try_validation ! (
508- self . ecx. check_ptr_access(
509- place. ptr( ) ,
510- size,
511- CheckInAllocMsg :: Dereferenceable , // will anyway be replaced by validity message
512- ) ,
513- self . path,
514- Ub ( DanglingIntPointer { addr: 0 , .. } ) => NullPtr { ptr_kind, maybe: false } ,
515- Ub ( DanglingIntPointer { addr: i, .. } ) => DanglingPtrNoProvenance {
516- ptr_kind,
517- // FIXME this says "null pointer" when null but we need translate
518- pointer: format!( "{}" , Pointer :: <Option <AllocId >>:: without_provenance( i) )
519- } ,
520- Ub ( PointerOutOfBounds { .. } ) => DanglingPtrOutOfBounds {
521- ptr_kind
522- } ,
523- Ub ( PointerUseAfterFree ( ..) ) => DanglingPtrUseAfterFree {
524- ptr_kind,
525- } ,
526- ) ;
510+
511+ if !self . may_dangle {
512+ // Make sure this is dereferenceable and all.
513+
514+ // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
515+ // Call `check_ptr_access` to avoid checking alignment here.
516+ try_validation ! (
517+ self . ecx. check_ptr_access(
518+ place. ptr( ) ,
519+ size,
520+ CheckInAllocMsg :: Dereferenceable , // will anyway be replaced by validity message
521+ ) ,
522+ self . path,
523+ Ub ( DanglingIntPointer { addr: 0 , .. } ) => NullPtr { ptr_kind, maybe: false } ,
524+ Ub ( DanglingIntPointer { addr: i, .. } ) => DanglingPtrNoProvenance {
525+ ptr_kind,
526+ pointer: format!( "{}" , Pointer :: <Option <AllocId >>:: without_provenance( i) )
527+ } ,
528+ Ub ( PointerOutOfBounds { .. } ) => DanglingPtrOutOfBounds {
529+ ptr_kind
530+ } ,
531+ Ub ( PointerUseAfterFree ( ..) ) => DanglingPtrUseAfterFree {
532+ ptr_kind,
533+ } ,
534+ ) ;
535+ }
536+
527537 try_validation ! (
528538 self . ecx. check_ptr_align(
529539 place. ptr( ) ,
@@ -536,8 +546,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
536546 found_bytes: has. bytes( )
537547 } ,
538548 ) ;
539- // Make sure this is non-null. We checked dereferenceability above, but if `size` is zero
540- // that does not imply non-null.
549+
550+ // Make sure this is non-null. This is obviously needed when `may_dangle` is set,
551+ // but even if we did check dereferenceability above that would still allow null
552+ // pointers if `size` is zero.
541553 let scalar = Scalar :: from_maybe_pointer ( place. ptr ( ) , self . ecx ) ;
542554 if self . ecx . scalar_may_be_null ( scalar) ? {
543555 let maybe = !M :: Provenance :: OFFSET_IS_ADDR && matches ! ( scalar, Scalar :: Ptr ( ..) ) ;
@@ -1265,6 +1277,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
12651277 ty:: PatternKind :: Or ( _patterns) => { }
12661278 }
12671279 }
1280+ ty:: Adt ( adt, _) if adt. is_maybe_dangling ( ) => {
1281+ let old_may_dangle = mem:: replace ( & mut self . may_dangle , true ) ;
1282+
1283+ let inner = self . ecx . project_field ( val, FieldIdx :: ZERO ) ?;
1284+ self . visit_value ( & inner) ?;
1285+
1286+ self . may_dangle = old_may_dangle;
1287+ }
12681288 _ => {
12691289 // default handler
12701290 try_validation ! (
@@ -1350,6 +1370,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
13501370 ecx,
13511371 reset_provenance_and_padding,
13521372 data_bytes : reset_padding. then_some ( RangeSet ( Vec :: new ( ) ) ) ,
1373+ may_dangle : false ,
13531374 } ;
13541375 v. visit_value ( val) ?;
13551376 v. reset_padding ( val) ?;
0 commit comments